mirror of
https://github.com/redstrate/Physis.git
synced 2025-04-22 20:57:46 +00:00
173 lines
3.9 KiB
Rust
173 lines
3.9 KiB
Rust
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
use std::io::{Cursor, Seek, SeekFrom};
|
|
|
|
use crate::ByteSpan;
|
|
use binrw::binrw;
|
|
use binrw::BinRead;
|
|
|
|
#[binrw]
|
|
#[allow(dead_code)]
|
|
#[brw(little)]
|
|
struct ChatLogHeader {
|
|
content_size: u32,
|
|
file_size: u32,
|
|
|
|
#[br(count = file_size.saturating_sub(content_size))]
|
|
offset_entries: Vec<u32>,
|
|
}
|
|
|
|
#[binrw]
|
|
#[brw(repr = u8)]
|
|
#[derive(Debug)]
|
|
pub enum EventFilter {
|
|
SystemMessages = 3,
|
|
Unknown = 20,
|
|
ProgressionMessage = 64,
|
|
NPCBattle = 41,
|
|
Unknown2 = 57,
|
|
Unknown7 = 29,
|
|
Unknown3 = 59,
|
|
EnemyBattle = 170,
|
|
Unknown4 = 581,
|
|
Unknown8 = 43,
|
|
Unknown9 = 60,
|
|
Unknown10 = 61,
|
|
Unknown11 = 62,
|
|
Unknown12 = 58,
|
|
Unknown13 = 169,
|
|
Unknown14 = 175,
|
|
Unknown15 = 42,
|
|
Unknown16 = 171,
|
|
Unknown17 = 177,
|
|
Unknown18 = 174,
|
|
Unknown19 = 47,
|
|
Unknown20 = 176,
|
|
Unknown21 = 44,
|
|
Unknown22 = 173,
|
|
Unknown23 = 46,
|
|
Unknown24 = 10,
|
|
Unknown25 = 185,
|
|
Unknown26 = 190,
|
|
Unknown27 = 11,
|
|
Unknown28 = 70,
|
|
Unknown29 = 105,
|
|
}
|
|
|
|
#[binrw]
|
|
#[derive(Debug)]
|
|
#[brw(repr = u8)]
|
|
pub enum EventChannel {
|
|
System = 0,
|
|
Unknown8 = 2,
|
|
ServerAnnouncement = 3,
|
|
Unknown9 = 8,
|
|
Unknown1 = 50,
|
|
Unknown7 = 29,
|
|
Others = 32,
|
|
Unknown5 = 41,
|
|
NPCEnemy = 51,
|
|
NPCFriendly = 59,
|
|
Unknown4 = 64,
|
|
Unknown6 = 170,
|
|
Unknown10 = 10,
|
|
Unknown11 = 66,
|
|
Unknown12 = 44,
|
|
Unknown13 = 40,
|
|
Unknown14 = 42,
|
|
Unknown15 = 11,
|
|
Unknown16 = 67,
|
|
Unknown17 = 68,
|
|
Unknown18 = 34,
|
|
Unknown19 = 110,
|
|
}
|
|
|
|
#[binrw]
|
|
#[derive(Debug)]
|
|
#[allow(dead_code)]
|
|
#[brw(little)]
|
|
/// Represents an entry in the chat log
|
|
pub struct ChatLogEntry {
|
|
timestamp: u32,
|
|
/// The event filter
|
|
pub filter: EventFilter,
|
|
/// The event channel
|
|
pub channel: EventChannel,
|
|
|
|
#[br(temp)]
|
|
#[bw(calc = 1)]
|
|
_garbage: u32,
|
|
|
|
/// The message
|
|
#[brw(ignore)]
|
|
pub message: String,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
#[allow(dead_code)]
|
|
/// Chat log, which contains previously recorded messages from other players
|
|
pub struct ChatLog {
|
|
pub entries: Vec<ChatLogEntry>,
|
|
}
|
|
|
|
impl ChatLog {
|
|
/// Reads an existing LOG file
|
|
pub fn from_existing(buffer: ByteSpan) -> Option<ChatLog> {
|
|
let mut cursor = Cursor::new(buffer);
|
|
|
|
let header = ChatLogHeader::read(&mut cursor).expect("Cannot parse header.");
|
|
// Dumb check for obviously wrong values
|
|
if header.content_size as usize > buffer.len() || header.file_size as usize > buffer.len() {
|
|
return None;
|
|
}
|
|
|
|
let content_offset = (8 + header.file_size * 4) as u64;
|
|
|
|
// beginning of content offset
|
|
//cursor.seek(SeekFrom::Start(content_offset)).ok()?;
|
|
|
|
let mut entries = vec![];
|
|
|
|
for (i, offset) in header.offset_entries.iter().enumerate() {
|
|
let new_last_offset = content_offset + *offset as u64;
|
|
|
|
cursor.seek(SeekFrom::Start(new_last_offset)).ok()?;
|
|
|
|
let mut entry = ChatLogEntry::read(&mut cursor).expect("Unable to parse log message.");
|
|
|
|
let next_offset = if i + 1 == header.offset_entries.len() {
|
|
buffer.len()
|
|
} else {
|
|
(content_offset + header.offset_entries[i + 1] as u64) as usize
|
|
};
|
|
|
|
// TODO: handle the coloring properly, in some way
|
|
entry.message =
|
|
String::from_utf8_lossy(&buffer[cursor.position() as usize..next_offset])
|
|
.to_string();
|
|
|
|
entries.push(entry);
|
|
}
|
|
|
|
Some(ChatLog { entries })
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::fs::read;
|
|
use std::path::PathBuf;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_invalid() {
|
|
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
d.push("resources/tests");
|
|
d.push("random");
|
|
|
|
// Feeding it invalid data should not panic
|
|
ChatLog::from_existing(&read(d).unwrap());
|
|
}
|
|
}
|