mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 03:39:42 +00:00
Fixes and refactoring
This commit is contained in:
parent
25cc884c17
commit
702eb19271
27 changed files with 253 additions and 158 deletions
|
@ -833,18 +833,17 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
class OMW::Engine::LuaWorker
|
||||
{
|
||||
public:
|
||||
explicit LuaWorker(Engine* engine) :
|
||||
mEngine(engine),
|
||||
mSeparateThread(Settings::Manager::getInt("lua num threads", "Lua") > 0)
|
||||
explicit LuaWorker(Engine* engine) : mEngine(engine)
|
||||
{
|
||||
if (mSeparateThread)
|
||||
if (Settings::Manager::getInt("lua num threads", "Lua") > 0)
|
||||
mThread = std::thread([this]{ threadBody(); });
|
||||
};
|
||||
|
||||
void allowUpdate(double dt)
|
||||
{
|
||||
mDt = dt;
|
||||
if (!mSeparateThread)
|
||||
mIsGuiMode = mEngine->mEnvironment.getWindowManager()->isGuiMode();
|
||||
if (!mThread)
|
||||
return;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(mMutex);
|
||||
|
@ -855,7 +854,7 @@ public:
|
|||
|
||||
void finishUpdate()
|
||||
{
|
||||
if (mSeparateThread)
|
||||
if (mThread)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(mMutex);
|
||||
mCV.wait(lk, [&]{ return !mUpdateRequest; });
|
||||
|
@ -867,8 +866,8 @@ public:
|
|||
|
||||
void join()
|
||||
{
|
||||
if (mSeparateThread)
|
||||
mThread.join();
|
||||
if (mThread)
|
||||
mThread->join();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -879,7 +878,7 @@ private:
|
|||
const unsigned int frameNumber = viewer->getFrameStamp()->getFrameNumber();
|
||||
ScopedProfile<UserStatsType::Lua> profile(frameStart, frameNumber, *osg::Timer::instance(), *viewer->getViewerStats());
|
||||
|
||||
mEngine->mLuaManager->update(mEngine->mEnvironment.getWindowManager()->isGuiMode(), mDt);
|
||||
mEngine->mLuaManager->update(mIsGuiMode, mDt);
|
||||
}
|
||||
|
||||
void threadBody()
|
||||
|
@ -898,12 +897,12 @@ private:
|
|||
}
|
||||
|
||||
Engine* mEngine;
|
||||
const bool mSeparateThread;
|
||||
std::mutex mMutex;
|
||||
std::condition_variable mCV;
|
||||
bool mUpdateRequest;
|
||||
double mDt = 0;
|
||||
std::thread mThread;
|
||||
bool mIsGuiMode = false;
|
||||
std::optional<std::thread> mThread;
|
||||
};
|
||||
|
||||
// Initialise and enter main loop.
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace ESM
|
|||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
class LuaScripts;
|
||||
struct LuaScripts;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
|
@ -40,15 +40,16 @@ namespace MWBase
|
|||
// virtual void objectOnHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object,
|
||||
// const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful) = 0;
|
||||
|
||||
struct ActorControls {
|
||||
bool disableAI;
|
||||
bool controlledFromLua;
|
||||
struct ActorControls
|
||||
{
|
||||
bool mDisableAI;
|
||||
bool mControlledFromLua;
|
||||
|
||||
bool jump;
|
||||
bool run;
|
||||
float movement;
|
||||
float sideMovement;
|
||||
float turn;
|
||||
bool mJump;
|
||||
bool mRun;
|
||||
float mMovement;
|
||||
float mSideMovement;
|
||||
float mTurn;
|
||||
};
|
||||
|
||||
virtual ActorControls* getActorControls(const MWWorld::Ptr&) const = 0;
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace MWLua
|
|||
std::fill(usedSlots.begin(), usedSlots.end(), false);
|
||||
|
||||
constexpr int anySlot = -1;
|
||||
auto tryEquipToSlot = [&](int slot, const Item& item) -> bool
|
||||
auto tryEquipToSlot = [&actor, &store, &usedSlots, &worldView, anySlot](int slot, const Item& item) -> bool
|
||||
{
|
||||
auto old_it = slot != anySlot ? store.getSlot(slot) : store.end();
|
||||
MWWorld::Ptr itemPtr;
|
||||
|
@ -83,23 +83,16 @@ namespace MWLua
|
|||
}
|
||||
|
||||
auto [allowedSlots, _] = itemPtr.getClass().getEquipmentSlots(itemPtr);
|
||||
bool requestedSlotIsAllowed = false;
|
||||
for (int allowedSlot : allowedSlots)
|
||||
requestedSlotIsAllowed = requestedSlotIsAllowed || allowedSlot == slot;
|
||||
bool requestedSlotIsAllowed = std::find(allowedSlots.begin(), allowedSlots.end(), slot) != allowedSlots.end();
|
||||
if (!requestedSlotIsAllowed)
|
||||
{
|
||||
slot = anySlot;
|
||||
for (int allowedSlot : allowedSlots)
|
||||
if (!usedSlots[allowedSlot])
|
||||
{
|
||||
slot = allowedSlot;
|
||||
break;
|
||||
}
|
||||
if (slot == anySlot)
|
||||
auto firstAllowed = std::find_if(allowedSlots.begin(), allowedSlots.end(), [&](int s) { return !usedSlots[s]; });
|
||||
if (firstAllowed == allowedSlots.end())
|
||||
{
|
||||
Log(Debug::Warning) << "No suitable slot for " << ptrToString(itemPtr);
|
||||
return false;
|
||||
}
|
||||
slot = *firstAllowed;
|
||||
}
|
||||
|
||||
// TODO: Refactor InventoryStore to accept Ptr and get rid of this linear search.
|
||||
|
@ -124,7 +117,7 @@ namespace MWLua
|
|||
if (tryEquipToSlot(slot, new_it->second))
|
||||
usedSlots[slot] = true;
|
||||
}
|
||||
for (auto [slot, item] : mEquipment)
|
||||
for (const auto& [slot, item] : mEquipment)
|
||||
if (slot >= MWWorld::InventoryStore::Slots)
|
||||
tryEquipToSlot(anySlot, item);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace MWLua
|
|||
|
||||
sol::function getAsyncPackageInitializer(const Context& context)
|
||||
{
|
||||
using TimeUnit = LuaUtil::ScriptsContainer::TimeUnit;
|
||||
sol::usertype<AsyncPackageId> api = context.mLua->sol().new_usertype<AsyncPackageId>("AsyncPackage");
|
||||
api["registerTimerCallback"] = [](const AsyncPackageId& asyncId, std::string_view name, sol::function callback)
|
||||
{
|
||||
|
@ -27,21 +28,25 @@ namespace MWLua
|
|||
const TimerCallback& callback, sol::object callbackArg)
|
||||
{
|
||||
callback.mAsyncId.mContainer->setupSerializableTimer(
|
||||
false, world->getGameTimeInSeconds() + delay, callback.mAsyncId.mScript, callback.mName, std::move(callbackArg));
|
||||
TimeUnit::SECONDS, world->getGameTimeInSeconds() + delay,
|
||||
callback.mAsyncId.mScript, callback.mName, std::move(callbackArg));
|
||||
};
|
||||
api["newTimerInHours"] = [world=context.mWorldView](const AsyncPackageId&, double delay,
|
||||
const TimerCallback& callback, sol::object callbackArg)
|
||||
{
|
||||
callback.mAsyncId.mContainer->setupSerializableTimer(
|
||||
true, world->getGameTimeInHours() + delay, callback.mAsyncId.mScript, callback.mName, std::move(callbackArg));
|
||||
TimeUnit::HOURS, world->getGameTimeInHours() + delay,
|
||||
callback.mAsyncId.mScript, callback.mName, std::move(callbackArg));
|
||||
};
|
||||
api["newUnsavableTimerInSeconds"] = [world=context.mWorldView](const AsyncPackageId& asyncId, double delay, sol::function callback)
|
||||
{
|
||||
asyncId.mContainer->setupUnsavableTimer(false, world->getGameTimeInSeconds() + delay, asyncId.mScript, std::move(callback));
|
||||
asyncId.mContainer->setupUnsavableTimer(
|
||||
TimeUnit::SECONDS, world->getGameTimeInSeconds() + delay, asyncId.mScript, std::move(callback));
|
||||
};
|
||||
api["newUnsavableTimerInHours"] = [world=context.mWorldView](const AsyncPackageId& asyncId, double delay, sol::function callback)
|
||||
{
|
||||
asyncId.mContainer->setupUnsavableTimer(true, world->getGameTimeInHours() + delay, asyncId.mScript, std::move(callback));
|
||||
asyncId.mContainer->setupUnsavableTimer(
|
||||
TimeUnit::HOURS, world->getGameTimeInHours() + delay, asyncId.mScript, std::move(callback));
|
||||
};
|
||||
|
||||
auto initializer = [](sol::table hiddenData)
|
||||
|
|
|
@ -22,11 +22,11 @@ namespace MWLua
|
|||
{
|
||||
using ActorControls = MWBase::LuaManager::ActorControls;
|
||||
sol::usertype<ActorControls> controls = context.mLua->sol().new_usertype<ActorControls>("ActorControls");
|
||||
controls["movement"] = &ActorControls::movement;
|
||||
controls["sideMovement"] = &ActorControls::sideMovement;
|
||||
controls["turn"] = &ActorControls::turn;
|
||||
controls["run"] = &ActorControls::run;
|
||||
controls["jump"] = &ActorControls::jump;
|
||||
controls["movement"] = &ActorControls::mMovement;
|
||||
controls["sideMovement"] = &ActorControls::mSideMovement;
|
||||
controls["turn"] = &ActorControls::mTurn;
|
||||
controls["run"] = &ActorControls::mRun;
|
||||
controls["jump"] = &ActorControls::mJump;
|
||||
|
||||
sol::usertype<SelfObject> selfAPI =
|
||||
context.mLua->sol().new_usertype<SelfObject>("SelfObject", sol::base_classes, sol::bases<LObject>());
|
||||
|
@ -34,8 +34,8 @@ namespace MWLua
|
|||
selfAPI["object"] = sol::readonly_property([](SelfObject& self) -> LObject { return LObject(self); });
|
||||
selfAPI["controls"] = sol::readonly_property([](SelfObject& self) { return &self.mControls; });
|
||||
selfAPI["isActive"] = [](SelfObject& self) { return &self.mIsActive; };
|
||||
selfAPI["setDirectControl"] = [](SelfObject& self, bool v) { self.mControls.controlledFromLua = v; };
|
||||
selfAPI["enableAI"] = [](SelfObject& self, bool v) { self.mControls.disableAI = !v; };
|
||||
selfAPI["setDirectControl"] = [](SelfObject& self, bool v) { self.mControls.mControlledFromLua = v; };
|
||||
selfAPI["enableAI"] = [](SelfObject& self, bool v) { self.mControls.mDisableAI = !v; };
|
||||
selfAPI["setEquipment"] = [manager=context.mLuaManager](const SelfObject& obj, sol::table equipment)
|
||||
{
|
||||
if (!obj.ptr().getClass().hasInventoryStore(obj.ptr()))
|
||||
|
@ -79,16 +79,11 @@ namespace MWLua
|
|||
};
|
||||
}
|
||||
|
||||
std::unique_ptr<LocalScripts> LocalScripts::create(LuaUtil::LuaState* lua, const LObject& obj)
|
||||
{
|
||||
return std::unique_ptr<LocalScripts>(new LocalScripts(lua, obj));
|
||||
}
|
||||
|
||||
LocalScripts::LocalScripts(LuaUtil::LuaState* lua, const LObject& obj)
|
||||
: LuaUtil::ScriptsContainer(lua, "L" + idToString(obj.id())), mData(obj)
|
||||
{
|
||||
mData.mControls.controlledFromLua = false;
|
||||
mData.mControls.disableAI = false;
|
||||
mData.mControls.mControlledFromLua = false;
|
||||
mData.mControls.mDisableAI = false;
|
||||
this->addPackage("openmw.self", sol::make_object(lua->sol(), &mData));
|
||||
registerEngineHandlers({&mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers});
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ namespace MWLua
|
|||
class LocalScripts : public LuaUtil::ScriptsContainer
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<LocalScripts> create(LuaUtil::LuaState* lua, const LObject& obj);
|
||||
static void initializeSelfPackage(const Context&);
|
||||
LocalScripts(LuaUtil::LuaState* lua, const LObject& obj);
|
||||
|
||||
MWBase::LuaManager::ActorControls* getActorControls() { return &mData.mControls; }
|
||||
|
||||
|
@ -42,8 +42,8 @@ namespace MWLua
|
|||
void receiveEngineEvent(const EngineEvent&, ObjectRegistry*);
|
||||
|
||||
protected:
|
||||
LocalScripts(LuaUtil::LuaState* lua, const LObject& obj);
|
||||
SelfObject mData;
|
||||
|
||||
private:
|
||||
EngineHandlerList mOnActiveHandlers{"onActive"};
|
||||
EngineHandlerList mOnInactiveHandlers{"onInactive"};
|
||||
|
|
|
@ -76,7 +76,7 @@ namespace MWLua
|
|||
if (cell)
|
||||
return GCell{cell};
|
||||
else
|
||||
return {};
|
||||
return sol::nullopt;
|
||||
};
|
||||
api["getExteriorCell"] = [worldView=context.mWorldView](int x, int y) -> sol::optional<GCell>
|
||||
{
|
||||
|
@ -84,7 +84,7 @@ namespace MWLua
|
|||
if (cell)
|
||||
return GCell{cell};
|
||||
else
|
||||
return {};
|
||||
return sol::nullopt;
|
||||
};
|
||||
api["activeActors"] = GObjectList{worldView->getActorsInScene()};
|
||||
api["selectObjects"] = [context](const Queries::Query& query)
|
||||
|
@ -156,7 +156,9 @@ namespace MWLua
|
|||
for (const Queries::Field* field : group.mFields)
|
||||
{
|
||||
sol::table subgroup = res;
|
||||
for (int i = 0; i < static_cast<int>(field->path().size()) - 1; ++i)
|
||||
if (field->path().empty())
|
||||
throw std::logic_error("Empty path in Queries::Field");
|
||||
for (size_t i = 0; i < field->path().size() - 1; ++i)
|
||||
{
|
||||
const std::string& name = field->path()[i];
|
||||
if (subgroup[name] == sol::nil)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <components/esm/luascripts.hpp>
|
||||
|
||||
#include <components/lua/utilpackage.hpp>
|
||||
#include <components/lua/omwscriptsparser.hpp>
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
|
@ -19,9 +20,10 @@
|
|||
namespace MWLua
|
||||
{
|
||||
|
||||
LuaManager::LuaManager(const VFS::Manager* vfs, const std::vector<std::string>& globalScriptLists) : mLua(vfs)
|
||||
LuaManager::LuaManager(const VFS::Manager* vfs, const std::vector<std::string>& scriptLists) : mLua(vfs)
|
||||
{
|
||||
Log(Debug::Info) << "Lua version: " << LuaUtil::getLuaVersion();
|
||||
mGlobalScriptList = LuaUtil::parseOMWScriptsFiles(vfs, scriptLists);
|
||||
|
||||
mGlobalSerializer = createUserdataSerializer(false, mWorldView.getObjectRegistry());
|
||||
mLocalSerializer = createUserdataSerializer(true, mWorldView.getObjectRegistry());
|
||||
|
@ -58,37 +60,6 @@ namespace MWLua
|
|||
mCameraPackage = initCameraPackage(localContext);
|
||||
mUserInterfacePackage = initUserInterfacePackage(localContext);
|
||||
mNearbyPackage = initNearbyPackage(localContext);
|
||||
|
||||
auto endsWith = [](std::string_view s, std::string_view suffix)
|
||||
{
|
||||
return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
|
||||
};
|
||||
for (const std::string& scriptListFile : globalScriptLists)
|
||||
{
|
||||
if (!endsWith(scriptListFile, ".omwscripts"))
|
||||
{
|
||||
Log(Debug::Error) << "Script list should have suffix '.omwscripts', got: '" << scriptListFile << "'";
|
||||
continue;
|
||||
}
|
||||
std::string content(std::istreambuf_iterator<char>(*vfs->get(scriptListFile)), {});
|
||||
std::string_view view(content);
|
||||
while (!view.empty())
|
||||
{
|
||||
size_t pos = 0;
|
||||
while (pos < view.size() && view[pos] != '\n')
|
||||
pos++;
|
||||
std::string_view line = view.substr(0, pos);
|
||||
view = view.substr(pos + 1);
|
||||
if (line.empty() || line[0] == '#')
|
||||
continue;
|
||||
if (line.back() == '\r')
|
||||
line = line.substr(0, pos - 1);
|
||||
if (endsWith(line, ".lua"))
|
||||
mGlobalScriptList.push_back(std::string(line));
|
||||
else
|
||||
Log(Debug::Error) << "Lua script should have suffix '.lua', got: '" << line.substr(0, 300) << "'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LuaManager::init()
|
||||
|
@ -306,18 +277,18 @@ namespace MWLua
|
|||
|
||||
LocalScripts* LuaManager::createLocalScripts(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
std::unique_ptr<LocalScripts> scripts;
|
||||
std::shared_ptr<LocalScripts> scripts;
|
||||
// When loading a game, it can be called before LuaManager::setPlayer,
|
||||
// so we can't just check ptr == mPlayer here.
|
||||
if (*ptr.getCellRef().getRefIdPtr() == "player")
|
||||
{
|
||||
mPlayerScripts = new PlayerScripts(&mLua, LObject(getId(ptr), mWorldView.getObjectRegistry()));
|
||||
scripts = std::unique_ptr<LocalScripts>(mPlayerScripts);
|
||||
scripts = std::shared_ptr<LocalScripts>(mPlayerScripts);
|
||||
scripts->addPackage("openmw.ui", mUserInterfacePackage);
|
||||
scripts->addPackage("openmw.camera", mCameraPackage);
|
||||
}
|
||||
else
|
||||
scripts = LocalScripts::create(&mLua, LObject(getId(ptr), mWorldView.getObjectRegistry()));
|
||||
scripts = std::make_shared<LocalScripts>(&mLua, LObject(getId(ptr), mWorldView.getObjectRegistry()));
|
||||
scripts->addPackage("openmw.nearby", mNearbyPackage);
|
||||
scripts->setSerializer(mLocalSerializer.get());
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ namespace MWLua
|
|||
{
|
||||
public:
|
||||
LuaManager(const VFS::Manager* vfs, const std::vector<std::string>& globalScriptLists);
|
||||
~LuaManager() {}
|
||||
|
||||
// Called by engine.cpp when environment is fully initialized.
|
||||
void init();
|
||||
|
|
|
@ -104,7 +104,7 @@ namespace MWLua
|
|||
if (ptr.isInCell())
|
||||
return Cell<ObjectT>{ptr.getCell()};
|
||||
else
|
||||
return {};
|
||||
return sol::nullopt;
|
||||
});
|
||||
objectT["position"] = sol::readonly_property([](const ObjectT& o) -> osg::Vec3f
|
||||
{
|
||||
|
@ -123,17 +123,17 @@ namespace MWLua
|
|||
context.mLocalEventQueue->push_back({dest.id(), std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer)});
|
||||
};
|
||||
|
||||
objectT["canMove"] = [context](const ObjectT& o)
|
||||
objectT["canMove"] = [](const ObjectT& o)
|
||||
{
|
||||
const MWWorld::Class& cls = o.ptr().getClass();
|
||||
return cls.getMaxSpeed(o.ptr()) > 0;
|
||||
};
|
||||
objectT["getRunSpeed"] = [context](const ObjectT& o)
|
||||
objectT["getRunSpeed"] = [](const ObjectT& o)
|
||||
{
|
||||
const MWWorld::Class& cls = o.ptr().getClass();
|
||||
return cls.getRunSpeed(o.ptr());
|
||||
};
|
||||
objectT["getWalkSpeed"] = [context](const ObjectT& o)
|
||||
objectT["getWalkSpeed"] = [](const ObjectT& o)
|
||||
{
|
||||
const MWWorld::Class& cls = o.ptr().getClass();
|
||||
return cls.getWalkSpeed(o.ptr());
|
||||
|
@ -182,12 +182,12 @@ namespace MWLua
|
|||
{
|
||||
const MWWorld::CellRef& cellRef = ptr(o).getCellRef();
|
||||
if (!cellRef.getTeleport())
|
||||
return {};
|
||||
return sol::nullopt;
|
||||
MWWorld::CellStore* cell = worldView->findCell(cellRef.getDestCell(), cellRef.getDoorDest().asVec3());
|
||||
if (cell)
|
||||
return Cell<ObjectT>{cell};
|
||||
else
|
||||
return {};
|
||||
return sol::nullopt;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -84,9 +84,12 @@ namespace MWLua
|
|||
}
|
||||
if (ptr.getRefData().getCount() == 0)
|
||||
return false;
|
||||
// It is stupid, but "prisonmarker" has class "Door" despite that it is only an invisible marker. So we ignore all markers.
|
||||
|
||||
// It is important to exclude all markers before checking what class it is.
|
||||
// For example "prisonmarker" has class "Door" despite that it is only an invisible marker.
|
||||
if (isMarker(ptr))
|
||||
return false;
|
||||
|
||||
const MWWorld::Class& cls = ptr.getClass();
|
||||
if (cls.isActivator() != (query.mQueryType == ObjectQueryTypes::ACTIVATORS))
|
||||
return false;
|
||||
|
|
|
@ -2065,7 +2065,7 @@ namespace MWMechanics
|
|||
if (iter->first != player)
|
||||
{
|
||||
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
|
||||
if (isConscious(iter->first) && !(luaControls && luaControls->disableAI))
|
||||
if (isConscious(iter->first) && !(luaControls && luaControls->mDisableAI))
|
||||
{
|
||||
stats.getAiSequence().execute(iter->first, *ctrl, duration);
|
||||
updateGreetingState(iter->first, *iter->second, timerUpdateHello > 0);
|
||||
|
@ -2074,7 +2074,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (aiActive && iter->first != player && isConscious(iter->first) && !(luaControls && luaControls->disableAI))
|
||||
else if (aiActive && iter->first != player && isConscious(iter->first) && !(luaControls && luaControls->mDisableAI))
|
||||
{
|
||||
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
|
||||
stats.getAiSequence().execute(iter->first, *ctrl, duration, /*outOfRange*/true);
|
||||
|
@ -2101,21 +2101,21 @@ namespace MWMechanics
|
|||
float rotationZ = mov.mRotation[2];
|
||||
bool jump = mov.mPosition[2] == 1;
|
||||
bool runFlag = stats.getMovementFlag(MWMechanics::CreatureStats::Flag_Run);
|
||||
if (luaControls->controlledFromLua)
|
||||
if (luaControls->mControlledFromLua)
|
||||
{
|
||||
mov.mPosition[0] = luaControls->sideMovement;
|
||||
mov.mPosition[1] = luaControls->movement;
|
||||
mov.mPosition[2] = luaControls->jump ? 1 : 0;
|
||||
mov.mPosition[0] = luaControls->mSideMovement;
|
||||
mov.mPosition[1] = luaControls->mMovement;
|
||||
mov.mPosition[2] = luaControls->mJump ? 1 : 0;
|
||||
mov.mRotation[1] = 0;
|
||||
mov.mRotation[2] = luaControls->turn;
|
||||
mov.mSpeedFactor = osg::Vec2(luaControls->movement, luaControls->sideMovement).length();
|
||||
stats.setMovementFlag(MWMechanics::CreatureStats::Flag_Run, luaControls->run);
|
||||
mov.mRotation[2] = luaControls->mTurn;
|
||||
mov.mSpeedFactor = osg::Vec2(luaControls->mMovement, luaControls->mSideMovement).length();
|
||||
stats.setMovementFlag(MWMechanics::CreatureStats::Flag_Run, luaControls->mRun);
|
||||
}
|
||||
luaControls->sideMovement = movement.x();
|
||||
luaControls->movement = movement.y();
|
||||
luaControls->turn = rotationZ;
|
||||
luaControls->jump = jump;
|
||||
luaControls->run = runFlag;
|
||||
luaControls->mSideMovement = movement.x();
|
||||
luaControls->mMovement = movement.y();
|
||||
luaControls->mTurn = rotationZ;
|
||||
luaControls->mJump = jump;
|
||||
luaControls->mRun = runFlag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,9 @@ namespace MWWorld
|
|||
lastAssignedRefNum.mIndex++;
|
||||
if (lastAssignedRefNum.mIndex == 0) // mIndex overflow, so mContentFile should be changed
|
||||
{
|
||||
lastAssignedRefNum.mContentFile--;
|
||||
if (lastAssignedRefNum.mContentFile > 0)
|
||||
if (lastAssignedRefNum.mContentFile > std::numeric_limits<int32_t>::min())
|
||||
lastAssignedRefNum.mContentFile--;
|
||||
else
|
||||
Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum";
|
||||
}
|
||||
mCellRef.mRefNum = lastAssignedRefNum;
|
||||
|
|
|
@ -23,7 +23,7 @@ enum RefDataFlags
|
|||
namespace MWWorld
|
||||
{
|
||||
|
||||
void RefData::setLuaScripts(std::unique_ptr<MWLua::LocalScripts>&& scripts)
|
||||
void RefData::setLuaScripts(std::shared_ptr<MWLua::LocalScripts>&& scripts)
|
||||
{
|
||||
mChanged = true;
|
||||
mLuaScripts = std::move(scripts);
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace MWWorld
|
|||
void setLocals (const ESM::Script& script);
|
||||
|
||||
MWLua::LocalScripts* getLuaScripts() { return mLuaScripts.get(); }
|
||||
void setLuaScripts(std::unique_ptr<MWLua::LocalScripts>&&);
|
||||
void setLuaScripts(std::shared_ptr<MWLua::LocalScripts>&&);
|
||||
|
||||
void setCount (int count);
|
||||
///< Set object count (an object pile is a simple object with a count >1).
|
||||
|
|
|
@ -20,6 +20,7 @@ if (GTEST_FOUND AND GMOCK_FOUND)
|
|||
lua/test_utilpackage.cpp
|
||||
lua/test_serialization.cpp
|
||||
lua/test_querypackage.cpp
|
||||
lua/test_omwscriptsparser.cpp
|
||||
|
||||
misc/test_stringops.cpp
|
||||
misc/test_endianness.cpp
|
||||
|
|
59
apps/openmw_test_suite/lua/test_omwscriptsparser.cpp
Normal file
59
apps/openmw_test_suite/lua/test_omwscriptsparser.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include "gmock/gmock.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <components/lua/omwscriptsparser.hpp>
|
||||
|
||||
#include "testing_util.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace testing;
|
||||
|
||||
TestFile file1(
|
||||
"#comment.lua\n"
|
||||
"\n"
|
||||
"script1.lua\n"
|
||||
"some mod/Some Script.lua"
|
||||
);
|
||||
TestFile file2(
|
||||
"#comment.lua\r\n"
|
||||
"\r\n"
|
||||
"script2.lua\r\n"
|
||||
"some other mod/Some Script.lua\r"
|
||||
);
|
||||
TestFile emptyFile("");
|
||||
TestFile invalidFile("Invalid file");
|
||||
|
||||
struct OMWScriptsParserTest : Test
|
||||
{
|
||||
std::unique_ptr<VFS::Manager> mVFS = createTestVFS({
|
||||
{"file1.omwscripts", &file1},
|
||||
{"file2.omwscripts", &file2},
|
||||
{"empty.omwscripts", &emptyFile},
|
||||
{"invalid.lua", &file1},
|
||||
{"invalid.omwscripts", &invalidFile},
|
||||
});
|
||||
};
|
||||
|
||||
TEST_F(OMWScriptsParserTest, Basic)
|
||||
{
|
||||
internal::CaptureStdout();
|
||||
std::vector<std::string> res = LuaUtil::parseOMWScriptsFiles(
|
||||
mVFS.get(), {"file2.omwscripts", "empty.omwscripts", "file1.omwscripts"});
|
||||
EXPECT_EQ(internal::GetCapturedStdout(), "");
|
||||
EXPECT_THAT(res, ElementsAre("script2.lua", "some other mod/Some Script.lua",
|
||||
"script1.lua", "some mod/Some Script.lua"));
|
||||
}
|
||||
|
||||
TEST_F(OMWScriptsParserTest, InvalidFiles)
|
||||
{
|
||||
internal::CaptureStdout();
|
||||
std::vector<std::string> res = LuaUtil::parseOMWScriptsFiles(
|
||||
mVFS.get(), {"invalid.lua", "invalid.omwscripts"});
|
||||
EXPECT_EQ(internal::GetCapturedStdout(),
|
||||
"Script list should have suffix '.omwscripts', got: 'invalid.lua'\n"
|
||||
"Lua script should have suffix '.lua', got: 'Invalid file'\n");
|
||||
EXPECT_THAT(res, ElementsAre());
|
||||
}
|
||||
|
||||
}
|
|
@ -304,6 +304,7 @@ return {
|
|||
|
||||
TEST_F(LuaScriptsContainerTest, Timers)
|
||||
{
|
||||
using TimeUnit = LuaUtil::ScriptsContainer::TimeUnit;
|
||||
LuaUtil::ScriptsContainer scripts(&mLua, "Test");
|
||||
EXPECT_TRUE(scripts.addNewScript("test1.lua"));
|
||||
EXPECT_TRUE(scripts.addNewScript("test2.lua"));
|
||||
|
@ -321,18 +322,18 @@ return {
|
|||
|
||||
scripts.processTimers(1, 2);
|
||||
|
||||
scripts.setupSerializableTimer(false, 10, "test1.lua", "B", sol::make_object(mLua.sol(), 3));
|
||||
scripts.setupSerializableTimer(true, 10, "test2.lua", "B", sol::make_object(mLua.sol(), 4));
|
||||
scripts.setupSerializableTimer(false, 5, "test1.lua", "A", sol::make_object(mLua.sol(), 1));
|
||||
scripts.setupSerializableTimer(true, 5, "test2.lua", "A", sol::make_object(mLua.sol(), 2));
|
||||
scripts.setupSerializableTimer(false, 15, "test1.lua", "A", sol::make_object(mLua.sol(), 10));
|
||||
scripts.setupSerializableTimer(false, 15, "test1.lua", "B", sol::make_object(mLua.sol(), 20));
|
||||
scripts.setupSerializableTimer(TimeUnit::SECONDS, 10, "test1.lua", "B", sol::make_object(mLua.sol(), 3));
|
||||
scripts.setupSerializableTimer(TimeUnit::HOURS, 10, "test2.lua", "B", sol::make_object(mLua.sol(), 4));
|
||||
scripts.setupSerializableTimer(TimeUnit::SECONDS, 5, "test1.lua", "A", sol::make_object(mLua.sol(), 1));
|
||||
scripts.setupSerializableTimer(TimeUnit::HOURS, 5, "test2.lua", "A", sol::make_object(mLua.sol(), 2));
|
||||
scripts.setupSerializableTimer(TimeUnit::SECONDS, 15, "test1.lua", "A", sol::make_object(mLua.sol(), 10));
|
||||
scripts.setupSerializableTimer(TimeUnit::SECONDS, 15, "test1.lua", "B", sol::make_object(mLua.sol(), 20));
|
||||
|
||||
scripts.setupUnsavableTimer(false, 10, "test2.lua", fn2);
|
||||
scripts.setupUnsavableTimer(true, 10, "test1.lua", fn2);
|
||||
scripts.setupUnsavableTimer(false, 5, "test2.lua", fn1);
|
||||
scripts.setupUnsavableTimer(true, 5, "test1.lua", fn1);
|
||||
scripts.setupUnsavableTimer(false, 15, "test2.lua", fn1);
|
||||
scripts.setupUnsavableTimer(TimeUnit::SECONDS, 10, "test2.lua", fn2);
|
||||
scripts.setupUnsavableTimer(TimeUnit::HOURS, 10, "test1.lua", fn2);
|
||||
scripts.setupUnsavableTimer(TimeUnit::SECONDS, 5, "test2.lua", fn1);
|
||||
scripts.setupUnsavableTimer(TimeUnit::HOURS, 5, "test1.lua", fn1);
|
||||
scripts.setupUnsavableTimer(TimeUnit::SECONDS, 15, "test2.lua", fn1);
|
||||
|
||||
EXPECT_EQ(counter1, 0);
|
||||
EXPECT_EQ(counter3, 0);
|
||||
|
|
|
@ -29,7 +29,7 @@ endif (GIT_CHECKOUT)
|
|||
# source files
|
||||
|
||||
add_component_dir (lua
|
||||
luastate scriptscontainer utilpackage serialization
|
||||
luastate scriptscontainer utilpackage serialization omwscriptsparser
|
||||
)
|
||||
|
||||
add_component_dir (settings
|
||||
|
|
|
@ -48,7 +48,7 @@ void ESM::LuaScripts::load(ESMReader& esm)
|
|||
{
|
||||
esm.getSubHeader();
|
||||
LuaTimer timer;
|
||||
esm.getT(timer.mHours);
|
||||
esm.getT(timer.mUnit);
|
||||
esm.getT(timer.mTime);
|
||||
timer.mCallbackName = esm.getHNString("LUAC");
|
||||
timer.mCallbackArgument = loadLuaBinaryData(esm);
|
||||
|
@ -68,7 +68,7 @@ void ESM::LuaScripts::save(ESMWriter& esm) const
|
|||
for (const LuaTimer& timer : script.mTimers)
|
||||
{
|
||||
esm.startSubRecord("LUAT");
|
||||
esm.writeT(timer.mHours);
|
||||
esm.writeT(timer.mUnit);
|
||||
esm.writeT(timer.mTime);
|
||||
esm.endRecord("LUAT");
|
||||
esm.writeHNString("LUAC", timer.mCallbackName);
|
||||
|
|
|
@ -14,8 +14,14 @@ namespace ESM
|
|||
|
||||
struct LuaTimer
|
||||
{
|
||||
enum class TimeUnit : bool
|
||||
{
|
||||
SECONDS = 0,
|
||||
HOURS = 1,
|
||||
};
|
||||
|
||||
TimeUnit mUnit;
|
||||
double mTime;
|
||||
bool mHours; // false - game seconds, true - game hours
|
||||
std::string mCallbackName;
|
||||
std::string mCallbackArgument; // Serialized Lua table. It is a binary data. Can contain '\0'.
|
||||
};
|
||||
|
|
|
@ -12,9 +12,7 @@ namespace LuaUtil
|
|||
static std::string packageNameToPath(std::string_view packageName)
|
||||
{
|
||||
std::string res(packageName);
|
||||
for (size_t i = 0; i < res.size(); ++i)
|
||||
if (res[i] == '.')
|
||||
res[i] = '/';
|
||||
std::replace(res.begin(), res.end(), '.', '/');
|
||||
res.append(".lua");
|
||||
return res;
|
||||
}
|
||||
|
@ -28,7 +26,7 @@ namespace LuaUtil
|
|||
{
|
||||
mLua.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::math, sol::lib::string, sol::lib::table);
|
||||
|
||||
mLua["math"]["randomseed"](static_cast<unsigned>(time(NULL)));
|
||||
mLua["math"]["randomseed"](static_cast<unsigned>(std::time(nullptr)));
|
||||
mLua["math"]["randomseed"] = sol::nil;
|
||||
|
||||
mLua["writeToLog"] = [](std::string_view s) { Log(Debug::Level::Info) << s; };
|
||||
|
|
44
components/lua/omwscriptsparser.cpp
Normal file
44
components/lua/omwscriptsparser.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include "omwscriptsparser.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
std::vector<std::string> LuaUtil::parseOMWScriptsFiles(const VFS::Manager* vfs, const std::vector<std::string>& scriptLists)
|
||||
{
|
||||
auto endsWith = [](std::string_view s, std::string_view suffix)
|
||||
{
|
||||
return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
|
||||
};
|
||||
std::vector<std::string> res;
|
||||
for (const std::string& scriptListFile : scriptLists)
|
||||
{
|
||||
if (!endsWith(scriptListFile, ".omwscripts"))
|
||||
{
|
||||
Log(Debug::Error) << "Script list should have suffix '.omwscripts', got: '" << scriptListFile << "'";
|
||||
continue;
|
||||
}
|
||||
std::string content(std::istreambuf_iterator<char>(*vfs->get(scriptListFile)), {});
|
||||
std::string_view view(content);
|
||||
while (!view.empty())
|
||||
{
|
||||
size_t pos = 0;
|
||||
while (pos < view.size() && view[pos] != '\n')
|
||||
pos++;
|
||||
std::string_view line = view.substr(0, pos);
|
||||
view = view.substr(std::min(pos + 1, view.size()));
|
||||
if (!line.empty() && line.back() == '\r')
|
||||
line = line.substr(0, pos - 1);
|
||||
// Lines starting with '#' are comments.
|
||||
// TODO: Maybe make the parser more robust. It is a bit inconsistent that 'path/#to/file.lua'
|
||||
// is a valid path, but '#path/to/file.lua' is considered as a comment and ignored.
|
||||
if (line.empty() || line[0] == '#')
|
||||
continue;
|
||||
if (endsWith(line, ".lua"))
|
||||
res.push_back(std::string(line));
|
||||
else
|
||||
Log(Debug::Error) << "Lua script should have suffix '.lua', got: '" << line.substr(0, 300) << "'";
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
14
components/lua/omwscriptsparser.hpp
Normal file
14
components/lua/omwscriptsparser.hpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef COMPONENTS_LUA_OMWSCRIPTSPARSER_H
|
||||
#define COMPONENTS_LUA_OMWSCRIPTSPARSER_H
|
||||
|
||||
#include <components/vfs/manager.hpp>
|
||||
|
||||
namespace LuaUtil
|
||||
{
|
||||
|
||||
// Parses list of `*.omwscripts` files.
|
||||
std::vector<std::string> parseOMWScriptsFiles(const VFS::Manager* vfs, const std::vector<std::string>& scriptLists);
|
||||
|
||||
}
|
||||
|
||||
#endif // COMPONENTS_LUA_OMWSCRIPTSPARSER_H
|
|
@ -78,10 +78,10 @@ namespace LuaUtil
|
|||
|
||||
bool ScriptsContainer::removeScript(const std::string& path)
|
||||
{
|
||||
auto it = mScripts.find(path);
|
||||
if (it == mScripts.end())
|
||||
auto scriptIter = mScripts.find(path);
|
||||
if (scriptIter == mScripts.end())
|
||||
return false; // no such script
|
||||
sol::object& script = it->second.mInterface;
|
||||
sol::object& script = scriptIter->second.mInterface;
|
||||
if (getFieldOrNil(script, INTERFACE_NAME) != sol::nil)
|
||||
{
|
||||
std::string_view interfaceName = getFieldOrNil(script, INTERFACE_NAME).as<std::string_view>();
|
||||
|
@ -110,10 +110,10 @@ namespace LuaUtil
|
|||
for (auto& [key, value] : sol::table(engineHandlers))
|
||||
{
|
||||
std::string_view handlerName = key.as<std::string_view>();
|
||||
auto it = mEngineHandlers.find(handlerName);
|
||||
if (it == mEngineHandlers.end())
|
||||
auto handlerIter = mEngineHandlers.find(handlerName);
|
||||
if (handlerIter == mEngineHandlers.end())
|
||||
continue;
|
||||
std::vector<sol::protected_function>& list = it->second->mList;
|
||||
std::vector<sol::protected_function>& list = handlerIter->second->mList;
|
||||
list.erase(std::find(list.begin(), list.end(), value.as<sol::protected_function>()));
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ namespace LuaUtil
|
|||
list.erase(std::find(list.begin(), list.end(), value.as<sol::protected_function>()));
|
||||
}
|
||||
}
|
||||
mScripts.erase(it);
|
||||
mScripts.erase(scriptIter);
|
||||
mScriptOrder.erase(std::find(mScriptOrder.begin(), mScriptOrder.end(), path));
|
||||
return true;
|
||||
}
|
||||
|
@ -201,13 +201,13 @@ namespace LuaUtil
|
|||
void ScriptsContainer::save(ESM::LuaScripts& data)
|
||||
{
|
||||
std::map<std::string, std::vector<ESM::LuaTimer>> timers;
|
||||
auto saveTimerFn = [&](const Timer& timer, bool inHours)
|
||||
auto saveTimerFn = [&](const Timer& timer, TimeUnit timeUnit)
|
||||
{
|
||||
if (!timer.mSerializable)
|
||||
return;
|
||||
ESM::LuaTimer savedTimer;
|
||||
savedTimer.mTime = timer.mTime;
|
||||
savedTimer.mHours = inHours;
|
||||
savedTimer.mUnit = timeUnit;
|
||||
savedTimer.mCallbackName = std::get<std::string>(timer.mCallback);
|
||||
savedTimer.mCallbackArgument = timer.mSerializedArg;
|
||||
if (timers.count(timer.mScript) == 0)
|
||||
|
@ -215,9 +215,9 @@ namespace LuaUtil
|
|||
timers[timer.mScript].push_back(std::move(savedTimer));
|
||||
};
|
||||
for (const Timer& timer : mSecondsTimersQueue)
|
||||
saveTimerFn(timer, false);
|
||||
saveTimerFn(timer, TimeUnit::SECONDS);
|
||||
for (const Timer& timer : mHoursTimersQueue)
|
||||
saveTimerFn(timer, true);
|
||||
saveTimerFn(timer, TimeUnit::HOURS);
|
||||
data.mScripts.clear();
|
||||
for (const std::string& path : mScriptOrder)
|
||||
{
|
||||
|
@ -291,7 +291,7 @@ namespace LuaUtil
|
|||
// updates refnums, so timer.mSerializedArg may be not equal to savedTimer.mCallbackArgument.
|
||||
timer.mSerializedArg = serialize(timer.mArg, mSerializer);
|
||||
|
||||
if (savedTimer.mHours)
|
||||
if (savedTimer.mUnit == TimeUnit::HOURS)
|
||||
mHoursTimersQueue.push_back(std::move(timer));
|
||||
else
|
||||
mSecondsTimersQueue.push_back(std::move(timer));
|
||||
|
@ -352,7 +352,7 @@ namespace LuaUtil
|
|||
std::push_heap(timerQueue.begin(), timerQueue.end());
|
||||
}
|
||||
|
||||
void ScriptsContainer::setupSerializableTimer(bool inHours, double time, const std::string& scriptPath,
|
||||
void ScriptsContainer::setupSerializableTimer(TimeUnit timeUnit, double time, const std::string& scriptPath,
|
||||
std::string_view callbackName, sol::object callbackArg)
|
||||
{
|
||||
Timer t;
|
||||
|
@ -362,10 +362,10 @@ namespace LuaUtil
|
|||
t.mTime = time;
|
||||
t.mArg = callbackArg;
|
||||
t.mSerializedArg = serialize(t.mArg, mSerializer);
|
||||
insertTimer(inHours ? mHoursTimersQueue : mSecondsTimersQueue, std::move(t));
|
||||
insertTimer(timeUnit == TimeUnit::HOURS ? mHoursTimersQueue : mSecondsTimersQueue, std::move(t));
|
||||
}
|
||||
|
||||
void ScriptsContainer::setupUnsavableTimer(bool inHours, double time, const std::string& scriptPath, sol::function callback)
|
||||
void ScriptsContainer::setupUnsavableTimer(TimeUnit timeUnit, double time, const std::string& scriptPath, sol::function callback)
|
||||
{
|
||||
Timer t;
|
||||
t.mScript = scriptPath;
|
||||
|
@ -376,7 +376,7 @@ namespace LuaUtil
|
|||
getHiddenData(scriptPath)[TEMPORARY_TIMER_CALLBACKS][mTemporaryCallbackCounter] = std::move(callback);
|
||||
mTemporaryCallbackCounter++;
|
||||
|
||||
insertTimer(inHours ? mHoursTimersQueue : mSecondsTimersQueue, std::move(t));
|
||||
insertTimer(timeUnit == TimeUnit::HOURS ? mHoursTimersQueue : mSecondsTimersQueue, std::move(t));
|
||||
}
|
||||
|
||||
void ScriptsContainer::callTimer(const Timer& t)
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace LuaUtil
|
|||
ScriptsContainer* mContainer;
|
||||
std::string mPath;
|
||||
};
|
||||
using TimeUnit = ESM::LuaTimer::TimeUnit;
|
||||
|
||||
// `namePrefix` is a common prefix for all scripts in the container. Used in logs for error messages and `print` output.
|
||||
ScriptsContainer(LuaUtil::LuaState* lua, std::string_view namePrefix);
|
||||
|
@ -122,17 +123,17 @@ namespace LuaUtil
|
|||
void registerTimerCallback(const std::string& scriptPath, std::string_view callbackName, sol::function callback);
|
||||
|
||||
// Sets up a timer, that can be automatically saved and loaded.
|
||||
// inHours - false if time unit is game seconds and true if time unit if game hours.
|
||||
// timeUnit - game seconds (TimeUnit::Seconds) or game hours (TimeUnit::Hours).
|
||||
// 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.
|
||||
// callbackName - callback (should be registered in advance) for this timer.
|
||||
// callbackArg - parameter for the callback (should be serializable).
|
||||
void setupSerializableTimer(bool inHours, double time, const std::string& scriptPath,
|
||||
void setupSerializableTimer(TimeUnit timeUnit, double time, const std::string& scriptPath,
|
||||
std::string_view callbackName, sol::object callbackArg);
|
||||
|
||||
// Creates a timer. `callback` is an arbitrary Lua function. This type of timers is called "unsavable"
|
||||
// because it can not be stored in saves. I.e. loading a saved game will not fully restore the state.
|
||||
void setupUnsavableTimer(bool inHours, double time, const std::string& scriptPath, sol::function callback);
|
||||
void setupUnsavableTimer(TimeUnit timeUnit, double time, const std::string& scriptPath, sol::function callback);
|
||||
|
||||
protected:
|
||||
struct EngineHandlerList
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace LuaUtil
|
|||
|
||||
constexpr unsigned char FORMAT_VERSION = 0;
|
||||
|
||||
enum class SerializedType
|
||||
enum class SerializedType : char
|
||||
{
|
||||
NUMBER = 0x0,
|
||||
LONG_STRING = 0x1,
|
||||
|
@ -20,8 +20,10 @@ namespace LuaUtil
|
|||
|
||||
VEC2 = 0x10,
|
||||
VEC3 = 0x11,
|
||||
|
||||
// All values should be lesser than 0x20 (SHORT_STRING_FLAG).
|
||||
};
|
||||
constexpr unsigned char SHORT_STRING_FLAG = 0x20; // 0x001SSSSS. SSSSS = string length
|
||||
constexpr unsigned char SHORT_STRING_FLAG = 0x20; // 0b001SSSSS. SSSSS = string length
|
||||
constexpr unsigned char CUSTOM_FULL_FLAG = 0x40; // 0b01TTTTTT + 32bit dataSize
|
||||
constexpr unsigned char CUSTOM_COMPACT_FLAG = 0x80; // 0b1SSSSTTT. SSSS = dataSize, TTT = (typeName size - 1)
|
||||
|
||||
|
@ -224,8 +226,8 @@ namespace LuaUtil
|
|||
sol::stack::push<osg::Vec3f>(lua.lua_state(), osg::Vec3f(x, y, z));
|
||||
return;
|
||||
}
|
||||
default: throw std::runtime_error("Unknown type: " + std::to_string(type));
|
||||
}
|
||||
throw std::runtime_error("Unknown type: " + std::to_string(type));
|
||||
}
|
||||
|
||||
BinaryData serialize(const sol::object& obj, const UserdataSerializer* customSerializer)
|
||||
|
|
Loading…
Reference in a new issue