| 1235 | } |
| 1236 | |
| 1237 | bool ContentResolver::TryLoadLevel(StringView path, GameDifficulty difficulty, LevelDescriptor& descriptor) |
| 1238 | { |
| 1239 | // Try "Content" directory first, then "Cache" directory |
| 1240 | auto pathNormalized = fs::ToNativeSeparators(path); |
| 1241 | if (_pathHandler) { |
| 1242 | descriptor.FullPath = _pathHandler(String(pathNormalized + ".j2l"_s)); |
| 1243 | } |
| 1244 | if (descriptor.FullPath.empty()) { |
| 1245 | descriptor.FullPath = fs::CombinePath({ GetContentPath(), "Episodes"_s, String(pathNormalized + ".j2l"_s) }); |
| 1246 | if (!fs::IsReadableFile(descriptor.FullPath)) { |
| 1247 | descriptor.FullPath = fs::CombinePath({ GetCachePath(), "Episodes"_s, String(pathNormalized + ".j2l"_s) }); |
| 1248 | } |
| 1249 | } |
| 1250 | |
| 1251 | auto s = fs::Open(descriptor.FullPath, FileAccess::Read, 16 * 1024); |
| 1252 | if (!s->IsValid()) return false; |
| 1253 | |
| 1254 | std::uint64_t signature = s->ReadValueAsLE<std::uint64_t>(); |
| 1255 | std::uint8_t fileType = s->ReadValue<std::uint8_t>(); |
| 1256 | DEATH_ASSERT(signature == 0x2095A59FF0BFBBEF && fileType == LevelFile, |
| 1257 | ("Level \"{}\" has invalid signature", descriptor.FullPath), false); |
| 1258 | |
| 1259 | LevelFlags flags = (LevelFlags)s->ReadValueAsLE<std::uint16_t>(); |
| 1260 | |
| 1261 | // Read compressed data |
| 1262 | std::int32_t compressedSize = s->ReadValueAsLE<std::int32_t>(); |
| 1263 | |
| 1264 | DeflateStream uc(*s, compressedSize); |
| 1265 | |
| 1266 | // Read metadata |
| 1267 | std::uint8_t stringSize = uc.ReadValue<std::uint8_t>(); |
| 1268 | descriptor.DisplayName = String(NoInit, stringSize); |
| 1269 | uc.Read(descriptor.DisplayName.data(), stringSize); |
| 1270 | |
| 1271 | stringSize = uc.ReadValue<std::uint8_t>(); |
| 1272 | descriptor.NextLevel = String(NoInit, stringSize); |
| 1273 | uc.Read(descriptor.NextLevel.data(), stringSize); |
| 1274 | |
| 1275 | stringSize = uc.ReadValue<std::uint8_t>(); |
| 1276 | descriptor.SecretLevel = String(NoInit, stringSize); |
| 1277 | uc.Read(descriptor.SecretLevel.data(), stringSize); |
| 1278 | |
| 1279 | stringSize = uc.ReadValue<std::uint8_t>(); |
| 1280 | descriptor.BonusLevel = String(NoInit, stringSize); |
| 1281 | uc.Read(descriptor.BonusLevel.data(), stringSize); |
| 1282 | |
| 1283 | // Default Tileset |
| 1284 | stringSize = uc.ReadValue<std::uint8_t>(); |
| 1285 | String defaultTileset(NoInit, stringSize); |
| 1286 | uc.Read(defaultTileset.data(), stringSize); |
| 1287 | |
| 1288 | // Default Music |
| 1289 | stringSize = uc.ReadValue<std::uint8_t>(); |
| 1290 | descriptor.MusicPath = String(NoInit, stringSize); |
| 1291 | uc.Read(descriptor.MusicPath.data(), stringSize); |
| 1292 | |
| 1293 | uint32_t rawAmbientColor = uc.ReadValueAsLE<std::uint32_t>(); |
| 1294 | descriptor.AmbientColor = Vector4f((rawAmbientColor & 0xff) / 255.0f, ((rawAmbientColor >> 8) & 0xff) / 255.0f, |
no test coverage detected