Более нормализованная обработка ресурсов на клиенте
This commit is contained in:
@@ -60,15 +60,40 @@ public:
|
||||
// states
|
||||
};
|
||||
|
||||
struct AssetsModelUpdate {
|
||||
ResourceId Id = 0;
|
||||
HeadlessModel Model;
|
||||
HeadlessModel::Header Header;
|
||||
};
|
||||
|
||||
struct AssetsNodestateUpdate {
|
||||
ResourceId Id = 0;
|
||||
HeadlessNodeState Nodestate;
|
||||
HeadlessNodeState::Header Header;
|
||||
};
|
||||
|
||||
struct AssetsTextureUpdate {
|
||||
ResourceId Id = 0;
|
||||
uint16_t Width = 0;
|
||||
uint16_t Height = 0;
|
||||
std::vector<uint32_t> Pixels;
|
||||
ResourceHeader Header;
|
||||
};
|
||||
|
||||
struct AssetsBinaryUpdate {
|
||||
ResourceId Id = 0;
|
||||
std::u8string Data;
|
||||
};
|
||||
|
||||
/* Интерфейс рендера текущего подключения к серверу */
|
||||
class IRenderSession {
|
||||
public:
|
||||
// Объект уведомления об изменениях
|
||||
struct TickSyncData {
|
||||
// Новые или изменённые используемые теперь двоичные ресурсы
|
||||
std::unordered_map<EnumAssets, std::vector<ResourceId>> Assets_ChangeOrAdd;
|
||||
// Более не используемые ресурсы
|
||||
std::unordered_map<EnumAssets, std::vector<ResourceId>> Assets_Lost;
|
||||
// Изменения в ассетах.
|
||||
std::vector<AssetsModelUpdate> AssetsModels;
|
||||
std::vector<AssetsNodestateUpdate> AssetsNodestates;
|
||||
std::vector<AssetsTextureUpdate> AssetsTextures;
|
||||
|
||||
// Новые или изменённые профили контента
|
||||
std::unordered_map<EnumDefContent, std::vector<ResourceId>> Profiles_ChangeOrAdd;
|
||||
@@ -87,7 +112,7 @@ public:
|
||||
// Началась стадия изменения данных IServerSession, все должны приостановить работу
|
||||
virtual void pushStageTickSync() = 0;
|
||||
// После изменения внутренних данных IServerSession, IRenderSession уведомляется об изменениях
|
||||
virtual void tickSync(const TickSyncData& data) = 0;
|
||||
virtual void tickSync(TickSyncData& data) = 0;
|
||||
|
||||
// Установить позицию для камеры
|
||||
virtual void setCameraPos(WorldId_t worldId, Pos::Object pos, glm::quat quat) = 0;
|
||||
@@ -190,9 +215,6 @@ public:
|
||||
// Включить логирование входящих сетевых пакетов на клиенте.
|
||||
bool DebugLogPackets = false;
|
||||
|
||||
// Используемые двоичные ресурсы
|
||||
std::unordered_map<EnumAssets, std::unordered_map<ResourceId, AssetEntry>> Assets;
|
||||
|
||||
// Используемые профили контента
|
||||
struct {
|
||||
std::unordered_map<DefVoxelId, DefVoxel_t> DefVoxel;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "boost/asio/io_context.hpp"
|
||||
#include "png++/image.hpp"
|
||||
#include <fstream>
|
||||
#include "Abstract.hpp"
|
||||
|
||||
namespace LV::Client {
|
||||
|
||||
@@ -33,41 +34,14 @@ namespace fs = std::filesystem;
|
||||
class AssetsManager : public IdProvider<EnumAssets> {
|
||||
public:
|
||||
struct ResourceUpdates {
|
||||
struct ModelUpdate {
|
||||
ResourceId Id = 0;
|
||||
HeadlessModel Model;
|
||||
HeadlessModel::Header Header;
|
||||
};
|
||||
|
||||
struct NodestateUpdate {
|
||||
ResourceId Id = 0;
|
||||
HeadlessNodeState Nodestate;
|
||||
HeadlessNodeState::Header Header;
|
||||
};
|
||||
|
||||
struct TextureUpdate {
|
||||
ResourceId Id = 0;
|
||||
uint16_t Width = 0;
|
||||
uint16_t Height = 0;
|
||||
std::vector<uint32_t> Pixels;
|
||||
std::string Domain;
|
||||
std::string Key;
|
||||
ResourceHeader Header;
|
||||
};
|
||||
|
||||
struct BinaryUpdate {
|
||||
ResourceId Id = 0;
|
||||
std::u8string Data;
|
||||
};
|
||||
|
||||
std::vector<ModelUpdate> Models;
|
||||
std::vector<NodestateUpdate> Nodestates;
|
||||
/// TODO: Добавить анимацию из меты
|
||||
std::vector<TextureUpdate> Textures;
|
||||
std::vector<BinaryUpdate> Particles;
|
||||
std::vector<BinaryUpdate> Animations;
|
||||
std::vector<BinaryUpdate> Sounds;
|
||||
std::vector<BinaryUpdate> Fonts;
|
||||
std::vector<AssetsModelUpdate> Models;
|
||||
std::vector<AssetsNodestateUpdate> Nodestates;
|
||||
std::vector<AssetsTextureUpdate> Textures;
|
||||
std::vector<AssetsBinaryUpdate> Particles;
|
||||
std::vector<AssetsBinaryUpdate> Animations;
|
||||
std::vector<AssetsBinaryUpdate> Sounds;
|
||||
std::vector<AssetsBinaryUpdate> Fonts;
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -115,6 +89,23 @@ public:
|
||||
Out_applyResourcesUpdate applyResourcesUpdate(const Out_checkAndPrepareResourcesUpdate& orr) {
|
||||
Out_applyResourcesUpdate result;
|
||||
|
||||
for(size_t type = 0; type < static_cast<size_t>(EnumAssets::MAX_ENUM); ++type) {
|
||||
for(ResourceId id : orr.RP.LostLinks[type]) {
|
||||
std::optional<AssetsPreloader::Out_Resource> res = ResourcePacks.getResource((EnumAssets) type, id);
|
||||
assert(res);
|
||||
|
||||
auto hashIter = HashToPath.find(res->Hash);
|
||||
assert(hashIter != HashToPath.end());
|
||||
auto& entry = hashIter->second;
|
||||
auto iter = std::find(entry.begin(), entry.end(), res->Path);
|
||||
assert(iter != entry.end());
|
||||
entry.erase(iter);
|
||||
|
||||
if(entry.empty())
|
||||
HashToPath.erase(hashIter);
|
||||
}
|
||||
}
|
||||
|
||||
ResourcePacks.applyResourcesUpdate(orr.RP);
|
||||
ExtraSource.applyResourcesUpdate(orr.ES);
|
||||
|
||||
@@ -124,6 +115,7 @@ public:
|
||||
for(const auto& res : orr.RP.ResourceUpdates[type]) {
|
||||
// Помечаем ресурс для обновления
|
||||
PendingUpdateFromAsync[type].push_back(std::get<ResourceId>(res));
|
||||
HashToPath[std::get<ResourceFile::Hash_t>(res)].push_back(std::get<fs::path>(res));
|
||||
}
|
||||
|
||||
for(ResourceId id : orr.RP.LostLinks[type]) {
|
||||
@@ -476,17 +468,20 @@ private:
|
||||
const auto& map = ServerToClientMap[static_cast<size_t>(EnumAssets::Model)];
|
||||
if(id >= map.size())
|
||||
return 0;
|
||||
|
||||
return map[id];
|
||||
};
|
||||
auto mapTextureId = [&](ResourceId id) -> ResourceId {
|
||||
const auto& map = ServerToClientMap[static_cast<size_t>(EnumAssets::Texture)];
|
||||
if(id >= map.size())
|
||||
return 0;
|
||||
|
||||
return map[id];
|
||||
};
|
||||
auto rebindHeader = [&](EnumAssets type, const ResourceHeader& header) -> ResourceHeader {
|
||||
if(header.empty())
|
||||
return {};
|
||||
|
||||
std::vector<uint8_t> bytes;
|
||||
bytes.resize(header.size());
|
||||
std::memcpy(bytes.data(), header.data(), header.size());
|
||||
@@ -497,6 +492,7 @@ private:
|
||||
mapTextureId,
|
||||
[](const std::string&) {}
|
||||
);
|
||||
|
||||
return ResourceHeader(reinterpret_cast<const char8_t*>(rebound.data()), rebound.size());
|
||||
};
|
||||
|
||||
@@ -570,31 +566,30 @@ private:
|
||||
RU.Models.push_back({id, std::move(hm), std::move(headerParsed)});
|
||||
updated++;
|
||||
} else if(type == EnumAssets::Texture) {
|
||||
ResourceUpdates::TextureUpdate update;
|
||||
update.Id = id;
|
||||
update.Domain = std::move(domain);
|
||||
update.Key = std::move(key);
|
||||
update.Header = std::move(finalHeader);
|
||||
AssetsTextureUpdate entry;
|
||||
entry.Id = id;
|
||||
entry.Header = std::move(finalHeader);
|
||||
if(!data.empty()) {
|
||||
iResource sres(reinterpret_cast<const uint8_t*>(data.data()), data.size());
|
||||
iBinaryStream stream = sres.makeStream();
|
||||
png::image<png::rgba_pixel> img(stream.Stream);
|
||||
update.Width = static_cast<uint16_t>(img.get_width());
|
||||
update.Height = static_cast<uint16_t>(img.get_height());
|
||||
update.Pixels.resize(static_cast<size_t>(update.Width) * update.Height);
|
||||
for(uint32_t y = 0; y < update.Height; ++y) {
|
||||
entry.Width = static_cast<uint16_t>(img.get_width());
|
||||
entry.Height = static_cast<uint16_t>(img.get_height());
|
||||
entry.Pixels.resize(static_cast<size_t>(entry.Width) * entry.Height);
|
||||
for(uint32_t y = 0; y < entry.Height; ++y) {
|
||||
const auto& row = img.get_pixbuf().operator[](y);
|
||||
for(uint32_t x = 0; x < update.Width; ++x) {
|
||||
for(uint32_t x = 0; x < entry.Width; ++x) {
|
||||
const auto& px = row[x];
|
||||
uint32_t rgba = (uint32_t(px.alpha) << 24)
|
||||
| (uint32_t(px.red) << 16)
|
||||
| (uint32_t(px.green) << 8)
|
||||
| uint32_t(px.blue);
|
||||
update.Pixels[x + y * update.Width] = rgba;
|
||||
entry.Pixels[x + y * entry.Width] = rgba;
|
||||
}
|
||||
}
|
||||
}
|
||||
RU.Textures.push_back(std::move(update));
|
||||
|
||||
RU.Textures.push_back(std::move(entry));
|
||||
updated++;
|
||||
} else if(type == EnumAssets::Particle) {
|
||||
RU.Particles.push_back({id, std::move(data)});
|
||||
|
||||
@@ -512,90 +512,9 @@ void ServerSession::update(GlobalTime gTime, float dTime) {
|
||||
|
||||
{
|
||||
AssetsManager::ResourceUpdates updates = AM.pullResourceUpdates();
|
||||
|
||||
if(!updates.Models.empty()) {
|
||||
auto& map = Assets[EnumAssets::Model];
|
||||
for(auto& update : updates.Models) {
|
||||
AssetEntry entry;
|
||||
entry.Id = update.Id;
|
||||
entry.Model = std::move(update.Model);
|
||||
entry.ModelHeader = std::move(update.Header);
|
||||
map[entry.Id] = std::move(entry);
|
||||
result.Assets_ChangeOrAdd[EnumAssets::Model].push_back(update.Id);
|
||||
}
|
||||
}
|
||||
|
||||
if(!updates.Nodestates.empty()) {
|
||||
auto& map = Assets[EnumAssets::Nodestate];
|
||||
for(auto& update : updates.Nodestates) {
|
||||
AssetEntry entry;
|
||||
entry.Id = update.Id;
|
||||
entry.Nodestate = std::move(update.Nodestate);
|
||||
entry.NodestateHeader = std::move(update.Header);
|
||||
map[entry.Id] = std::move(entry);
|
||||
result.Assets_ChangeOrAdd[EnumAssets::Nodestate].push_back(update.Id);
|
||||
}
|
||||
}
|
||||
|
||||
if(!updates.Textures.empty()) {
|
||||
auto& map = Assets[EnumAssets::Texture];
|
||||
for(auto& update : updates.Textures) {
|
||||
AssetEntry entry;
|
||||
entry.Id = update.Id;
|
||||
entry.Domain = std::move(update.Domain);
|
||||
entry.Key = std::move(update.Key);
|
||||
entry.Width = update.Width;
|
||||
entry.Height = update.Height;
|
||||
entry.Pixels = std::move(update.Pixels);
|
||||
entry.Header = std::move(update.Header);
|
||||
map[entry.Id] = std::move(entry);
|
||||
result.Assets_ChangeOrAdd[EnumAssets::Texture].push_back(update.Id);
|
||||
}
|
||||
}
|
||||
|
||||
if(!updates.Particles.empty()) {
|
||||
auto& map = Assets[EnumAssets::Particle];
|
||||
for(auto& update : updates.Particles) {
|
||||
AssetEntry entry;
|
||||
entry.Id = update.Id;
|
||||
entry.Data = std::move(update.Data);
|
||||
map[entry.Id] = std::move(entry);
|
||||
result.Assets_ChangeOrAdd[EnumAssets::Particle].push_back(update.Id);
|
||||
}
|
||||
}
|
||||
|
||||
if(!updates.Animations.empty()) {
|
||||
auto& map = Assets[EnumAssets::Animation];
|
||||
for(auto& update : updates.Animations) {
|
||||
AssetEntry entry;
|
||||
entry.Id = update.Id;
|
||||
entry.Data = std::move(update.Data);
|
||||
map[entry.Id] = std::move(entry);
|
||||
result.Assets_ChangeOrAdd[EnumAssets::Animation].push_back(update.Id);
|
||||
}
|
||||
}
|
||||
|
||||
if(!updates.Sounds.empty()) {
|
||||
auto& map = Assets[EnumAssets::Sound];
|
||||
for(auto& update : updates.Sounds) {
|
||||
AssetEntry entry;
|
||||
entry.Id = update.Id;
|
||||
entry.Data = std::move(update.Data);
|
||||
map[entry.Id] = std::move(entry);
|
||||
result.Assets_ChangeOrAdd[EnumAssets::Sound].push_back(update.Id);
|
||||
}
|
||||
}
|
||||
|
||||
if(!updates.Fonts.empty()) {
|
||||
auto& map = Assets[EnumAssets::Font];
|
||||
for(auto& update : updates.Fonts) {
|
||||
AssetEntry entry;
|
||||
entry.Id = update.Id;
|
||||
entry.Data = std::move(update.Data);
|
||||
map[entry.Id] = std::move(entry);
|
||||
result.Assets_ChangeOrAdd[EnumAssets::Font].push_back(update.Id);
|
||||
}
|
||||
}
|
||||
result.AssetsNodestates = std::move(updates.Nodestates);
|
||||
result.AssetsModels = std::move(updates.Models);
|
||||
result.AssetsTextures = std::move(updates.Textures);
|
||||
}
|
||||
|
||||
for(auto& [id, _] : profile_Voxel_AddOrChange)
|
||||
|
||||
@@ -1662,7 +1662,7 @@ void VulkanRenderSession::pushStageTickSync() {
|
||||
CP.pushStageTickSync();
|
||||
}
|
||||
|
||||
void VulkanRenderSession::tickSync(const TickSyncData& data) {
|
||||
void VulkanRenderSession::tickSync(TickSyncData& data) {
|
||||
// Изменение ассетов
|
||||
// Профили
|
||||
// Чанки
|
||||
@@ -1680,77 +1680,16 @@ void VulkanRenderSession::tickSync(const TickSyncData& data) {
|
||||
if(auto iter = data.Profiles_Lost.find(EnumDefContent::Voxel); iter != data.Profiles_Lost.end())
|
||||
mcpData.ChangedVoxels.insert(mcpData.ChangedVoxels.end(), iter->second.begin(), iter->second.end());
|
||||
|
||||
std::vector<const AssetEntry*> modelResources;
|
||||
std::vector<AssetsModel> modelLost;
|
||||
if(auto iter = data.Assets_ChangeOrAdd.find(EnumAssets::Model); iter != data.Assets_ChangeOrAdd.end()) {
|
||||
const auto& list = ServerSession->Assets[EnumAssets::Model];
|
||||
for(ResourceId id : iter->second) {
|
||||
auto entryIter = list.find(id);
|
||||
if(entryIter == list.end())
|
||||
continue;
|
||||
|
||||
modelResources.push_back(&entryIter->second);
|
||||
}
|
||||
}
|
||||
if(auto iter = data.Assets_Lost.find(EnumAssets::Model); iter != data.Assets_Lost.end())
|
||||
modelLost.insert(modelLost.end(), iter->second.begin(), iter->second.end());
|
||||
|
||||
std::vector<AssetsModel> changedModels;
|
||||
if(!modelResources.empty() || !modelLost.empty()) {
|
||||
const auto& modelAssets = ServerSession->Assets[EnumAssets::Model];
|
||||
changedModels = MP.onModelChanges(std::move(modelResources), std::move(modelLost), &modelAssets);
|
||||
}
|
||||
if(!data.AssetsModels.empty())
|
||||
changedModels = MP.onModelChanges(std::move(data.AssetsModels));
|
||||
|
||||
if(TP) {
|
||||
std::vector<TextureProvider::TextureUpdate> textureResources;
|
||||
std::vector<AssetsTexture> textureLost;
|
||||
|
||||
if(auto iter = data.Assets_ChangeOrAdd.find(EnumAssets::Texture); iter != data.Assets_ChangeOrAdd.end()) {
|
||||
const auto& list = ServerSession->Assets[EnumAssets::Texture];
|
||||
for(ResourceId id : iter->second) {
|
||||
auto entryIter = list.find(id);
|
||||
if(entryIter == list.end())
|
||||
continue;
|
||||
|
||||
textureResources.push_back({
|
||||
.Id = id,
|
||||
.Width = entryIter->second.Width,
|
||||
.Height = entryIter->second.Height,
|
||||
.Pixels = entryIter->second.Pixels,
|
||||
.Domain = entryIter->second.Domain,
|
||||
.Key = entryIter->second.Key
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(auto iter = data.Assets_Lost.find(EnumAssets::Texture); iter != data.Assets_Lost.end())
|
||||
textureLost.insert(textureLost.end(), iter->second.begin(), iter->second.end());
|
||||
|
||||
if(!textureResources.empty() || !textureLost.empty())
|
||||
TP->onTexturesChanges(std::move(textureResources), std::move(textureLost));
|
||||
}
|
||||
if(TP && !data.AssetsTextures.empty())
|
||||
TP->onTexturesChanges(std::move(data.AssetsTextures));
|
||||
|
||||
std::vector<AssetsNodestate> changedNodestates;
|
||||
if(NSP) {
|
||||
std::vector<const AssetEntry*> nodestateResources;
|
||||
std::vector<AssetsNodestate> nodestateLost;
|
||||
|
||||
if(auto iter = data.Assets_ChangeOrAdd.find(EnumAssets::Nodestate); iter != data.Assets_ChangeOrAdd.end()) {
|
||||
const auto& list = ServerSession->Assets[EnumAssets::Nodestate];
|
||||
for(ResourceId id : iter->second) {
|
||||
auto entryIter = list.find(id);
|
||||
if(entryIter == list.end())
|
||||
continue;
|
||||
|
||||
nodestateResources.push_back(&entryIter->second);
|
||||
}
|
||||
}
|
||||
|
||||
if(auto iter = data.Assets_Lost.find(EnumAssets::Nodestate); iter != data.Assets_Lost.end())
|
||||
nodestateLost.insert(nodestateLost.end(), iter->second.begin(), iter->second.end());
|
||||
|
||||
if(!nodestateResources.empty() || !nodestateLost.empty() || !changedModels.empty())
|
||||
changedNodestates = NSP->onNodestateChanges(std::move(nodestateResources), std::move(nodestateLost), changedModels);
|
||||
if(NSP && (!data.AssetsNodestates.empty() || !changedModels.empty())) {
|
||||
changedNodestates = NSP->onNodestateChanges(std::move(data.AssetsNodestates), std::move(changedModels));
|
||||
}
|
||||
|
||||
if(!changedNodestates.empty()) {
|
||||
@@ -2050,29 +1989,7 @@ void VulkanRenderSession::ensureEntityTexture() {
|
||||
if(EntityTextureReady || !TP || !NSP)
|
||||
return;
|
||||
|
||||
auto iter = ServerSession->Assets.find(EnumAssets::Texture);
|
||||
if(iter == ServerSession->Assets.end() || iter->second.empty())
|
||||
return;
|
||||
|
||||
const AssetEntry* picked = nullptr;
|
||||
for(const auto& [id, entry] : iter->second) {
|
||||
if(entry.Key == "default.png") {
|
||||
picked = &entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!picked) {
|
||||
for(const auto& [id, entry] : iter->second) {
|
||||
if(entry.Key == "grass.png") {
|
||||
picked = &entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!picked)
|
||||
picked = &iter->second.begin()->second;
|
||||
|
||||
updateTestQuadTexture(NSP->getTextureId(picked->Id));
|
||||
return;
|
||||
}
|
||||
|
||||
void VulkanRenderSession::ensureAtlasLayerPreview() {
|
||||
|
||||
@@ -89,11 +89,8 @@ public:
|
||||
}
|
||||
|
||||
// Применяет изменения, возвращая все затронутые модели
|
||||
std::vector<AssetsModel> onModelChanges(std::vector<const AssetEntry*> newOrChanged,
|
||||
std::vector<AssetsModel> lost,
|
||||
const std::unordered_map<ResourceId, AssetEntry>* modelAssets) {
|
||||
std::vector<AssetsModel> onModelChanges(std::vector<AssetsModelUpdate> entries) {
|
||||
std::vector<AssetsModel> result;
|
||||
(void)modelAssets;
|
||||
|
||||
std::move_only_function<void(ResourceId)> makeUnready;
|
||||
makeUnready = [&](ResourceId id) {
|
||||
@@ -124,29 +121,15 @@ public:
|
||||
|
||||
iterModel->second.Ready = false;
|
||||
};
|
||||
|
||||
for(ResourceId lostId : lost) {
|
||||
makeUnready(lostId);
|
||||
}
|
||||
|
||||
for(ResourceId lostId : lost) {
|
||||
auto iterModel = Models.find(lostId);
|
||||
if(iterModel == Models.end())
|
||||
continue;
|
||||
|
||||
Models.erase(iterModel);
|
||||
}
|
||||
|
||||
for(const AssetEntry* entry : newOrChanged) {
|
||||
if(!entry)
|
||||
continue;
|
||||
const AssetsModel key = entry->Id;
|
||||
for(const AssetsModelUpdate& entry : entries) {
|
||||
const AssetsModel key = entry.Id;
|
||||
result.push_back(key);
|
||||
|
||||
makeUnready(key);
|
||||
ModelObject model;
|
||||
const HeadlessModel& hm = entry->Model;
|
||||
const HeadlessModel::Header& header = entry->ModelHeader;
|
||||
const HeadlessModel& hm = entry.Model;
|
||||
const HeadlessModel::Header& header = entry.Header;
|
||||
|
||||
try {
|
||||
model.TextureMap.clear();
|
||||
@@ -587,30 +570,25 @@ public:
|
||||
}
|
||||
|
||||
// Применяет изменения, возвращая все затронутые модели
|
||||
std::vector<AssetsTexture> onTexturesChanges(std::vector<TextureUpdate> newOrChanged, std::vector<AssetsTexture> lost) {
|
||||
std::vector<AssetsTexture> onTexturesChanges(std::vector<AssetsTextureUpdate> entries) {
|
||||
std::lock_guard lock(Mutex);
|
||||
std::vector<AssetsTexture> result;
|
||||
|
||||
for(auto& update : newOrChanged) {
|
||||
const AssetsTexture key = update.Id;
|
||||
for(auto& entry : entries) {
|
||||
const AssetsTexture key = entry.Id;
|
||||
result.push_back(key);
|
||||
|
||||
if(update.Width == 0 || update.Height == 0 || update.Pixels.empty())
|
||||
if(entry.Width == 0 || entry.Height == 0 || entry.Pixels.empty())
|
||||
continue;
|
||||
|
||||
Atlas->updateTexture(key, StoredTexture(
|
||||
update.Width,
|
||||
update.Height,
|
||||
std::move(update.Pixels)
|
||||
entry.Width,
|
||||
entry.Height,
|
||||
std::move(entry.Pixels)
|
||||
));
|
||||
|
||||
bool animated = false;
|
||||
if(auto anim = getDefaultAnimation(update.Key, update.Width, update.Height)) {
|
||||
AnimatedSources[key] = *anim;
|
||||
animated = true;
|
||||
} else {
|
||||
AnimatedSources.erase(key);
|
||||
}
|
||||
AnimatedSources.erase(key);
|
||||
|
||||
NeedsUpload = true;
|
||||
|
||||
@@ -618,19 +596,11 @@ public:
|
||||
uint32_t idx = debugTextureLogCount.fetch_add(1);
|
||||
if(idx < 128) {
|
||||
LOG.debug() << "Texture loaded id=" << key
|
||||
<< " key=" << update.Domain << ':' << update.Key
|
||||
<< " size=" << update.Width << 'x' << update.Height
|
||||
<< " size=" << entry.Width << 'x' << entry.Height
|
||||
<< " animated=" << (animated ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
for(AssetsTexture key : lost) {
|
||||
result.push_back(key);
|
||||
Atlas->freeTexture(key);
|
||||
AnimatedSources.erase(key);
|
||||
NeedsUpload = true;
|
||||
}
|
||||
|
||||
std::sort(result.begin(), result.end());
|
||||
auto eraseIter = std::unique(result.begin(), result.end());
|
||||
result.erase(eraseIter, result.end());
|
||||
@@ -844,27 +814,16 @@ public:
|
||||
{}
|
||||
|
||||
// Применяет изменения, возвращает изменённые описания состояний
|
||||
std::vector<AssetsNodestate> onNodestateChanges(std::vector<const AssetEntry*> newOrChanged, std::vector<AssetsNodestate> lost, std::vector<AssetsModel> changedModels) {
|
||||
std::vector<AssetsNodestate> onNodestateChanges(std::vector<AssetsNodestateUpdate> newOrChanged, std::vector<AssetsModel> changedModels) {
|
||||
std::vector<AssetsNodestate> result;
|
||||
|
||||
for(ResourceId lostId : lost) {
|
||||
auto iterNodestate = Nodestates.find(lostId);
|
||||
if(iterNodestate == Nodestates.end())
|
||||
continue;
|
||||
|
||||
result.push_back(lostId);
|
||||
Nodestates.erase(iterNodestate);
|
||||
}
|
||||
|
||||
for(const AssetEntry* entry : newOrChanged) {
|
||||
if(!entry)
|
||||
continue;
|
||||
const AssetsNodestate key = entry->Id;
|
||||
for(const AssetsNodestateUpdate& entry : newOrChanged) {
|
||||
const AssetsNodestate key = entry.Id;
|
||||
result.push_back(key);
|
||||
|
||||
PreparedNodeState nodestate;
|
||||
static_cast<HeadlessNodeState&>(nodestate) = entry->Nodestate;
|
||||
nodestate.LocalToModel.assign(entry->NodestateHeader.Models.begin(), entry->NodestateHeader.Models.end());
|
||||
static_cast<HeadlessNodeState&>(nodestate) = entry.Nodestate;
|
||||
nodestate.LocalToModel.assign(entry.Header.Models.begin(), entry.Header.Models.end());
|
||||
|
||||
Nodestates.insert_or_assign(key, std::move(nodestate));
|
||||
if(key < 64) {
|
||||
@@ -1321,7 +1280,7 @@ public:
|
||||
|
||||
virtual void prepareTickSync() override;
|
||||
virtual void pushStageTickSync() override;
|
||||
virtual void tickSync(const TickSyncData& data) override;
|
||||
virtual void tickSync(TickSyncData& data) override;
|
||||
|
||||
virtual void setCameraPos(WorldId_t worldId, Pos::Object pos, glm::quat quat) override;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user