Skip to content

Commit 2e16e3a

Browse files
add support for fo4 next-gen update
1 parent 431dd02 commit 2e16e3a

5 files changed

Lines changed: 68 additions & 17 deletions

File tree

data/fo4_next_gen_test.7z

1.96 MB
Binary file not shown.

include/bsa/fo4.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ namespace bsa::fo4
5252

5353
/// \brief Intoduced in Starfield.
5454
v3,
55+
56+
/// \brief Intoduced in the Fallout 4 next-gen update.
57+
v7 = 7,
58+
59+
/// \brief Intoduced in the Fallout 4 next-gen update.
60+
v8,
5561
};
5662

5763
/// \brief Specifies the compression level to use when compressing data.

src/bsa/fo4.cpp

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -106,23 +106,18 @@ namespace bsa::fo4
106106
[[nodiscard]] auto sizeof_header(version a_version) noexcept
107107
-> std::size_t
108108
{
109-
std::size_t size = 0;
110-
111109
switch (a_version) {
112-
case version::v3:
113-
size += sizeof(std::uint32_t);
114-
[[fallthrough]];
115-
case version::v2:
116-
size += sizeof(std::uint64_t);
117-
[[fallthrough]];
118110
case version::v1:
119-
size += 0x18;
120-
break;
111+
case version::v7:
112+
case version::v8:
113+
return 0x18;
114+
case version::v2:
115+
return 0x20;
116+
case version::v3:
117+
return 0x24;
121118
default:
122119
detail::declare_unreachable();
123120
}
124-
125-
return size;
126121
}
127122
}
128123

@@ -141,7 +136,7 @@ namespace bsa::fo4
141136
_stringTableOffset(a_stringTableOffset),
142137
_compression_format(a_meta.compression_format_)
143138
{
144-
if (a_meta.compression_format_ == compression_format::lz4 && a_meta.version_ < version::v3) {
139+
if (a_meta.compression_format_ == compression_format::lz4 && a_meta.version_ != version::v3) {
145140
throw exception("compression format is not valid for the given version");
146141
}
147142
}
@@ -170,17 +165,19 @@ namespace bsa::fo4
170165
case 1:
171166
case 2:
172167
case 3:
168+
case 7:
169+
case 8:
173170
break;
174171
default:
175172
throw exception("invalid version");
176173
}
177174
}
178175

179-
if (a_header._version >= 2) {
176+
if (a_header._version == 2 || a_header._version == 3) {
180177
(void)a_in->read<std::uint64_t>();
181178
}
182179

183-
if (a_header._version >= 3) {
180+
if (a_header._version == 3) {
184181
const auto [compression] = a_in->read<std::uint32_t>();
185182
if (compression == constants::compression_lz4) {
186183
a_header._compression_format = fo4::compression_format::lz4;
@@ -202,11 +199,11 @@ namespace bsa::fo4
202199
a_header._fileCount,
203200
a_header._stringTableOffset);
204201

205-
if (a_header._version >= 2) {
202+
if (a_header._version == 2 || a_header._version == 3) {
206203
a_out.write(std::uint64_t{ 1 });
207204
}
208205

209-
if (a_header._version >= 3) {
206+
if (a_header._version == 3) {
210207
std::uint32_t format =
211208
a_header._compression_format == fo4::compression_format::lz4 ?
212209
constants::compression_lz4 :

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ acquire_test("fo4_dds_test")
6262
acquire_test("fo4_dx9_test")
6363
acquire_test("fo4_invalid_test")
6464
acquire_test("fo4_missing_string_table_test")
65+
acquire_test("fo4_next_gen_test")
6566
acquire_test("fo4_write_test")
6667

6768
acquire_test("tes3_invalid_test")

tests/src/bsa/fo4.test.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,4 +618,51 @@ TEST_CASE("bsa::fo4::archive", "[src][fo4][archive]")
618618
});
619619
}
620620
}
621+
622+
SECTION("we can archives from the fallout 4 next-gen update")
623+
{
624+
const std::filesystem::path root{ "fo4_next_gen_test"sv };
625+
const std::array formats = {
626+
std::make_pair(bsa::fo4::format::directx, "dx10"sv),
627+
std::make_pair(bsa::fo4::format::general, "gnrl"sv),
628+
};
629+
const std::array versions = { bsa::fo4::version::v7, bsa::fo4::version::v8 };
630+
631+
for (const auto [format, format_str] : formats) {
632+
for (const auto version : versions) {
633+
std::span<const std::string_view> files;
634+
switch (format) {
635+
case bsa::fo4::format::general:
636+
{
637+
constexpr std::array a = { "License.txt"sv, "SampleA.png"sv };
638+
files = std::span(a);
639+
}
640+
break;
641+
case bsa::fo4::format::directx:
642+
{
643+
constexpr std::array a = { "Fence006_1K_Roughness.dds"sv };
644+
files = std::span(a);
645+
}
646+
break;
647+
default:
648+
REQUIRE(false);
649+
}
650+
651+
bsa::fo4::archive ba2;
652+
const auto path = root / std::format("{}_v{}.ba2", format_str, static_cast<std::uint32_t>(version));
653+
const auto meta = ba2.read(path);
654+
REQUIRE(meta.version_ == version);
655+
REQUIRE(meta.format_ == format);
656+
657+
REQUIRE(ba2.size() == files.size());
658+
for (const auto filename : files) {
659+
const auto file = ba2[filename];
660+
REQUIRE(static_cast<bool>(file));
661+
}
662+
663+
auto os = binary_io::any_ostream(std::in_place_type<binary_io::memory_ostream>);
664+
ba2.write({ os }, meta);
665+
}
666+
}
667+
}
621668
}

0 commit comments

Comments
 (0)