New: initial functionality

This commit is contained in:
Pavel Perestoronin committed 2022-12-02 23:56:42 +01:00
1 parent 31b3c21b65
commit 3e5ad63679
19 files changed
+309 -1

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
[alias]
c = "check"
cc = "clippy"
u = "update"
o = "outdated"
r = "run"
+51
View File
@@ -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
+52
View File
@@ -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 }}
+8
View File
@@ -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
View File
@@ -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
View File
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
+4
View File
@@ -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>
+8
View File
@@ -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
View File
@@ -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>
+12
View File
@@ -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
View File
@@ -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"
+10
View File
@@ -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"
+19
View File
@@ -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),
}
+8
View File
@@ -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;
+31
View File
@@ -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,
}
+35
View File
@@ -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)
}
}
+3
View File
@@ -0,0 +1,3 @@
use crate::error::Error;
pub type Result<T = ()> = std::result::Result<T, Error>;
+26
View File
@@ -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(())
}