mirror of
https://codeberg.org/icewind/log-normalizer.git
synced 2026-06-03 13:54:11 +02:00
basic parsing
This commit is contained in:
parent
a03771e4b5
commit
0151dfce7d
10 changed files with 6974 additions and 2 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
|||
/target
|
||||
.env
|
||||
1468
Cargo.lock
generated
Normal file
1468
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
12
Cargo.toml
12
Cargo.toml
|
|
@ -4,6 +4,14 @@ version = "0.1.0"
|
|||
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
sqlx = { version = "0.3", default_features = false, features = ["macros", "postgres", "json", "runtime-tokio"] }
|
||||
dotenv = "0.15.0"
|
||||
main_error = "0.1.0"
|
||||
tokio = { version = "0.2.13", features = ["macros", "time"] }
|
||||
reqwest = { version = "0.10.4", features = [] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
steamid-ng = "0.3.4"
|
||||
test-case = "1.0.0"
|
||||
395
schema.sql
Normal file
395
schema.sql
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public;
|
||||
|
||||
CREATE TYPE team AS ENUM ('Blue', 'Red');
|
||||
|
||||
CREATE TYPE class_type AS ENUM ('scout', 'soldier', 'pyro', 'demoman', 'heavyweapons', 'engineer', 'medic', 'sniper', 'spy');
|
||||
|
||||
CREATE TYPE game_mode AS ENUM ('ultiduo', '4v4', '6v6', '7v7', '9v9', 'other');
|
||||
|
||||
CREATE TYPE event_type AS ENUM ('charge', 'pointcap', 'medic_death', 'round_win');
|
||||
|
||||
CREATE TYPE medigun AS ENUM ('medigun', 'kritzkrieg', 'quickfix', 'vacinator');
|
||||
|
||||
CREATE TYPE weapon_id AS ENUM (
|
||||
'sniperrifle',
|
||||
'taunt_sniper',
|
||||
'sydney_sleeper',
|
||||
'the_winger',
|
||||
'hot_hand',
|
||||
'deflect_rocket',
|
||||
'scout_sword',
|
||||
'voodoo_pin',
|
||||
'degreaser',
|
||||
'shortstop',
|
||||
'robot_arm',
|
||||
'tf_pumpkin_bomb',
|
||||
'kunai',
|
||||
'wrench',
|
||||
'necro_smasher',
|
||||
'headtaker',
|
||||
'proto_syringe',
|
||||
'eternal_reward',
|
||||
'eureka_effect',
|
||||
'dragons_fury_bonus',
|
||||
'grappling_hook',
|
||||
'pep_pistol',
|
||||
'guillotine',
|
||||
'lava_axe',
|
||||
'wrangler_kill',
|
||||
'panic_attack',
|
||||
'loose_cannon',
|
||||
'thirddegree',
|
||||
'taunt_pyro',
|
||||
'iron_bomber',
|
||||
'persian_persuader',
|
||||
'amputator',
|
||||
'tf_projectile_pipe',
|
||||
'awper_hand',
|
||||
'demokatana',
|
||||
'loose_cannon_reflect',
|
||||
'obj_minisentry',
|
||||
'back_scratcher',
|
||||
'pomson',
|
||||
'the_classic',
|
||||
'sandman',
|
||||
'axtinguisher',
|
||||
'obj_sentrygun2',
|
||||
'jar',
|
||||
'samrevolver',
|
||||
'deflect_flare',
|
||||
'loch_n_load',
|
||||
'tf_projectile_rocket',
|
||||
'annihilator',
|
||||
'rocketpack_stomp',
|
||||
'ullapool_caber_explosion',
|
||||
'minigun',
|
||||
'deflect_promode',
|
||||
'liberty_launcher',
|
||||
'nessieclub',
|
||||
'quickiebomb_launcher',
|
||||
'cow_mangler',
|
||||
'wrap_assassin',
|
||||
'blackbox',
|
||||
'candy_cane',
|
||||
'rocketlauncher_directhit',
|
||||
'ai_flamethrower',
|
||||
'soda_popper',
|
||||
'frontier_justice',
|
||||
'rescue_ranger_reflect',
|
||||
'warrior_spirit',
|
||||
'widowmaker',
|
||||
'quake_rl',
|
||||
'tf_projectile_arrow',
|
||||
'sledgehammer',
|
||||
'deflect_arrow',
|
||||
'market_gardener',
|
||||
'unique_pickaxe_escape',
|
||||
'pistol_scout',
|
||||
'boston_basher',
|
||||
'spellbook_bats',
|
||||
'holymackerel',
|
||||
'club',
|
||||
'ball',
|
||||
'fireaxe',
|
||||
'backburner',
|
||||
'eviction_notice',
|
||||
'holiday_punch',
|
||||
'taunt_soldier',
|
||||
'shotgun_primary',
|
||||
'nonnonviolent_protest',
|
||||
'force_a_nature',
|
||||
'paintrain',
|
||||
'freedom_staff',
|
||||
'shotgun_hwg',
|
||||
'long_heatmaker',
|
||||
'shotgun_soldier',
|
||||
'knife',
|
||||
'batsaber',
|
||||
'mailbox',
|
||||
'compound_bow',
|
||||
'ullapool_caber',
|
||||
'ambassador',
|
||||
'player_penetration',
|
||||
'powerjack',
|
||||
'crusaders_crossbow',
|
||||
'scotland_shard',
|
||||
'wrench_jag',
|
||||
'scattergun',
|
||||
'unknown',
|
||||
'shahanshah',
|
||||
'pistol',
|
||||
'spellbook_boss',
|
||||
'smg',
|
||||
'dragons_fury',
|
||||
'revolver',
|
||||
'player',
|
||||
'the_maul',
|
||||
'skullbat',
|
||||
'ham_shank',
|
||||
'solemn_vow',
|
||||
'iron_curtain',
|
||||
'bonesaw',
|
||||
'dumpster_device',
|
||||
'bushwacka',
|
||||
'builder',
|
||||
'bread_bite',
|
||||
'southern_hospitality',
|
||||
'tribalkukri',
|
||||
'the_capper',
|
||||
'fists',
|
||||
'disciplinary_action',
|
||||
'tf_projectile_flare',
|
||||
'bleed_kill',
|
||||
'black_rose',
|
||||
'letranger',
|
||||
'tomislav',
|
||||
'atomizer',
|
||||
'back_scatter',
|
||||
'pep_brawlerblaster',
|
||||
'tf_projectile_pipe_remote',
|
||||
'battleaxe',
|
||||
'deflect_flare_detonator',
|
||||
'taunt_medic',
|
||||
'telefrag',
|
||||
'stickybomb_defender',
|
||||
'splendid_screen',
|
||||
'claidheamohmor',
|
||||
'airstrike',
|
||||
'righteous_bison',
|
||||
'gloves_running_urgently',
|
||||
'sword',
|
||||
'mantreads',
|
||||
'deflect_sticky',
|
||||
'enforcer',
|
||||
'scorch_shot',
|
||||
'pro_rifle',
|
||||
'spy_cicle',
|
||||
'bat',
|
||||
'sharp_dresser',
|
||||
'spellbook_lightning',
|
||||
'tide_turner',
|
||||
'shotgun_pyro',
|
||||
'lava_bat',
|
||||
'taunt_heavy',
|
||||
'bottle',
|
||||
'unique_pickaxe',
|
||||
'phlogistinator',
|
||||
'crossing_guard',
|
||||
'giger_counter',
|
||||
'charged_smg',
|
||||
'syringegun_medic',
|
||||
'gloves',
|
||||
'bazaar_bargain',
|
||||
'spellbook_mirv',
|
||||
'big_earner',
|
||||
'battleneedle',
|
||||
'warfan',
|
||||
'obj_sentrygun',
|
||||
'manmelter',
|
||||
'family_business',
|
||||
'reserve_shooter',
|
||||
'short_circuit',
|
||||
'flaregun',
|
||||
'spellbook_fireball',
|
||||
'world',
|
||||
'jar_milk',
|
||||
'flamethrower',
|
||||
'shooting_star',
|
||||
'trigger_hurt',
|
||||
'blutsauger',
|
||||
'taunt_spy',
|
||||
'tf_projectile_energy_ball',
|
||||
'jar_gas',
|
||||
'tf_projectile_mechanicalarmorb',
|
||||
'obj_sentrygun3',
|
||||
'diamondback',
|
||||
'shovel',
|
||||
'brass_beast',
|
||||
'loose_cannon_impact',
|
||||
'demoshield',
|
||||
'prinny_machete',
|
||||
'machina',
|
||||
'rocketlauncher_fireball',
|
||||
'sticky_resistance',
|
||||
'detonator',
|
||||
'tf_projectile_sentryrocket',
|
||||
'unarmed_combat',
|
||||
'spellbook_skeleton',
|
||||
'ubersaw',
|
||||
'maxgun',
|
||||
'robot_arm_combo_kill',
|
||||
'rescue_ranger',
|
||||
'apocofists',
|
||||
'natascha',
|
||||
'pro_smg',
|
||||
'steel_fists',
|
||||
'fryingpan',
|
||||
);
|
||||
|
||||
CREATE TABLE logs (
|
||||
id INTEGER PRIMARY KEY,
|
||||
red_score INTEGER NOT NULL,
|
||||
blue_score INTEGER NOT NULL,
|
||||
length INTEGER NOT NULL,
|
||||
game_mode game_mode NOT NULL,
|
||||
map TEXT NOT NULL,
|
||||
date TIMESTAMP WITHOUT TIME ZONE NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX logs_map_idx
|
||||
ON logs USING BTREE (map);
|
||||
|
||||
CREATE INDEX logs_mode_idx
|
||||
ON logs USING BTREE (game_mode);
|
||||
|
||||
CREATE TABLE rounds (
|
||||
id SERIAL PRIMARY KEY,
|
||||
round INTEGER NOT NULL,
|
||||
log_id INTEGER NOT NULL REFERENCES logs(id),
|
||||
length INTEGER NOT NULL,
|
||||
winner team NOT NULL,
|
||||
first_cap team NOT NULL,
|
||||
red_score INTEGER NOT NULL,
|
||||
blue_score INTEGER NOT NULL,
|
||||
red_kills INTEGER NOT NULL,
|
||||
blue_kills INTEGER NOT NULL,
|
||||
red_dmg INTEGER NOT NULL,
|
||||
blue_dmg INTEGER NOT NULL,
|
||||
red_ubers INTEGER NOT NULL,
|
||||
blue_ubers INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX rounds_log_id_idx
|
||||
ON rounds USING BTREE (log_id);
|
||||
|
||||
CREATE UNIQUE INDEX rounds_round_log_id_idx
|
||||
ON rounds USING BTREE (round, log_id);
|
||||
|
||||
CREATE INDEX rounds_winner_idx
|
||||
ON rounds USING BTREE (winner);
|
||||
|
||||
CREATE INDEX rounds_first_cap_idx
|
||||
ON rounds USING BTREE (first_cap);
|
||||
|
||||
CREATE TABLE events_charge (
|
||||
id SERIAL PRIMARY KEY,
|
||||
round_id INTEGER NOT NULL REFERENCES rounds(id),
|
||||
time INTEGER NOT NULL,
|
||||
team team NOT NULL,
|
||||
steam_id BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX events_charge_round_id_idx
|
||||
ON events_charge USING BTREE (round_id);
|
||||
|
||||
CREATE INDEX events_charge_steam_id_idx
|
||||
ON events_charge USING BTREE (steam_id);
|
||||
|
||||
CREATE TABLE events_point_cap (
|
||||
id SERIAL PRIMARY KEY,
|
||||
round_id INTEGER NOT NULL REFERENCES rounds(id),
|
||||
time INTEGER NOT NULL,
|
||||
team team NOT NULL,
|
||||
point INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX events_point_cap_round_id_idx
|
||||
ON events_point_cap USING BTREE (round_id);
|
||||
|
||||
CREATE TABLE events_medic_death (
|
||||
id SERIAL PRIMARY KEY,
|
||||
round_id INTEGER NOT NULL REFERENCES rounds(id),
|
||||
time INTEGER NOT NULL,
|
||||
team team NOT NULL,
|
||||
steam_id BIGINT NOT NULL,
|
||||
killer BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX events_medic_death_round_id_idx
|
||||
ON events_medic_death USING BTREE (round_id);
|
||||
|
||||
CREATE TABLE events_round_win (
|
||||
id SERIAL PRIMARY KEY,
|
||||
round_id INTEGER NOT NULL REFERENCES rounds(id),
|
||||
time INTEGER NOT NULL,
|
||||
team team NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX events_round_win_round_id_idx
|
||||
ON events_round_win USING BTREE (round_id);
|
||||
|
||||
CREATE TABLE players (
|
||||
id SERIAL PRIMARY KEY,
|
||||
log_id INTEGER NOT NULL REFERENCES logs(id),
|
||||
steam_id BIGINT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
kills INTEGER NOT NULL,
|
||||
deaths INTEGER NOT NULL,
|
||||
assists INTEGER NOT NULL,
|
||||
suicides INTEGER NOT NULL,
|
||||
dmg INTEGER NOT NULL,
|
||||
damage_taken INTEGER NOT NULL,
|
||||
ubers INTEGER NOT NULL,
|
||||
medigun_ubers INTEGER NOT NULL,
|
||||
kritzkrieg_ubers INTEGER NOT NULL,
|
||||
quickfix_ubers INTEGER NOT NULL,
|
||||
vacinator_ubers INTEGER NOT NULL,
|
||||
drops INTEGER NOT NULL,
|
||||
medkits INTEGER NOT NULL,
|
||||
medkits_hp INTEGER NOT NULL,
|
||||
backstabs INTEGER NOT NULL,
|
||||
headshots INTEGER NOT NULL,
|
||||
heal INTEGER NOT NULL,
|
||||
heals_received INTEGER NOT NULL,
|
||||
scout_kills INTEGER NOT NULL,
|
||||
soldier_kills INTEGER NOT NULL,
|
||||
pyro_kills INTEGER NOT NULL,
|
||||
demoman_kills INTEGER NOT NULL,
|
||||
heavy_kills INTEGER NOT NULL,
|
||||
engineer_kills INTEGER NOT NULL,
|
||||
medic_kills INTEGER NOT NULL,
|
||||
sniper_kills INTEGER NOT NULL,
|
||||
spy_kills INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX players_log_id_idx
|
||||
ON players USING BTREE (log_id);
|
||||
|
||||
CREATE UNIQUE INDEX players_log_steam_id_idx
|
||||
ON players USING BTREE (log_id, steam_id);
|
||||
|
||||
CREATE INDEX players_steam_id_idx
|
||||
ON players USING BTREE (steam_id);
|
||||
|
||||
CREATE TABLE class_stats (
|
||||
id SERIAL PRIMARY KEY,
|
||||
player_id INTEGER NOT NULL REFERENCES players(id),
|
||||
type class_type NOT NULL,
|
||||
time INTEGER NOT NULL,
|
||||
kills INTEGER NOT NULL,
|
||||
deaths INTEGER NOT NULL,
|
||||
assists INTEGER NOT NULL,
|
||||
dmg INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX class_stats_player_id_idx
|
||||
ON class_stats USING BTREE (player_id);
|
||||
|
||||
CREATE UNIQUE INDEX class_stats_player_id_type_idx
|
||||
ON class_stats USING BTREE (player_id, type);
|
||||
|
||||
CREATE TABLE player_weapon_stats (
|
||||
id SERIAL PRIMARY KEY,
|
||||
class_stat_id INTEGER NOT NULL REFERENCES class_stats(id),
|
||||
weapon weapon_id NOT NULL,
|
||||
kills INTEGER NOT NULL,
|
||||
shots INTEGER NOT NULL,
|
||||
hits INTEGER NOT NULL,
|
||||
dmg INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX player_weapon_stats_class_stat_id_idx
|
||||
ON player_weapon_stats USING BTREE (class_stat_id);
|
||||
|
||||
CREATE UNIQUE INDEX player_weapon_stats_class_stat_id_weapon_idx
|
||||
ON player_weapon_stats USING BTREE (class_stat_id, weapon);
|
||||
272
src/data.rs
Normal file
272
src/data.rs
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, sqlx::Type, Deserialize)]
|
||||
pub enum Team {
|
||||
Blue,
|
||||
Red,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, sqlx::Type, Deserialize)]
|
||||
pub enum Class {
|
||||
Scout,
|
||||
Soldier,
|
||||
Pyro,
|
||||
Demoman,
|
||||
HeavyWeapons,
|
||||
Engineer,
|
||||
Medic,
|
||||
Sniper,
|
||||
Spy,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, sqlx::Type, Deserialize)]
|
||||
pub enum GameMode {
|
||||
UltiDuo,
|
||||
Fours,
|
||||
Sixes,
|
||||
Sevens,
|
||||
Highlander,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, sqlx::Type, Deserialize)]
|
||||
pub enum EventType {
|
||||
Charge,
|
||||
PointCap,
|
||||
MedicDeath,
|
||||
RoundWin,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, sqlx::Type, Deserialize, Hash, Eq, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum Medigun {
|
||||
Medigun,
|
||||
KritzKrieg,
|
||||
QuickFix,
|
||||
Vacinator
|
||||
}
|
||||
|
||||
impl Default for Medigun {
|
||||
fn default() -> Self {
|
||||
Medigun::Medigun
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, sqlx::Type, Deserialize, Hash, Eq, PartialEq)]
|
||||
// #[sqlx(rename_all = "snake_case")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Weapon {
|
||||
Sniperrifle,
|
||||
TauntSniper,
|
||||
SydneySleeper,
|
||||
TheWinger,
|
||||
HotHand,
|
||||
DeflectRocket,
|
||||
ScoutSword,
|
||||
VoodooPin,
|
||||
Degreaser,
|
||||
Shortstop,
|
||||
RobotArm,
|
||||
TfPumpkinBomb,
|
||||
Kunai,
|
||||
Wrench,
|
||||
NecroSmasher,
|
||||
Headtaker,
|
||||
ProtoSyringe,
|
||||
EternalReward,
|
||||
EurekaEffect,
|
||||
DragonsFuryBonus,
|
||||
GrapplingHook,
|
||||
PepPistol,
|
||||
Guillotine,
|
||||
LavaAxe,
|
||||
WranglerKill,
|
||||
PanicAttack,
|
||||
LooseCannon,
|
||||
Thirddegree,
|
||||
TauntPyro,
|
||||
IronBomber,
|
||||
PersianPersuader,
|
||||
Amputator,
|
||||
TfProjectilePipe,
|
||||
AwperHand,
|
||||
Demokatana,
|
||||
LooseCannonReflect,
|
||||
ObjMinisentry,
|
||||
BackScratcher,
|
||||
Pomson,
|
||||
TheClassic,
|
||||
Sandman,
|
||||
Axtinguisher,
|
||||
ObjSentrygun2,
|
||||
Jar,
|
||||
Samrevolver,
|
||||
DeflectFlare,
|
||||
LochNLoad,
|
||||
TfProjectileRocket,
|
||||
Annihilator,
|
||||
RocketpackStomp,
|
||||
UllapoolCaberExplosion,
|
||||
Minigun,
|
||||
DeflectPromode,
|
||||
LibertyLauncher,
|
||||
Nessieclub,
|
||||
QuickiebombLauncher,
|
||||
CowMangler,
|
||||
WrapAssassin,
|
||||
Blackbox,
|
||||
CandyCane,
|
||||
RocketlauncherDirecthit,
|
||||
AiFlamethrower,
|
||||
SodaPopper,
|
||||
FrontierJustice,
|
||||
RescueRangerReflect,
|
||||
WarriorSpirit,
|
||||
Widowmaker,
|
||||
QuakeRl,
|
||||
TfProjectileArrow,
|
||||
Sledgehammer,
|
||||
DeflectArrow,
|
||||
MarketGardener,
|
||||
UniquePickaxeEscape,
|
||||
PistolScout,
|
||||
BostonBasher,
|
||||
SpellbookBats,
|
||||
Holymackerel,
|
||||
Club,
|
||||
Ball,
|
||||
Fireaxe,
|
||||
Backburner,
|
||||
EvictionNotice,
|
||||
HolidayPunch,
|
||||
TauntSoldier,
|
||||
ShotgunPrimary,
|
||||
NonnonviolentProtest,
|
||||
ForceANature,
|
||||
Paintrain,
|
||||
FreedomStaff,
|
||||
ShotgunHwg,
|
||||
LongHeatmaker,
|
||||
ShotgunSoldier,
|
||||
Knife,
|
||||
Batsaber,
|
||||
Mailbox,
|
||||
CompoundBow,
|
||||
UllapoolCaber,
|
||||
Ambassador,
|
||||
PlayerPenetration,
|
||||
Powerjack,
|
||||
CrusadersCrossbow,
|
||||
ScotlandShard,
|
||||
WrenchJag,
|
||||
Scattergun,
|
||||
Unknown,
|
||||
Shahanshah,
|
||||
Pistol,
|
||||
SpellbookBoss,
|
||||
Smg,
|
||||
DragonsFury,
|
||||
Revolver,
|
||||
Player,
|
||||
TheMaul,
|
||||
Skullbat,
|
||||
HamShank,
|
||||
SolemnVow,
|
||||
IronCurtain,
|
||||
Bonesaw,
|
||||
DumpsterDevice,
|
||||
Bushwacka,
|
||||
Builder,
|
||||
BreadBite,
|
||||
SouthernHospitality,
|
||||
Tribalkukri,
|
||||
TheCapper,
|
||||
Fists,
|
||||
DisciplinaryAction,
|
||||
TfProjectileFlare,
|
||||
BleedKill,
|
||||
BlackRose,
|
||||
Letranger,
|
||||
Tomislav,
|
||||
Atomizer,
|
||||
BackScatter,
|
||||
PepBrawlerblaster,
|
||||
TfProjectilePipeRemote,
|
||||
Battleaxe,
|
||||
DeflectFlareDetonator,
|
||||
TauntMedic,
|
||||
Telefrag,
|
||||
StickybombDefender,
|
||||
SplendidScreen,
|
||||
Claidheamohmor,
|
||||
Airstrike,
|
||||
RighteousBison,
|
||||
GlovesRunningUrgently,
|
||||
Sword,
|
||||
Mantreads,
|
||||
DeflectSticky,
|
||||
Enforcer,
|
||||
ScorchShot,
|
||||
ProRifle,
|
||||
SpyCicle,
|
||||
Bat,
|
||||
SharpDresser,
|
||||
SpellbookLightning,
|
||||
TideTurner,
|
||||
ShotgunPyro,
|
||||
LavaBat,
|
||||
TauntHeavy,
|
||||
Bottle,
|
||||
UniquePickaxe,
|
||||
Phlogistinator,
|
||||
CrossingGuard,
|
||||
GigerCounter,
|
||||
ChargedSmg,
|
||||
SyringegunMedic,
|
||||
Gloves,
|
||||
BazaarBargain,
|
||||
SpellbookMirv,
|
||||
BigEarner,
|
||||
Battleneedle,
|
||||
Warfan,
|
||||
ObjSentrygun,
|
||||
Manmelter,
|
||||
FamilyBusiness,
|
||||
ReserveShooter,
|
||||
ShortCircuit,
|
||||
Flaregun,
|
||||
SpellbookFireball,
|
||||
World,
|
||||
JarMilk,
|
||||
Flamethrower,
|
||||
ShootingStar,
|
||||
TriggerHurt,
|
||||
Blutsauger,
|
||||
TauntSpy,
|
||||
TfProjectileEnergyBall,
|
||||
JarGas,
|
||||
TfProjectileMechanicalarmorb,
|
||||
ObjSentrygun3,
|
||||
Diamondback,
|
||||
Shovel,
|
||||
BrassBeast,
|
||||
LooseCannonImpact,
|
||||
Demoshield,
|
||||
PrinnyMachete,
|
||||
Machina,
|
||||
RocketlauncherFireball,
|
||||
StickyResistance,
|
||||
Detonator,
|
||||
TfProjectileSentryrocket,
|
||||
UnarmedCombat,
|
||||
SpellbookSkeleton,
|
||||
Ubersaw,
|
||||
Maxgun,
|
||||
RobotArmComboKill,
|
||||
RescueRanger,
|
||||
Apocofists,
|
||||
Natascha,
|
||||
ProSmg,
|
||||
SteelFists,
|
||||
Fryingpan,
|
||||
}
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
mod data;
|
||||
mod raw;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
|
|
|||
294
src/raw.rs
Normal file
294
src/raw.rs
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
use std::collections::HashMap;
|
||||
use steamid_ng::SteamID;
|
||||
use crate::data::{Medigun, Class, Weapon, Team as TeamId};
|
||||
use serde::Deserialize;
|
||||
use serde::export::TryFrom;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct RawLog {
|
||||
#[serde(default)]
|
||||
pub version: u8,
|
||||
#[serde(default)]
|
||||
pub length: u32,
|
||||
pub teams: Option<Teams>,
|
||||
pub players: HashMap<SteamID, Player>,
|
||||
pub names: HashMap<SteamID, String>,
|
||||
pub rounds: Option<Vec<Round>>,
|
||||
pub healspread: HashMap<SteamID, HashMap<SteamID, u32>>,
|
||||
pub classkills: HashMap<SteamID, ClassNumbers>,
|
||||
pub classdeaths: HashMap<SteamID, ClassNumbers>,
|
||||
pub classkillassists: Option<HashMap<SteamID, ClassNumbers>>,
|
||||
pub chat: Vec<ChatMessage>,
|
||||
pub info: Info,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Teams {
|
||||
pub red: Team,
|
||||
pub blue: Team,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Team {
|
||||
pub score: u32,
|
||||
pub kills: u32,
|
||||
#[serde(default)]
|
||||
pub deaths: u32,
|
||||
pub dmg: u32,
|
||||
#[serde(default)]
|
||||
pub charges: u32,
|
||||
#[serde(default)]
|
||||
pub drops: u32,
|
||||
#[serde(default)]
|
||||
pub firstcaps: u32,
|
||||
#[serde(default)]
|
||||
pub caps: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Player {
|
||||
pub team: TeamId,
|
||||
pub kills: u16,
|
||||
pub deaths: u16,
|
||||
pub assists: u16,
|
||||
#[serde(default)]
|
||||
pub suicides: u16,
|
||||
#[serde(default)]
|
||||
pub dmg: u32,
|
||||
#[serde(default)]
|
||||
pub dmg_real: u32,
|
||||
#[serde(default)]
|
||||
pub dt: u32,
|
||||
#[serde(default)]
|
||||
pub dt_real: u32,
|
||||
#[serde(default)]
|
||||
pub hr: u16,
|
||||
#[serde(default)]
|
||||
pub lks: u16,
|
||||
pub ubers: u8,
|
||||
#[serde(default)]
|
||||
pub ubertypes: HashMap<Medigun, u8>,
|
||||
pub drops: u8,
|
||||
pub medkits: u8,
|
||||
#[serde(default)]
|
||||
pub medkits_hp: u16,
|
||||
pub backstabs: u8,
|
||||
pub headshots: u8,
|
||||
#[serde(default)]
|
||||
pub headshots_hit: u8,
|
||||
pub heal: u32,
|
||||
pub cpc: u8,
|
||||
pub ic: u8,
|
||||
pub medicstat: Option<MedicStats>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct MedicStats {
|
||||
pub advantages_lost: u8,
|
||||
pub biggest_advantage_list: u16,
|
||||
pub deaths_within_20s_after_uber: u8,
|
||||
pub deaths_with_95_99_uber: u8,
|
||||
pub avg_time_before_healing: f32,
|
||||
pub avg_time_to_build: f32,
|
||||
pub avg_time_before_using: f32,
|
||||
pub avg_uber_length: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ClassStat {
|
||||
#[serde(rename = "type")]
|
||||
pub class: Class,
|
||||
pub kills: u16,
|
||||
pub dmg: u32,
|
||||
pub total_time: u32,
|
||||
pub weapon: HashMap<Weapon, WeaponStat>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct WeaponStat {
|
||||
pub kills: u32,
|
||||
pub dmg: u32,
|
||||
pub avg_dmg: u32,
|
||||
pub shots: u32,
|
||||
pub hits: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Round {
|
||||
#[serde(default)]
|
||||
pub start_time: u64,
|
||||
pub winner: TeamId,
|
||||
#[serde(rename = "firstcap")]
|
||||
pub first_cap: Option<TeamId>,
|
||||
pub length: u32,
|
||||
pub team: Option<Teams>,
|
||||
pub players: HashMap<SteamID, RoundPlayer>,
|
||||
pub events: Vec<Event>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct RoundPlayer {
|
||||
pub kills: u32,
|
||||
pub dmg: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Event {
|
||||
Charge {
|
||||
#[serde(default)]
|
||||
medigun: Medigun,
|
||||
time: u32,
|
||||
steamid: SteamID,
|
||||
team: TeamId,
|
||||
},
|
||||
#[serde(rename = "pointcap")]
|
||||
PointCap {
|
||||
time: u32,
|
||||
team: TeamId,
|
||||
point: u8,
|
||||
},
|
||||
MedicDeath {
|
||||
time: u32,
|
||||
team: TeamId,
|
||||
steamid: SteamID,
|
||||
killer: SteamID,
|
||||
},
|
||||
RoundWin {
|
||||
time: u32,
|
||||
team: TeamId,
|
||||
},
|
||||
Drop {
|
||||
time: u32,
|
||||
steamid: SteamID,
|
||||
team: TeamId,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ClassNumbers {
|
||||
#[serde(default)]
|
||||
pub scout: u8,
|
||||
#[serde(default)]
|
||||
pub soldier: u8,
|
||||
#[serde(default)]
|
||||
pub pyro: u8,
|
||||
#[serde(default)]
|
||||
pub demoman: u8,
|
||||
#[serde(default)]
|
||||
pub heavyweapons: u8,
|
||||
#[serde(default)]
|
||||
pub engineer: u8,
|
||||
#[serde(default)]
|
||||
pub medic: u8,
|
||||
#[serde(default)]
|
||||
pub sniper: u8,
|
||||
#[serde(default)]
|
||||
pub spy: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ChatMessage {
|
||||
pub steamid: ChatFrom,
|
||||
pub name: String,
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[serde(try_from = "String")]
|
||||
pub enum ChatFrom {
|
||||
Player(SteamID),
|
||||
Console,
|
||||
}
|
||||
|
||||
impl TryFrom<String> for ChatFrom {
|
||||
type Error = steamid_ng::SteamIDParseError;
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
if value == "Console" {
|
||||
Ok(ChatFrom::Console)
|
||||
} else {
|
||||
value.parse().map(ChatFrom::Player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Info {
|
||||
pub map: String,
|
||||
pub total_length: u32,
|
||||
#[serde(default)]
|
||||
pub supplemental: bool,
|
||||
#[serde(default)]
|
||||
pub has_real_damage: bool,
|
||||
#[serde(default)]
|
||||
pub has_weapon_damage: bool,
|
||||
#[serde(default)]
|
||||
pub has_accuracy: bool,
|
||||
#[serde(default)]
|
||||
pub has_hp: bool,
|
||||
#[serde(default)]
|
||||
pub has_hp_real: bool,
|
||||
#[serde(default)]
|
||||
pub has_hs: bool,
|
||||
#[serde(default)]
|
||||
pub has_hs_hit: bool,
|
||||
#[serde(default)]
|
||||
pub has_bs: bool,
|
||||
#[serde(default)]
|
||||
pub has_cp: bool,
|
||||
#[serde(default)]
|
||||
pub has_sb: bool,
|
||||
#[serde(default)]
|
||||
pub has_dt: bool,
|
||||
#[serde(default)]
|
||||
pub has_as: bool,
|
||||
#[serde(default)]
|
||||
pub has_hr: bool,
|
||||
#[serde(default)]
|
||||
pub has_intel: bool,
|
||||
pub title: String,
|
||||
pub date: u64,
|
||||
pub uploader: Uploader,
|
||||
pub rounds: Option<Vec<Round>>,
|
||||
#[serde(flatten)]
|
||||
pub teams: Option<InfoTeams>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct InfoTeams {
|
||||
pub red: InfoTeam,
|
||||
pub blue: InfoTeam,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct InfoTeam {
|
||||
pub score: u32
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Uploader {
|
||||
pub id: SteamID,
|
||||
pub name: String,
|
||||
pub info: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fs;
|
||||
use test_case::test_case;
|
||||
use super::*;
|
||||
|
||||
#[test_case("1.json")]
|
||||
#[test_case("550237.json")]
|
||||
fn test_parse(file: &str) {
|
||||
let content = fs::read_to_string(format!("tests/data/{}", file)).unwrap();
|
||||
let parsed: RawLog = serde_json::from_str(&content).unwrap();
|
||||
assert!(parsed.teams.is_some() || parsed.info.teams.is_some());
|
||||
assert!(parsed.rounds.is_some() || parsed.info.rounds.is_some());
|
||||
}
|
||||
}
|
||||
1989
tests/data/1.json
Normal file
1989
tests/data/1.json
Normal file
File diff suppressed because it is too large
Load diff
2542
tests/data/550237.json
Normal file
2542
tests/data/550237.json
Normal file
File diff suppressed because it is too large
Load diff
0
tests/raw.rs
Normal file
0
tests/raw.rs
Normal file
Loading…
Add table
Add a link
Reference in a new issue