codex5.2: исправил ошибки в работе с ресурсами на стороне клиента
This commit is contained in:
@@ -310,14 +310,14 @@ void AssetsManager::readWriteThread(AsyncUseControl::Lock lock) {
|
||||
sqlite3_reset(STMT_DISK_CONTAINS);
|
||||
|
||||
if(finded) {
|
||||
sqlite3_bind_blob(STMT_DISK_CONTAINS, 1, (const void*) rk.Hash.data(), 32, SQLITE_STATIC);
|
||||
sqlite3_bind_int(STMT_DISK_CONTAINS, 2, time(nullptr));
|
||||
if(sqlite3_step(STMT_DISK_CONTAINS) != SQLITE_DONE) {
|
||||
sqlite3_reset(STMT_DISK_CONTAINS);
|
||||
MAKE_ERROR("Не удалось выполнить подготовленный запрос STMT_DISK_CONTAINS: " << sqlite3_errmsg(DB));
|
||||
sqlite3_bind_int(STMT_DISK_UPDATE_TIME, 1, time(nullptr));
|
||||
sqlite3_bind_blob(STMT_DISK_UPDATE_TIME, 2, (const void*) rk.Hash.data(), 32, SQLITE_STATIC);
|
||||
if(sqlite3_step(STMT_DISK_UPDATE_TIME) != SQLITE_DONE) {
|
||||
sqlite3_reset(STMT_DISK_UPDATE_TIME);
|
||||
MAKE_ERROR("Не удалось выполнить подготовленный запрос STMT_DISK_UPDATE_TIME: " << sqlite3_errmsg(DB));
|
||||
}
|
||||
|
||||
sqlite3_reset(STMT_DISK_CONTAINS);
|
||||
|
||||
sqlite3_reset(STMT_DISK_UPDATE_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,6 +372,7 @@ void AssetsManager::readWriteThread(AsyncUseControl::Lock lock) {
|
||||
}
|
||||
|
||||
fs::path end = PathFiles / hashKey.substr(0, 2) / hashKey.substr(2);
|
||||
fs::create_directories(end.parent_path());
|
||||
std::ofstream fd(end, std::ios::binary);
|
||||
fd.write((const char*) res.data(), res.size());
|
||||
|
||||
@@ -412,4 +413,4 @@ std::string AssetsManager::hashToString(const Hash_t& hash) {
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1100,6 +1100,10 @@ coro<> ServerSession::rP_Resource(Net::AsyncSocket &sock) {
|
||||
);
|
||||
|
||||
AsyncContext.AssetsLoading.erase(AsyncContext.AssetsLoading.find(hash));
|
||||
|
||||
auto iter = std::lower_bound(AsyncContext.AlreadyLoading.begin(), AsyncContext.AlreadyLoading.end(), hash);
|
||||
if(iter != AsyncContext.AlreadyLoading.end() && *iter == hash)
|
||||
AsyncContext.AlreadyLoading.erase(iter);
|
||||
}
|
||||
} catch(const std::exception& exc) {
|
||||
std::string err = exc.what();
|
||||
@@ -1246,4 +1250,4 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
57
docs/resources.md
Normal file
57
docs/resources.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Resources and asset transfer
|
||||
|
||||
This document describes how binary resources are discovered, cached, and transferred from server to client.
|
||||
|
||||
## Resource types
|
||||
- Binary resources are grouped by EnumAssets (nodestate, particle, animation, model, texture, sound, font).
|
||||
- Each resource is addressed by a domain + key pair and also identified by a SHA-256 hash (Hash_t).
|
||||
- The hash is the canonical payload identity: if the hash matches, the content is identical.
|
||||
|
||||
## High-level flow
|
||||
1) Server tracks resource usage per client.
|
||||
2) Server announces bindings (type + id + domain:key + hash) to the client.
|
||||
3) Client checks local packs and cache; if missing, client requests by hash.
|
||||
4) Server streams requested resources in chunks.
|
||||
5) Client assembles the payload, stores it in cache, and marks the resource as loaded.
|
||||
|
||||
## Server side
|
||||
- Resource usage counters are maintained in `RemoteClient::NetworkAndResource_t::ResUses`.
|
||||
- When content references change, `incrementAssets` and `decrementAssets` update counters.
|
||||
- `ResourceRequest` is built from per-client usage and sent to `GameServer::stepSyncContent`.
|
||||
- `GameServer::stepSyncContent` resolves resource data via `AssetsManager` and calls `RemoteClient::informateAssets`.
|
||||
- `RemoteClient::informateAssets`:
|
||||
- Sends bind notifications when a hash for an id changes or is new to the client.
|
||||
- Queues full resources only if the client explicitly requested the hash.
|
||||
- Streaming happens in `RemoteClient::onUpdate`:
|
||||
- `InitResSend` announces the total size + hash + type/id + domain/key.
|
||||
- `ChunkSend` transmits raw payload slices until complete.
|
||||
|
||||
## Client side
|
||||
- `ServerSession::rP_Resource` handles bind/lost/init/chunk packets.
|
||||
- `Bind` and `Lost` update the in-memory bindings queue.
|
||||
- `InitResSend` creates an `AssetLoading` entry keyed by hash.
|
||||
- `ChunkSend` appends bytes to the loading entry; when finished, the asset is enqueued for cache write.
|
||||
- The update loop (`ServerSession::update`) pulls assets from `AssetsManager`:
|
||||
- If cache miss: sends `ResourceRequest` with the hash.
|
||||
- If cache hit: directly marks the resource as loaded.
|
||||
|
||||
## Client cache (`AssetsManager`)
|
||||
- Reads check, in order:
|
||||
1) Resource packs on disk (assets directories)
|
||||
2) Inline sqlite cache (small resources)
|
||||
3) File-based cache (large resources)
|
||||
- Writes store small resources in sqlite and larger ones as files under `Cache/blobs/`.
|
||||
- The cache also tracks last-used timestamps for eviction policies.
|
||||
|
||||
## Packet types (Resources)
|
||||
- `Bind`: server -> client mapping of (type, id, domain, key, hash).
|
||||
- `Lost`: server -> client removing mapping of (type, id).
|
||||
- `InitResSend`: server -> client resource stream header.
|
||||
- `ChunkSend`: server -> client resource stream payload.
|
||||
- `ResourceRequest`: client -> server, list of hashes that are missing.
|
||||
|
||||
## Common failure modes
|
||||
- Missing bind update: client will never request the hash.
|
||||
- Missing cache entry or stale `AlreadyLoading`: client stops requesting resources it still needs.
|
||||
- Interrupted streaming: asset stays in `AssetsLoading` without being finalized.
|
||||
|
||||
Reference in New Issue
Block a user