Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
SequenceChildSchedule.cpp
Go to the documentation of this file.
2
3#include <utility>
4
5namespace monopoly::sequence
6{
7 SequenceChildSchedule::SequenceChildSchedule(
8 std::shared_ptr<const Description> description)
9 : description_(std::move(description)) {}
10
11 std::expected<SequenceChildSchedule, ChildScheduleError>
12 SequenceChildSchedule::read(data::SharedDataBytes bytes,
13 data::DataId containingDataId, std::size_t maximumRecords)
14 {
15 return readChildren(data::LegacyChunkReader(std::move(bytes)),
16 containingDataId, maximumRecords);
17 }
18
19 std::expected<SequenceChildSchedule, ChildScheduleError>
20 SequenceChildSchedule::readChildren(data::LegacyChunkReader reader,
21 data::DataId containingDataId, std::size_t maximumRecords)
22 {
23 auto description = std::make_shared<Description>(Description{reader, containingDataId, {}});
24 while (reader.remaining() != 0)
25 {
26 auto probe = reader;
27 auto chunk = probe.descend();
28 if (!chunk) return std::unexpected(ChildScheduleError{ chunk.error() });
29 // L_Seqncr.cpp:5300 tests 1 <= ID < SEQ_MAX (11).
30 if (chunk->id >= 1 && chunk->id < 11)
31 {
32 if (description->records.size() >= maximumRecords)
33 return std::unexpected(ChildScheduleError{ data::SequenceError{
34 data::SequenceErrorCode::RecordLimitExceeded,
35 chunk->headerOffset, "child sequence record budget exceeded",
36 std::nullopt } });
37 auto record = data::readLegacySequenceRecord(reader);
38 if (!record)
39 return std::unexpected(ChildScheduleError{ record.error() });
40 description->records.push_back(std::move(*record));
41 auto ascended = reader.ascend();
42 if (!ascended)
43 return std::unexpected(ChildScheduleError{ ascended.error() });
44 }
45 else
46 {
47 // Not an execution claim for attributes: preserve in reader_.
48 auto skipped = reader.seek(chunk->endOffset);
49 if (!skipped)
50 return std::unexpected(ChildScheduleError{ skipped.error() });
51 }
52 }
53 return SequenceChildSchedule(std::move(description));
54 }
55
56 std::span<const data::LegacySequenceRecord>
57 SequenceChildSchedule::records() const noexcept { return description_->records; }
58 data::DataId SequenceChildSchedule::containingDataId() const noexcept
59 { return description_->containingDataId; }
60 std::size_t SequenceChildSchedule::nextIndex() const noexcept { return nextIndex_; }
61
62 std::expected<std::vector<std::size_t>, data::SequenceError>
63 SequenceChildSchedule::select(std::optional<std::int32_t> previous,
64 std::int32_t current)
65 {
66 if (previous && current < *previous)
67 return std::unexpected(data::SequenceError{
68 data::SequenceErrorCode::InvalidClockRange, description_->reader.currentOffset(),
69 "child scan cannot run backwards; rewind and rescan from minus infinity",
70 std::nullopt });
71 std::vector<std::size_t> selected;
72 auto next = nextIndex_;
73 for (; next < description_->records.size(); ++next)
74 {
75 const auto& header = description_->records[next].header;
76 if (header.parentStartTime > current) break;
77 const auto end = static_cast<std::int64_t>(header.parentStartTime) +
78 header.endTime;
79 if ((!previous || header.parentStartTime > *previous) &&
80 (header.endingAction != 1 || header.endTime == 0 || end > current))
81 selected.push_back(next);
82 }
83 nextIndex_ = next;
84 return selected;
85 }
86
87 void SequenceChildSchedule::rewind() noexcept { nextIndex_ = 0; }
88
89 std::expected<data::LegacyChunkReader, data::ChunkError>
90 SequenceChildSchedule::readerForChild(std::size_t index) const
91 {
92 if (index >= description_->records.size())
93 return std::unexpected(data::ChunkError{
94 data::ChunkErrorCode::PositionOutOfRange, description_->reader.currentOffset(),
95 "child record index is out of range" });
96 auto reader = description_->reader;
97 const auto seek = reader.seek(description_->records[index].chunk.headerOffset);
98 if (!seek) return std::unexpected(seek.error());
99 return reader;
100 }
101
102 std::expected<SequenceChildSchedule, ChildScheduleError>
104 data::DataId parentDataId, std::size_t parentOffset, std::size_t maximumRecords)
105 {
106 auto reader = data::openLegacyChunkReader(source, parentDataId);
107 if (!reader) return std::unexpected(ChildScheduleError{ reader.error() });
108 const auto seek = reader->seek(parentOffset);
109 if (!seek) return std::unexpected(ChildScheduleError{ seek.error() });
110 auto parent = data::readLegacySequenceRecord(*reader);
111 if (!parent) return std::unexpected(ChildScheduleError{ parent.error() });
112 if (const auto* indirect = std::get_if<data::SequenceIndirectData>(&parent->data))
113 {
114 const auto id = data::resolveSequenceDataId(parent->header,
115 indirect->subsequenceDataId, parentDataId);
116 // Absolute zero means no children. Relative zero is group:tag0,
117 // not empty (the legacy remapping macro must run first).
118 if (id == 0)
119 return SequenceChildSchedule::read({}, id, maximumRecords);
120 if (id == parentDataId)
121 {
122 // AddNewlyBornChildren (5269-5279) chooses parent bounds by
123 // DATA identity, even for an indirect sequence. Its seek to
124 // zero then fails (L_Chunk.cpp:2497-2511). Do not accidentally
125 // turn this historically invalid case into recursive playback.
126 return std::unexpected(ChildScheduleError{ data::ChunkError{
127 data::ChunkErrorCode::PositionOutOfRange, 0,
128 "same-item indirect child list starts outside its parent chunk" } });
129 }
130 auto external = data::openLegacyChunkReader(source, id);
131 if (!external) return std::unexpected(ChildScheduleError{ external.error() });
132 return SequenceChildSchedule::readChildren(std::move(*external), id, maximumRecords);
133 }
134 return SequenceChildSchedule::readChildren(std::move(*reader), parentDataId, maximumRecords);
135 }
136}
const char * header
std::vector< std::byte > bytes
data::DataId id
std::shared_ptr< const data::HmdTextureImage > source
unsigned index
std::expected< void, ChunkError > ascend()
std::expected< ChunkInfo, ChunkError > descend(std::uint8_t findId=NullStandardId)
std::expected< void, ChunkError > seek(std::size_t absoluteOffset)
std::size_t remaining() const noexcept
std::uint32_t DataId
Definition DataBanks.hpp:10
std::shared_ptr< const DataBytes > SharedDataBytes
std::expected< SequenceChildSchedule, ChildScheduleError > openSequenceChildSchedule(const data::DataSource &source, data::DataId parentDataId, std::size_t parentOffset, std::size_t maximumRecords)
std::variant< data::DataError, data::ChunkError, data::SequenceError > ChildScheduleError