1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 19:19:56 +00:00

Introduce a separate class to control world date and time

This commit is contained in:
Andrei Kortunov 2020-06-03 11:32:28 +04:00
parent 2eb9d4ad4e
commit 81805b7263
12 changed files with 340 additions and 221 deletions

View file

@ -71,7 +71,7 @@ add_openmw_dir (mwworld
actionequip timestamp actionalchemy cellstore actionapply actioneat actionequip timestamp actionalchemy cellstore actionapply actioneat
store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager
cellpreloader cellpreloader datetimemanager
) )
add_openmw_dir (mwphysics add_openmw_dir (mwphysics

View file

@ -48,6 +48,7 @@ namespace ESM
struct EffectList; struct EffectList;
struct CreatureLevList; struct CreatureLevList;
struct ItemLevList; struct ItemLevList;
struct TimeStamp;
} }
namespace MWRender namespace MWRender
@ -204,24 +205,14 @@ namespace MWBase
virtual void advanceTime (double hours, bool incremental = false) = 0; virtual void advanceTime (double hours, bool incremental = false) = 0;
///< Advance in-game time. ///< Advance in-game time.
virtual void setHour (double hour) = 0;
///< Set in-game time hour.
virtual void setMonth (int month) = 0;
///< Set in-game time month.
virtual void setDay (int day) = 0;
///< Set in-game time day.
virtual int getDay() const = 0;
virtual int getMonth() const = 0;
virtual int getYear() const = 0;
virtual std::string getMonthName (int month = -1) const = 0; virtual std::string getMonthName (int month = -1) const = 0;
///< Return name of month (-1: current month) ///< Return name of month (-1: current month)
virtual MWWorld::TimeStamp getTimeStamp() const = 0; virtual MWWorld::TimeStamp getTimeStamp() const = 0;
///< Return current in-game time stamp. ///< Return current in-game time and number of day since new game start.
virtual ESM::EpochTimeStamp getEpochTimeStamp() const = 0;
///< Return current in-game date and time.
virtual bool toggleSky() = 0; virtual bool toggleSky() = 0;
///< \return Resulting mode ///< \return Resulting mode

View file

@ -150,11 +150,10 @@ namespace MWGui
if (hour >= 13) hour -= 12; if (hour >= 13) hour -= 12;
if (hour == 0) hour = 12; if (hour == 0) hour = 12;
std::string dateTimeText = ESM::EpochTimeStamp currentDate = MWBase::Environment::get().getWorld()->getEpochTimeStamp();
MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getDay ()) + " " int daysPassed = MWBase::Environment::get().getWorld()->getTimeStamp().getDay();
+ month + " (#{sDay} " + MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay()) std::string formattedHour = pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}";
+ ") " + MyGUI::utility::toString(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); std::string dateTimeText = Misc::StringUtils::format("%i %s (#{sDay} %i) %i %s", currentDate.mDay, month, daysPassed, hour, formattedHour);
mDateTimeText->setCaptionWithReplacing (dateTimeText); mDateTimeText->setCaptionWithReplacing (dateTimeText);
} }

View file

@ -213,11 +213,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
profile.mPlayerClassId = classId; profile.mPlayerClassId = classId;
profile.mPlayerCell = world.getCellName(); profile.mPlayerCell = world.getCellName();
profile.mInGameTime = world.getEpochTimeStamp();
profile.mInGameTime.mGameHour = world.getTimeStamp().getHour();
profile.mInGameTime.mDay = world.getDay();
profile.mInGameTime.mMonth = world.getMonth();
profile.mInGameTime.mYear = world.getYear();
profile.mTimePlayed = mTimePlayed; profile.mTimePlayed = mTimePlayed;
profile.mDescription = description; profile.mDescription = description;

View file

