Commit is being made to allow additions of GPL3+ code previously un-addable. With these changes, contributions back to cuberite are possible with the backporting exemtion, as well as adding stuff in minetest with minetest code properly being read through and implimented to upgrade it to GPL3 from GPL2. project still has Apache2.0 license and credits to all its contributers, but now has the freedom of GPL3+ and all the code that can be implimented and shared with it.
155 lines
3.3 KiB
C++
155 lines
3.3 KiB
C++
|
|
/*
|
|
* Copyright 2011-2022 Cuberite Contributors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include "Globals.h"
|
|
#include "RegionCache.h"
|
|
#include <QMutexLocker>
|
|
#include <QThreadPool>
|
|
#include "ChunkSource.h"
|
|
#include "RegionLoader.h"
|
|
#include "Region.h"
|
|
|
|
|
|
|
|
|
|
|
|
RegionCache::RegionCache(QObject * parent) :
|
|
super(parent)
|
|
{
|
|
m_Cache.setMaxCost(1024 * 1024 * 1024); // 1 GiB of memory for the cache
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RegionPtr RegionCache::fetch(int a_RegionX, int a_RegionZ)
|
|
{
|
|
// Retrieve from the cache:
|
|
quint32 hash = getRegionHash(a_RegionX, a_RegionZ);
|
|
RegionPtr * res;
|
|
{
|
|
QMutexLocker lock(&m_Mtx);
|
|
res = m_Cache[hash];
|
|
// If succesful and region loaded, return the retrieved value:
|
|
if ((res != nullptr) && (*res)->isValid())
|
|
{
|
|
return *res;
|
|
}
|
|
}
|
|
|
|
// If the region is in cache but not valid, it means it has been already queued for rendering, do nothing now:
|
|
if (res != nullptr)
|
|
{
|
|
return RegionPtr(nullptr);
|
|
}
|
|
|
|
// There's no such item in the cache, create it now:
|
|
try
|
|
{
|
|
res = new RegionPtr(new Region);
|
|
}
|
|
catch (const std::bad_alloc &)
|
|
{
|
|
/* Allocation failed (32-bit process hit the 2 GiB barrier?)
|
|
This may happen even with the cache set to 1 GiB, because it contains shared ptrs and so they may be
|
|
held by another place in the code even when they are removed from cache.
|
|
*/
|
|
return RegionPtr(nullptr);
|
|
}
|
|
if (res == nullptr)
|
|
{
|
|
return RegionPtr(nullptr);
|
|
}
|
|
{
|
|
QMutexLocker lock(&m_Mtx);
|
|
m_Cache.insert(hash, res, sizeof(Region));
|
|
}
|
|
|
|
// Queue the region for rendering:
|
|
queueRegionRender(a_RegionX, a_RegionZ, *res);
|
|
|
|
// Return failure, the region is not yet rendered:
|
|
return RegionPtr(nullptr);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegionCache::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource)
|
|
{
|
|
// Replace the chunk source:
|
|
m_ChunkSource = a_ChunkSource;
|
|
|
|
// Clear the cache:
|
|
QMutexLocker lock(&m_Mtx);
|
|
m_Cache.clear();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegionCache::reload()
|
|
{
|
|
assert(m_ChunkSource.get() != nullptr);
|
|
|
|
// Reload the chunk source:
|
|
m_ChunkSource->reload();
|
|
|
|
// Clear the cache:
|
|
QMutexLocker lock(&m_Mtx);
|
|
m_Cache.clear();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegionCache::gotRegion(int a_RegionX, int a_RegionZ)
|
|
{
|
|
emit regionAvailable(a_RegionX, a_RegionZ);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
quint32 RegionCache::getRegionHash(int a_RegionX, int a_RegionZ)
|
|
{
|
|
// Simply join the two coords into a single int
|
|
// The coords will never be larger than 16-bits, so we can do this safely
|
|
return (((static_cast<quint32>(a_RegionX) & 0xffff) << 16) | (static_cast<quint32>(a_RegionZ) & 0xffff));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegionCache::queueRegionRender(int a_RegionX, int a_RegionZ, RegionPtr & a_Region)
|
|
{
|
|
// Create a new loader task:
|
|
RegionLoader * loader = new RegionLoader(a_RegionX, a_RegionZ, a_Region, m_ChunkSource);
|
|
connect(loader, SIGNAL(loaded(int, int)), this, SLOT(gotRegion(int, int)));
|
|
|
|
QThreadPool::globalInstance()->start(loader);
|
|
}
|
|
|
|
|
|
|
|
|