mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 07:23:51 +00:00
Merge branch 'master' into lighting
This commit is contained in:
commit
10643a10f2
6 changed files with 132 additions and 26 deletions
|
@ -58,6 +58,7 @@
|
||||||
Bug #4948: Footstep sounds while levitating on ground level
|
Bug #4948: Footstep sounds while levitating on ground level
|
||||||
Bug #4963: Enchant skill progress is incorrect
|
Bug #4963: Enchant skill progress is incorrect
|
||||||
Bug #4965: Global light attenuation settings setup is lacking
|
Bug #4965: Global light attenuation settings setup is lacking
|
||||||
|
Bug #4969: "Miss" sound plays for any actor
|
||||||
Feature #2229: Improve pathfinding AI
|
Feature #2229: Improve pathfinding AI
|
||||||
Feature #3442: Default values for fallbacks from ini file
|
Feature #3442: Default values for fallbacks from ini file
|
||||||
Feature #3610: Option to invert X axis
|
Feature #3610: Option to invert X axis
|
||||||
|
|
|
@ -376,6 +376,7 @@ namespace MWClass
|
||||||
if (!successful)
|
if (!successful)
|
||||||
{
|
{
|
||||||
// Missed
|
// Missed
|
||||||
|
if (!attacker.isEmpty() && attacker == MWMechanics::getPlayer())
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "miss", 1.0f, 1.0f);
|
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "miss", 1.0f, 1.0f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -710,6 +710,7 @@ namespace MWClass
|
||||||
if (!successful)
|
if (!successful)
|
||||||
{
|
{
|
||||||
// Missed
|
// Missed
|
||||||
|
if (!attacker.isEmpty() && attacker == MWMechanics::getPlayer())
|
||||||
sndMgr->playSound3D(ptr, "miss", 1.0f, 1.0f);
|
sndMgr->playSound3D(ptr, "miss", 1.0f, 1.0f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,9 +126,13 @@ namespace DetourNavigator
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (auto job = getNextJob())
|
if (auto job = getNextJob())
|
||||||
if (!processJob(*job))
|
{
|
||||||
|
const auto processed = processJob(*job);
|
||||||
|
unlockTile(job->mAgentHalfExtents, job->mChangedTile);
|
||||||
|
if (!processed)
|
||||||
repost(std::move(*job));
|
repost(std::move(*job));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "AsyncNavMeshUpdater::process exception: ", e.what();
|
Log(Debug::Error) << "AsyncNavMeshUpdater::process exception: ", e.what();
|
||||||
|
@ -178,19 +182,47 @@ namespace DetourNavigator
|
||||||
boost::optional<AsyncNavMeshUpdater::Job> AsyncNavMeshUpdater::getNextJob()
|
boost::optional<AsyncNavMeshUpdater::Job> AsyncNavMeshUpdater::getNextJob()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
std::unique_lock<std::mutex> lock(mMutex);
|
||||||
if (!mHasJob.wait_for(lock, std::chrono::milliseconds(10), [&] { return !mJobs.empty(); }))
|
|
||||||
|
const auto threadId = std::this_thread::get_id();
|
||||||
|
auto& threadQueue = mThreadsQueues[threadId];
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
const auto hasJob = [&] { return !mJobs.empty() || !threadQueue.mPushed.empty(); };
|
||||||
|
|
||||||
|
if (!mHasJob.wait_for(lock, std::chrono::milliseconds(10), hasJob))
|
||||||
{
|
{
|
||||||
mFirstStart.lock()->reset();
|
mFirstStart.lock()->reset();
|
||||||
mDone.notify_all();
|
mDone.notify_all();
|
||||||
return boost::none;
|
return boost::none;
|
||||||
}
|
}
|
||||||
Log(Debug::Debug) << "Got " << mJobs.size() << " navigator jobs";
|
|
||||||
const auto job = mJobs.top();
|
Log(Debug::Debug) << "Got " << mJobs.size() << " navigator jobs and "
|
||||||
mJobs.pop();
|
<< threadQueue.mJobs.size() << " thread jobs";
|
||||||
const auto pushed = mPushed.find(job.mAgentHalfExtents);
|
|
||||||
pushed->second.erase(job.mChangedTile);
|
auto job = threadQueue.mJobs.empty()
|
||||||
if (pushed->second.empty())
|
? getJob(mJobs, mPushed)
|
||||||
mPushed.erase(pushed);
|
: getJob(threadQueue.mJobs, threadQueue.mPushed);
|
||||||
|
|
||||||
|
const auto owner = lockTile(job.mAgentHalfExtents, job.mChangedTile);
|
||||||
|
|
||||||
|
if (owner == threadId)
|
||||||
|
return job;
|
||||||
|
|
||||||
|
postThreadJob(std::move(job), mThreadsQueues[owner]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncNavMeshUpdater::Job AsyncNavMeshUpdater::getJob(Jobs& jobs, Pushed& pushed)
|
||||||
|
{
|
||||||
|
auto job = jobs.top();
|
||||||
|
jobs.pop();
|
||||||
|
|
||||||
|
const auto it = pushed.find(job.mAgentHalfExtents);
|
||||||
|
it->second.erase(job.mChangedTile);
|
||||||
|
if (it->second.empty())
|
||||||
|
pushed.erase(it);
|
||||||
|
|
||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,4 +271,60 @@ namespace DetourNavigator
|
||||||
mHasJob.notify_all();
|
mHasJob.notify_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsyncNavMeshUpdater::postThreadJob(Job&& job, Queue& queue)
|
||||||
|
{
|
||||||
|
if (queue.mPushed[job.mAgentHalfExtents].insert(job.mChangedTile).second)
|
||||||
|
{
|
||||||
|
queue.mJobs.push(std::move(job));
|
||||||
|
mHasJob.notify_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread::id AsyncNavMeshUpdater::lockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile)
|
||||||
|
{
|
||||||
|
if (mSettings.get().mAsyncNavMeshUpdaterThreads <= 1)
|
||||||
|
return std::this_thread::get_id();
|
||||||
|
|
||||||
|
auto locked = mProcessingTiles.lock();
|
||||||
|
|
||||||
|
auto agent = locked->find(agentHalfExtents);
|
||||||
|
if (agent == locked->end())
|
||||||
|
{
|
||||||
|
const auto threadId = std::this_thread::get_id();
|
||||||
|
locked->emplace(agentHalfExtents, std::map<TilePosition, std::thread::id>({{changedTile, threadId}}));
|
||||||
|
return threadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tile = agent->second.find(changedTile);
|
||||||
|
if (tile == agent->second.end())
|
||||||
|
{
|
||||||
|
const auto threadId = std::this_thread::get_id();
|
||||||
|
agent->second.emplace(changedTile, threadId);
|
||||||
|
return threadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tile->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncNavMeshUpdater::unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile)
|
||||||
|
{
|
||||||
|
if (mSettings.get().mAsyncNavMeshUpdaterThreads <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto locked = mProcessingTiles.lock();
|
||||||
|
|
||||||
|
auto agent = locked->find(agentHalfExtents);
|
||||||
|
if (agent == locked->end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto tile = agent->second.find(changedTile);
|
||||||
|
if (tile == agent->second.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
agent->second.erase(tile);
|
||||||
|
|
||||||
|
if (agent->second.empty())
|
||||||
|
locked->erase(agent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,15 @@ namespace DetourNavigator
|
||||||
};
|
};
|
||||||
|
|
||||||
using Jobs = std::priority_queue<Job, std::deque<Job>>;
|
using Jobs = std::priority_queue<Job, std::deque<Job>>;
|
||||||
|
using Pushed = std::map<osg::Vec3f, std::set<TilePosition>>;
|
||||||
|
|
||||||
|
struct Queue
|
||||||
|
{
|
||||||
|
Jobs mJobs;
|
||||||
|
Pushed mPushed;
|
||||||
|
|
||||||
|
Queue() = default;
|
||||||
|
};
|
||||||
|
|
||||||
std::reference_wrapper<const Settings> mSettings;
|
std::reference_wrapper<const Settings> mSettings;
|
||||||
std::reference_wrapper<TileCachedRecastMeshManager> mRecastMeshManager;
|
std::reference_wrapper<TileCachedRecastMeshManager> mRecastMeshManager;
|
||||||
|
@ -82,6 +91,8 @@ namespace DetourNavigator
|
||||||
Misc::ScopeGuarded<TilePosition> mPlayerTile;
|
Misc::ScopeGuarded<TilePosition> mPlayerTile;
|
||||||
Misc::ScopeGuarded<boost::optional<std::chrono::steady_clock::time_point>> mFirstStart;
|
Misc::ScopeGuarded<boost::optional<std::chrono::steady_clock::time_point>> mFirstStart;
|
||||||
NavMeshTilesCache mNavMeshTilesCache;
|
NavMeshTilesCache mNavMeshTilesCache;
|
||||||
|
Misc::ScopeGuarded<std::map<osg::Vec3f, std::map<TilePosition, std::thread::id>>> mProcessingTiles;
|
||||||
|
std::map<std::thread::id, Queue> mThreadsQueues;
|
||||||
std::vector<std::thread> mThreads;
|
std::vector<std::thread> mThreads;
|
||||||
|
|
||||||
void process() throw();
|
void process() throw();
|
||||||
|
@ -90,11 +101,19 @@ namespace DetourNavigator
|
||||||
|
|
||||||
boost::optional<Job> getNextJob();
|
boost::optional<Job> getNextJob();
|
||||||
|
|
||||||
|
static Job getJob(Jobs& jobs, Pushed& pushed);
|
||||||
|
|
||||||
|
void postThreadJob(Job&& job, Queue& queue);
|
||||||
|
|
||||||
void writeDebugFiles(const Job& job, const RecastMesh* recastMesh) const;
|
void writeDebugFiles(const Job& job, const RecastMesh* recastMesh) const;
|
||||||
|
|
||||||
std::chrono::steady_clock::time_point setFirstStart(const std::chrono::steady_clock::time_point& value);
|
std::chrono::steady_clock::time_point setFirstStart(const std::chrono::steady_clock::time_point& value);
|
||||||
|
|
||||||
void repost(Job&& job);
|
void repost(Job&& job);
|
||||||
|
|
||||||
|
std::thread::id lockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile);
|
||||||
|
|
||||||
|
void unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,19 +119,13 @@ static const std::map<std::string,RecordFactoryEntry> factories = makeFactory();
|
||||||
|
|
||||||
std::string NIFFile::printVersion(unsigned int version)
|
std::string NIFFile::printVersion(unsigned int version)
|
||||||
{
|
{
|
||||||
union ver_quad
|
int major = (version >> 24) & 0xFF;
|
||||||
{
|
int minor = (version >> 16) & 0xFF;
|
||||||
uint32_t full;
|
int patch = (version >> 8) & 0xFF;
|
||||||
uint8_t quad[4];
|
int rev = version & 0xFF;
|
||||||
} version_out;
|
|
||||||
|
|
||||||
version_out.full = version;
|
|
||||||
|
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << version_out.quad[3] << "."
|
stream << major << "." << minor << "." << patch << "." << rev;
|
||||||
<< version_out.quad[2] << "."
|
|
||||||
<< version_out.quad[1] << "."
|
|
||||||
<< version_out.quad[0];
|
|
||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +140,9 @@ void NIFFile::parse(Files::IStreamPtr stream)
|
||||||
|
|
||||||
// Get BCD version
|
// Get BCD version
|
||||||
ver = nif.getUInt();
|
ver = nif.getUInt();
|
||||||
if(ver != VER_MW)
|
// 4.0.0.0 is an older, practically identical version of the format.
|
||||||
|
// It's not used by Morrowind assets but Morrowind supports it.
|
||||||
|
if(ver != 0x04000000 && ver != VER_MW)
|
||||||
fail("Unsupported NIF version: " + printVersion(ver));
|
fail("Unsupported NIF version: " + printVersion(ver));
|
||||||
// Number of records
|
// Number of records
|
||||||
size_t recNum = nif.getInt();
|
size_t recNum = nif.getInt();
|
||||||
|
|
Loading…
Reference in a new issue