@ -0,0 +1,227 @@
#include "datetimemanager.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "esmstore.hpp"
#include "globals.hpp"
#include "timestamp.hpp"
namespace
{
static int getDaysPerMonth(int month)
{
switch (month)
{
case 0: return 31;
case 1: return 28;
case 2: return 31;
case 3: return 30;
case 4: return 31;
case 5: return 30;
case 6: return 31;
case 7: return 31;
case 8: return 30;
case 9: return 31;
case 10: return 30;
case 11: return 31;
}
throw std::runtime_error ("month out of range");
}
}
namespace MWWorld
{
void DateTimeManager::setup(Globals& globalVariables)
{
mGameHour = globalVariables["gamehour"].getFloat();
mDaysPassed = globalVariables["dayspassed"].getInteger();
mDay = globalVariables["day"].getInteger();
mMonth = globalVariables["month"].getInteger();
mYear = globalVariables["year"].getInteger();
mTimeScale = globalVariables["timescale"].getFloat();
}
void DateTimeManager::setHour(double hour)
{
if (hour < 0)
hour = 0;
int days = static_cast<int>(hour / 24);
hour = std::fmod(hour, 24);
mGameHour = static_cast<float>(hour);
if (days > 0)
setDay(days + mDay);
}
void DateTimeManager::setDay(int day)
{
if (day < 1)
day = 1;
int month = mMonth;
while (true)
{
int days = getDaysPerMonth(month);
if (day <= days)
break;
if (month < 11)
{
++month;
}
else
{
month = 0;
mYear++;
}
day -= days;
}
mDay = day;
mMonth = month;
}
TimeStamp DateTimeManager::getTimeStamp() const
{
return TimeStamp(mGameHour, mDaysPassed);
}
float DateTimeManager::getTimeScaleFactor() const
{
return mTimeScale;
}
ESM::EpochTimeStamp DateTimeManager::getEpochTimeStamp() const
{
ESM::EpochTimeStamp timeStamp;
timeStamp.mGameHour = mGameHour;
timeStamp.mDay = mDay;
timeStamp.mMonth = mMonth;
timeStamp.mYear = mYear;
return timeStamp;
}
void DateTimeManager::setMonth(int month)
{
if (month < 0)
month = 0;
int years = month / 12;
month = month % 12;
int days = getDaysPerMonth(month);
if (mDay > days)
mDay = days;
mMonth = month;
if (years > 0)
mYear += years;
}
void DateTimeManager::advanceTime(double hours, Globals& globalVariables)
{
hours += mGameHour;
setHour(hours);
int days = static_cast<int>(hours / 24);
if (days > 0)
mDaysPassed += days;
globalVariables["gamehour"].setFloat(mGameHour);
globalVariables["dayspassed"].setInteger(mDaysPassed);
globalVariables["day"].setInteger(mDay);
globalVariables["month"].setInteger(mMonth);
globalVariables["year"].setInteger(mYear);
}
std::string DateTimeManager::getMonthName(int month) const
{
if (month == -1)
month = mMonth;
const int months = 12;
if (month < 0 || month >= months)
return std::string();
static const char *monthNames[months] =
{
"sMonthMorningstar", "sMonthSunsdawn", "sMonthFirstseed", "sMonthRainshand",
"sMonthSecondseed", "sMonthMidyear", "sMonthSunsheight", "sMonthLastseed",
"sMonthHeartfire", "sMonthFrostfall", "sMonthSunsdusk", "sMonthEveningstar"
};
const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(monthNames[month]);
return setting->mValue.getString();
}
bool DateTimeManager::updateGlobalFloat(const std::string& name, float value)
{
if (name=="gamehour")
{
setHour(value);
return true;
}
else if (name=="day")
{
setDay(static_cast<int>(value));
return true;
}
else if (name=="month")
{
setMonth(static_cast<int>(value));
return true;
}
else if (name=="year")
{
mYear = static_cast<int>(value);
}
else if (name=="timescale")
{
mTimeScale = value;
}
else if (name=="dayspassed")
{
mDaysPassed = static_cast<int>(value);
}
return false;
}
bool DateTimeManager::updateGlobalInt(const std::string& name, int value)
{
if (name=="gamehour")
{
setHour(static_cast<float>(value));
return true;
}
else if (name=="day")
{
setDay(value);
return true;
}
else if (name=="month")
{
setMonth(value);
return true;
}
else if (name=="year")
{
mYear = value;
}
else if (name=="timescale")
{
mTimeScale = static_cast<float>(value);
}
else if (name=="dayspassed")
{
mDaysPassed = value;
}
return false;
}
}

