#define RT_DEFINE_DEPENDENCY_FILE_STRUCTURES #include "asset_dependencies.h" #include "aio.h" #include "buffer_manager.h" #include #include #include #include typedef struct { uint32_t begin; uint32_t count; } rt_dep_list; typedef struct { rt_uid *uids; rt_dep_list *lists; uint32_t capacity; } rt_dep_map; static rt_dep_map _map; static rt_uid *_list_mem; rt_result LoadAssetDependencies(void) { rt_dependency_file_header header; rt_file_id fid = rtAddFile("data/deps.bin"); if (rtSubmitSingleLoadSync((rt_file_load){.dest = &header, .num_bytes = sizeof(header), .offset = 0, .file = fid}) != RT_AIO_STATE_FINISHED) { rtReportError("core", "Failed to load deps.bin"); return RT_UNKNOWN_ERROR; } void *buffer = rtAllocBuffer(header.data_size); if (rtSubmitSingleLoadSync((rt_file_load){.dest = buffer, .num_bytes = header.data_size, .offset = sizeof(header), .file = fid}) != RT_AIO_STATE_FINISHED) { rtReportError("core", "Failed to load deps.bin"); return RT_UNKNOWN_ERROR; } /* We know the exact number of list entries */ uint64_t total_list_entries = (header.data_size - header.num_lists * sizeof(rt_dependency_file_list_header)) / sizeof(rt_uid); _list_mem = malloc(total_list_entries * sizeof(rt_uid)); if (!_list_mem) { rtReleaseBuffer(buffer, header.data_size); rtReportError("core", "Failed to allocate dependency list storage."); return RT_UNKNOWN_ERROR; } _map.capacity = rtNextPowerOfTwo32(header.num_lists); _map.uids = calloc(_map.capacity, sizeof(rt_uid)); if (!_map.uids) { free(_list_mem); rtReleaseBuffer(buffer, header.data_size); rtReportError("core", "Failed to allocate dependency list storage."); return RT_UNKNOWN_ERROR; } _map.lists = calloc(_map.capacity, sizeof(rt_dep_list)); if (!_map.uids) { free(_list_mem); free(_map.uids); rtReleaseBuffer(buffer, header.data_size); rtReportError("core", "Failed to allocate dependency list storage."); return RT_UNKNOWN_ERROR; } uint32_t storage_at = 0; rt_dependency_file_list_header *list = buffer; for (uint32_t i = 0; i < header.num_lists; ++i) { const rt_uid *entries = (rt_uid *)(list + 1); /* Validate the checksum */ XXH64_hash_t file_hash = XXH64_hashFromCanonical(&list->checksum); XXH64_hash_t calc_hash = XXH3_64bits(entries, sizeof(rt_uid) * list->num_entries); if (file_hash != calc_hash) { rtReportError("core", "Checksum mismatch in list %u", i); rtReleaseBuffer(buffer, header.data_size); return RT_UNKNOWN_ERROR; } /* Store the list */ memcpy(_list_mem + storage_at, entries, sizeof(rt_uid) * list->num_entries); bool inserted = false; for (uint32_t j = 0; j < _map.capacity; ++j) { uint32_t slot = (list->uid + j) % _map.capacity; if (_map.uids[slot] == RT_INVALID_UID) { _map.uids[slot] = list->uid; _map.lists[slot].begin = storage_at; _map.lists[slot].count = list->num_entries; inserted = true; break; } } storage_at += list->num_entries; assert(inserted); assert(storage_at <= total_list_entries); list = (rt_dependency_file_list_header *)(entries + list->num_entries); } rtReleaseBuffer(buffer, header.data_size); return RT_SUCCESS; } void ReleaseAssetDependencies(void) { free(_list_mem); free(_map.uids); free(_map.lists); } RT_DLLEXPORT rt_asset_dependency_list rtGetAssetDependencies(rt_uid asset) { rt_asset_dependency_list result = { .dependencies = NULL, .count = 0, }; for (uint32_t i = 0; i < _map.capacity; ++i) { uint32_t slot = (asset + i) % _map.capacity; if (_map.uids[slot] == asset) { result.dependencies = &_list_mem[_map.lists[slot].begin]; result.count = _map.lists[slot].count; break; } else if (_map.uids[slot] == RT_INVALID_UID) { break; } } return result; }