mirror of
https://github.com/eigenein/wotbreplay-parser.git
synced 2026-10-21 02:17:02 +02:00
New: initial functionality
This commit is contained in:
1 parent
31b3c21b65
commit
3e5ad63679
19 files changed
+309
-1
No files matched your search
@@ -0,0 +1,6 @@
|
|||||||
|
[alias]
|
||||||
|
c = "check"
|
||||||
|
cc = "clippy"
|
||||||
|
u = "update"
|
||||||
|
o = "outdated"
|
||||||
|
r = "run"
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
name: Check
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
checks: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
name: Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up the toolchain
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: stable
|
||||||
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Rust Cache
|
||||||
|
uses: Swatinem/rust-cache@v1
|
||||||
|
with:
|
||||||
|
cache-on-failure: true
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: --doc
|
||||||
|
|
||||||
|
- name: Clippy
|
||||||
|
uses: actions-rs/clippy-check@v1
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
args: --all-targets --all-features --tests -- -D warnings
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
ame: Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: ["published"]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout the repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set the versions
|
||||||
|
run: |
|
||||||
|
sed -i -e 's/version = "0\.0\.0"/version = "${{ github.ref_name }}"/g' Cargo.toml
|
||||||
|
- name: Rustup
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: stable
|
||||||
|
|
||||||
|
- name: Build the changelog
|
||||||
|
id: changelog
|
||||||
|
uses: Bullrich/generate-release-changelog@master
|
||||||
|
env:
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
|
|
||||||
|
- name: Update the release
|
||||||
|
uses: tubone24/[email protected]
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
release_name: ${{ github.ref_name }}
|
||||||
|
body: ${{ steps.changelog.outputs.changelog }}
|
||||||
|
prerelease: false
|
||||||
|
|
||||||
|
- name: Publish the crates
|
||||||
|
run: |
|
||||||
|
cargo login
|
||||||
|
cargo publish --allow-dirty
|
||||||
|
env:
|
||||||
|
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ourVersions">
|
||||||
|
<value>
|
||||||
|
<list size="3">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="3.9" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="3.10" />
|
||||||
|
<item index="2" class="java.lang.String" itemvalue="3.11" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
Generated
+4
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/wotbreplay-parser.iml" filepath="$PROJECT_DIR$/.idea/wotbreplay-parser.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+12
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
+8
-1
@@ -14,4 +14,11 @@ categories = []
|
|||||||
default = []
|
default = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror = "1.0.31"
|
prost = "0.11.3"
|
||||||
|
serde_bytes = "0.11.7"
|
||||||
|
serde-pickle = "1.1.1"
|
||||||
|
thiserror = "1.0.37"
|
||||||
|
zip = { version = "0.6.3", default-features = false, features = ["deflate"] }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
anyhow = "1.0.66"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
edition = "2021"
|
||||||
|
fn_call_width = 80
|
||||||
|
format_code_in_doc_comments = true
|
||||||
|
format_macro_matchers = true
|
||||||
|
group_imports = "StdExternalCrate"
|
||||||
|
imports_granularity = "Module"
|
||||||
|
reorder_impl_items = true
|
||||||
|
unstable_features = true
|
||||||
|
use_field_init_shorthand = true
|
||||||
|
version = "Two"
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("failed to open the ZIP-archive")]
|
||||||
|
OpenArchiveFailed(#[source] zip::result::ZipError),
|
||||||
|
|
||||||
|
#[error("failed to open the battle results entry in the replay archive")]
|
||||||
|
OpenBattleResultsFailed(#[source] zip::result::ZipError),
|
||||||
|
|
||||||
|
#[error("failed to read the archive entry")]
|
||||||
|
ReadEntryFailed(#[source] std::io::Error),
|
||||||
|
|
||||||
|
#[error("failed to decode")]
|
||||||
|
DecodeFailed(#[source] prost::DecodeError),
|
||||||
|
|
||||||
|
#[error("failed to un-pickle")]
|
||||||
|
UnpickleFailed(#[source] serde_pickle::Error),
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
mod error;
|
||||||
|
pub mod models;
|
||||||
|
mod replay;
|
||||||
|
mod result;
|
||||||
|
|
||||||
|
pub use crate::error::Error;
|
||||||
|
pub use crate::replay::Replay;
|
||||||
|
pub use crate::result::Result;
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
use ::prost::Message;
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
pub struct BattleResults {
|
||||||
|
#[prost(int64, tag = "2")]
|
||||||
|
pub timestamp: i64,
|
||||||
|
|
||||||
|
#[prost(message, repeated, tag = "201")]
|
||||||
|
pub players: Vec<Player>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
pub struct Player {
|
||||||
|
#[prost(uint32, tag = "1")]
|
||||||
|
pub account_id: u32,
|
||||||
|
|
||||||
|
#[prost(message, required, tag = "2")]
|
||||||
|
pub info: PlayerInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
pub struct PlayerInfo {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub nickname: String,
|
||||||
|
|
||||||
|
#[prost(uint32, optional, tag = "2")]
|
||||||
|
pub platoon_id: Option<u32>,
|
||||||
|
|
||||||
|
#[prost(uint32, tag = "3")]
|
||||||
|
pub team_number: u32,
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
|
use prost::Message;
|
||||||
|
use serde_bytes::ByteBuf;
|
||||||
|
use zip::ZipArchive;
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::models::BattleResults;
|
||||||
|
use crate::result::Result;
|
||||||
|
|
||||||
|
pub struct Replay<R>(pub(crate) ZipArchive<R>);
|
||||||
|
|
||||||
|
impl<R: Read + Seek> Replay<R> {
|
||||||
|
/// Opens a replay from the reader.
|
||||||
|
pub fn open(reader: R) -> Result<Self> {
|
||||||
|
ZipArchive::new(reader)
|
||||||
|
.map_err(Error::OpenArchiveFailed)
|
||||||
|
.map(Self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_battle_results(&mut self) -> Result<BattleResults> {
|
||||||
|
let mut pickled_battle_results = self
|
||||||
|
.0
|
||||||
|
.by_name("battle_results.dat")
|
||||||
|
.map_err(Error::OpenBattleResultsFailed)?;
|
||||||
|
let mut serialized_battle_results = Vec::new();
|
||||||
|
pickled_battle_results
|
||||||
|
.read_to_end(&mut serialized_battle_results)
|
||||||
|
.map_err(Error::ReadEntryFailed)?;
|
||||||
|
let (_, battle_results): (u64, ByteBuf) =
|
||||||
|
serde_pickle::from_slice(&serialized_battle_results, Default::default())
|
||||||
|
.map_err(Error::UnpickleFailed)?;
|
||||||
|
BattleResults::decode(battle_results.as_ref()).map_err(Error::DecodeFailed)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
use crate::error::Error;
|
||||||
|
|
||||||
|
pub type Result<T = ()> = std::result::Result<T, Error>;
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use wotbreplay_parser::Replay;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn battle_results_ok() -> Result<()> {
|
||||||
|
let mut replay = Replay::open(File::open(
|
||||||
|
"tests/replays/20221202_2259__zeekrab_It20_Car_Comb_45t_2308705958773814583.wotbreplay",
|
||||||
|
)?)?;
|
||||||
|
let battle_results = replay.read_battle_results()?;
|
||||||
|
|
||||||
|
assert_eq!(battle_results.timestamp, 1670018359);
|
||||||
|
assert_eq!(battle_results.players.len(), 14);
|
||||||
|
|
||||||
|
assert_eq!(battle_results.players[0].account_id, 520886428);
|
||||||
|
assert_eq!(battle_results.players[0].info.nickname, "77mmmr");
|
||||||
|
assert_eq!(battle_results.players[0].info.team_number, 2);
|
||||||
|
assert_eq!(battle_results.players[0].info.platoon_id, None);
|
||||||
|
|
||||||
|
assert_eq!(battle_results.players[1].info.nickname, "SNAK_THE_RIPPER");
|
||||||
|
assert_eq!(battle_results.players[1].info.team_number, 1);
|
||||||
|
assert_eq!(battle_results.players[1].info.platoon_id, Some(547466834));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Binary file not shown.
Reference in new issue
Block a user