View file

@ -0,0 +1,43 @@
#ifndef GAME_MWWORLD_DATETIMEMANAGER_H
#define GAME_MWWORLD_DATETIMEMANAGER_H
#include <string>
namespace ESM
{
struct EpochTimeStamp;
}
namespace MWWorld
{
class Globals;
class TimeStamp;
class DateTimeManager
{
int mDaysPassed = 0;
int mDay = 0;
int mMonth = 0;
int mYear = 0;
float mGameHour = 0.f;
float mTimeScale = 0.f;
void setHour(double hour);
void setDay(int day);
void setMonth(int month);
public:
std::string getMonthName(int month) const;
TimeStamp getTimeStamp() const;
ESM::EpochTimeStamp getEpochTimeStamp() const;
float getTimeScaleFactor() const;
void advanceTime(double hours, Globals& globalVariables);
void setup(Globals& globalVariables);
bool updateGlobalInt(const std::string& name, int value);
bool updateGlobalFloat(const std::string& name, float value);
};
}
#endif

View file

@ -2,10 +2,9 @@
#include <stdexcept> #include <stdexcept>
#include <components/misc/stringops.hpp>
#include <components/esm/esmwriter.hpp> #include <components/esm/esmwriter.hpp>
#include <components/esm/esmreader.hpp> #include <components/esm/esmreader.hpp>
#include <components/misc/stringops.hpp>
#include "esmstore.hpp" #include "esmstore.hpp"

View file

