mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-06 11:57:13 +00:00
feat: read and keep a scene file's sounds and particles as the client does
Files from before chunks now read their sounds and particles after the objects, and chunked files their particle chunk: - sounds (SceneLoader::LoadSounds, version 5 on, only before chunks): position and config (before 35 a 260 character name, kept as soundName); - particles (SceneLoader::LoadParticles, version 5 on): priority (43 on), position, rotation, effect names and config (46 on; before, an unused u16); the client stops at one with no effect, and before 44 a file may end before them. Every scene file of every client on disk reads each part to the next part's start (up to the client's 16 byte padding): 5408 referenced by zone files and 5125 on disk, versions 31-43 before chunks and 44-49 chunked. One client file, a LUP world, ends before its sounds; its objects are kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -243,6 +243,8 @@ void Level::ReadChunks(std::istream& file) {
|
||||
if (fileInfo.fileInfo.particleChunkStart != 0) {
|
||||
const auto header = ReadChunkHeader(file, fileInfo.fileInfo.particleChunkStart);
|
||||
m_ChunkHeaders.insert({ header.id, header });
|
||||
file.seekg(header.startPosition);
|
||||
ReadParticles(file);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -270,6 +272,8 @@ void Level::ReadChunks(std::istream& file) {
|
||||
ReadSkydomeInfo(file);
|
||||
ReadEditorSettings(file);
|
||||
ReadSceneObjectDataChunk(file);
|
||||
ReadSounds(file);
|
||||
ReadParticles(file);
|
||||
}
|
||||
|
||||
Level::Header Level::ReadChunkHeader(std::istream& file, uint32_t start) {
|
||||
@@ -419,3 +423,52 @@ void Level::ReadSceneObjectDataChunk(std::istream& file) {
|
||||
m_Objects.push_back(std::move(obj));
|
||||
}
|
||||
}
|
||||
|
||||
void Level::ReadSounds(std::istream& file) {
|
||||
// SceneLoader::LoadSounds (0x0103c110), only in files from before chunks
|
||||
if (m_Version < 5) return;
|
||||
uint32_t count = 0;
|
||||
BinaryIO::BinaryRead(file, count);
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
LevelSound sound;
|
||||
BinaryIO::BinaryRead(file, sound.position);
|
||||
if (m_Version < 35) {
|
||||
// A 260 character name, up to its first null
|
||||
std::u16string name(260, u'\0');
|
||||
file.read(reinterpret_cast<char*>(name.data()), static_cast<std::streamsize>(name.size() * sizeof(char16_t)));
|
||||
name.resize(std::min(name.find(u'\0'), name.size()));
|
||||
sound.config.Insert<std::u16string>(u"soundName", name);
|
||||
} else {
|
||||
for (const auto& token : GeneralUtils::SplitString(ReadWideString32(file), '\n')) sound.config.ParseInsert(token);
|
||||
}
|
||||
if (file.fail()) throw std::runtime_error("Failed to read from istream.");
|
||||
m_Sounds.push_back(std::move(sound));
|
||||
}
|
||||
}
|
||||
|
||||
void Level::ReadParticles(std::istream& file) {
|
||||
// SceneLoader::LoadParticles (0x01048320); before version 44 a file may end before them
|
||||
if (m_Version < 5) return;
|
||||
if (m_Version < 44 && file.peek() == std::char_traits<char>::eof()) {
|
||||
file.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t count = 0;
|
||||
BinaryIO::BinaryRead(file, count);
|
||||
std::string config;
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
LevelParticle particle;
|
||||
if (m_Version >= 43) BinaryIO::BinaryRead(file, particle.priority);
|
||||
BinaryIO::BinaryRead(file, particle.position);
|
||||
BinaryIO::BinaryRead(file, particle.rotation);
|
||||
particle.effectNames = ReadWideString32(file);
|
||||
if (m_Version < 46) BinaryIO::BinaryRead(file, particle.unknown);
|
||||
else config = ReadWideString32(file);
|
||||
particle.config = config;
|
||||
if (file.fail()) throw std::runtime_error("Failed to read from istream.");
|
||||
// The client stops at a particle with no effect
|
||||
if (particle.effectNames.empty()) break;
|
||||
m_Particles.push_back(std::move(particle));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,23 @@ struct LevelSkydome {
|
||||
std::array<std::string, 5> extraFilenames;
|
||||
};
|
||||
|
||||
// A sound placed in the scene (SceneLoader::LoadSounds, version 5 on). Only the level editor makes anything of them
|
||||
struct LevelSound {
|
||||
NiPoint3 position;
|
||||
LwoNameValue config; // before version 35 only a 260 character soundName
|
||||
};
|
||||
|
||||
// A particle effect placed in the scene (SceneLoader::LoadParticles, version 5 on)
|
||||
struct LevelParticle {
|
||||
int16_t priority{}; // version 43 on
|
||||
NiPoint3 position;
|
||||
NiQuaternion rotation = QuatUtils::IDENTITY;
|
||||
std::string effectNames; // separated by ';'
|
||||
uint16_t unknown{}; // before version 46
|
||||
// Version 46 on. The client keeps the last one it read for a particle without one
|
||||
std::string config;
|
||||
};
|
||||
|
||||
// A scene file (.lvl), read as the client reads it (SceneLoader::LoadLvlFile)
|
||||
class Level {
|
||||
public:
|
||||
@@ -108,6 +125,8 @@ public:
|
||||
const LevelSkydome& GetSkydome() const { return m_Skydome; }
|
||||
const std::vector<NiColor>& GetEditorColors() const { return m_EditorColors; }
|
||||
const std::vector<SceneObject>& GetObjects() const { return m_Objects; }
|
||||
const std::vector<LevelSound>& GetSounds() const { return m_Sounds; }
|
||||
const std::vector<LevelParticle>& GetParticles() const { return m_Particles; }
|
||||
|
||||
std::map<uint32_t, Header> m_ChunkHeaders;
|
||||
private:
|
||||
@@ -125,6 +144,8 @@ private:
|
||||
// Version 37 on: the editor's saved colours (the client keeps at most 32)
|
||||
std::vector<NiColor> m_EditorColors;
|
||||
std::vector<SceneObject> m_Objects;
|
||||
std::vector<LevelSound> m_Sounds;
|
||||
std::vector<LevelParticle> m_Particles;
|
||||
|
||||
//private functions:
|
||||
void ReadChunks(std::istream& file);
|
||||
@@ -134,5 +155,7 @@ private:
|
||||
void ReadSkydomeInfo(std::istream& file);
|
||||
void ReadEditorSettings(std::istream& file);
|
||||
void ReadSceneObjectDataChunk(std::istream& file);
|
||||
void ReadSounds(std::istream& file);
|
||||
void ReadParticles(std::istream& file);
|
||||
void LoadSceneObjects();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user