mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-21 09:53:52 +00:00
Merge branch 'lua_pause' into 'master'
A bit more lua bindings for game time See merge request OpenMW/openmw!1455
This commit is contained in:
commit
0826de7edf
25 changed files with 566 additions and 169 deletions
|
@ -19,36 +19,36 @@ namespace MWLua
|
||||||
|
|
||||||
sol::function getAsyncPackageInitializer(const Context& context)
|
sol::function getAsyncPackageInitializer(const Context& context)
|
||||||
{
|
{
|
||||||
using TimeUnit = LuaUtil::ScriptsContainer::TimeUnit;
|
using TimerType = LuaUtil::ScriptsContainer::TimerType;
|
||||||
sol::usertype<AsyncPackageId> api = context.mLua->sol().new_usertype<AsyncPackageId>("AsyncPackage");
|
sol::usertype<AsyncPackageId> api = context.mLua->sol().new_usertype<AsyncPackageId>("AsyncPackage");
|
||||||
api["registerTimerCallback"] = [](const AsyncPackageId& asyncId, std::string_view name, sol::function callback)
|
api["registerTimerCallback"] = [](const AsyncPackageId& asyncId, std::string_view name, sol::function callback)
|
||||||
{
|
{
|
||||||
asyncId.mContainer->registerTimerCallback(asyncId.mScriptId, name, std::move(callback));
|
asyncId.mContainer->registerTimerCallback(asyncId.mScriptId, name, std::move(callback));
|
||||||
return TimerCallback{asyncId, std::string(name)};
|
return TimerCallback{asyncId, std::string(name)};
|
||||||
};
|
};
|
||||||
api["newTimerInSeconds"] = [world=context.mWorldView](const AsyncPackageId&, double delay,
|
api["newSimulationTimer"] = [world=context.mWorldView](const AsyncPackageId&, double delay,
|
||||||
const TimerCallback& callback, sol::object callbackArg)
|
const TimerCallback& callback, sol::object callbackArg)
|
||||||
{
|
{
|
||||||
callback.mAsyncId.mContainer->setupSerializableTimer(
|
callback.mAsyncId.mContainer->setupSerializableTimer(
|
||||||
TimeUnit::SECONDS, world->getGameTimeInSeconds() + delay,
|
TimerType::SIMULATION_TIME, world->getSimulationTime() + delay,
|
||||||
callback.mAsyncId.mScriptId, callback.mName, std::move(callbackArg));
|
callback.mAsyncId.mScriptId, callback.mName, std::move(callbackArg));
|
||||||
};
|
};
|
||||||
api["newTimerInHours"] = [world=context.mWorldView](const AsyncPackageId&, double delay,
|
api["newGameTimer"] = [world=context.mWorldView](const AsyncPackageId&, double delay,
|
||||||
const TimerCallback& callback, sol::object callbackArg)
|
const TimerCallback& callback, sol::object callbackArg)
|
||||||
{
|
{
|
||||||
callback.mAsyncId.mContainer->setupSerializableTimer(
|
callback.mAsyncId.mContainer->setupSerializableTimer(
|
||||||
TimeUnit::HOURS, world->getGameTimeInHours() + delay,
|
TimerType::GAME_TIME, world->getGameTime() + delay,
|
||||||
callback.mAsyncId.mScriptId, callback.mName, std::move(callbackArg));
|
callback.mAsyncId.mScriptId, callback.mName, std::move(callbackArg));
|
||||||
};
|
};
|
||||||
api["newUnsavableTimerInSeconds"] = [world=context.mWorldView](const AsyncPackageId& asyncId, double delay, sol::function callback)
|
api["newUnsavableSimulationTimer"] = [world=context.mWorldView](const AsyncPackageId& asyncId, double delay, sol::function callback)
|
||||||
{
|
{
|
||||||
asyncId.mContainer->setupUnsavableTimer(
|
asyncId.mContainer->setupUnsavableTimer(
|
||||||
TimeUnit::SECONDS, world->getGameTimeInSeconds() + delay, asyncId.mScriptId, std::move(callback));
|
TimerType::SIMULATION_TIME, world->getSimulationTime() + delay, asyncId.mScriptId, std::move(callback));
|
||||||
};
|
};
|
||||||
api["newUnsavableTimerInHours"] = [world=context.mWorldView](const AsyncPackageId& asyncId, double delay, sol::function callback)
|
api["newUnsavableGameTimer"] = [world=context.mWorldView](const AsyncPackageId& asyncId, double delay, sol::function callback)
|
||||||
{
|
{
|
||||||
asyncId.mContainer->setupUnsavableTimer(
|
asyncId.mContainer->setupUnsavableTimer(
|
||||||
TimeUnit::HOURS, world->getGameTimeInHours() + delay, asyncId.mScriptId, std::move(callback));
|
TimerType::GAME_TIME, world->getGameTime() + delay, asyncId.mScriptId, std::move(callback));
|
||||||
};
|
};
|
||||||
api["callback"] = [](const AsyncPackageId& asyncId, sol::function fn)
|
api["callback"] = [](const AsyncPackageId& asyncId, sol::function fn)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,11 +22,32 @@ namespace MWLua
|
||||||
return LuaUtil::makeReadOnly(res);
|
return LuaUtil::makeReadOnly(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void addTimeBindings(sol::table& api, const Context& context, bool global)
|
||||||
|
{
|
||||||
|
api["getSimulationTime"] = [world=context.mWorldView]() { return world->getSimulationTime(); };
|
||||||
|
api["getSimulationTimeScale"] = [world=context.mWorldView]() { return world->getSimulationTimeScale(); };
|
||||||
|
api["getGameTime"] = [world=context.mWorldView]() { return world->getGameTime(); };
|
||||||
|
api["getGameTimeScale"] = [world=context.mWorldView]() { return world->getGameTimeScale(); };
|
||||||
|
api["isWorldPaused"] = [world=context.mWorldView]() { return world->isPaused(); };
|
||||||
|
|
||||||
|
if (!global)
|
||||||
|
return;
|
||||||
|
|
||||||
|
api["setGameTimeScale"] = [world=context.mWorldView](double scale) { world->setGameTimeScale(scale); };
|
||||||
|
|
||||||
|
// TODO: Ability to make game time slower or faster than real time (needed for example for mechanics like VATS)
|
||||||
|
// api["setSimulationTimeScale"] = [](double scale) {};
|
||||||
|
|
||||||
|
// TODO: Ability to pause/resume world from Lua (needed for UI dehardcoding)
|
||||||
|
// api["pause"] = []() {};
|
||||||
|
// api["resume"] = []() {};
|
||||||
|
}
|
||||||
|
|
||||||
sol::table initCorePackage(const Context& context)
|
sol::table initCorePackage(const Context& context)
|
||||||
{
|
{
|
||||||
auto* lua = context.mLua;
|
auto* lua = context.mLua;
|
||||||
sol::table api(lua->sol(), sol::create);
|
sol::table api(lua->sol(), sol::create);
|
||||||
api["API_REVISION"] = 12;
|
api["API_REVISION"] = 13;
|
||||||
api["quit"] = [lua]()
|
api["quit"] = [lua]()
|
||||||
{
|
{
|
||||||
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback();
|
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback();
|
||||||
|
@ -36,9 +57,7 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
context.mGlobalEventQueue->push_back({std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer)});
|
context.mGlobalEventQueue->push_back({std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer)});
|
||||||
};
|
};
|
||||||
api["getGameTimeInSeconds"] = [world=context.mWorldView]() { return world->getGameTimeInSeconds(); };
|
addTimeBindings(api, context, false);
|
||||||
api["getGameTimeInHours"] = [world=context.mWorldView]() { return world->getGameTimeInHours(); };
|
|
||||||
api["isWorldPaused"] = [world=context.mWorldView]() { return world->isPaused(); };
|
|
||||||
api["OBJECT_TYPE"] = definitionList(*lua,
|
api["OBJECT_TYPE"] = definitionList(*lua,
|
||||||
{
|
{
|
||||||
"Activator", "Armor", "Book", "Clothing", "Creature", "Door", "Ingredient",
|
"Activator", "Armor", "Book", "Clothing", "Creature", "Door", "Ingredient",
|
||||||
|
@ -73,6 +92,7 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
sol::table api(context.mLua->sol(), sol::create);
|
sol::table api(context.mLua->sol(), sol::create);
|
||||||
WorldView* worldView = context.mWorldView;
|
WorldView* worldView = context.mWorldView;
|
||||||
|
addTimeBindings(api, context, true);
|
||||||
api["getCellByName"] = [worldView=context.mWorldView](const std::string& name) -> sol::optional<GCell>
|
api["getCellByName"] = [worldView=context.mWorldView](const std::string& name) -> sol::optional<GCell>
|
||||||
{
|
{
|
||||||
MWWorld::CellStore* cell = worldView->findNamedCell(name);
|
MWWorld::CellStore* cell = worldView->findNamedCell(name);
|
||||||
|
|
|
@ -113,13 +113,13 @@ namespace MWLua
|
||||||
|
|
||||||
if (!mWorldView.isPaused())
|
if (!mWorldView.isPaused())
|
||||||
{ // Update time and process timers
|
{ // Update time and process timers
|
||||||
double seconds = mWorldView.getGameTimeInSeconds() + frameDuration;
|
double simulationTime = mWorldView.getSimulationTime() + frameDuration;
|
||||||
mWorldView.setGameTimeInSeconds(seconds);
|
mWorldView.setSimulationTime(simulationTime);
|
||||||
double hours = mWorldView.getGameTimeInHours();
|
double gameTime = mWorldView.getGameTime();
|
||||||
|
|
||||||
mGlobalScripts.processTimers(seconds, hours);
|
mGlobalScripts.processTimers(simulationTime, gameTime);
|
||||||
for (LocalScripts* scripts : mActiveLocalScripts)
|
for (LocalScripts* scripts : mActiveLocalScripts)
|
||||||
scripts->processTimers(seconds, hours);
|
scripts->processTimers(simulationTime, gameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive events
|
// Receive events
|
||||||
|
|
|
@ -70,16 +70,16 @@ namespace MWLua
|
||||||
removeFromGroup(*group, ptr);
|
removeFromGroup(*group, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
double WorldView::getGameTimeInHours() const
|
double WorldView::getGameTime() const
|
||||||
{
|
{
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
MWWorld::TimeStamp timeStamp = world->getTimeStamp();
|
MWWorld::TimeStamp timeStamp = world->getTimeStamp();
|
||||||
return static_cast<double>(timeStamp.getDay()) * 24 + timeStamp.getHour();
|
return (static_cast<double>(timeStamp.getDay()) * 24 + timeStamp.getHour()) * 3600.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldView::load(ESM::ESMReader& esm)
|
void WorldView::load(ESM::ESMReader& esm)
|
||||||
{
|
{
|
||||||
esm.getHNT(mGameSeconds, "LUAW");
|
esm.getHNT(mSimulationTime, "LUAW");
|
||||||
ObjectId lastAssignedId;
|
ObjectId lastAssignedId;
|
||||||
lastAssignedId.load(esm, true);
|
lastAssignedId.load(esm, true);
|
||||||
mObjectRegistry.setLastAssignedId(lastAssignedId);
|
mObjectRegistry.setLastAssignedId(lastAssignedId);
|
||||||
|
@ -87,7 +87,7 @@ namespace MWLua
|
||||||
|
|
||||||
void WorldView::save(ESM::ESMWriter& esm) const
|
void WorldView::save(ESM::ESMWriter& esm) const
|
||||||
{
|
{
|
||||||
esm.writeHNT("LUAW", mGameSeconds);
|
esm.writeHNT("LUAW", mSimulationTime);
|
||||||
mObjectRegistry.getLastAssignedId().save(esm, true);
|
mObjectRegistry.getLastAssignedId().save(esm, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,13 +22,16 @@ namespace MWLua
|
||||||
// Whether the world is paused (i.e. game time is not changing and actors don't move).
|
// Whether the world is paused (i.e. game time is not changing and actors don't move).
|
||||||
bool isPaused() const { return mPaused; }
|
bool isPaused() const { return mPaused; }
|
||||||
|
|
||||||
// Returns the number of seconds passed from the beginning of the game.
|
// The number of seconds passed from the beginning of the game.
|
||||||
double getGameTimeInSeconds() const { return mGameSeconds; }
|
double getSimulationTime() const { return mSimulationTime; }
|
||||||
void setGameTimeInSeconds(double t) { mGameSeconds = t; }
|
void setSimulationTime(double t) { mSimulationTime = t; }
|
||||||
|
double getSimulationTimeScale() const { return 1.0; }
|
||||||
|
|
||||||
// Returns the number of game hours passed from the beginning of the game.
|
// The game time (in game seconds) passed from the beginning of the game.
|
||||||
// Note that the number of seconds in a game hour is not fixed.
|
// Note that game time generally goes faster than the simulation time.
|
||||||
double getGameTimeInHours() const;
|
double getGameTime() const;
|
||||||
|
double getGameTimeScale() const { return MWBase::Environment::get().getWorld()->getTimeScaleFactor(); }
|
||||||
|
void setGameTimeScale(double s) { MWBase::Environment::get().getWorld()->setGlobalFloat("timescale", s); }
|
||||||
|
|
||||||
ObjectIdList getActivatorsInScene() const { return mActivatorsInScene.mList; }
|
ObjectIdList getActivatorsInScene() const { return mActivatorsInScene.mList; }
|
||||||
ObjectIdList getActorsInScene() const { return mActorsInScene.mList; }
|
ObjectIdList getActorsInScene() const { return mActorsInScene.mList; }
|
||||||
|
@ -76,7 +79,7 @@ namespace MWLua
|
||||||
ObjectGroup mDoorsInScene;
|
ObjectGroup mDoorsInScene;
|
||||||
ObjectGroup mItemsInScene;
|
ObjectGroup mItemsInScene;
|
||||||
|
|
||||||
double mGameSeconds = 0;
|
double mSimulationTime = 0;
|
||||||
bool mPaused = false;
|
bool mPaused = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -364,7 +364,7 @@ return {
|
||||||
|
|
||||||
TEST_F(LuaScriptsContainerTest, Timers)
|
TEST_F(LuaScriptsContainerTest, Timers)
|
||||||
{
|
{
|
||||||
using TimeUnit = LuaUtil::ScriptsContainer::TimeUnit;
|
using TimerType = LuaUtil::ScriptsContainer::TimerType;
|
||||||
LuaUtil::ScriptsContainer scripts(&mLua, "Test");
|
LuaUtil::ScriptsContainer scripts(&mLua, "Test");
|
||||||
int test1Id = *mCfg.findId("test1.lua");
|
int test1Id = *mCfg.findId("test1.lua");
|
||||||
int test2Id = *mCfg.findId("test2.lua");
|
int test2Id = *mCfg.findId("test2.lua");
|
||||||
|
@ -387,18 +387,18 @@ return {
|
||||||
|
|
||||||
scripts.processTimers(1, 2);
|
scripts.processTimers(1, 2);
|
||||||
|
|
||||||
scripts.setupSerializableTimer(TimeUnit::SECONDS, 10, test1Id, "B", sol::make_object(mLua.sol(), 3));
|
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 10, test1Id, "B", sol::make_object(mLua.sol(), 3));
|
||||||
scripts.setupSerializableTimer(TimeUnit::HOURS, 10, test2Id, "B", sol::make_object(mLua.sol(), 4));
|
scripts.setupSerializableTimer(TimerType::GAME_TIME, 10, test2Id, "B", sol::make_object(mLua.sol(), 4));
|
||||||
scripts.setupSerializableTimer(TimeUnit::SECONDS, 5, test1Id, "A", sol::make_object(mLua.sol(), 1));
|
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 5, test1Id, "A", sol::make_object(mLua.sol(), 1));
|
||||||
scripts.setupSerializableTimer(TimeUnit::HOURS, 5, test2Id, "A", sol::make_object(mLua.sol(), 2));
|
scripts.setupSerializableTimer(TimerType::GAME_TIME, 5, test2Id, "A", sol::make_object(mLua.sol(), 2));
|
||||||
scripts.setupSerializableTimer(TimeUnit::SECONDS, 15, test1Id, "A", sol::make_object(mLua.sol(), 10));
|
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 15, test1Id, "A", sol::make_object(mLua.sol(), 10));
|
||||||
scripts.setupSerializableTimer(TimeUnit::SECONDS, 15, test1Id, "B", sol::make_object(mLua.sol(), 20));
|
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 15, test1Id, "B", sol::make_object(mLua.sol(), 20));
|
||||||
|
|
||||||
scripts.setupUnsavableTimer(TimeUnit::SECONDS, 10, test2Id, fn2);
|
scripts.setupUnsavableTimer(TimerType::SIMULATION_TIME, 10, test2Id, fn2);
|
||||||
scripts.setupUnsavableTimer(TimeUnit::HOURS, 10, test1Id, fn2);
|
scripts.setupUnsavableTimer(TimerType::GAME_TIME, 10, test1Id, fn2);
|
||||||
scripts.setupUnsavableTimer(TimeUnit::SECONDS, 5, test2Id, fn1);
|
scripts.setupUnsavableTimer(TimerType::SIMULATION_TIME, 5, test2Id, fn1);
|
||||||
scripts.setupUnsavableTimer(TimeUnit::HOURS, 5, test1Id, fn1);
|
scripts.setupUnsavableTimer(TimerType::GAME_TIME, 5, test1Id, fn1);
|
||||||
scripts.setupUnsavableTimer(TimeUnit::SECONDS, 15, test2Id, fn1);
|
scripts.setupUnsavableTimer(TimerType::SIMULATION_TIME, 15, test2Id, fn1);
|
||||||
|
|
||||||
EXPECT_EQ(counter1, 0);
|
EXPECT_EQ(counter1, 0);
|
||||||
EXPECT_EQ(counter3, 0);
|
EXPECT_EQ(counter3, 0);
|
||||||
|
|
|
@ -72,7 +72,7 @@ void ESM::LuaScripts::load(ESMReader& esm)
|
||||||
{
|
{
|
||||||
esm.getSubHeader();
|
esm.getSubHeader();
|
||||||
LuaTimer timer;
|
LuaTimer timer;
|
||||||
esm.getT(timer.mUnit);
|
esm.getT(timer.mType);
|
||||||
esm.getT(timer.mTime);
|
esm.getT(timer.mTime);
|
||||||
timer.mCallbackName = esm.getHNString("LUAC");
|
timer.mCallbackName = esm.getHNString("LUAC");
|
||||||
timer.mCallbackArgument = loadLuaBinaryData(esm);
|
timer.mCallbackArgument = loadLuaBinaryData(esm);
|
||||||
|
@ -91,7 +91,7 @@ void ESM::LuaScripts::save(ESMWriter& esm) const
|
||||||
for (const LuaTimer& timer : script.mTimers)
|
for (const LuaTimer& timer : script.mTimers)
|
||||||
{
|
{
|
||||||
esm.startSubRecord("LUAT");
|
esm.startSubRecord("LUAT");
|
||||||
esm.writeT(timer.mUnit);
|
esm.writeT(timer.mType);
|
||||||
esm.writeT(timer.mTime);
|
esm.writeT(timer.mTime);
|
||||||
esm.endRecord("LUAT");
|
esm.endRecord("LUAT");
|
||||||
esm.writeHNString("LUAC", timer.mCallbackName);
|
esm.writeHNString("LUAC", timer.mCallbackName);
|
||||||
|
|
|
@ -51,13 +51,13 @@ namespace ESM
|
||||||
|
|
||||||
struct LuaTimer
|
struct LuaTimer
|
||||||
{
|
{
|
||||||
enum class TimeUnit : bool
|
enum class Type : bool
|
||||||
{
|
{
|
||||||
SECONDS = 0,
|
SIMULATION_TIME = 0,
|
||||||
HOURS = 1,
|
GAME_TIME = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
TimeUnit mUnit;
|
Type mType;
|
||||||
double mTime;
|
double mTime;
|
||||||
std::string mCallbackName;
|
std::string mCallbackName;
|
||||||
std::string mCallbackArgument; // Serialized Lua table. It is a binary data. Can contain '\0'.
|
std::string mCallbackArgument; // Serialized Lua table. It is a binary data. Can contain '\0'.
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace LuaUtil
|
||||||
LuaState::LuaState(const VFS::Manager* vfs, const ScriptsConfiguration* conf) : mConf(conf), mVFS(vfs)
|
LuaState::LuaState(const VFS::Manager* vfs, const ScriptsConfiguration* conf) : mConf(conf), mVFS(vfs)
|
||||||
{
|
{
|
||||||
mLua.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::math,
|
mLua.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::math,
|
||||||
sol::lib::string, sol::lib::table, sol::lib::debug);
|
sol::lib::string, sol::lib::table, sol::lib::os, sol::lib::debug);
|
||||||
|
|
||||||
mLua["math"]["randomseed"](static_cast<unsigned>(std::time(nullptr)));
|
mLua["math"]["randomseed"](static_cast<unsigned>(std::time(nullptr)));
|
||||||
mLua["math"]["randomseed"] = []{};
|
mLua["math"]["randomseed"] = []{};
|
||||||
|
@ -85,6 +85,11 @@ namespace LuaUtil
|
||||||
if (mLua[s] == sol::nil) throw std::logic_error("Lua package not found: " + s);
|
if (mLua[s] == sol::nil) throw std::logic_error("Lua package not found: " + s);
|
||||||
mCommonPackages[s] = mSandboxEnv[s] = makeReadOnly(mLua[s]);
|
mCommonPackages[s] = mSandboxEnv[s] = makeReadOnly(mLua[s]);
|
||||||
}
|
}
|
||||||
|
mCommonPackages["os"] = mSandboxEnv["os"] = makeReadOnly(tableFromPairs<std::string_view, sol::function>({
|
||||||
|
{"date", mLua["os"]["date"]},
|
||||||
|
{"difftime", mLua["os"]["difftime"]},
|
||||||
|
{"time", mLua["os"]["time"]}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaState::~LuaState()
|
LuaState::~LuaState()
|
||||||
|
|
|
@ -309,21 +309,21 @@ namespace LuaUtil
|
||||||
void ScriptsContainer::save(ESM::LuaScripts& data)
|
void ScriptsContainer::save(ESM::LuaScripts& data)
|
||||||
{
|
{
|
||||||
std::map<int, std::vector<ESM::LuaTimer>> timers;
|
std::map<int, std::vector<ESM::LuaTimer>> timers;
|
||||||
auto saveTimerFn = [&](const Timer& timer, TimeUnit timeUnit)
|
auto saveTimerFn = [&](const Timer& timer, TimerType timerType)
|
||||||
{
|
{
|
||||||
if (!timer.mSerializable)
|
if (!timer.mSerializable)
|
||||||
return;
|
return;
|
||||||
ESM::LuaTimer savedTimer;
|
ESM::LuaTimer savedTimer;
|
||||||
savedTimer.mTime = timer.mTime;
|
savedTimer.mTime = timer.mTime;
|
||||||
savedTimer.mUnit = timeUnit;
|
savedTimer.mType = timerType;
|
||||||
savedTimer.mCallbackName = std::get<std::string>(timer.mCallback);
|
savedTimer.mCallbackName = std::get<std::string>(timer.mCallback);
|
||||||
savedTimer.mCallbackArgument = timer.mSerializedArg;
|
savedTimer.mCallbackArgument = timer.mSerializedArg;
|
||||||
timers[timer.mScriptId].push_back(std::move(savedTimer));
|
timers[timer.mScriptId].push_back(std::move(savedTimer));
|
||||||
};
|
};
|
||||||
for (const Timer& timer : mSecondsTimersQueue)
|
for (const Timer& timer : mSimulationTimersQueue)
|
||||||
saveTimerFn(timer, TimeUnit::SECONDS);
|
saveTimerFn(timer, TimerType::SIMULATION_TIME);
|
||||||
for (const Timer& timer : mHoursTimersQueue)
|
for (const Timer& timer : mGameTimersQueue)
|
||||||
saveTimerFn(timer, TimeUnit::HOURS);
|
saveTimerFn(timer, TimerType::GAME_TIME);
|
||||||
data.mScripts.clear();
|
data.mScripts.clear();
|
||||||
for (auto& [scriptId, script] : mScripts)
|
for (auto& [scriptId, script] : mScripts)
|
||||||
{
|
{
|
||||||
|
@ -408,17 +408,17 @@ namespace LuaUtil
|
||||||
// updates refnums, so timer.mSerializedArg may be not equal to savedTimer.mCallbackArgument.
|
// updates refnums, so timer.mSerializedArg may be not equal to savedTimer.mCallbackArgument.
|
||||||
timer.mSerializedArg = serialize(timer.mArg, mSerializer);
|
timer.mSerializedArg = serialize(timer.mArg, mSerializer);
|
||||||
|
|
||||||
if (savedTimer.mUnit == TimeUnit::HOURS)
|
if (savedTimer.mType == TimerType::GAME_TIME)
|
||||||
mHoursTimersQueue.push_back(std::move(timer));
|
mGameTimersQueue.push_back(std::move(timer));
|
||||||
else
|
else
|
||||||
mSecondsTimersQueue.push_back(std::move(timer));
|
mSimulationTimersQueue.push_back(std::move(timer));
|
||||||
}
|
}
|
||||||
catch (std::exception& e) { printError(scriptId, "can not load timer", e); }
|
catch (std::exception& e) { printError(scriptId, "can not load timer", e); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::make_heap(mSecondsTimersQueue.begin(), mSecondsTimersQueue.end());
|
std::make_heap(mSimulationTimersQueue.begin(), mSimulationTimersQueue.end());
|
||||||
std::make_heap(mHoursTimersQueue.begin(), mHoursTimersQueue.end());
|
std::make_heap(mGameTimersQueue.begin(), mGameTimersQueue.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptsContainer::~ScriptsContainer()
|
ScriptsContainer::~ScriptsContainer()
|
||||||
|
@ -437,8 +437,8 @@ namespace LuaUtil
|
||||||
for (auto& [_, handlers] : mEngineHandlers)
|
for (auto& [_, handlers] : mEngineHandlers)
|
||||||
handlers->mList.clear();
|
handlers->mList.clear();
|
||||||
mEventHandlers.clear();
|
mEventHandlers.clear();
|
||||||
mSecondsTimersQueue.clear();
|
mSimulationTimersQueue.clear();
|
||||||
mHoursTimersQueue.clear();
|
mGameTimersQueue.clear();
|
||||||
|
|
||||||
mPublicInterfaces.clear();
|
mPublicInterfaces.clear();
|
||||||
// Assigned by LuaUtil::makeReadOnly, but `clear` removes it, so we need to assign it again.
|
// Assigned by LuaUtil::makeReadOnly, but `clear` removes it, so we need to assign it again.
|
||||||
|
@ -464,7 +464,7 @@ namespace LuaUtil
|
||||||
std::push_heap(timerQueue.begin(), timerQueue.end());
|
std::push_heap(timerQueue.begin(), timerQueue.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptsContainer::setupSerializableTimer(TimeUnit timeUnit, double time, int scriptId,
|
void ScriptsContainer::setupSerializableTimer(TimerType type, double time, int scriptId,
|
||||||
std::string_view callbackName, sol::object callbackArg)
|
std::string_view callbackName, sol::object callbackArg)
|
||||||
{
|
{
|
||||||
Timer t;
|
Timer t;
|
||||||
|
@ -474,10 +474,10 @@ namespace LuaUtil
|
||||||
t.mTime = time;
|
t.mTime = time;
|
||||||
t.mArg = callbackArg;
|
t.mArg = callbackArg;
|
||||||
t.mSerializedArg = serialize(t.mArg, mSerializer);
|
t.mSerializedArg = serialize(t.mArg, mSerializer);
|
||||||
insertTimer(timeUnit == TimeUnit::HOURS ? mHoursTimersQueue : mSecondsTimersQueue, std::move(t));
|
insertTimer(type == TimerType::GAME_TIME ? mGameTimersQueue : mSimulationTimersQueue, std::move(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptsContainer::setupUnsavableTimer(TimeUnit timeUnit, double time, int scriptId, sol::function callback)
|
void ScriptsContainer::setupUnsavableTimer(TimerType type, double time, int scriptId, sol::function callback)
|
||||||
{
|
{
|
||||||
Timer t;
|
Timer t;
|
||||||
t.mScriptId = scriptId;
|
t.mScriptId = scriptId;
|
||||||
|
@ -488,7 +488,7 @@ namespace LuaUtil
|
||||||
getScript(t.mScriptId).mTemporaryCallbacks.emplace(mTemporaryCallbackCounter, std::move(callback));
|
getScript(t.mScriptId).mTemporaryCallbacks.emplace(mTemporaryCallbackCounter, std::move(callback));
|
||||||
mTemporaryCallbackCounter++;
|
mTemporaryCallbackCounter++;
|
||||||
|
|
||||||
insertTimer(timeUnit == TimeUnit::HOURS ? mHoursTimersQueue : mSecondsTimersQueue, std::move(t));
|
insertTimer(type == TimerType::GAME_TIME ? mGameTimersQueue : mSimulationTimersQueue, std::move(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptsContainer::callTimer(const Timer& t)
|
void ScriptsContainer::callTimer(const Timer& t)
|
||||||
|
@ -524,10 +524,10 @@ namespace LuaUtil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptsContainer::processTimers(double gameSeconds, double gameHours)
|
void ScriptsContainer::processTimers(double simulationTime, double gameTime)
|
||||||
{
|
{
|
||||||
updateTimerQueue(mSecondsTimersQueue, gameSeconds);
|
updateTimerQueue(mSimulationTimersQueue, simulationTime);
|
||||||
updateTimerQueue(mHoursTimersQueue, gameHours);
|
updateTimerQueue(mGameTimersQueue, gameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace LuaUtil
|
||||||
ScriptsContainer* mContainer;
|
ScriptsContainer* mContainer;
|
||||||
int mIndex; // index in LuaUtil::ScriptsConfiguration
|
int mIndex; // index in LuaUtil::ScriptsConfiguration
|
||||||
};
|
};
|
||||||
using TimeUnit = ESM::LuaTimer::TimeUnit;
|
using TimerType = ESM::LuaTimer::Type;
|
||||||
|
|
||||||
// `namePrefix` is a common prefix for all scripts in the container. Used in logs for error messages and `print` output.
|
// `namePrefix` is a common prefix for all scripts in the container. Used in logs for error messages and `print` output.
|
||||||
// `autoStartMode` specifies the list of scripts that should be autostarted in this container; the list itself is
|
// `autoStartMode` specifies the list of scripts that should be autostarted in this container; the list itself is
|
||||||
|
@ -99,8 +99,7 @@ namespace LuaUtil
|
||||||
bool hasScript(int scriptId) const { return mScripts.count(scriptId) != 0; }
|
bool hasScript(int scriptId) const { return mScripts.count(scriptId) != 0; }
|
||||||
void removeScript(int scriptId);
|
void removeScript(int scriptId);
|
||||||
|
|
||||||
// Processes timers. gameSeconds and gameHours are time (in seconds and in game hours) passed from the game start.
|
void processTimers(double simulationTime, double gameTime);
|
||||||
void processTimers(double gameSeconds, double gameHours);
|
|
||||||
|
|
||||||
// Calls `onUpdate` (if present) for every script in the container.
|
// Calls `onUpdate` (if present) for every script in the container.
|
||||||
// Handlers are called in the same order as scripts were added.
|
// Handlers are called in the same order as scripts were added.
|
||||||
|
@ -134,17 +133,17 @@ namespace LuaUtil
|
||||||
void registerTimerCallback(int scriptId, std::string_view callbackName, sol::function callback);
|
void registerTimerCallback(int scriptId, std::string_view callbackName, sol::function callback);
|
||||||
|
|
||||||
// Sets up a timer, that can be automatically saved and loaded.
|
// Sets up a timer, that can be automatically saved and loaded.
|
||||||
// timeUnit - game seconds (TimeUnit::Seconds) or game hours (TimeUnit::Hours).
|
// type - the type of timer, either SIMULATION_TIME or GAME_TIME.
|
||||||
// time - the absolute game time (in seconds or in hours) when the timer should be executed.
|
// time - the absolute game time (in seconds or in hours) when the timer should be executed.
|
||||||
// scriptPath - script path in VFS is used as script id. The script with the given path should already present in the container.
|
// scriptPath - script path in VFS is used as script id. The script with the given path should already present in the container.
|
||||||
// callbackName - callback (should be registered in advance) for this timer.
|
// callbackName - callback (should be registered in advance) for this timer.
|
||||||
// callbackArg - parameter for the callback (should be serializable).
|
// callbackArg - parameter for the callback (should be serializable).
|
||||||
void setupSerializableTimer(TimeUnit timeUnit, double time, int scriptId,
|
void setupSerializableTimer(TimerType type, double time, int scriptId,
|
||||||
std::string_view callbackName, sol::object callbackArg);
|
std::string_view callbackName, sol::object callbackArg);
|
||||||
|
|
||||||
// Creates a timer. `callback` is an arbitrary Lua function. This type of timers is called "unsavable"
|
// Creates a timer. `callback` is an arbitrary Lua function. These timers are called "unsavable"
|
||||||
// because it can not be stored in saves. I.e. loading a saved game will not fully restore the state.
|
// because they can not be stored in saves. I.e. loading a saved game will not fully restore the state.
|
||||||
void setupUnsavableTimer(TimeUnit timeUnit, double time, int scriptId, sol::function callback);
|
void setupUnsavableTimer(TimerType type, double time, int scriptId, sol::function callback);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct Handler
|
struct Handler
|
||||||
|
@ -237,8 +236,8 @@ namespace LuaUtil
|
||||||
std::map<std::string_view, EngineHandlerList*> mEngineHandlers;
|
std::map<std::string_view, EngineHandlerList*> mEngineHandlers;
|
||||||
std::map<std::string, EventHandlerList, std::less<>> mEventHandlers;
|
std::map<std::string, EventHandlerList, std::less<>> mEventHandlers;
|
||||||
|
|
||||||
std::vector<Timer> mSecondsTimersQueue;
|
std::vector<Timer> mSimulationTimersQueue;
|
||||||
std::vector<Timer> mHoursTimersQueue;
|
std::vector<Timer> mGameTimersQueue;
|
||||||
int64_t mTemporaryCallbackCounter = 0;
|
int64_t mTemporaryCallbackCounter = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ Lua API reference
|
||||||
openmw_input
|
openmw_input
|
||||||
openmw_ui
|
openmw_ui
|
||||||
openmw_camera
|
openmw_camera
|
||||||
|
openmw_aux_calendar
|
||||||
openmw_aux_util
|
openmw_aux_util
|
||||||
|
openmw_aux_time
|
||||||
interface_camera
|
interface_camera
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,8 +75,12 @@ Sources can be found in ``resources/vfs/openmw_aux``. In theory mods can overrid
|
||||||
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
| Built-in library | Can be used | Description |
|
| Built-in library | Can be used | Description |
|
||||||
+=========================================================+====================+===============================================================+
|
+=========================================================+====================+===============================================================+
|
||||||
|
|:ref:`openmw_aux.calendar <Package openmw_aux.calendar>` | everywhere | | Game time calendar |
|
||||||
|
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw_aux.util <Package openmw_aux.util>` | everywhere | | Miscellaneous utils |
|
|:ref:`openmw_aux.util <Package openmw_aux.util>` | everywhere | | Miscellaneous utils |
|
||||||
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw_aux.time <Package openmw_aux.time>` | everywhere | | Timers and game time utils |
|
||||||
|
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|
||||||
**Interfaces of built-in scripts**
|
**Interfaces of built-in scripts**
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
Package openmw_aux.calendar
|
||||||
|
===========================
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: generated_html/openmw_aux_calendar.html
|
5
docs/source/reference/lua-scripting/openmw_aux_time.rst
Normal file
5
docs/source/reference/lua-scripting/openmw_aux_time.rst
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Package openmw_aux.time
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: generated_html/openmw_aux_time.html
|
|
@ -15,10 +15,11 @@ Here are starting points for learning Lua:
|
||||||
Each script works in a separate sandbox and doesn't have any access to the underlying operating system.
|
Each script works in a separate sandbox and doesn't have any access to the underlying operating system.
|
||||||
Only a limited list of allowed standard libraries can be used:
|
Only a limited list of allowed standard libraries can be used:
|
||||||
`coroutine <https://www.lua.org/manual/5.1/manual.html#5.2>`__,
|
`coroutine <https://www.lua.org/manual/5.1/manual.html#5.2>`__,
|
||||||
`math <https://www.lua.org/manual/5.1/manual.html#5.6>`__,
|
`math <https://www.lua.org/manual/5.1/manual.html#5.6>`__ (except `math.randomseed` -- it is called by the engine on startup and not available from scripts),
|
||||||
`string <https://www.lua.org/manual/5.1/manual.html#5.4>`__,
|
`string <https://www.lua.org/manual/5.1/manual.html#5.4>`__,
|
||||||
`table <https://www.lua.org/manual/5.1/manual.html#5.5>`__.
|
`table <https://www.lua.org/manual/5.1/manual.html#5.5>`__,
|
||||||
These libraries are loaded automatically and are always available (except the function `math.randomseed` -- it is called by the engine on startup and not available from scripts).
|
`os <https://www.lua.org/manual/5.1/manual.html#5.8>`__ (only `os.date`, `os.difftime`, `os.time`).
|
||||||
|
These libraries are loaded automatically and are always available.
|
||||||
|
|
||||||
Allowed `basic functions <https://www.lua.org/manual/5.1/manual.html#5.1>`__:
|
Allowed `basic functions <https://www.lua.org/manual/5.1/manual.html#5.1>`__:
|
||||||
``assert``, ``error``, ``ipairs``, ``next``, ``pairs``, ``pcall``, ``print``, ``select``, ``tonumber``, ``tostring``, ``type``, ``unpack``, ``xpcall``, ``rawequal``, ``rawget``, ``rawset``, ``getmetatable``, ``setmetatable``.
|
``assert``, ``error``, ``ipairs``, ``next``, ``pairs``, ``pcall``, ``print``, ``select``, ``tonumber``, ``tostring``, ``type``, ``unpack``, ``xpcall``, ``rawequal``, ``rawget``, ``rawset``, ``getmetatable``, ``setmetatable``.
|
||||||
|
@ -364,15 +365,19 @@ Sources can be found in ``resources/vfs/openmw_aux``. In theory mods can overrid
|
||||||
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
| Built-in library | Can be used | Description |
|
| Built-in library | Can be used | Description |
|
||||||
+=========================================================+====================+===============================================================+
|
+=========================================================+====================+===============================================================+
|
||||||
|
|:ref:`openmw_aux.calendar <Package openmw_aux.calendar>` | everywhere | | Game time calendar |
|
||||||
|
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw_aux.util <Package openmw_aux.util>` | everywhere | | Miscellaneous utils |
|
|:ref:`openmw_aux.util <Package openmw_aux.util>` | everywhere | | Miscellaneous utils |
|
||||||
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw_aux.time <Package openmw_aux.time>` | everywhere | | Timers and game time utils |
|
||||||
|
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|
||||||
They can be loaded with ``require`` the same as API packages. For example:
|
They can be loaded with ``require`` the same as API packages. For example:
|
||||||
|
|
||||||
.. code-block:: Lua
|
.. code-block:: Lua
|
||||||
|
|
||||||
local aux_util = require('openmw_aux.util')
|
local time = require('openmw_aux.time')
|
||||||
aux_util.runEveryNSeconds(15, doSomething) -- run `doSomething()` every 15 seconds
|
time.runRepeatedly(doSomething, 15 * time.second) -- run `doSomething()` every 15 seconds
|
||||||
|
|
||||||
|
|
||||||
Script interfaces
|
Script interfaces
|
||||||
|
|
|
@ -7,8 +7,14 @@ set(SDIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
set(DDIRRELATIVE resources/vfs)
|
set(DDIRRELATIVE resources/vfs)
|
||||||
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_RESOURCES_ROOT} ${DDIRRELATIVE} "builtin.omwscripts")
|
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_RESOURCES_ROOT} ${DDIRRELATIVE} "builtin.omwscripts")
|
||||||
|
|
||||||
|
set(LUA_AUX_FILES
|
||||||
|
openmw_aux/util.lua
|
||||||
|
openmw_aux/time.lua
|
||||||
|
openmw_aux/calendar.lua
|
||||||
|
)
|
||||||
|
|
||||||
set(DDIRRELATIVE resources/vfs/openmw_aux)
|
set(DDIRRELATIVE resources/vfs/openmw_aux)
|
||||||
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_RESOURCES_ROOT} ${DDIRRELATIVE} "openmw_aux/util.lua")
|
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_RESOURCES_ROOT} ${DDIRRELATIVE} "${LUA_AUX_FILES}")
|
||||||
|
|
||||||
set(LUA_SCRIPTS_FILES
|
set(LUA_SCRIPTS_FILES
|
||||||
scripts/omw/camera.lua
|
scripts/omw/camera.lua
|
||||||
|
|
42
files/builtin_scripts/i18n/Calendar/en.lua
Normal file
42
files/builtin_scripts/i18n/Calendar/en.lua
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
-- source: https://en.uesp.net/wiki/Lore:Calendar
|
||||||
|
|
||||||
|
return {
|
||||||
|
month1 = "Morning Star",
|
||||||
|
month2 = "Sun's Dawn",
|
||||||
|
month3 = "First Seed",
|
||||||
|
month4 = "Rain's Hand",
|
||||||
|
month5 = "Second Seed",
|
||||||
|
month6 = "Midyear",
|
||||||
|
month7 = "Sun's Height",
|
||||||
|
month8 = "Last Seed",
|
||||||
|
month9 = "Hearthfire",
|
||||||
|
month10 = "Frostfall",
|
||||||
|
month11 = "Sun's Dusk",
|
||||||
|
month12 = "Evening Star",
|
||||||
|
|
||||||
|
-- The variant of month names in the context "day X of month Y".
|
||||||
|
-- In English it is the same, but some languages require a different form.
|
||||||
|
monthInGenitive1 = "Morning Star",
|
||||||
|
monthInGenitive2 = "Sun's Dawn",
|
||||||
|
monthInGenitive3 = "First Seed",
|
||||||
|
monthInGenitive4 = "Rain's Hand",
|
||||||
|
monthInGenitive5 = "Second Seed",
|
||||||
|
monthInGenitive6 = "Midyear",
|
||||||
|
monthInGenitive7 = "Sun's Height",
|
||||||
|
monthInGenitive8 = "Last Seed",
|
||||||
|
monthInGenitive9 = "Hearthfire",
|
||||||
|
monthInGenitive10 = "Frostfall",
|
||||||
|
monthInGenitive11 = "Sun's Dusk",
|
||||||
|
monthInGenitive12 = "Evening Star",
|
||||||
|
|
||||||
|
dateFormat = "day %{day} of %{monthInGenitive} %{year}",
|
||||||
|
|
||||||
|
weekday1 = "Sundas",
|
||||||
|
weekday2 = "Morndas",
|
||||||
|
weekday3 = "Tirdas",
|
||||||
|
weekday4 = "Middas",
|
||||||
|
weekday5 = "Turdas",
|
||||||
|
weekday6 = "Fredas",
|
||||||
|
weekday7 = "Loredas",
|
||||||
|
}
|
||||||
|
|
159
files/builtin_scripts/openmw_aux/calendar.lua
Normal file
159
files/builtin_scripts/openmw_aux/calendar.lua
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
---
|
||||||
|
-- `openmw_aux.calendar` defines utility functions for formatting game time.
|
||||||
|
-- Implementation can be found in `resources/vfs/openmw_aux/calendar.lua`.
|
||||||
|
-- @module calendar
|
||||||
|
-- @usage local calendar = require('openmw_aux.calendar')
|
||||||
|
|
||||||
|
local core = require('openmw.core')
|
||||||
|
local time = require('openmw_aux.time')
|
||||||
|
local i18n = core.i18n('Calendar')
|
||||||
|
|
||||||
|
local monthsDuration = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||||
|
local daysInWeek = 7
|
||||||
|
local daysInYear = 0
|
||||||
|
for _, d in ipairs(monthsDuration) do daysInYear = daysInYear + d end
|
||||||
|
|
||||||
|
local startingYear = 427
|
||||||
|
local startingYearDay = 227
|
||||||
|
local startingWeekDay = 1
|
||||||
|
|
||||||
|
local function gameTime(t)
|
||||||
|
if not t then
|
||||||
|
return core.getGameTime()
|
||||||
|
else
|
||||||
|
local days = (t.year or 0) * daysInYear + (t.day or 0)
|
||||||
|
for i = 1, (t.month or 1)-1 do
|
||||||
|
days = days + monthsDuration[i]
|
||||||
|
end
|
||||||
|
return days * time.day + (t.hour or 0) * time.hour +
|
||||||
|
(t.min or 0) * time.minute + (t.sec or 0) * time.second
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function defaultDateFormat(t)
|
||||||
|
return i18n('dateFormat', {
|
||||||
|
day = t.day,
|
||||||
|
month = i18n('month' .. t.month),
|
||||||
|
monthInGenitive = i18n('monthInGenitive' .. t.month),
|
||||||
|
year = t.year,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function formatGameTime(formatStr, timestamp)
|
||||||
|
timestamp = timestamp or core.getGameTime()
|
||||||
|
|
||||||
|
local t = {}
|
||||||
|
local day = math.floor(timestamp / time.day)
|
||||||
|
t.year = math.floor(day / daysInYear) + startingYear
|
||||||
|
t.yday = (day + startingYearDay - 1) % daysInYear + 1
|
||||||
|
t.wday = (day + startingWeekDay - 1) % daysInWeek + 1
|
||||||
|
timestamp = timestamp % time.day
|
||||||
|
t.hour = math.floor(timestamp / time.hour)
|
||||||
|
timestamp = timestamp % time.hour
|
||||||
|
t.min = math.floor(timestamp / time.minute)
|
||||||
|
t.sec = math.floor(timestamp) % time.minute
|
||||||
|
|
||||||
|
t.day = t.yday
|
||||||
|
t.month = 1
|
||||||
|
while t.day > monthsDuration[t.month] do
|
||||||
|
t.day = t.day - monthsDuration[t.month]
|
||||||
|
t.month = t.month + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if formatStr == '*t' then return t end
|
||||||
|
|
||||||
|
local replFn = function(tag)
|
||||||
|
if tag == '%a' or tag == '%A' then return i18n('weekday' .. t.wday) end
|
||||||
|
if tag == '%b' or tag == '%B' then return i18n('monthInGenitive' .. t.month) end
|
||||||
|
if tag == '%c' then
|
||||||
|
return string.format('%02d:%02d %s', t.hour, t.min, defaultDateFormat(t))
|
||||||
|
end
|
||||||
|
if tag == '%d' then return string.format('%02d', t.day) end
|
||||||
|
if tag == '%e' then return string.format('%2d', t.day) end
|
||||||
|
if tag == '%H' then return string.format('%02d', t.hour) end
|
||||||
|
if tag == '%I' then return string.format('%02d', (t.hour - 1) % 12 + 1) end
|
||||||
|
if tag == '%M' then return string.format('%02d', t.min) end
|
||||||
|
if tag == '%m' then return string.format('%02d', t.month) end
|
||||||
|
if tag == '%p' then
|
||||||
|
if t.hour > 0 and t.hour <= 12 then
|
||||||
|
return 'am'
|
||||||
|
else
|
||||||
|
return 'pm'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if tag == '%S' then return string.format('%02d', t.sec) end
|
||||||
|
if tag == '%w' then return t.wday - 1 end
|
||||||
|
if tag == '%x' then return defaultDateFormat(t) end
|
||||||
|
if tag == '%X' then return string.format('%02d:%02d', t.hour, t.min) end
|
||||||
|
if tag == '%Y' then return t.year end
|
||||||
|
if tag == '%y' then return string.format('%02d', t.year % 100) end
|
||||||
|
if tag == '%%' then return '%' end
|
||||||
|
error('Unknown tag "'..tag..'"')
|
||||||
|
end
|
||||||
|
|
||||||
|
res, _ = string.gsub(formatStr or '%c', '%%.', replFn)
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
--- An equivalent of `os.time` for game time.
|
||||||
|
-- See [https://www.lua.org/pil/22.1.html](https://www.lua.org/pil/22.1.html)
|
||||||
|
-- @function [parent=#calendar] gameTime
|
||||||
|
-- @param #table table a table which describes a date (optional).
|
||||||
|
-- @return #number a timestamp.
|
||||||
|
gameTime = gameTime,
|
||||||
|
|
||||||
|
--- An equivalent of `os.date` for game time.
|
||||||
|
-- See [https://www.lua.org/pil/22.1.html](https://www.lua.org/pil/22.1.html).
|
||||||
|
-- It is a slow function. Please try not to use it in every frame.
|
||||||
|
-- @function [parent=#calendar] formatGameTime
|
||||||
|
-- @param #string format format of date (optional)
|
||||||
|
-- @param #number time time to format (default value is current time)
|
||||||
|
-- @return #string a formatted string representation of `time`.
|
||||||
|
formatGameTime = formatGameTime,
|
||||||
|
|
||||||
|
--- The number of months in a year
|
||||||
|
-- @field [parent=#calendar] #number monthCount
|
||||||
|
monthCount = #monthsDuration,
|
||||||
|
|
||||||
|
--- The number of days in a year
|
||||||
|
-- @field [parent=#calendar] #number daysInYear
|
||||||
|
daysInYear = daysInYear,
|
||||||
|
|
||||||
|
--- The number of days in a week
|
||||||
|
-- @field [parent=#calendar] #number daysInWeek
|
||||||
|
daysInWeek = daysInWeek,
|
||||||
|
|
||||||
|
--- The number of days in a month
|
||||||
|
-- @function [parent=#calendar] daysInMonth
|
||||||
|
-- @param monthIndex
|
||||||
|
-- @return #number
|
||||||
|
daysInMonth = function(m)
|
||||||
|
return monthsDuration[(m-1) % #monthsDuration + 1]
|
||||||
|
end,
|
||||||
|
|
||||||
|
--- The name of a month
|
||||||
|
-- @function [parent=#calendar] monthName
|
||||||
|
-- @param monthIndex
|
||||||
|
-- @return #string
|
||||||
|
monthName = function(m)
|
||||||
|
return i18n('month' .. ((m-1) % #monthsDuration + 1))
|
||||||
|
end,
|
||||||
|
|
||||||
|
--- The name of a month in genitive (for English is the same as `monthName`, but in some languages the form can differ).
|
||||||
|
-- @function [parent=#calendar] monthNameInGenitive
|
||||||
|
-- @param monthIndex
|
||||||
|
-- @return #string
|
||||||
|
monthNameInGenitive = function(m)
|
||||||
|
return i18n('monthInGenitive' .. ((m-1) % #monthsDuration + 1))
|
||||||
|
end,
|
||||||
|
|
||||||
|
--- The name of a weekday
|
||||||
|
-- @function [parent=#calendar] weekdayName
|
||||||
|
-- @param dayIndex
|
||||||
|
-- @return #string
|
||||||
|
weekdayName = function(d)
|
||||||
|
return i18n('weekday' .. ((d-1) % daysInWeek + 1))
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
104
files/builtin_scripts/openmw_aux/time.lua
Normal file
104
files/builtin_scripts/openmw_aux/time.lua
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
---
|
||||||
|
-- `openmw_aux.time` defines utility functions for timers.
|
||||||
|
-- Implementation can be found in `resources/vfs/openmw_aux/time.lua`.
|
||||||
|
-- @module time
|
||||||
|
-- @usage local time = require('openmw_aux.time')
|
||||||
|
|
||||||
|
local time = {
|
||||||
|
second = 1,
|
||||||
|
minute = 60,
|
||||||
|
hour = 3600,
|
||||||
|
day = 3600 * 24,
|
||||||
|
GameTime = 'GameTime',
|
||||||
|
SimulationTime = 'SimulationTime',
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Alias of async:registerTimerCallback ; register a function as a timer callback.
|
||||||
|
-- @function [parent=#time] registerTimerCallback
|
||||||
|
-- @param #string name
|
||||||
|
-- @param #function func
|
||||||
|
-- @return openmw.async#TimerCallback
|
||||||
|
function time.registerTimerCallback(name, fn)
|
||||||
|
local async = require('openmw.async')
|
||||||
|
return async:registerTimerCallback(name, fn)
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Alias of async:newSimulationTimer ; call callback(arg) in `delay` game seconds.
|
||||||
|
-- Callback must be registered in advance.
|
||||||
|
-- @function [parent=#time] newGameTimer
|
||||||
|
-- @param #number delay
|
||||||
|
-- @param openmw.async#TimerCallback callback A callback returned by `registerTimerCallback`
|
||||||
|
-- @param arg An argument for `callback`; can be `nil`.
|
||||||
|
function time.newGameTimer(delay, callback, callbackArg)
|
||||||
|
local async = require('openmw.async')
|
||||||
|
return async:newGameTimer(delay, callback, callbackArg)
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Alias of async:newSimulationTimer ; call callback(arg) in `delay` simulation seconds.
|
||||||
|
-- Callback must be registered in advance.
|
||||||
|
-- @function [parent=#time] newSimulationTimer
|
||||||
|
-- @param #number delay
|
||||||
|
-- @param openmw.async#TimerCallback callback A callback returned by `registerTimerCallback`
|
||||||
|
-- @param arg An argument for `callback`; can be `nil`.
|
||||||
|
function time.newSimulationTimer(delay, callback, callbackArg)
|
||||||
|
local async = require('openmw.async')
|
||||||
|
return async:newSimulationTimer(delay, callback, callbackArg)
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Run given function repeatedly.
|
||||||
|
-- Note that loading a save stops the evaluation. If it should work always, call it during initialization of the script (i.e. not in a handler)
|
||||||
|
-- @function [parent=#time] runRepeatedly
|
||||||
|
-- @param #function fn the function that should be called
|
||||||
|
-- @param #number period interval
|
||||||
|
-- @param #table options additional options `initialDelay` and `type`.
|
||||||
|
-- `initialDelay` - delay before the first call. If missed then the delay is a random number in range [0, N]. Randomization is used for performance reasons -- to prevent all scripts from doing time consuming operations at the same time.
|
||||||
|
-- `type` - either `time.SimulationTime` (by default, timer uses simulation time) or `time.GameTime` (timer uses game time).
|
||||||
|
-- @return #function a function without arguments that can be used to stop the periodical evaluation.
|
||||||
|
-- @usage
|
||||||
|
-- local stopFn = time.runRepeatedly(function() print('Test') end,
|
||||||
|
-- 5 * time.second) -- print 'Test' every 5 seconds
|
||||||
|
-- stopFn() -- stop printing 'Test'
|
||||||
|
-- time.runRepeatedly( -- print 'Test' every 5 minutes with initial 30 second delay
|
||||||
|
-- function() print('Test2') end, 5 * time.minute,
|
||||||
|
-- { initialDelay = 30 * time.second })
|
||||||
|
-- @usage
|
||||||
|
-- local timeBeforeMidnight = time.day - time.gameTime() % time.day
|
||||||
|
-- time.runRepeatedly(doSomething, time.day, {
|
||||||
|
-- initialDelay = timeBeforeMidnight,
|
||||||
|
-- type = time.GameTime,
|
||||||
|
-- }) -- call `doSomething` at the end of every game day.
|
||||||
|
function time.runRepeatedly(fn, period, options)
|
||||||
|
if period <= 0 then
|
||||||
|
error('Period must be positive. If you want it to be as small '..
|
||||||
|
'as possible, use the engine handler `onUpdate` instead', 2)
|
||||||
|
end
|
||||||
|
local async = require('openmw.async')
|
||||||
|
local core = require('openmw.core')
|
||||||
|
local initialDelay = (options and options.initialDelay) or math.random() * period
|
||||||
|
local getTimeFn, newTimerFn
|
||||||
|
if (options and options.type) == time.GameTime then
|
||||||
|
getTimeFn = core.getGameTime
|
||||||
|
newTimerFn = async.newUnsavableGameTimer
|
||||||
|
else
|
||||||
|
getTimeFn = core.getSimulationTime
|
||||||
|
newTimerFn = async.newUnsavableSimulationTimer
|
||||||
|
end
|
||||||
|
local baseTime = getTimeFn() + initialDelay
|
||||||
|
local breakFlag = false
|
||||||
|
local wrappedFn
|
||||||
|
wrappedFn = function()
|
||||||
|
if breakFlag then return end
|
||||||
|
fn()
|
||||||
|
local nextDelay = 1.5 * period - math.fmod(getTimeFn() - baseTime + period / 2, period)
|
||||||
|
newTimerFn(async, nextDelay, wrappedFn)
|
||||||
|
end
|
||||||
|
newTimerFn(async, initialDelay, wrappedFn)
|
||||||
|
return function() breakFlag = true end
|
||||||
|
end
|
||||||
|
|
||||||
|
return time
|
||||||
|
|
|
@ -28,72 +28,5 @@ function aux_util.findNearestTo(point, objectList)
|
||||||
return res, resDist
|
return res, resDist
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- Runs given function every N game seconds (seconds when the game is not paused).
|
|
||||||
-- Note that loading a save stops the evaluation. If it should work always, call it in 2 places --
|
|
||||||
-- when a script starts and in the engine handler `onLoad`.
|
|
||||||
-- @function [parent=#util] runEveryNSeconds
|
|
||||||
-- @param #number N interval in seconds
|
|
||||||
-- @param #function fn the function that should be called every N seconds
|
|
||||||
-- @param #number initialDelay optional argument -- delay in seconds before the first call. If missed then the delay is a random number in range [0, N]. Randomization is used for performance reasons -- to prevent all scripts from doing time consuming operations at the same time.
|
|
||||||
-- @return #function a function without arguments that can be used to stop the periodical evaluation.
|
|
||||||
-- @usage
|
|
||||||
-- local stopFn = aux_util.runEveryNSeconds(5, function() print('Test') end) -- print 'Test' every 5 seconds
|
|
||||||
-- stopFn() -- stop printing 'Test'
|
|
||||||
-- aux_util.runEveryNSeconds(5, function() print('Test2') end, 1) -- print 'Test' every 5 seconds starting from the next second
|
|
||||||
function aux_util.runEveryNSeconds(N, fn, initialDelay)
|
|
||||||
if N <= 0 then
|
|
||||||
error('Interval must be positive. If you want it to be as small '..
|
|
||||||
'as possible, use the engine handler `onUpdate` instead', 2)
|
|
||||||
end
|
|
||||||
local async = require('openmw.async')
|
|
||||||
local core = require('openmw.core')
|
|
||||||
local breakFlag = false
|
|
||||||
local initialDelay = initialDelay or math.random() * N
|
|
||||||
local baseTime = core.getGameTimeInSeconds() + initialDelay
|
|
||||||
local wrappedFn
|
|
||||||
wrappedFn = function()
|
|
||||||
if breakFlag then return end
|
|
||||||
fn()
|
|
||||||
local nextDelay = 1.5 * N - math.fmod(core.getGameTimeInSeconds() - baseTime + N / 2, N)
|
|
||||||
async:newUnsavableTimerInSeconds(nextDelay, wrappedFn)
|
|
||||||
end
|
|
||||||
async:newUnsavableTimerInSeconds(initialDelay, wrappedFn)
|
|
||||||
return function() breakFlag = true end
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- Runs given function every N game hours.
|
|
||||||
-- Note that loading a save stops the evaluation. If it should work always, call it in 2 places --
|
|
||||||
-- when a script starts and in the engine handler `onLoad`.
|
|
||||||
-- @function [parent=#util] runEveryNHours
|
|
||||||
-- @param #number N interval in game hours
|
|
||||||
-- @param #function fn the function that should be called every N game hours
|
|
||||||
-- @param #number initialDelay optional argument -- delay in game hours before the first call. If missed then the delay is a random number in range [0, N]. Randomization is used for performance reasons -- to prevent all scripts from doing time consuming operations at the same time.
|
|
||||||
-- @return #function a function without arguments that can be used to stop the periodical evaluation.
|
|
||||||
-- @usage
|
|
||||||
-- local timeBeforeMidnight = 24 - math.fmod(core.getGameTimeInHours(), 24)
|
|
||||||
-- aux_util.runEveryNHours(24, doSomething, timeBeforeMidnight) -- call `doSomething` at the end of every game day.
|
|
||||||
function aux_util.runEveryNHours(N, fn, initialDelay)
|
|
||||||
if N <= 0 then
|
|
||||||
error('Interval must be positive. If you want it to be as small '..
|
|
||||||
'as possible, use the engine handler `onUpdate` instead', 2)
|
|
||||||
end
|
|
||||||
local async = require('openmw.async')
|
|
||||||
local core = require('openmw.core')
|
|
||||||
local breakFlag = false
|
|
||||||
local initialDelay = initialDelay or math.random() * N
|
|
||||||
local baseTime = core.getGameTimeInHours() + initialDelay
|
|
||||||
local wrappedFn
|
|
||||||
wrappedFn = function()
|
|
||||||
if breakFlag then return end
|
|
||||||
fn()
|
|
||||||
local nextDelay = 1.5 * N - math.fmod(core.getGameTimeInHours() - baseTime + N / 2, N)
|
|
||||||
async:newUnsavableTimerInHours(nextDelay, wrappedFn)
|
|
||||||
end
|
|
||||||
async:newUnsavableTimerInHours(initialDelay, wrappedFn)
|
|
||||||
return function() breakFlag = true end
|
|
||||||
end
|
|
||||||
|
|
||||||
return aux_util
|
return aux_util
|
||||||
|
|
||||||
|
|
|
@ -175,10 +175,12 @@ return {
|
||||||
--- @module Camera
|
--- @module Camera
|
||||||
-- @usage require('openmw.interfaces').Camera
|
-- @usage require('openmw.interfaces').Camera
|
||||||
interface = {
|
interface = {
|
||||||
--- @field [parent=#Camera] #number version Interface version
|
--- Interface version
|
||||||
|
-- @field [parent=#Camera] #number version
|
||||||
version = 0,
|
version = 0,
|
||||||
|
|
||||||
--- @function [parent=#Camera] getPrimaryMode Returns primary mode (MODE.FirstPerson or MODE.ThirdPerson).
|
--- Return primary mode (MODE.FirstPerson or MODE.ThirdPerson).
|
||||||
|
-- @function [parent=#Camera] getPrimaryMode
|
||||||
getPrimaryMode = function() return primaryMode end,
|
getPrimaryMode = function() return primaryMode end,
|
||||||
--- @function [parent=#Camera] getBaseThirdPersonDistance
|
--- @function [parent=#Camera] getBaseThirdPersonDistance
|
||||||
getBaseThirdPersonDistance = function() return third_person.baseDistance end,
|
getBaseThirdPersonDistance = function() return third_person.baseDistance end,
|
||||||
|
|
|
@ -15,35 +15,35 @@
|
||||||
-- @return #TimerCallback
|
-- @return #TimerCallback
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Calls callback(arg) in `delay` seconds.
|
-- Calls callback(arg) in `delay` simulation seconds.
|
||||||
-- Callback must be registered in advance.
|
-- Callback must be registered in advance.
|
||||||
-- @function [parent=#async] newTimerInSeconds
|
-- @function [parent=#async] newSimulationTimer
|
||||||
-- @param self
|
-- @param self
|
||||||
-- @param #number delay
|
-- @param #number delay
|
||||||
-- @param #TimerCallback callback A callback returned by `registerTimerCallback`
|
-- @param #TimerCallback callback A callback returned by `registerTimerCallback`
|
||||||
-- @param arg An argument for `callback`; can be `nil`.
|
-- @param arg An argument for `callback`; can be `nil`.
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Calls callback(arg) in `delay` game hours.
|
-- Calls callback(arg) in `delay` game seconds.
|
||||||
-- Callback must be registered in advance.
|
-- Callback must be registered in advance.
|
||||||
-- @function [parent=#async] newTimerInHours
|
-- @function [parent=#async] newGameTimer
|
||||||
-- @param self
|
-- @param self
|
||||||
-- @param #number delay
|
-- @param #number delay
|
||||||
-- @param #TimerCallback callback A callback returned by `registerTimerCallback`
|
-- @param #TimerCallback callback A callback returned by `registerTimerCallback`
|
||||||
-- @param arg An argument for `callback`; can be `nil`.
|
-- @param arg An argument for `callback`; can be `nil`.
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Calls `func()` in `delay` seconds.
|
-- Calls `func()` in `delay` simulation seconds.
|
||||||
-- The timer will be lost if the game is saved and loaded.
|
-- The timer will be lost if the game is saved and loaded.
|
||||||
-- @function [parent=#async] newUnsavableTimerInSeconds
|
-- @function [parent=#async] newUnsavableSimulationTimer
|
||||||
-- @param self
|
-- @param self
|
||||||
-- @param #number delay
|
-- @param #number delay
|
||||||
-- @param #function func
|
-- @param #function func
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Calls `func()` in `delay` game hours.
|
-- Calls `func()` in `delay` game seconds.
|
||||||
-- The timer will be lost if the game is saved and loaded.
|
-- The timer will be lost if the game is saved and loaded.
|
||||||
-- @function [parent=#async] newUnsavableTimerInHours
|
-- @function [parent=#async] newUnsavableGameTimer
|
||||||
-- @param self
|
-- @param self
|
||||||
-- @param #number delay
|
-- @param #number delay
|
||||||
-- @param #function func
|
-- @param #function func
|
||||||
|
|
|
@ -21,15 +21,24 @@
|
||||||
-- @param eventData
|
-- @param eventData
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Game time in seconds.
|
-- Simulation time in seconds.
|
||||||
-- The number of seconds passed in the game world since starting a new game.
|
-- The number of simulation seconds passed in the game world since starting a new game.
|
||||||
-- @function [parent=#core] getGameTimeInSeconds
|
-- @function [parent=#core] getSimulationTime
|
||||||
-- @return #number
|
-- @return #number
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Current time of the game world in hours.
|
-- The scale of simulation time relative to real time.
|
||||||
-- Note that the number of game seconds in a game hour is not guaranteed to be fixed.
|
-- @function [parent=#core] getSimulationTimeScale
|
||||||
-- @function [parent=#core] getGameTimeInHours
|
-- @return #number
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Game time in seconds.
|
||||||
|
-- @function [parent=#core] getGameTime
|
||||||
|
-- @return #number
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- The scale of game time relative to simulation time.
|
||||||
|
-- @function [parent=#core] getGameTimeScale
|
||||||
-- @return #number
|
-- @return #number
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
|
@ -29,6 +29,36 @@
|
||||||
-- @param #number gridY
|
-- @param #number gridY
|
||||||
-- @return openmw.core#Cell
|
-- @return openmw.core#Cell
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Simulation time in seconds.
|
||||||
|
-- The number of simulation seconds passed in the game world since starting a new game.
|
||||||
|
-- @function [parent=#core] getSimulationTime
|
||||||
|
-- @return #number
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- The scale of simulation time relative to real time.
|
||||||
|
-- @function [parent=#core] getSimulationTimeScale
|
||||||
|
-- @return #number
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Game time in seconds.
|
||||||
|
-- @function [parent=#core] getGameTime
|
||||||
|
-- @return #number
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- The scale of game time relative to simulation time.
|
||||||
|
-- @function [parent=#core] getGameTimeScale
|
||||||
|
-- @return #number
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Set the ratio of game time speed to simulation time speed.
|
||||||
|
-- @function [parent=#world] setGameTimeScale
|
||||||
|
-- @param #number ratio
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Whether the world is paused (onUpdate doesn't work when the world is paused).
|
||||||
|
-- @function [parent=#world] isWorldPaused
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
|
64
files/lua_api/os.doclua
Normal file
64
files/lua_api/os.doclua
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Operating System Facilities.
|
||||||
|
-- This library is implemented through table os.
|
||||||
|
-- @module os
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Returns a string or a table containing date and time, formatted according
|
||||||
|
-- to the given string `format`.
|
||||||
|
--
|
||||||
|
-- If the `time` argument is present, this is the time to be formatted
|
||||||
|
-- (see the `os.time` function for a description of this value). Otherwise,
|
||||||
|
-- `date` formats the current time.
|
||||||
|
--
|
||||||
|
-- If `format` starts with '`!`', then the date is formatted in Coordinated
|
||||||
|
-- Universal Time. After this optional character, if `format` is the string
|
||||||
|
-- "`*t`", then `date` returns a table with the following fields:
|
||||||
|
--
|
||||||
|
-- * `year` (four digits)
|
||||||
|
-- * `month` (1--12)
|
||||||
|
-- * `day` (1--31)
|
||||||
|
-- * `hour` (0--23)
|
||||||
|
-- * `min` (0--59)
|
||||||
|
-- * `sec` (0--61)
|
||||||
|
-- * `wday` (weekday, Sunday is 1)
|
||||||
|
-- * `yday` (day of the year)
|
||||||
|
-- * `isdst` (daylight saving flag, a boolean).
|
||||||
|
--
|
||||||
|
-- If `format` is not "`*t`", then `date` returns the date as a string,
|
||||||
|
-- formatted according to the same rules as the C function `strftime`.
|
||||||
|
-- When called without arguments, `date` returns a reasonable date and time
|
||||||
|
-- representation that depends on the host system and on the current locale
|
||||||
|
-- (that is, `os.date()` is equivalent to `os.date("%c")`).
|
||||||
|
-- @function [parent=#os] date
|
||||||
|
-- @param #string format format of date. (optional)
|
||||||
|
-- @param #number time time to format. (default value is current time)
|
||||||
|
-- @return #string a formatted string representation of `time`.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Returns the number of seconds from time `t1` to time `t2`. In POSIX,
|
||||||
|
-- Windows, and some other systems, this value is exactly `t2`*-*`t1`.
|
||||||
|
-- @function [parent=#os] difftime
|
||||||
|
-- @param #number t2
|
||||||
|
-- @param #number t1
|
||||||
|
-- @return #number the number of seconds from time `t1` to time `t2`.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Returns the current time when called without arguments, or a time
|
||||||
|
-- representing the date and time specified by the given table. This table
|
||||||
|
-- must have fields `year`, `month`, and `day`, and may have fields `hour`,
|
||||||
|
-- `min`, `sec`, and `isdst` (for a description of these fields, see the
|
||||||
|
-- `os.date` function).
|
||||||
|
--
|
||||||
|
-- The returned value is a number, whose meaning depends on your system. In
|
||||||
|
-- POSIX, Windows, and some other systems, this number counts the number
|
||||||
|
-- of seconds since some given start time (the "epoch"). In other systems,
|
||||||
|
-- the meaning is not specified, and the number returned by `time` can be
|
||||||
|
-- used only as an argument to `date` and `difftime`.
|
||||||
|
-- @function [parent=#os] time
|
||||||
|
-- @param #table table a table which describes a date.
|
||||||
|
-- @return #number a number meaning a date.
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
Loading…
Reference in a new issue