@ -60,6 +60,7 @@
#include "../mwphysics/object.hpp" #include "../mwphysics/object.hpp"
#include "../mwphysics/constants.hpp" #include "../mwphysics/constants.hpp"
#include "datetimemanager.hpp"
#include "player.hpp" #include "player.hpp"
#include "manualref.hpp" #include "manualref.hpp"
#include "cellstore.hpp" #include "cellstore.hpp"
@ -121,33 +122,11 @@ namespace MWWorld
LoadersContainer mLoaders; LoadersContainer mLoaders;
}; };
int World::getDaysPerMonth (int month) const
{
switch (month)
{
case 0: return 31;
case 1: return 28;
case 2: return 31;
case 3: return 30;
case 4: return 31;
case 5: return 30;
case 6: return 31;
case 7: return 31;
case 8: return 30;
case 9: return 31;
case 10: return 30;
case 11: return 31;
}
throw std::runtime_error ("month out of range");
}
void World::adjustSky() void World::adjustSky()
{ {
if (mSky && (isCellExterior() || isCellQuasiExterior())) if (mSky && (isCellExterior() || isCellQuasiExterior()))
{ {
mRendering->skySetDate (mDay->getInteger(), mMonth->getInteger()); updateSkyDate();
mRendering->setSkyEnabled(true); mRendering->setSkyEnabled(true);
} }
else else
@ -193,6 +172,8 @@ namespace MWWorld
if (mEsm[0].getFormat() == 0) if (mEsm[0].getFormat() == 0)
ensureNeededRecords(); ensureNeededRecords();
mCurrentDate.reset(new DateTimeManager());
fillGlobalVariables(); fillGlobalVariables();
mStore.setUp(true); mStore.setUp(true);
@ -227,13 +208,7 @@ namespace MWWorld
void World::fillGlobalVariables() void World::fillGlobalVariables()
{ {
mGlobalVariables.fill (mStore); mGlobalVariables.fill (mStore);
mCurrentDate->setup(mGlobalVariables);
mGameHour = &mGlobalVariables["gamehour"];
mDaysPassed = &mGlobalVariables["dayspassed"];
mDay = &mGlobalVariables["day"];
mMonth = &mGlobalVariables["month"];
mYear = &mGlobalVariables["year"];
mTimeScale = &mGlobalVariables["timescale"];
} }
void World::startNewGame (bool bypass) void World::startNewGame (bool bypass)
@ -310,6 +285,7 @@ namespace MWWorld
mPhysics->toggleCollisionMode(); mPhysics->toggleCollisionMode();
MWBase::Environment::get().getWindowManager()->updatePlayer(); MWBase::Environment::get().getWindowManager()->updatePlayer();
mCurrentDate->setup(mGlobalVariables);
} }
void World::clear() void World::clear()
@ -639,26 +615,20 @@ namespace MWWorld
void World::setGlobalInt (const std::string& name, int value) void World::setGlobalInt (const std::string& name, int value)
{ {
if (name=="gamehour") bool dateUpdated = mCurrentDate->updateGlobalInt(name, value);
setHour (value); if (dateUpdated)
else if (name=="day") updateSkyDate();
setDay (value);
else if (name=="month") mGlobalVariables[name].setInteger (value);
setMonth (value);
else
mGlobalVariables[name].setInteger (value);
} }
void World::setGlobalFloat (const std::string& name, float value) void World::setGlobalFloat (const std::string& name, float value)
{ {
if (name=="gamehour") bool dateUpdated = mCurrentDate->updateGlobalFloat(name, value);
setHour (value); if (dateUpdated)
else if (name=="day") updateSkyDate();
setDay(static_cast<int>(value));
else if (name=="month") mGlobalVariables[name].setFloat(value);
setMonth(static_cast<int>(value));
else
mGlobalVariables[name].setFloat (value);
} }
int World::getGlobalInt (const std::string& name) const int World::getGlobalInt (const std::string& name) const
@ -676,6 +646,11 @@ namespace MWWorld
return mGlobalVariables.getType (name); return mGlobalVariables.getType (name);
} }
std::string World::getMonthName (int month) const
{
return mCurrentDate->getMonthName(month);
}
std::string World::getCellName (const MWWorld::CellStore *cell) const std::string World::getCellName (const MWWorld::CellStore *cell) const
{ {
if (!cell) if (!cell)
@ -894,130 +869,29 @@ namespace MWWorld
} }
mWeatherManager->advanceTime (hours, incremental); mWeatherManager->advanceTime (hours, incremental);
mCurrentDate->advanceTime(hours, mGlobalVariables);
updateSkyDate();
if (!incremental) if (!incremental)
{ {
mRendering->notifyWorldSpaceChanged(); mRendering->notifyWorldSpaceChanged();
mProjectileManager->clear(); mProjectileManager->clear();
} }
hours += mGameHour->getFloat();
setHour (hours);
int days = static_cast<int>(hours / 24);
if (days>0)
mDaysPassed->setInteger (
days + mDaysPassed->getInteger());
} }
void World::setHour (double hour) float World::getTimeScaleFactor() const
{ {
if (hour<0) return mCurrentDate->getTimeScaleFactor();
hour = 0;
int days = static_cast<int>(hour / 24);
hour = std::fmod (hour, 24);
mGameHour->setFloat(static_cast<float>(hour));
if (days>0)
setDay (days + mDay->getInteger());
}
void World::setDay (int day)
{
if (day<1)
day = 1;
int month = mMonth->getInteger();
while (true)
{
int days = getDaysPerMonth (month);
if (day<=days)
break;
if (month<11)
{
++month;
}
else
{
month = 0;
mYear->setInteger(mYear->getInteger()+1);
}
day -= days;
}
mDay->setInteger(day);
mMonth->setInteger(month);
mRendering->skySetDate(day, month);
}
void World::setMonth (int month)
{
if (month<0)
month = 0;
int years = month / 12;
month = month % 12;
int days = getDaysPerMonth (month);
if (mDay->getInteger()>days)
mDay->setInteger (days);
mMonth->setInteger (month);
if (years>0)
mYear->setInteger (years+mYear->getInteger());
mRendering->skySetDate (mDay->getInteger(), month);
}
int World::getDay() const
{
return mDay->getInteger();
}
int World::getMonth() const
{
return mMonth->getInteger();
}
int World::getYear() const
{
return mYear->getInteger();
}
std::string World::getMonthName (int month) const
{
if (month==-1)
month = getMonth();
const int months = 12;
if (month<0 || month>=months)
return "";
static const char *monthNames[months] =
{
"sMonthMorningstar", "sMonthSunsdawn", "sMonthFirstseed", "sMonthRainshand",
"sMonthSecondseed", "sMonthMidyear", "sMonthSunsheight", "sMonthLastseed",
"sMonthHeartfire", "sMonthFrostfall", "sMonthSunsdusk", "sMonthEveningstar"
};
return mStore.get<ESM::GameSetting>().find (monthNames[month])->mValue.getString();
} }
TimeStamp World::getTimeStamp() const TimeStamp World::getTimeStamp() const
{ {
return TimeStamp (mGameHour->getFloat(), mDaysPassed->getInteger()); return mCurrentDate->getTimeStamp();
}
ESM::EpochTimeStamp World::getEpochTimeStamp() const
{
return mCurrentDate->getEpochTimeStamp();
} }
bool World::toggleSky() bool World::toggleSky()
@ -1042,11 +916,6 @@ namespace MWWorld
mRendering->skySetMoonColour (red); mRendering->skySetMoonColour (red);
} }
float World::getTimeScaleFactor() const
{
return mTimeScale->getFloat();
}
void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
{ {
mPhysics->clearQueuedMovement(); mPhysics->clearQueuedMovement();
@ -1089,6 +958,8 @@ namespace MWWorld
changeToExteriorCell (position, adjustPlayerPos, changeEvent); changeToExteriorCell (position, adjustPlayerPos, changeEvent);
else else
changeToInteriorCell (cellId.mWorldspace, position, adjustPlayerPos, changeEvent); changeToInteriorCell (cellId.mWorldspace, position, adjustPlayerPos, changeEvent);
mCurrentDate->setup(mGlobalVariables);
} }
void World::markCellAsUnchanged() void World::markCellAsUnchanged()
@ -3968,4 +3839,10 @@ namespace MWWorld
mNavigator->reportStats(frameNumber, stats); mNavigator->reportStats(frameNumber, stats);
mPhysics->reportStats(frameNumber, stats); mPhysics->reportStats(frameNumber, stats);
} }
void World::updateSkyDate()
{
ESM::EpochTimeStamp currentDate = mCurrentDate->getEpochTimeStamp();
mRendering->skySetDate(currentDate.mDay, currentDate.mMonth);
}
} }

View file

@ -69,6 +69,7 @@ namespace MWPhysics
namespace MWWorld namespace MWWorld
{ {
class DateTimeManager;
class WeatherManager; class WeatherManager;
class Player; class Player;
class ProjectileManager; class ProjectileManager;
@ -85,13 +86,6 @@ namespace MWWorld
LocalScripts mLocalScripts; LocalScripts mLocalScripts;
MWWorld::Globals mGlobalVariables; MWWorld::Globals mGlobalVariables;
ESM::Variant* mGameHour;
ESM::Variant* mDaysPassed;
ESM::Variant* mDay;
ESM::Variant* mMonth;
ESM::Variant* mYear;
ESM::Variant* mTimeScale;
Cells mCells; Cells mCells;
std::string mCurrentWorldSpace; std::string mCurrentWorldSpace;
@ -102,6 +96,7 @@ namespace MWWorld
std::unique_ptr<MWRender::RenderingManager> mRendering; std::unique_ptr<MWRender::RenderingManager> mRendering;
std::unique_ptr<MWWorld::Scene> mWorldScene; std::unique_ptr<MWWorld::Scene> mWorldScene;
std::unique_ptr<MWWorld::WeatherManager> mWeatherManager; std::unique_ptr<MWWorld::WeatherManager> mWeatherManager;
std::unique_ptr<MWWorld::DateTimeManager> mCurrentDate;
std::shared_ptr<ProjectileManager> mProjectileManager; std::shared_ptr<ProjectileManager> mProjectileManager;
bool mSky; bool mSky;
@ -139,7 +134,6 @@ namespace MWWorld
World& operator= (const World&); World& operator= (const World&);
void updateWeather(float duration, bool paused = false); void updateWeather(float duration, bool paused = false);
int getDaysPerMonth (int month) const;
void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags); void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags);
@ -173,6 +167,8 @@ namespace MWWorld
void fillGlobalVariables(); void fillGlobalVariables();
void updateSkyDate();
/** /**
* @brief loadContentFiles - Loads content files (esm,esp,omwgame,omwaddon) * @brief loadContentFiles - Loads content files (esm,esp,omwgame,omwaddon)
* @param fileCollections- Container which holds content file names and their paths * @param fileCollections- Container which holds content file names and their paths
@ -318,24 +314,14 @@ namespace MWWorld
void advanceTime (double hours, bool incremental = false) override; void advanceTime (double hours, bool incremental = false) override;
///< Advance in-game time. ///< Advance in-game time.
void setHour (double hour) override;
///< Set in-game time hour.
void setMonth (int month) override;
///< Set in-game time month.
void setDay (int day) override;
///< Set in-game time day.
int getDay() const override;
int getMonth() const override;
int getYear() const override;
std::string getMonthName (int month = -1) const override; std::string getMonthName (int month = -1) const override;
///< Return name of month (-1: current month) ///< Return name of month (-1: current month)
TimeStamp getTimeStamp() const override; TimeStamp getTimeStamp() const override;
///< Return current in-game time stamp. ///< Return current in-game time and number of day since new game start.
ESM::EpochTimeStamp getEpochTimeStamp() const override;
///< Return current in-game date and time.
bool toggleSky() override; bool toggleSky() override;
///< \return Resulting mode ///< \return Resulting mode

View file

@ -14,6 +14,14 @@ struct TimeStamp
int mDay; int mDay;
}; };
struct EpochTimeStamp
{
float mGameHour;
int mDay;
int mMonth;
int mYear;
};
// Pixel color value. Standard four-byte rr,gg,bb,aa format. // Pixel color value. Standard four-byte rr,gg,bb,aa format.
typedef uint32_t Color; typedef uint32_t Color;

View file

@ -2,7 +2,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp"
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
int ESM::SavedGame::sCurrentFormat = 10; int ESM::SavedGame::sCurrentFormat = 10;

View file

@ -4,6 +4,8 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include "defs.hpp"
namespace ESM namespace ESM
{ {
class ESMReader; class ESMReader;
@ -17,14 +19,6 @@ namespace ESM
static int sCurrentFormat; static int sCurrentFormat;
struct TimeStamp
{
float mGameHour;
int mDay;
int mMonth;
int mYear;
};
std::vector<std::string> mContentFiles; std::vector<std::string> mContentFiles;
std::string mPlayerName; std::string mPlayerName;
int mPlayerLevel; int mPlayerLevel;
@ -36,7 +30,7 @@ namespace ESM
std::string mPlayerClassName; std::string mPlayerClassName;
std::string mPlayerCell; std::string mPlayerCell;
TimeStamp mInGameTime; EpochTimeStamp mInGameTime;
double mTimePlayed; double mTimePlayed;
std::string mDescription; std::string mDescription;
std::vector<char> mScreenshot; // raw jpg-encoded data std::vector<char> mScreenshot; // raw jpg-encoded data