initial push of Loot Processing Tool
This commit is contained in:
commit
8e3af6a893
400
.gitignore
vendored
Normal file
400
.gitignore
vendored
Normal file
@ -0,0 +1,400 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# rider
|
||||
.idea/
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||
*.vbp
|
||||
|
||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||
*.dsw
|
||||
*.dsp
|
||||
|
||||
# Visual Studio 6 technical files
|
||||
*.ncb
|
||||
*.aps
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# Visual Studio History (VSHistory) files
|
||||
.vshistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
*.sln.iml
|
48
Config/config.json
Normal file
48
Config/config.json
Normal file
@ -0,0 +1,48 @@
|
||||
{
|
||||
"serverLocation": "D:\\Spt Stuff\\server",
|
||||
"threads": 20,
|
||||
"threadPoolingTimeoutMs": 1000,
|
||||
"jsonSerializer": "DotNet",
|
||||
"manualGarbageCollectionCalls": false,
|
||||
"dataStorageConfig": {
|
||||
"dataStorageType": "Memory",
|
||||
"fileDataStorageTempLocation": "D:\\Spt Stuff\\Lootgenerator\\Dumps\\cache"
|
||||
},
|
||||
"loggerConfig": {
|
||||
"logLevel": "Info",
|
||||
"queueLoggerPoolingTimeoutMs": 500
|
||||
},
|
||||
"readerConfig": {
|
||||
"preProcessorConfig": {
|
||||
"preProcessors": [
|
||||
"SevenZip"
|
||||
],
|
||||
"preProcessorTempFolder": "D:\\Spt Stuff\\Lootgenerator\\TEMP",
|
||||
"cleanupTempFolderAfterProcess": true
|
||||
},
|
||||
"intakeReaderConfig": {
|
||||
"readerType": "Json",
|
||||
"ignoredDumpLocations": [
|
||||
"Hideout"
|
||||
]
|
||||
},
|
||||
"dumpFilesLocation": [
|
||||
"D:\\Spt Stuff\\Lootgenerator\\dumps\\input"
|
||||
],
|
||||
"thresholdDate": "2023-01-08",
|
||||
"acceptedFileExtensions": [
|
||||
"json",
|
||||
"7z"
|
||||
],
|
||||
"processSubFolders": true,
|
||||
"fileFilters": [
|
||||
"JsonDump"
|
||||
]
|
||||
},
|
||||
"processorConfig": {
|
||||
"spawnPointToleranceForForced": 99.5
|
||||
},
|
||||
"writerConfig": {
|
||||
"outputLocation": "D:\\Spt Stuff\\Lootgenerator\\dumps\\output"
|
||||
}
|
||||
}
|
97
Config/forced_loose.yaml
Normal file
97
Config/forced_loose.yaml
Normal file
@ -0,0 +1,97 @@
|
||||
---
|
||||
Customs:
|
||||
- 5938188786f77474f723e87f # Case 0031
|
||||
- 5c12301c86f77419522ba7e4 # Flash drive with fake info
|
||||
- 593965cf86f774087a77e1b6 # Case 0048
|
||||
- 591092ef86f7747bb8703422 # Secure folder 0022 in big red offices
|
||||
- 590c62a386f77412b0130255 # Sliderkey Secure Flash drive in Dorms 2-way room 220
|
||||
- 5939e9b286f77462a709572c # Sealed letter (Terragroup)
|
||||
- 5ac620eb86f7743a8e6e0da0 # Package of graphics cards in big red offices
|
||||
- 590dde5786f77405e71908b2 # Bank case
|
||||
- 5910922b86f7747d96753483 # Carbon case
|
||||
- 5937fd0086f7742bf33fc198 # Bronze pocket watch on a chain
|
||||
- 5939a00786f7742fe8132936 # Golden Zibbo lighter
|
||||
- 5939e5a786f77461f11c0098 # Secure Folder 0013
|
||||
#- 64bd1abff3a668f08805ce4f # Secure Flash drive V4 REMOVED BY BSG
|
||||
|
||||
Woods:
|
||||
- 5938878586f7741b797c562f # Case 0052
|
||||
- 5d3ec50586f774183a607442 # Jaeger's message Underneath the wooden lookout post.
|
||||
- 5af04e0a86f7743a532b79e2 # Single-axis Fiber Optic Gyroscope: item_barter_electr_gyroscope
|
||||
- 5a687e7886f7740c4a5133fb # Blood sample
|
||||
- 5af04c0b86f774138708f78e # Motor Controller: item_barter_electr_controller
|
||||
#- 64bde2248f3a947a990aa4a5 # Sliderkey Secure Flash drive #1 REMOVED BY BSG
|
||||
#- 64bde265807321a9b905f076 # Sliderkey Secure Flash drive #2 REMOVED BY BSG
|
||||
|
||||
Shoreline:
|
||||
- 5a294d7c86f7740651337cf9 # Drone 1 SAS disk
|
||||
- 5a294d8486f774068638cd93 # Drone 2 SAS disk: ambiguous with itemTpl 5a294f1686f774340c7b7e4a
|
||||
- 5efdafc1e70b5e33f86de058 # Sanitar's Surgery kit marked with a blue symbol
|
||||
- 5939e5a786f77461f11c0098 # Secure folder 0013
|
||||
- 5a6860d886f77411cd3a9e47 # Secure folder 0060
|
||||
- 5a29357286f77409c705e025 # Sliderkey Flash drive
|
||||
- 5efdaf6de6a30218ed211a48 # Sanitar's Ophthalmoscope In potted plant on dining room table.
|
||||
- 5d357d6b86f7745b606e3508 # Photo album in west wing room 303
|
||||
- 5b4c72b386f7745b453af9c0 # Motor Controller: item_barter_electr_controller2
|
||||
- 5a0448bc86f774736f14efa8 # Key to the closed premises of the Health Resort
|
||||
- 5a29276886f77435ed1b117c # Working hard drive
|
||||
- 5b4c72fb86f7745cef1cffc5 # Single-axis Fiber Optic Gyroscope: item_barter_electr_gyroscope2
|
||||
- 5b4c72c686f77462ac37e907 # Motor Controller: item_barter_electr_controller3
|
||||
- 5b43237186f7742f3a4ab252 # Chemical container: item_quest_chem_container
|
||||
- 5a29284f86f77463ef3db363 # Toughbook reinforced laptop
|
||||
|
||||
Interchange:
|
||||
- 5ae9a18586f7746e381e16a3 # OLI cargo manifests
|
||||
- 5ae9a0dd86f7742e5f454a05 # Goshan cargo manifests
|
||||
- 5ae9a1b886f77404c8537c62 # Idea cargo manifests
|
||||
- 5ae9a25386f7746dd946e6d9 # OLI cargo route documents (locked)
|
||||
- 5ae9a3f586f7740aab00e4e6 # Clothes design handbook - Part 1
|
||||
- 5ae9a4fc86f7746e381e1753 # Clothes design handbook - Part 2
|
||||
- 5b4c81a086f77417d26be63f # Chemical container item_quest_chem_container2
|
||||
- 5b4c81bd86f77418a75ae159 # Chemical container item_quest_chem_container3
|
||||
|
||||
Factory:
|
||||
- 591093bb86f7747caa7bb2ee # On the neck of the dead scav in the bunker (Postman Pat Part 2)
|
||||
- 593a87af86f774122f54a951 # Syringe with a chemical
|
||||
|
||||
Lighthouse:
|
||||
- 61904c9df62c89219a56e034 # The message is tucked under the bottom of the door to the cabin.
|
||||
- 619268ad78f4fa33f173dbe5 # Water pump operation data On the desk between other documents in the upper office.
|
||||
- 619268de2be33f2604340159 # Pumping Station Operation Data In the upper floor office on the shelf.
|
||||
- 61a00bcb177fb945751bbe6a # Stolen military documents On the back corner of the dining room table on the third floor at Chalet.
|
||||
- 619252352be33f26043400a7 # Laptop with information
|
||||
- 628393620d8524273e7eb028 # Working hard drive
|
||||
- 6331bb0d1aa9f42b804997a6 # V3 Flash Drive
|
||||
- 6398a0861c712b1e1d4dadf1 # Forged Lightkeeper intelligence (Snatch)
|
||||
- 6399f54b0a36db13c823ad21 # Radio transmitter body (Key to the Tower)
|
||||
# - 64b91627dd13d43b9d01d6d1 # Toughbook reinforced laptop (Event quest) REMOVED BY BSG
|
||||
|
||||
ReserveBase:
|
||||
- 60915994c49cf53e4772cc38 # Military documents 1 on the table inside bunker control room (Documents)
|
||||
- 60a3b6359c427533db36cf84 # Military documents 2 On the bottom shelf of the cupboard near the corner.
|
||||
- 60a3b65c27adf161da7b6e14 # Military documents 3 Inside the cupboard next to the 4x4 Weapon Box.
|
||||
- 608c22a003292f4ba43f8a1a # Medical record 1 (locked by RB-KSM key) (Disease history)
|
||||
- 60a3b5b05f84d429b732e934 # Medical record 2 (locked by RB-SMP key) Disease history)
|
||||
- 609267a2bb3f46069c3e6c7d # T-90M Commander Control Panel
|
||||
- 60c080eb991ac167ad1c3ad4 # MBT Integrated Navigation System
|
||||
- 6398a072e301557ae24cec92 # Original Lightkeeper Intelligence (Snatch)
|
||||
|
||||
Laboratory:
|
||||
- 5eff135be0d3331e9d282b7b # Flash drive marked with blue tape (TerraGroup employee)
|
||||
- 6398a4cfb5992f573c6562b3 # Secured tape
|
||||
#- 64bdcfed8f3a947a990aa49a # Hermetic container for storing various chemicals #1 REMOVED BY BSG
|
||||
#- 64bdd008b0bf3baa6702f35f # Hermetic container for storing various chemicals #2 REMOVED BY BSG
|
||||
#- 64bdd014f3a668f08805ce64 # Hermetic container for storing various chemicals #3 REMOVED BY BSG
|
||||
|
||||
Streets of Tarkov:
|
||||
- 63a943cead5cc12f22161ff7 # Accountant's notes (Audit)
|
||||
- 638cbc68a63f1b49be6a3010 # Registered letter (Youve Got Mail)
|
||||
- 638df4cc7b560b03794a18d2 # AG guitar pick (Audiophile)
|
||||
- 638e0057ab150a5f56238960 # Housing office journal (Population Census)
|
||||
- 63927b29c115f907b14700b9 # Chemical container with samples (Urban Medicine)
|
||||
- 638dfc803083a019d447768e # Working hard drive (Surveillance)
|
||||
- 638e9d5536b3b72c944e2fc7 # Flash drive with recordings (Watching You)
|
||||
- 6393262086e646067c176aa2 # Medical observation record (?)
|
||||
- 63989ced706b793c7d60cfef # Informant's journal (Missing Informant)
|
||||
- 638cbb3ba63f1b49be6a300e # Secure Flash drive (Your Car Needs a Service)
|
||||
- 63a39e1d234195315d4020bd # Primorsky 46-48 skybridge key
|
16
Config/forced_static.yaml
Normal file
16
Config/forced_static.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
static_weapon_ids:
|
||||
# ids for static weapons
|
||||
- 5d52cc5ba4b9367408500062
|
||||
- 5cdeb229d7f00c000e7ce174
|
||||
|
||||
forced_items:
|
||||
Customs:
|
||||
# unknown key
|
||||
- containerId: custom_multiScene_00058
|
||||
itemTpl: 593962ca86f774068014d9af
|
||||
|
||||
Streets of Tarkov:
|
||||
# Backup hideout key
|
||||
- containerId: container_City_SE_02_Primorskiy_51_indoor_00001
|
||||
itemTpl: 6398fd8ad3de3849057f5128
|
29
Config/map_directory_mapping.yaml
Normal file
29
Config/map_directory_mapping.yaml
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
Customs:
|
||||
name:
|
||||
- bigmap
|
||||
Factory:
|
||||
name:
|
||||
- factory4_day
|
||||
- factory4_night
|
||||
Interchange:
|
||||
name:
|
||||
- interchange
|
||||
Laboratory:
|
||||
name:
|
||||
- laboratory
|
||||
Lighthouse:
|
||||
name:
|
||||
- lighthouse
|
||||
ReserveBase:
|
||||
name:
|
||||
- rezervbase
|
||||
Shoreline:
|
||||
name:
|
||||
- shoreline
|
||||
Woods:
|
||||
name:
|
||||
- woods
|
||||
Streets of Tarkov:
|
||||
name:
|
||||
- tarkovstreets
|
12
GCHandler.cs
Normal file
12
GCHandler.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace LootDumpProcessor;
|
||||
|
||||
public class GCHandler
|
||||
{
|
||||
public static void Collect()
|
||||
{
|
||||
if (LootDumpProcessorContext.GetConfig().ManualGarbageCollectionCalls)
|
||||
{
|
||||
GC.Collect();
|
||||
}
|
||||
}
|
||||
}
|
8
Logger/ILogger.cs
Normal file
8
Logger/ILogger.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace LootDumpProcessor.Logger;
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
void Setup();
|
||||
void Log(string message, LogLevel level);
|
||||
void Stop();
|
||||
}
|
9
Logger/LogLevel.cs
Normal file
9
Logger/LogLevel.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace LootDumpProcessor.Logger;
|
||||
|
||||
public enum LogLevel
|
||||
{
|
||||
Error,
|
||||
Warning,
|
||||
Info,
|
||||
Debug
|
||||
}
|
14
Logger/LoggerFactory.cs
Normal file
14
Logger/LoggerFactory.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace LootDumpProcessor.Logger;
|
||||
|
||||
public static class LoggerFactory
|
||||
{
|
||||
private static ILogger? _logger;
|
||||
|
||||
public static ILogger GetInstance()
|
||||
{
|
||||
if (_logger == null)
|
||||
_logger = new QueueLogger();
|
||||
// TODO: implement factory
|
||||
return _logger;
|
||||
}
|
||||
}
|
109
Logger/QueueLogger.cs
Normal file
109
Logger/QueueLogger.cs
Normal file
@ -0,0 +1,109 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace LootDumpProcessor.Logger;
|
||||
|
||||
public class QueueLogger : ILogger
|
||||
{
|
||||
private BlockingCollection<LoggedMessage> queuedMessages = new BlockingCollection<LoggedMessage>();
|
||||
private Task? loggerThread;
|
||||
private bool isRunning;
|
||||
private int logLevel;
|
||||
private static readonly int _logTerminationTimeoutMs = 1000;
|
||||
private static readonly int _logTerminationRetryCount = 3;
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
SetLogLevel();
|
||||
isRunning = true;
|
||||
loggerThread = Task.Factory.StartNew(() =>
|
||||
{
|
||||
while (isRunning)
|
||||
{
|
||||
while (queuedMessages.TryTake(out var value))
|
||||
{
|
||||
Console.ResetColor();
|
||||
switch (value.LogLevel)
|
||||
{
|
||||
case LogLevel.Error:
|
||||
Console.BackgroundColor = ConsoleColor.Red;
|
||||
Console.ForegroundColor = ConsoleColor.Black;
|
||||
break;
|
||||
case LogLevel.Warning:
|
||||
Console.BackgroundColor = ConsoleColor.Yellow;
|
||||
Console.ForegroundColor = ConsoleColor.Black;
|
||||
break;
|
||||
case LogLevel.Debug:
|
||||
Console.ForegroundColor = ConsoleColor.DarkCyan;
|
||||
break;
|
||||
case LogLevel.Info:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Console.WriteLine(value.Message);
|
||||
}
|
||||
|
||||
Thread.Sleep(
|
||||
TimeSpan.FromMilliseconds(LootDumpProcessorContext.GetConfig().LoggerConfig.QueueLoggerPoolingTimeoutMs));
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
private void SetLogLevel()
|
||||
{
|
||||
logLevel = GetLogLevel(LootDumpProcessorContext.GetConfig().LoggerConfig.LogLevel);
|
||||
}
|
||||
|
||||
private int GetLogLevel(LogLevel level)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case LogLevel.Error:
|
||||
return 1;
|
||||
case LogLevel.Warning:
|
||||
return 2;
|
||||
case LogLevel.Info:
|
||||
return 3;
|
||||
case LogLevel.Debug:
|
||||
return 4;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public void Log(string message, LogLevel level)
|
||||
{
|
||||
if (GetLogLevel(level) <= logLevel)
|
||||
queuedMessages.Add(new LoggedMessage { Message = message, LogLevel = level });
|
||||
}
|
||||
|
||||
// Wait for graceful termination of the logging thread
|
||||
public void Stop()
|
||||
{
|
||||
isRunning = false;
|
||||
if (loggerThread != null)
|
||||
{
|
||||
Console.ResetColor();
|
||||
int retryCount = 0;
|
||||
while (!loggerThread.IsCompleted)
|
||||
{
|
||||
if (retryCount == _logTerminationRetryCount)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"Logger thread did not terminate by itself after {retryCount} retries. Some log messages may be lost.");
|
||||
break;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Waiting {_logTerminationTimeoutMs}ms for logger termination");
|
||||
Thread.Sleep(_logTerminationTimeoutMs);
|
||||
retryCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LoggedMessage
|
||||
{
|
||||
public string Message { get; init; }
|
||||
public LogLevel LogLevel { get; init; }
|
||||
}
|
||||
}
|
36
LootDumpProcessor.csproj
Normal file
36
LootDumpProcessor.csproj
Normal file
@ -0,0 +1,36 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="7z.Libs" Version="21.7.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="NumSharp" Version="0.30.0" />
|
||||
<PackageReference Include="SevenZipSharp.Interop" Version="19.0.2" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" />
|
||||
<PackageReference Include="YamlDotNet" Version="13.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Config\forced_loose.yaml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Config\forced_static.yaml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Config\map_directory_mapping.yaml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Config\config.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
25
LootDumpProcessor.sln
Normal file
25
LootDumpProcessor.sln
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33213.308
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LootDumpProcessor", "LootDumpProcessor.csproj", "{887819E1-72BF-4F10-9246-77D8088AC7D2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{887819E1-72BF-4F10-9246-77D8088AC7D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{887819E1-72BF-4F10-9246-77D8088AC7D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{887819E1-72BF-4F10-9246-77D8088AC7D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{887819E1-72BF-4F10-9246-77D8088AC7D2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {39C0A9FF-B0F5-4C3F-AAA7-F9E9225AE70F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
127
LootDumpProcessorContext.cs
Normal file
127
LootDumpProcessorContext.cs
Normal file
@ -0,0 +1,127 @@
|
||||
using LootDumpProcessor.Model.Config;
|
||||
using LootDumpProcessor.Model.Output.StaticContainer;
|
||||
using LootDumpProcessor.Process;
|
||||
using LootDumpProcessor.Serializers.Json;
|
||||
using LootDumpProcessor.Serializers.Yaml;
|
||||
|
||||
namespace LootDumpProcessor;
|
||||
|
||||
public class LootDumpProcessorContext
|
||||
{
|
||||
private static Config? _config;
|
||||
private static readonly object _configLock = new object();
|
||||
private static ForcedStatic? _forcedStatic;
|
||||
private static readonly object _forcedStaticLock = new object();
|
||||
private static Dictionary<string, MapDirectoryMapping>? _mapDirectoryMappings;
|
||||
private static readonly object _mapDirectoryMappingsLock = new object();
|
||||
private static HashSet<string>? _staticWeaponIds;
|
||||
private static readonly object _staticWeaponIdsLock = new object();
|
||||
private static Dictionary<string, List<StaticForced>>? _forcedItems;
|
||||
private static readonly object _forcedItemsLock = new object();
|
||||
private static Dictionary<string, HashSet<string>>? _forcedLoose;
|
||||
private static readonly object _forcedLooseLock = new object();
|
||||
private static TarkovItems? _tarkovItems;
|
||||
private static readonly object _tarkovItemsLock = new object();
|
||||
|
||||
public static Config GetConfig()
|
||||
{
|
||||
lock (_configLock)
|
||||
{
|
||||
if (_config == null)
|
||||
{
|
||||
// This is the only instance where manual selection of the serializer is required
|
||||
// after this, GetInstance() for the JsonSerializerFactory should used without
|
||||
// parameters
|
||||
_config = JsonSerializerFactory.GetInstance(JsonSerializerTypes.DotNet)
|
||||
.Deserialize<Config>(File.ReadAllText("./Config/config.json"));
|
||||
}
|
||||
}
|
||||
|
||||
return _config;
|
||||
}
|
||||
|
||||
public static ForcedStatic GetForcedStatic()
|
||||
{
|
||||
lock (_forcedStaticLock)
|
||||
{
|
||||
if (_forcedStatic == null)
|
||||
{
|
||||
_forcedStatic = YamlSerializerFactory.GetInstance()
|
||||
.Deserialize<ForcedStatic>(File.ReadAllText("./Config/forced_static.yaml"));
|
||||
}
|
||||
}
|
||||
|
||||
return _forcedStatic;
|
||||
}
|
||||
|
||||
public static Dictionary<string, MapDirectoryMapping> GetDirectoryMappings()
|
||||
{
|
||||
lock (_mapDirectoryMappingsLock)
|
||||
{
|
||||
if (_mapDirectoryMappings == null)
|
||||
{
|
||||
_mapDirectoryMappings = YamlSerializerFactory.GetInstance()
|
||||
.Deserialize<Dictionary<string, MapDirectoryMapping>>(
|
||||
File.ReadAllText("./Config/map_directory_mapping.yaml"));
|
||||
}
|
||||
}
|
||||
|
||||
return _mapDirectoryMappings;
|
||||
}
|
||||
|
||||
public static HashSet<string> GetStaticWeaponIds()
|
||||
{
|
||||
lock (_staticWeaponIdsLock)
|
||||
{
|
||||
if (_staticWeaponIds == null)
|
||||
{
|
||||
_staticWeaponIds = GetForcedStatic().StaticWeaponIds.ToHashSet();
|
||||
}
|
||||
}
|
||||
|
||||
return _staticWeaponIds;
|
||||
}
|
||||
|
||||
public static Dictionary<string, List<StaticForced>> GetForcedItems()
|
||||
{
|
||||
lock (_forcedItemsLock)
|
||||
{
|
||||
if (_forcedItems == null)
|
||||
{
|
||||
_forcedItems = GetForcedStatic().ForcedItems;
|
||||
}
|
||||
}
|
||||
|
||||
return _forcedItems;
|
||||
}
|
||||
|
||||
public static Dictionary<string, HashSet<string>> GetForcedLooseItems()
|
||||
{
|
||||
lock (_forcedLooseLock)
|
||||
{
|
||||
if (_forcedLoose == null)
|
||||
{
|
||||
_forcedLoose = YamlSerializerFactory.GetInstance().Deserialize<Dictionary<string, HashSet<string>>>(
|
||||
File.ReadAllText("./Config/forced_loose.yaml"));
|
||||
}
|
||||
}
|
||||
|
||||
return _forcedLoose;
|
||||
}
|
||||
|
||||
public static TarkovItems GetTarkovItems()
|
||||
{
|
||||
lock (_tarkovItemsLock)
|
||||
{
|
||||
if (_tarkovItems == null)
|
||||
{
|
||||
_tarkovItems = new TarkovItems(
|
||||
$"{GetConfig().ServerLocation}/project/assets/database/templates/items.json",
|
||||
$"{GetConfig().ServerLocation}/project/assets/database/templates/handbook.json"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return _tarkovItems;
|
||||
}
|
||||
}
|
41
Model/ComposedKey.cs
Normal file
41
Model/ComposedKey.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Model.Processing;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model;
|
||||
|
||||
public class ComposedKey
|
||||
{
|
||||
[JsonProperty("key")]
|
||||
[JsonPropertyName("key")]
|
||||
public string Key { get; init; }
|
||||
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public Item? FirstItem { get; }
|
||||
|
||||
public ComposedKey(Template template) : this(template.Items)
|
||||
{
|
||||
}
|
||||
|
||||
public ComposedKey(List<Item>? items)
|
||||
{
|
||||
Key = items?.Select(i => i.Tpl)
|
||||
.Where(i => !string.IsNullOrEmpty(i) &&
|
||||
!LootDumpProcessorContext.GetTarkovItems().IsBaseClass(i, BaseClasses.Ammo))
|
||||
.Cast<string>()
|
||||
.Select(i => (double)i.GetHashCode())
|
||||
.Sum()
|
||||
.ToString() ?? Guid.NewGuid().ToString();
|
||||
FirstItem = items?[0];
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is not ComposedKey key)
|
||||
return false;
|
||||
return this.Key == key.Key;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => Key.GetHashCode();
|
||||
}
|
48
Model/Config/Config.cs
Normal file
48
Model/Config/Config.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Serializers.Json;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Config;
|
||||
|
||||
public class Config
|
||||
{
|
||||
[JsonProperty("serverLocation")]
|
||||
[JsonPropertyName("serverLocation")]
|
||||
public string? ServerLocation { get; set; }
|
||||
|
||||
[JsonProperty("threads")]
|
||||
[JsonPropertyName("threads")]
|
||||
public int Threads { get; set; } = 6;
|
||||
|
||||
[JsonProperty("threadPoolingTimeoutMs")]
|
||||
[JsonPropertyName("threadPoolingTimeoutMs")]
|
||||
public int ThreadPoolingTimeoutMs { get; set; } = 1000;
|
||||
|
||||
[JsonProperty("jsonSerializer")]
|
||||
[JsonPropertyName("jsonSerializer")]
|
||||
public JsonSerializerTypes JsonSerializer { get; set; } = JsonSerializerTypes.DotNet;
|
||||
|
||||
[JsonProperty("manualGarbageCollectionCalls")]
|
||||
[JsonPropertyName("manualGarbageCollectionCalls")]
|
||||
public bool ManualGarbageCollectionCalls { get; set; }
|
||||
|
||||
[JsonProperty("dataStorageConfig")]
|
||||
[JsonPropertyName("dataStorageConfig")]
|
||||
public DataStorageConfig DataStorageConfig { get; set; }
|
||||
|
||||
[JsonProperty("loggerConfig")]
|
||||
[JsonPropertyName("loggerConfig")]
|
||||
public LoggerConfig LoggerConfig { get; set; }
|
||||
|
||||
[JsonProperty("readerConfig")]
|
||||
[JsonPropertyName("readerConfig")]
|
||||
public ReaderConfig ReaderConfig { get; set; }
|
||||
|
||||
[JsonProperty("processorConfig")]
|
||||
[JsonPropertyName("processorConfig")]
|
||||
public ProcessorConfig ProcessorConfig { get; set; }
|
||||
|
||||
[JsonProperty("writerConfig")]
|
||||
[JsonPropertyName("writerConfig")]
|
||||
public WriterConfig WriterConfig { get; set; }
|
||||
}
|
16
Model/Config/DataStorageConfig.cs
Normal file
16
Model/Config/DataStorageConfig.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Storage;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Config;
|
||||
|
||||
public class DataStorageConfig
|
||||
{
|
||||
[JsonProperty("dataStorageType")]
|
||||
[JsonPropertyName("dataStorageType")]
|
||||
public DataStorageTypes DataStorageType { get; set; } = DataStorageTypes.File;
|
||||
|
||||
[JsonProperty("fileDataStorageTempLocation")]
|
||||
[JsonPropertyName("fileDataStorageTempLocation")]
|
||||
public string? FileDataStorageTempLocation { get; set; }
|
||||
}
|
12
Model/Config/ForcedStatic.cs
Normal file
12
Model/Config/ForcedStatic.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using LootDumpProcessor.Model.Output.StaticContainer;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace LootDumpProcessor.Model.Config;
|
||||
|
||||
public class ForcedStatic
|
||||
{
|
||||
[YamlMember(Alias = "static_weapon_ids")]
|
||||
public List<string> StaticWeaponIds { get; set; }
|
||||
|
||||
[YamlMember(Alias = "forced_items")] public Dictionary<string, List<StaticForced>> ForcedItems { get; set; }
|
||||
}
|
16
Model/Config/IntakeReaderConfig.cs
Normal file
16
Model/Config/IntakeReaderConfig.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Process.Reader;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Config;
|
||||
|
||||
public class IntakeReaderConfig
|
||||
{
|
||||
[JsonProperty("readerType")]
|
||||
[JsonPropertyName("readerType")]
|
||||
public IntakeReaderTypes IntakeReaderType { get; set; } = IntakeReaderTypes.Json;
|
||||
|
||||
[JsonProperty("ignoredDumpLocations")]
|
||||
[JsonPropertyName("ignoredDumpLocations")]
|
||||
public List<string> IgnoredDumpLocations { get; set; } = new List<string>();
|
||||
}
|
16
Model/Config/LoggerConfig.cs
Normal file
16
Model/Config/LoggerConfig.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Logger;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Config;
|
||||
|
||||
public class LoggerConfig
|
||||
{
|
||||
[JsonProperty("logLevel")]
|
||||
[JsonPropertyName("logLevel")]
|
||||
public LogLevel LogLevel { get; set; } = LogLevel.Info;
|
||||
|
||||
[JsonProperty("queueLoggerPoolingTimeoutMs")]
|
||||
[JsonPropertyName("queueLoggerPoolingTimeoutMs")]
|
||||
public int QueueLoggerPoolingTimeoutMs { get; set; } = 1000;
|
||||
}
|
11
Model/Config/MapDirectoryMapping.cs
Normal file
11
Model/Config/MapDirectoryMapping.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace LootDumpProcessor.Model.Config;
|
||||
|
||||
public class MapDirectoryMapping
|
||||
{
|
||||
[YamlMember(Alias = "name")]
|
||||
public List<string> Name { get; set; }
|
||||
[YamlMember(Alias = "threshold_date")]
|
||||
public string ThresholdDate { get; set; }
|
||||
}
|
20
Model/Config/PreProcessorConfig.cs
Normal file
20
Model/Config/PreProcessorConfig.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Process.Reader.PreProcess;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Config;
|
||||
|
||||
public class PreProcessorConfig
|
||||
{
|
||||
[JsonProperty("preProcessors")]
|
||||
[JsonPropertyName("preProcessors")]
|
||||
public List<PreProcessReaderTypes>? PreProcessors { get; set; }
|
||||
|
||||
[JsonProperty("preProcessorTempFolder")]
|
||||
[JsonPropertyName("preProcessorTempFolder")]
|
||||
public string? PreProcessorTempFolder { get; set; }
|
||||
|
||||
[JsonProperty("cleanupTempFolderAfterProcess")]
|
||||
[JsonPropertyName("cleanupTempFolderAfterProcess")]
|
||||
public bool CleanupTempFolderAfterProcess { get; set; } = true;
|
||||
}
|
11
Model/Config/ProcessorConfig.cs
Normal file
11
Model/Config/ProcessorConfig.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Config;
|
||||
|
||||
public class ProcessorConfig
|
||||
{
|
||||
[JsonProperty("spawnPointToleranceForForced")]
|
||||
[JsonPropertyName("spawnPointToleranceForForced")]
|
||||
public double SpawnPointToleranceForForced { get; set; } = 99D;
|
||||
}
|
36
Model/Config/ReaderConfig.cs
Normal file
36
Model/Config/ReaderConfig.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Process.Reader.Filters;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Config;
|
||||
|
||||
public class ReaderConfig
|
||||
{
|
||||
[JsonProperty("intakeReaderConfig")]
|
||||
[JsonPropertyName("intakeReaderConfig")]
|
||||
public IntakeReaderConfig? IntakeReaderConfig { get; set; }
|
||||
|
||||
[JsonProperty("preProcessorConfig")]
|
||||
[JsonPropertyName("preProcessorConfig")]
|
||||
public PreProcessorConfig? PreProcessorConfig { get; set; }
|
||||
|
||||
[JsonProperty("dumpFilesLocation")]
|
||||
[JsonPropertyName("dumpFilesLocation")]
|
||||
public List<string>? DumpFilesLocation { get; set; }
|
||||
|
||||
[JsonProperty("thresholdDate")]
|
||||
[JsonPropertyName("thresholdDate")]
|
||||
public string? ThresholdDate { get; set; }
|
||||
|
||||
[JsonProperty("acceptedFileExtensions")]
|
||||
[JsonPropertyName("acceptedFileExtensions")]
|
||||
public List<string> AcceptedFileExtensions { get; set; } = new List<string>();
|
||||
|
||||
[JsonProperty("processSubFolders")]
|
||||
[JsonPropertyName("processSubFolders")]
|
||||
public bool ProcessSubFolders { get; set; }
|
||||
|
||||
[JsonProperty("fileFilters")]
|
||||
[JsonPropertyName("fileFilters")]
|
||||
public List<FileFilterTypes>? FileFilters { get; set; }
|
||||
}
|
11
Model/Config/WriterConfig.cs
Normal file
11
Model/Config/WriterConfig.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Config;
|
||||
|
||||
public class WriterConfig
|
||||
{
|
||||
[JsonProperty("outputLocation")]
|
||||
[JsonPropertyName("outputLocation")]
|
||||
public string? OutputLocation { get; set; }
|
||||
}
|
20
Model/FireMode.cs
Normal file
20
Model/FireMode.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model
|
||||
{
|
||||
public class FireMode : ICloneable
|
||||
{
|
||||
[JsonProperty("FireMode", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("FireMode")]
|
||||
public string? FireModeType { get; set; }
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new FireMode
|
||||
{
|
||||
FireModeType = this.FireModeType
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
20
Model/Foldable.cs
Normal file
20
Model/Foldable.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model
|
||||
{
|
||||
public class Foldable : ICloneable
|
||||
{
|
||||
[JsonProperty("Folded", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Folded")]
|
||||
public bool? Folded { get; set; }
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new Foldable
|
||||
{
|
||||
Folded = this.Folded
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
36
Model/GroupPosition.cs
Normal file
36
Model/GroupPosition.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Process.Processor;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model
|
||||
{
|
||||
public class GroupPosition : ICloneable
|
||||
{
|
||||
[JsonProperty("Name", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[JsonProperty("Weight", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Weight")]
|
||||
public int? Weight { get; set; }
|
||||
|
||||
[JsonProperty("Position", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Position")]
|
||||
public Vector3? Position { get; set; }
|
||||
|
||||
[JsonProperty("Rotation", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Rotation")]
|
||||
public Vector3? Rotation { get; set; }
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new GroupPosition
|
||||
{
|
||||
Name = this.Name,
|
||||
Weight = this.Weight,
|
||||
Position = ProcessorUtil.Copy(this.Position),
|
||||
Rotation = ProcessorUtil.Copy(this.Rotation)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
48
Model/Input/AirdropParameter.cs
Normal file
48
Model/Input/AirdropParameter.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class AirdropParameter
|
||||
{
|
||||
[JsonProperty("PlaneAirdropStartMin", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("PlaneAirdropStartMin")]
|
||||
public int? PlaneAirdropStartMin { get; set; }
|
||||
|
||||
[JsonProperty("PlaneAirdropStartMax", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("PlaneAirdropStartMax")]
|
||||
public int? PlaneAirdropStartMax { get; set; }
|
||||
|
||||
[JsonProperty("PlaneAirdropEnd", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("PlaneAirdropEnd")]
|
||||
public int? PlaneAirdropEnd { get; set; }
|
||||
|
||||
[JsonProperty("PlaneAirdropChance", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("PlaneAirdropChance")]
|
||||
public double? PlaneAirdropChance { get; set; }
|
||||
|
||||
[JsonProperty("PlaneAirdropMax", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("PlaneAirdropMax")]
|
||||
public int? PlaneAirdropMax { get; set; }
|
||||
|
||||
[JsonProperty("PlaneAirdropCooldownMin", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("PlaneAirdropCooldownMin")]
|
||||
public int? PlaneAirdropCooldownMin { get; set; }
|
||||
|
||||
[JsonProperty("PlaneAirdropCooldownMax", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("PlaneAirdropCooldownMax")]
|
||||
public int? PlaneAirdropCooldownMax { get; set; }
|
||||
|
||||
[JsonProperty("AirdropPointDeactivateDistance", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("AirdropPointDeactivateDistance")]
|
||||
public int? AirdropPointDeactivateDistance { get; set; }
|
||||
|
||||
[JsonProperty("MinPlayersCountToSpawnAirdrop", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MinPlayersCountToSpawnAirdrop")]
|
||||
public int? MinPlayersCountToSpawnAirdrop { get; set; }
|
||||
|
||||
[JsonProperty("UnsuccessfulTryPenalty", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("UnsuccessfulTryPenalty")]
|
||||
public int? UnsuccessfulTryPenalty { get; set; }
|
||||
}
|
||||
}
|
14
Model/Input/Banner.cs
Normal file
14
Model/Input/Banner.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class Banner
|
||||
{
|
||||
[JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] [JsonPropertyName("id")]
|
||||
public string? Id { get; set; }
|
||||
|
||||
[JsonProperty("pic")] [JsonPropertyName("pic")]
|
||||
public Preview? Pic { get; set; }
|
||||
}
|
||||
}
|
28
Model/Input/BotLocationModifier.cs
Normal file
28
Model/Input/BotLocationModifier.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class BotLocationModifier
|
||||
{
|
||||
[JsonProperty("AccuracySpeed", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("AccuracySpeed")]
|
||||
public double? AccuracySpeed { get; set; }
|
||||
|
||||
[JsonProperty("Scattering", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Scattering")]
|
||||
public double? Scattering { get; set; }
|
||||
|
||||
[JsonProperty("GainSight", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("GainSight")]
|
||||
public double? GainSight { get; set; }
|
||||
|
||||
[JsonProperty("MarksmanAccuratyCoef", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MarksmanAccuratyCoef")]
|
||||
public double? MarksmanAccuratyCoef { get; set; }
|
||||
|
||||
[JsonProperty("VisibleDistance", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("VisibleDistance")]
|
||||
public double? VisibleDistance { get; set; }
|
||||
}
|
||||
}
|
16
Model/Input/ColliderParams.cs
Normal file
16
Model/Input/ColliderParams.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class ColliderParams
|
||||
{
|
||||
[JsonProperty("_parent", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("_parent")]
|
||||
public string? Parent { get; set; }
|
||||
|
||||
[JsonProperty("_props", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("_props")]
|
||||
public Props? Props { get; set; }
|
||||
}
|
||||
}
|
320
Model/Input/Data.cs
Normal file
320
Model/Input/Data.cs
Normal file
@ -0,0 +1,320 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class Data
|
||||
{
|
||||
[JsonProperty("Enabled", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Enabled")]
|
||||
public bool? Enabled { get; set; }
|
||||
|
||||
[JsonProperty("EnableCoop", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("EnableCoop")]
|
||||
public bool? EnableCoop { get; set; }
|
||||
|
||||
[JsonProperty("Locked", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Locked")]
|
||||
public bool? Locked { get; set; }
|
||||
|
||||
[JsonProperty("Insurance", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Insurance")]
|
||||
public bool? Insurance { get; set; }
|
||||
|
||||
[JsonProperty("SafeLocation", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("SafeLocation")]
|
||||
public bool? SafeLocation { get; set; }
|
||||
|
||||
[JsonProperty("Name", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[JsonProperty("Description", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Description")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
[JsonProperty("Scene", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Scene")]
|
||||
public Preview? Scene { get; set; }
|
||||
|
||||
[JsonProperty("Area", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Area")]
|
||||
public double? Area { get; set; }
|
||||
|
||||
[JsonProperty("RequiredPlayerLevel", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("RequiredPlayerLevel")]
|
||||
public int? RequiredPlayerLevel { get; set; }
|
||||
|
||||
[JsonProperty("PmcMaxPlayersInGroup", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("PmcMaxPlayersInGroup")]
|
||||
public int? PmcMaxPlayersInGroup { get; set; }
|
||||
|
||||
[JsonProperty("ScavMaxPlayersInGroup", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("ScavMaxPlayersInGroup")]
|
||||
public int? ScavMaxPlayersInGroup { get; set; }
|
||||
|
||||
[JsonProperty("MinPlayers", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MinPlayers")]
|
||||
public int? MinPlayers { get; set; }
|
||||
|
||||
[JsonProperty("MaxPlayers", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MaxPlayers")]
|
||||
public int? MaxPlayers { get; set; }
|
||||
|
||||
[JsonProperty("MaxCoopGroup", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MaxCoopGroup")]
|
||||
public int? MaxCoopGroup { get; set; }
|
||||
|
||||
[JsonProperty("exit_count", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("exit_count")]
|
||||
public int? ExitCount { get; set; }
|
||||
|
||||
[JsonProperty("exit_access_time", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("exit_access_time")]
|
||||
public int? ExitAccessTime { get; set; }
|
||||
|
||||
[JsonProperty("exit_time", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("exit_time")]
|
||||
public int? ExitTime { get; set; }
|
||||
|
||||
[JsonProperty("Preview", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Preview")]
|
||||
public Preview? Preview { get; set; }
|
||||
|
||||
[JsonProperty("IconX", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("IconX")]
|
||||
public int? IconX { get; set; }
|
||||
|
||||
[JsonProperty("IconY", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("IconY")]
|
||||
public int? IconY { get; set; }
|
||||
|
||||
[JsonProperty("filter_ex", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("filter_ex")]
|
||||
public List<object>? FilterEx { get; set; }
|
||||
|
||||
[JsonProperty("waves", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("waves")]
|
||||
public List<Wave>? Waves { get; set; }
|
||||
|
||||
[JsonProperty("limits", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("limits")]
|
||||
public List<object>? Limits { get; set; }
|
||||
|
||||
[JsonProperty("AveragePlayTime", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("AveragePlayTime")]
|
||||
public int? AveragePlayTime { get; set; }
|
||||
|
||||
[JsonProperty("AveragePlayerLevel", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("AveragePlayerLevel")]
|
||||
public int? AveragePlayerLevel { get; set; }
|
||||
|
||||
[JsonProperty("EscapeTimeLimit", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("EscapeTimeLimit")]
|
||||
public int? EscapeTimeLimit { get; set; }
|
||||
|
||||
[JsonProperty("EscapeTimeLimitCoop", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("EscapeTimeLimitCoop")]
|
||||
public int? EscapeTimeLimitCoop { get; set; }
|
||||
|
||||
[JsonProperty("Rules", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Rules")]
|
||||
public string? Rules { get; set; }
|
||||
|
||||
[JsonProperty("IsSecret", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("IsSecret")]
|
||||
public bool? IsSecret { get; set; }
|
||||
|
||||
[JsonProperty("doors", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("doors")]
|
||||
public List<object>? Doors { get; set; }
|
||||
|
||||
[JsonProperty("tmp_location_field_remove_me", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("tmp_location_field_remove_me")]
|
||||
public int? TmpLocationFieldRemoveMe { get; set; }
|
||||
|
||||
[JsonProperty("MinDistToExitPoint", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MinDistToExitPoint")]
|
||||
public int? MinDistToExitPoint { get; set; }
|
||||
|
||||
[JsonProperty("MaxDistToFreePoint", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MaxDistToFreePoint")]
|
||||
public int? MaxDistToFreePoint { get; set; }
|
||||
|
||||
[JsonProperty("MinDistToFreePoint", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MinDistToFreePoint")]
|
||||
public int? MinDistToFreePoint { get; set; }
|
||||
|
||||
[JsonProperty("MaxBotPerZone", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MaxBotPerZone")]
|
||||
public int? MaxBotPerZone { get; set; }
|
||||
|
||||
[JsonProperty("OpenZones", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("OpenZones")]
|
||||
public string? OpenZones { get; set; }
|
||||
|
||||
[JsonProperty("OcculsionCullingEnabled", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("OcculsionCullingEnabled")]
|
||||
public bool? OcculsionCullingEnabled { get; set; }
|
||||
|
||||
[JsonProperty("GlobalLootChanceModifier", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("GlobalLootChanceModifier")]
|
||||
public double? GlobalLootChanceModifier { get; set; }
|
||||
|
||||
[JsonProperty("OldSpawn", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("OldSpawn")]
|
||||
public bool? OldSpawn { get; set; }
|
||||
|
||||
[JsonProperty("NewSpawn", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("NewSpawn")]
|
||||
public bool? NewSpawn { get; set; }
|
||||
|
||||
[JsonProperty("BotMax", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotMax")]
|
||||
public int? BotMax { get; set; }
|
||||
|
||||
[JsonProperty("BotStart", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotStart")]
|
||||
public int? BotStart { get; set; }
|
||||
|
||||
[JsonProperty("BotStop", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotStop")]
|
||||
public int? BotStop { get; set; }
|
||||
|
||||
[JsonProperty("BotMaxTimePlayer", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotMaxTimePlayer")]
|
||||
public int? BotMaxTimePlayer { get; set; }
|
||||
|
||||
[JsonProperty("BotSpawnTimeOnMin", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotSpawnTimeOnMin")]
|
||||
public int? BotSpawnTimeOnMin { get; set; }
|
||||
|
||||
[JsonProperty("BotSpawnTimeOnMax", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotSpawnTimeOnMax")]
|
||||
public int? BotSpawnTimeOnMax { get; set; }
|
||||
|
||||
[JsonProperty("BotSpawnTimeOffMin", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotSpawnTimeOffMin")]
|
||||
public int? BotSpawnTimeOffMin { get; set; }
|
||||
|
||||
[JsonProperty("BotSpawnTimeOffMax", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotSpawnTimeOffMax")]
|
||||
public int? BotSpawnTimeOffMax { get; set; }
|
||||
|
||||
[JsonProperty("BotMaxPlayer", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotMaxPlayer")]
|
||||
public int? BotMaxPlayer { get; set; }
|
||||
|
||||
[JsonProperty("BotEasy", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotEasy")]
|
||||
public int? BotEasy { get; set; }
|
||||
|
||||
[JsonProperty("BotNormal", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotNormal")]
|
||||
public int? BotNormal { get; set; }
|
||||
|
||||
[JsonProperty("BotHard", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotHard")]
|
||||
public int? BotHard { get; set; }
|
||||
|
||||
[JsonProperty("BotImpossible", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotImpossible")]
|
||||
public int? BotImpossible { get; set; }
|
||||
|
||||
[JsonProperty("BotAssault", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotAssault")]
|
||||
public int? BotAssault { get; set; }
|
||||
|
||||
[JsonProperty("BotMarksman", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotMarksman")]
|
||||
public int? BotMarksman { get; set; }
|
||||
|
||||
[JsonProperty("DisabledScavExits", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("DisabledScavExits")]
|
||||
public string? DisabledScavExits { get; set; }
|
||||
|
||||
[JsonProperty("AccessKeys", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("AccessKeys")]
|
||||
public List<object>? AccessKeys { get; set; }
|
||||
|
||||
[JsonProperty("UnixDateTime", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("UnixDateTime")]
|
||||
public int? UnixDateTime { get; set; }
|
||||
|
||||
[JsonProperty("users_gather_seconds", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("users_gather_seconds")]
|
||||
public int? UsersGatherSeconds { get; set; }
|
||||
|
||||
[JsonProperty("users_spawn_seconds_n", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("users_spawn_seconds_n")]
|
||||
public int? UsersSpawnSecondsN { get; set; }
|
||||
|
||||
[JsonProperty("users_spawn_seconds_n2", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("users_spawn_seconds_n2")]
|
||||
public int? UsersSpawnSecondsN2 { get; set; }
|
||||
|
||||
[JsonProperty("users_summon_seconds", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("users_summon_seconds")]
|
||||
public int? UsersSummonSeconds { get; set; }
|
||||
|
||||
[JsonProperty("sav_summon_seconds", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("sav_summon_seconds")]
|
||||
public int? SavSummonSeconds { get; set; }
|
||||
|
||||
[JsonProperty("matching_min_seconds", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("matching_min_seconds")]
|
||||
public int? MatchingMinSeconds { get; set; }
|
||||
|
||||
[JsonProperty("GenerateLocalLootCache", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("GenerateLocalLootCache")]
|
||||
public bool? GenerateLocalLootCache { get; set; }
|
||||
|
||||
[JsonProperty("MinMaxBots", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MinMaxBots")]
|
||||
public List<object>? MinMaxBots { get; set; }
|
||||
|
||||
[JsonProperty("BotLocationModifier", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotLocationModifier")]
|
||||
public BotLocationModifier? BotLocationModifier { get; set; }
|
||||
|
||||
[JsonProperty("exits", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("exits")]
|
||||
public List<Exit>? Exits { get; set; }
|
||||
|
||||
[JsonProperty("DisabledForScav", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("DisabledForScav")]
|
||||
public bool? DisabledForScav { get; set; }
|
||||
|
||||
[JsonProperty("ExitZones", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("ExitZones")]
|
||||
public ExitZones? ExitZones { get; set; }
|
||||
|
||||
[JsonProperty("SpawnPointParams", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("SpawnPointParams")]
|
||||
public List<SpawnPointParam>? SpawnPointParams { get; set; }
|
||||
|
||||
[JsonProperty("AirdropParameters", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("AirdropParameters")]
|
||||
public List<AirdropParameter>? AirdropParameters { get; set; }
|
||||
|
||||
[JsonProperty("Id", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Id")]
|
||||
public string? Id { get; set; }
|
||||
|
||||
[JsonProperty("_Id", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("_Id")]
|
||||
public string? _Id { get; set; }
|
||||
|
||||
[JsonProperty("Loot", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Loot")]
|
||||
public List<Template>? Loot { get; set; }
|
||||
|
||||
[JsonProperty("Banners", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Banners")]
|
||||
public List<Banner>? Banners { get; set; }
|
||||
|
||||
[JsonProperty("BossLocationSpawn", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BossLocationSpawn")]
|
||||
public List<object>? BossLocationSpawn { get; set; }
|
||||
}
|
||||
}
|
60
Model/Input/Exit.cs
Normal file
60
Model/Input/Exit.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class Exit
|
||||
{
|
||||
[JsonProperty("Name", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[JsonProperty("EntryPoints", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("EntryPoints")]
|
||||
public string? EntryPoints { get; set; }
|
||||
|
||||
[JsonProperty("Chance", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Chance")]
|
||||
public int? Chance { get; set; }
|
||||
|
||||
[JsonProperty("MinTime", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MinTime")]
|
||||
public int? MinTime { get; set; }
|
||||
|
||||
[JsonProperty("MaxTime", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MaxTime")]
|
||||
public int? MaxTime { get; set; }
|
||||
|
||||
[JsonProperty("PlayersCount", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("PlayersCount")]
|
||||
public int? PlayersCount { get; set; }
|
||||
|
||||
[JsonProperty("ExfiltrationTime", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("ExfiltrationTime")]
|
||||
public int? ExfiltrationTime { get; set; }
|
||||
|
||||
[JsonProperty("PassageRequirement", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("PassageRequirement")]
|
||||
public string? PassageRequirement { get; set; }
|
||||
|
||||
[JsonProperty("ExfiltrationType", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("ExfiltrationType")]
|
||||
public string? ExfiltrationType { get; set; }
|
||||
|
||||
[JsonProperty("RequiredSlot", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("RequiredSlot")]
|
||||
public string? RequiredSlot { get; set; }
|
||||
|
||||
[JsonProperty("Id", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Id")]
|
||||
public string? Id { get; set; }
|
||||
|
||||
[JsonProperty("RequirementTip", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("RequirementTip")]
|
||||
public string? RequirementTip { get; set; }
|
||||
|
||||
[JsonProperty("Count", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Count")]
|
||||
public int? Count { get; set; }
|
||||
}
|
||||
}
|
12
Model/Input/ExitZones.cs
Normal file
12
Model/Input/ExitZones.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class ExitZones
|
||||
{
|
||||
[JsonProperty("$oid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("$oid")]
|
||||
public string? Oid { get; set; }
|
||||
}
|
||||
}
|
16
Model/Input/Preview.cs
Normal file
16
Model/Input/Preview.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class Preview
|
||||
{
|
||||
[JsonProperty("path", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("path")]
|
||||
public string? Path { get; set; }
|
||||
|
||||
[JsonProperty("rcid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("rcid")]
|
||||
public string? Rcid { get; set; }
|
||||
}
|
||||
}
|
16
Model/Input/Props.cs
Normal file
16
Model/Input/Props.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class Props
|
||||
{
|
||||
[JsonProperty("Center", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Center")]
|
||||
public Vector3? Center { get; set; }
|
||||
|
||||
[JsonProperty("Radius", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Radius")]
|
||||
public double? Radius { get; set; }
|
||||
}
|
||||
}
|
20
Model/Input/RootData.cs
Normal file
20
Model/Input/RootData.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class RootData
|
||||
{
|
||||
[JsonProperty("err", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("err")]
|
||||
public int? Err { get; set; }
|
||||
|
||||
[JsonProperty("errmsg")]
|
||||
[JsonPropertyName("errmsg")]
|
||||
public object? errmsg { get; set; }
|
||||
|
||||
[JsonProperty("data", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("data")]
|
||||
public Data? Data { get; set; }
|
||||
}
|
||||
}
|
40
Model/Input/SpawnPointParam.cs
Normal file
40
Model/Input/SpawnPointParam.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class SpawnPointParam
|
||||
{
|
||||
[JsonProperty("Id", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Id")]
|
||||
public string? Id { get; set; }
|
||||
|
||||
[JsonProperty("Position", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Position")]
|
||||
public Vector3? Position { get; set; }
|
||||
|
||||
[JsonProperty("Rotation", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Rotation")]
|
||||
public double? Rotation { get; set; }
|
||||
|
||||
[JsonProperty("Sides", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Sides")]
|
||||
public List<string>? Sides { get; set; }
|
||||
|
||||
[JsonProperty("Categories", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Categories")]
|
||||
public List<string>? Categories { get; set; }
|
||||
|
||||
[JsonProperty("Infiltration", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Infiltration")]
|
||||
public string? Infiltration { get; set; }
|
||||
|
||||
[JsonProperty("DelayToCanSpawnSec", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("DelayToCanSpawnSec")]
|
||||
public int? DelayToCanSpawnSec { get; set; }
|
||||
|
||||
[JsonProperty("ColliderParams", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("ColliderParams")]
|
||||
public ColliderParams? ColliderParams { get; set; }
|
||||
}
|
||||
}
|
48
Model/Input/Wave.cs
Normal file
48
Model/Input/Wave.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Input
|
||||
{
|
||||
public class Wave
|
||||
{
|
||||
[JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("number")]
|
||||
public int? Number { get; set; }
|
||||
|
||||
[JsonProperty("time_min", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("time_min")]
|
||||
public int? TimeMin { get; set; }
|
||||
|
||||
[JsonProperty("time_max", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("time_max")]
|
||||
public int? TimeMax { get; set; }
|
||||
|
||||
[JsonProperty("slots_min", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("slots_min")]
|
||||
public int? SlotsMin { get; set; }
|
||||
|
||||
[JsonProperty("slots_max", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("slots_max")]
|
||||
public int? SlotsMax { get; set; }
|
||||
|
||||
[JsonProperty("SpawnPoints", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("SpawnPoints")]
|
||||
public string? SpawnPoints { get; set; }
|
||||
|
||||
[JsonProperty("BotSide", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotSide")]
|
||||
public string? BotSide { get; set; }
|
||||
|
||||
[JsonProperty("BotPreset", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("BotPreset")]
|
||||
public string? BotPreset { get; set; }
|
||||
|
||||
[JsonProperty("isPlayers", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("isPlayers")]
|
||||
public bool? IsPlayers { get; set; }
|
||||
|
||||
[JsonProperty("WildSpawnType", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("WildSpawnType")]
|
||||
public string? WildSpawnType { get; set; }
|
||||
}
|
||||
}
|
58
Model/Item.cs
Normal file
58
Model/Item.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Process.Processor;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model
|
||||
{
|
||||
public class Item : ICloneable
|
||||
{
|
||||
[JsonProperty("_id", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("_id")]
|
||||
public string? Id { get; set; }
|
||||
|
||||
[JsonProperty("_tpl", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("_tpl")]
|
||||
public string? Tpl { get; set; }
|
||||
|
||||
[JsonProperty("parentId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("parentId")]
|
||||
public string? ParentId { get; set; }
|
||||
|
||||
[JsonProperty("slotId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("slotId")]
|
||||
public string? SlotId { get; set; }
|
||||
|
||||
[JsonProperty("location", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("location")]
|
||||
public object? Location { get; set; }
|
||||
|
||||
[JsonProperty("upd", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("upd")]
|
||||
public Upd? Upd { get; set; }
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is not Item parsed)
|
||||
return false;
|
||||
return parsed.Tpl == this.Tpl && parsed.ParentId == this.ParentId;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (this.Tpl?.GetHashCode() + this.ParentId?.GetHashCode()) ?? base.GetHashCode();
|
||||
}
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new Item
|
||||
{
|
||||
Id = this.Id,
|
||||
Tpl = this.Tpl,
|
||||
ParentId = this.ParentId,
|
||||
SlotId = this.SlotId,
|
||||
Location = this.Location,
|
||||
Upd = ProcessorUtil.Copy(this.Upd)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
11
Model/Output/AbstractDistribution.cs
Normal file
11
Model/Output/AbstractDistribution.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output;
|
||||
|
||||
public abstract class AbstractDistribution
|
||||
{
|
||||
[JsonProperty("relativeProbability", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("relativeProbability")]
|
||||
public int? RelativeProbability { get; set; }
|
||||
}
|
11
Model/Output/AmmoDistribution.cs
Normal file
11
Model/Output/AmmoDistribution.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output;
|
||||
|
||||
public class AmmoDistribution : AbstractDistribution
|
||||
{
|
||||
[JsonProperty("tpl", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("tpl")]
|
||||
public string? Tpl { get; set; }
|
||||
}
|
16
Model/Output/ItemCountDistribution.cs
Normal file
16
Model/Output/ItemCountDistribution.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output
|
||||
{
|
||||
public class ItemCountDistribution
|
||||
{
|
||||
[JsonProperty("count", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("count")]
|
||||
public int? Count { get; set; }
|
||||
|
||||
[JsonProperty("relativeProbability", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("relativeProbability")]
|
||||
public int? RelativeProbability { get; set; }
|
||||
}
|
||||
}
|
12
Model/Output/ItemDistribution.cs
Normal file
12
Model/Output/ItemDistribution.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output
|
||||
{
|
||||
public class ItemDistribution : AbstractDistribution
|
||||
{
|
||||
[JsonProperty("composedKey", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("composedKey")]
|
||||
public ComposedKey? ComposedKey { get; set; }
|
||||
}
|
||||
}
|
20
Model/Output/LooseLoot/LooseLootRoot.cs
Normal file
20
Model/Output/LooseLoot/LooseLootRoot.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output.LooseLoot
|
||||
{
|
||||
public class LooseLootRoot
|
||||
{
|
||||
[JsonProperty("spawnpointCount", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("spawnpointCount")]
|
||||
public SpawnPointCount? SpawnPointCount { get; set; }
|
||||
|
||||
[JsonProperty("spawnpointsForced", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("spawnpointsForced")]
|
||||
public List<SpawnPointsForced>? SpawnPointsForced { get; set; }
|
||||
|
||||
[JsonProperty("spawnpoints", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("spawnpoints")]
|
||||
public List<SpawnPoint>? SpawnPoints { get; set; }
|
||||
}
|
||||
}
|
24
Model/Output/LooseLoot/SpawnPoint.cs
Normal file
24
Model/Output/LooseLoot/SpawnPoint.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output.LooseLoot
|
||||
{
|
||||
public class SpawnPoint
|
||||
{
|
||||
[JsonProperty("locationId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("locationId")]
|
||||
public string? LocationId { get; set; }
|
||||
|
||||
[JsonProperty("probability", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("probability")]
|
||||
public double? Probability { get; set; }
|
||||
|
||||
[JsonProperty("template", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("template")]
|
||||
public Template? Template { get; set; }
|
||||
|
||||
[JsonProperty("itemDistribution", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("itemDistribution")]
|
||||
public List<ItemDistribution>? ItemDistribution { get; set; }
|
||||
}
|
||||
}
|
16
Model/Output/LooseLoot/SpawnPointCount.cs
Normal file
16
Model/Output/LooseLoot/SpawnPointCount.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output.LooseLoot
|
||||
{
|
||||
public class SpawnPointCount
|
||||
{
|
||||
[JsonProperty("mean", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("mean")]
|
||||
public double? Mean { get; set; }
|
||||
|
||||
[JsonProperty("std", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("std")]
|
||||
public double? Std { get; set; }
|
||||
}
|
||||
}
|
20
Model/Output/LooseLoot/SpawnPointsForced.cs
Normal file
20
Model/Output/LooseLoot/SpawnPointsForced.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output.LooseLoot
|
||||
{
|
||||
public class SpawnPointsForced
|
||||
{
|
||||
[JsonProperty("locationId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("locationId")]
|
||||
public string? LocationId { get; set; }
|
||||
|
||||
[JsonProperty("probability", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("probability")]
|
||||
public double? Probability { get; set; }
|
||||
|
||||
[JsonProperty("template", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("template")]
|
||||
public Template? Template { get; set; }
|
||||
}
|
||||
}
|
20
Model/Output/StaticContainer/MapStaticLoot.cs
Normal file
20
Model/Output/StaticContainer/MapStaticLoot.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output.StaticContainer
|
||||
{
|
||||
public class MapStaticLoot
|
||||
{
|
||||
[JsonProperty("staticWeapons", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("staticWeapons")]
|
||||
public List<Template>? StaticWeapons { get; set; }
|
||||
|
||||
[JsonProperty("staticContainers", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("staticContainers")]
|
||||
public List<StaticDataPoint>? StaticContainers { get; set; }
|
||||
|
||||
[JsonProperty("staticForced", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("staticForced")]
|
||||
public List<StaticForced>? StaticForced { get; set; }
|
||||
}
|
||||
}
|
44
Model/Output/StaticContainer/StaticContainerRoot.cs
Normal file
44
Model/Output/StaticContainer/StaticContainerRoot.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output.StaticContainer
|
||||
{
|
||||
public class StaticContainerRoot
|
||||
{
|
||||
[JsonProperty("Laboratory", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Laboratory")]
|
||||
public MapStaticLoot? Laboratory { get; set; }
|
||||
|
||||
[JsonProperty("Shoreline", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Shoreline")]
|
||||
public MapStaticLoot? Shoreline { get; set; }
|
||||
|
||||
[JsonProperty("Streets of Tarkov", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Streets of Tarkov")]
|
||||
public MapStaticLoot? StreetsofTarkov { get; set; }
|
||||
|
||||
[JsonProperty("Interchange", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Interchange")]
|
||||
public MapStaticLoot? Interchange { get; set; }
|
||||
|
||||
[JsonProperty("Customs", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Customs")]
|
||||
public MapStaticLoot? Customs { get; set; }
|
||||
|
||||
[JsonProperty("Woods", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Woods")]
|
||||
public MapStaticLoot? Woods { get; set; }
|
||||
|
||||
[JsonProperty("Factory", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Factory")]
|
||||
public MapStaticLoot? Factory { get; set; }
|
||||
|
||||
[JsonProperty("ReserveBase", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("ReserveBase")]
|
||||
public MapStaticLoot? ReserveBase { get; set; }
|
||||
|
||||
[JsonProperty("Lighthouse", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Lighthouse")]
|
||||
public MapStaticLoot? Lighthouse { get; set; }
|
||||
}
|
||||
}
|
15
Model/Output/StaticContainer/StaticDataPoint.cs
Normal file
15
Model/Output/StaticContainer/StaticDataPoint.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output.StaticContainer;
|
||||
|
||||
public class StaticDataPoint
|
||||
{
|
||||
[JsonProperty("probability", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("probability")]
|
||||
public double? Probability { get; set; }
|
||||
|
||||
[JsonProperty("template", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("template")]
|
||||
public Template? Template { get; set; }
|
||||
}
|
19
Model/Output/StaticContainer/StaticForced.cs
Normal file
19
Model/Output/StaticContainer/StaticForced.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output.StaticContainer
|
||||
{
|
||||
public class StaticForced
|
||||
{
|
||||
[JsonProperty("containerId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("containerId")]
|
||||
[YamlMember(Alias = "containerId")]
|
||||
public string? ContainerId { get; set; }
|
||||
|
||||
[JsonProperty("itemTpl", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("itemTpl")]
|
||||
[YamlMember(Alias = "itemTpl")]
|
||||
public string? ItemTpl { get; set; }
|
||||
}
|
||||
}
|
11
Model/Output/StaticDistribution.cs
Normal file
11
Model/Output/StaticDistribution.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output;
|
||||
|
||||
public class StaticDistribution : AbstractDistribution
|
||||
{
|
||||
[JsonProperty("tpl", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("tpl")]
|
||||
public string? Tpl { get; set; }
|
||||
}
|
16
Model/Output/StaticItemDistribution.cs
Normal file
16
Model/Output/StaticItemDistribution.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Output
|
||||
{
|
||||
public class StaticItemDistribution
|
||||
{
|
||||
[JsonProperty("itemcountDistribution", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("itemcountDistribution")]
|
||||
public List<ItemCountDistribution>? ItemCountDistribution { get; set; }
|
||||
|
||||
[JsonProperty("itemDistribution", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("itemDistribution")]
|
||||
public List<StaticDistribution>? ItemDistribution { get; set; }
|
||||
}
|
||||
}
|
81
Model/Processing/BaseClasses.cs
Normal file
81
Model/Processing/BaseClasses.cs
Normal file
@ -0,0 +1,81 @@
|
||||
namespace LootDumpProcessor.Model.Processing;
|
||||
|
||||
public static class BaseClasses
|
||||
{
|
||||
public static string DefaultInventory = "55d7217a4bdc2d86028b456d";
|
||||
public static string Inventory = "55d720f24bdc2d88028b456d";
|
||||
public static string Pockets = "557596e64bdc2dc2118b4571";
|
||||
public static string Weapon = "5422acb9af1c889c16000029";
|
||||
public static string Headwear = "5a341c4086f77401f2541505";
|
||||
public static string Armor = "5448e54d4bdc2dcc718b4568";
|
||||
public static string Vest = "5448e5284bdc2dcb718b4567";
|
||||
public static string Backpack = "5448e53e4bdc2d60728b4567";
|
||||
public static string Visors = "5448e5724bdc2ddf718b4568";
|
||||
public static string Food = "5448e8d04bdc2ddf718b4569";
|
||||
public static string Drink = "5448e8d64bdc2dce718b4568";
|
||||
public static string BarterItem = "5448eb774bdc2d0a728b4567";
|
||||
public static string Info = "5448ecbe4bdc2d60728b4568";
|
||||
public static string MedKit = "5448f39d4bdc2d0a728b4568";
|
||||
public static string Drugs = "5448f3a14bdc2d27728b4569";
|
||||
public static string Stimulator = "5448f3a64bdc2d60728b456a";
|
||||
public static string Medical = "5448f3ac4bdc2dce718b4569";
|
||||
public static string MedicalSupplies = "57864c8c245977548867e7f1";
|
||||
public static string Mod = "5448fe124bdc2da5018b4567";
|
||||
public static string Stock = "55818a594bdc2db9688b456a";
|
||||
public static string Foregrip = "55818af64bdc2d5b648b4570";
|
||||
public static string Mount = "55818b224bdc2dde698b456f";
|
||||
public static string Muzzle = "5448fe394bdc2d0d028b456c";
|
||||
public static string Sights = "5448fe7a4bdc2d6f028b456b";
|
||||
public static string Meds = "543be5664bdc2dd4348b4569";
|
||||
public static string Money = "543be5dd4bdc2deb348b4569";
|
||||
public static string Key = "543be5e94bdc2df1348b4568";
|
||||
public static string KeyMechanical = "5c99f98d86f7745c314214b3";
|
||||
public static string Keycard = "5c164d2286f774194c5e69fa";
|
||||
public static string Equipment = "543be5f84bdc2dd4348b456a";
|
||||
public static string ThrowWeap = "543be6564bdc2df4348b4568";
|
||||
public static string FoodDrink = "543be6674bdc2df1348b4569";
|
||||
public static string Pistol = "5447b5cf4bdc2d65278b4567";
|
||||
public static string Smg = "5447b5e04bdc2d62278b4567";
|
||||
public static string AssaultRifle = "5447b5f14bdc2d61278b4567";
|
||||
public static string AssaultCarbine = "5447b5fc4bdc2d87278b4567";
|
||||
public static string Shotgun = "5447b6094bdc2dc3278b4567";
|
||||
public static string MarksmanRifle = "5447b6194bdc2d67278b4567";
|
||||
public static string SniperRifle = "5447b6254bdc2dc3278b4568";
|
||||
public static string MachineGun = "5447bed64bdc2d97278b4568";
|
||||
public static string GrenadeLauncher = "5447bedf4bdc2d87278b4568";
|
||||
public static string SpecialWeapon = "5447bee84bdc2dc3278b4569";
|
||||
public static string SpecItem = "5447e0e74bdc2d3c308b4567";
|
||||
public static string Knife = "5447e1d04bdc2dff2f8b4567";
|
||||
public static string Ammo = "5485a8684bdc2da71d8b4567";
|
||||
public static string AmmoBox = "543be5cb4bdc2deb348b4568";
|
||||
public static string LootContainer = "566965d44bdc2d814c8b4571";
|
||||
public static string MobContainer = "5448bf274bdc2dfc2f8b456a";
|
||||
public static string SearchableItem = "566168634bdc2d144c8b456c";
|
||||
public static string Stash = "566abbb64bdc2d144c8b457d";
|
||||
public static string SortingTable = "6050cac987d3f925bf016837";
|
||||
public static string LockableContainer = "5671435f4bdc2d96058b4569";
|
||||
public static string SimpleContainer = "5795f317245977243854e041";
|
||||
public static string StationaryContainer = "567583764bdc2d98058b456e";
|
||||
public static string Armband = "5b3f15d486f77432d0509248";
|
||||
public static string DogTagUsec = "59f32c3b86f77472a31742f0";
|
||||
public static string DogTagBear = "59f32bb586f774757e1e8442";
|
||||
public static string Jewelry = "57864a3d24597754843f8721";
|
||||
public static string Electronics = "57864a66245977548f04a81f";
|
||||
public static string BuildingMaterial = "57864ada245977548638de91";
|
||||
public static string Tool = "57864bb7245977548b3b66c2";
|
||||
public static string HouseholdGoods = "57864c322459775490116fbf";
|
||||
public static string Lubricant = "57864e4c24597754843f8723";
|
||||
public static string Battery = "57864ee62459775490116fc1";
|
||||
public static string FunctionalMod = "550aa4154bdc2dd8348b456b";
|
||||
public static string GearMod = "55802f3e4bdc2de7118b4584";
|
||||
public static string MasterMod = "55802f4a4bdc2ddb688b4569";
|
||||
public static string Other = "590c745b86f7743cc433c5f2";
|
||||
public static string AssaultScope = "55818add4bdc2d5b648b456f";
|
||||
public static string ReflexSight = "55818ad54bdc2ddc698b4569";
|
||||
public static string TacticalCombo = "55818b164bdc2ddc698b456c";
|
||||
public static string Magazine = "5448bc234bdc2d3c308b4569";
|
||||
public static string LightLaser = "55818b0e4bdc2dde698b456e";
|
||||
public static string Silencer = "550aa4cd4bdc2dd8348b456c";
|
||||
public static string PortableRangeFinder = "61605ddea09d851a0a0c1bbc";
|
||||
public static string Item = "54009119af1c881c07000029";
|
||||
}
|
26
Model/Processing/BasicInfo.cs
Normal file
26
Model/Processing/BasicInfo.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using LootDumpProcessor.Model.Input;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Processing;
|
||||
|
||||
public class BasicInfo
|
||||
{
|
||||
public string Map { get; set; }
|
||||
public string FileHash { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public RootData Data { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public string FileName { get; set; }
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is BasicInfo info)
|
||||
return FileHash == info.FileHash;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return FileHash.GetHashCode();
|
||||
}
|
||||
}
|
8
Model/Processing/CaliberTemplateCount.cs
Normal file
8
Model/Processing/CaliberTemplateCount.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace LootDumpProcessor.Model.Processing;
|
||||
|
||||
public class CaliberTemplateCount
|
||||
{
|
||||
public string Caliber { get; set; }
|
||||
public string Template { get; set; }
|
||||
public int Count { get; set; }
|
||||
}
|
10
Model/Processing/DumpProcessData.cs
Normal file
10
Model/Processing/DumpProcessData.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using LootDumpProcessor.Storage;
|
||||
|
||||
namespace LootDumpProcessor.Model.Processing;
|
||||
|
||||
public class DumpProcessData
|
||||
{
|
||||
public Dictionary<string, IKey> LooseLootCounts { get; set; } = new();
|
||||
public List<PreProcessedStaticLoot> ContainerCounts { get; set; } = new();
|
||||
public Dictionary<string, int> MapCounts { get; set; } = new();
|
||||
}
|
23
Model/Processing/LooseLootCounts.cs
Normal file
23
Model/Processing/LooseLootCounts.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Storage;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Processing;
|
||||
|
||||
public class LooseLootCounts : IKeyable
|
||||
{
|
||||
[JsonProperty("__id__")]
|
||||
[JsonPropertyName("__id__")]
|
||||
public string __ID { get; set; } = Guid.NewGuid().ToString();
|
||||
|
||||
public IKey Counts { get; set; }
|
||||
|
||||
// public IKey Items { get; set; }
|
||||
public IKey ItemProperties { get; set; }
|
||||
public List<int> MapSpawnpointCount { get; set; } = new();
|
||||
|
||||
public IKey GetKey()
|
||||
{
|
||||
return new FlatUniqueKey(new[] { __ID });
|
||||
}
|
||||
}
|
31
Model/Processing/ParsedDump.cs
Normal file
31
Model/Processing/ParsedDump.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using LootDumpProcessor.Storage;
|
||||
|
||||
namespace LootDumpProcessor.Model.Processing;
|
||||
|
||||
public class ParsedDump : IKeyable
|
||||
{
|
||||
private static readonly Regex _hashRegex = new Regex("([^a-zA-Z0-9])");
|
||||
public BasicInfo BasicInfo { get; set; }
|
||||
public PreProcessedLooseLoot LooseLoot { get; set; }
|
||||
public List<PreProcessedStaticLoot> Containers { get; set; }
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is ParsedDump dump)
|
||||
return dump.BasicInfo.Equals(this.BasicInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.BasicInfo.GetHashCode();
|
||||
}
|
||||
|
||||
public IKey GetKey()
|
||||
{
|
||||
var sanitizedHash = _hashRegex.Replace(BasicInfo.FileHash, "");
|
||||
return new SubdivisionedUniqueKey(new[]
|
||||
{ "parsedDumps", BasicInfo.Map, $"{BasicInfo.FileName.Split("\\").Last().Replace(".", "")}-{sanitizedHash}" });
|
||||
}
|
||||
}
|
21
Model/Processing/PartialData.cs
Normal file
21
Model/Processing/PartialData.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using LootDumpProcessor.Storage;
|
||||
|
||||
namespace LootDumpProcessor.Model.Processing;
|
||||
|
||||
public class PartialData
|
||||
{
|
||||
public BasicInfo BasicInfo { get; set; }
|
||||
public IKey ParsedDumpKey { get; set; }
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is ParsedDump dump)
|
||||
return dump.BasicInfo.Equals(this.BasicInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.BasicInfo.GetHashCode();
|
||||
}
|
||||
}
|
19
Model/Processing/PreProcessedLooseLoot.cs
Normal file
19
Model/Processing/PreProcessedLooseLoot.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using LootDumpProcessor.Storage;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Processing;
|
||||
|
||||
public class PreProcessedLooseLoot : IKeyable
|
||||
{
|
||||
public Dictionary<string, int> Counts { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NewtonsoftJsonKeyConverter))]
|
||||
public IKey ItemProperties { get; set; }
|
||||
|
||||
public int MapSpawnpointCount { get; set; }
|
||||
|
||||
public IKey GetKey()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
8
Model/Processing/PreProcessedStaticLoot.cs
Normal file
8
Model/Processing/PreProcessedStaticLoot.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace LootDumpProcessor.Model.Processing;
|
||||
|
||||
public class PreProcessedStaticLoot
|
||||
{
|
||||
public string Type { get; set; }
|
||||
public string ContainerId { get; set; }
|
||||
public List<Item> Items { get; set; }
|
||||
}
|
25
Model/Repairable.cs
Normal file
25
Model/Repairable.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model
|
||||
{
|
||||
public class Repairable : ICloneable
|
||||
{
|
||||
[JsonProperty("Durability", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Durability")]
|
||||
public int? Durability { get; set; }
|
||||
|
||||
[JsonProperty("MaxDurability", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("MaxDurability")]
|
||||
public int? MaxDurability { get; set; }
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new Repairable
|
||||
{
|
||||
Durability = this.Durability,
|
||||
MaxDurability = this.MaxDurability
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
23
Model/Tarkov/Handbook.cs
Normal file
23
Model/Tarkov/Handbook.cs
Normal file
@ -0,0 +1,23 @@
|
||||
namespace LootDumpProcessor.Model.Tarkov;
|
||||
|
||||
public class Category
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string ParentId { get; set; }
|
||||
public string Icon { get; set; }
|
||||
public string Color { get; set; }
|
||||
public string Order { get; set; }
|
||||
}
|
||||
|
||||
public class HandbookItem
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string ParentId { get; set; }
|
||||
public int Price { get; set; }
|
||||
}
|
||||
|
||||
public class HandbookRoot
|
||||
{
|
||||
public List<Category> Categories { get; set; }
|
||||
public List<HandbookItem> Items { get; set; }
|
||||
}
|
152
Model/Tarkov/TemplateItems.cs
Normal file
152
Model/Tarkov/TemplateItems.cs
Normal file
@ -0,0 +1,152 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model.Tarkov;
|
||||
|
||||
public class TemplateFileItem
|
||||
{
|
||||
[JsonProperty("_id")]
|
||||
[JsonPropertyName("_id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonProperty("_name")]
|
||||
[JsonPropertyName("_name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("_parent")]
|
||||
[JsonPropertyName("_parent")]
|
||||
public string? Parent { get; set; }
|
||||
|
||||
[JsonProperty("_type")]
|
||||
[JsonPropertyName("_type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("_props")]
|
||||
[JsonPropertyName("_props")]
|
||||
public Props Props { get; set; }
|
||||
}
|
||||
|
||||
public class Props
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string ShortName { get; set; }
|
||||
public string Description { get; set; }
|
||||
public double? MaxDurability { get; set; }
|
||||
public string? Caliber { get; set; }
|
||||
|
||||
[JsonProperty("ammoCaliber")]
|
||||
[JsonPropertyName("ammoCaliber")]
|
||||
public string? AmmoCaliber { get; set; }
|
||||
|
||||
public bool QuestItem { get; set; }
|
||||
public int SpawnChance { get; set; }
|
||||
public List<string> SpawnFilter { get; set; }
|
||||
public List<Grid> Grids { get; set; }
|
||||
public string Rarity { get; set; }
|
||||
|
||||
public int ExtraSizeLeft { get; set; }
|
||||
public int ExtraSizeRight { get; set; }
|
||||
public int ExtraSizeUp { get; set; }
|
||||
public int ExtraSizeDown { get; set; }
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
public int? StackMinRandom { get; set; }
|
||||
public int? StackMaxRandom { get; set; }
|
||||
|
||||
public List<Chamber> Chambers { get; set; }
|
||||
public List<Slot> Slots { get; set; }
|
||||
|
||||
[JsonProperty("defAmmo")]
|
||||
[JsonPropertyName("defAmmo")]
|
||||
public string DefaultAmmo { get; set; }
|
||||
}
|
||||
|
||||
public class Grid
|
||||
{
|
||||
[JsonProperty("_props")]
|
||||
[JsonPropertyName("_props")]
|
||||
public GridProps Props { get; set; }
|
||||
}
|
||||
|
||||
public class GridProps
|
||||
{
|
||||
[JsonProperty("cellsH")]
|
||||
[JsonPropertyName("cellsH")]
|
||||
public int CellsHorizontal { get; set; }
|
||||
|
||||
[JsonProperty("cellsV")]
|
||||
[JsonPropertyName("cellsV")]
|
||||
public int CellsVertical { get; set; }
|
||||
|
||||
[JsonProperty("minCount")]
|
||||
[JsonPropertyName("minCount")]
|
||||
public int MinCount { get; set; }
|
||||
|
||||
[JsonProperty("maxCount")]
|
||||
[JsonPropertyName("maxCount")]
|
||||
public int MaxCount { get; set; }
|
||||
|
||||
[JsonProperty("filters")]
|
||||
[JsonPropertyName("filters")]
|
||||
public List<GridFilter> Filters { get; set; }
|
||||
}
|
||||
|
||||
public class GridFilter
|
||||
{
|
||||
}
|
||||
|
||||
public class Chamber
|
||||
{
|
||||
[JsonProperty("_name")]
|
||||
[JsonPropertyName("_name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("_id")]
|
||||
[JsonPropertyName("_id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonProperty("_parent")]
|
||||
[JsonPropertyName("_parent")]
|
||||
public string Parent { get; set; }
|
||||
|
||||
[JsonProperty("_props")]
|
||||
[JsonPropertyName("_props")]
|
||||
public ChamberProps Props { get; set; }
|
||||
|
||||
[JsonProperty("_required")]
|
||||
[JsonPropertyName("_required")]
|
||||
public bool Required { get; set; }
|
||||
|
||||
[JsonProperty("_mergeSlotWithChildren")]
|
||||
[JsonPropertyName("_mergeSlotWithChildren")]
|
||||
public bool MergeSlotWithChildren { get; set; }
|
||||
|
||||
[JsonProperty("_proto")]
|
||||
[JsonPropertyName("_proto")]
|
||||
public string Proto { get; set; }
|
||||
}
|
||||
|
||||
public class Slot
|
||||
{
|
||||
[JsonProperty("_name")]
|
||||
[JsonPropertyName("_name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("_required")]
|
||||
[JsonPropertyName("_required")]
|
||||
public bool Required { get; set; }
|
||||
}
|
||||
|
||||
public class ChamberProps
|
||||
{
|
||||
[JsonProperty("filters")]
|
||||
[JsonPropertyName("filters")]
|
||||
public List<FilterClass> Filters { get; set; }
|
||||
}
|
||||
|
||||
public class FilterClass
|
||||
{
|
||||
[JsonProperty("filter")]
|
||||
[JsonPropertyName("filter")]
|
||||
public List<string> Filter { get; set; }
|
||||
}
|
99
Model/Template.cs
Normal file
99
Model/Template.cs
Normal file
@ -0,0 +1,99 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Process.Processor;
|
||||
using LootDumpProcessor.Storage;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model
|
||||
{
|
||||
public class Template : IKeyable, ICloneable
|
||||
{
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public string __ID { get; } = Guid.NewGuid().ToString();
|
||||
|
||||
[JsonProperty("Id", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Id")]
|
||||
public string? Id { get; set; }
|
||||
|
||||
[JsonProperty("IsContainer", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("IsContainer")]
|
||||
public bool? IsContainer { get; set; }
|
||||
|
||||
[JsonProperty("useGravity", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("useGravity")]
|
||||
public bool? UseGravity { get; set; }
|
||||
|
||||
[JsonProperty("randomRotation", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("randomRotation")]
|
||||
public bool? RandomRotation { get; set; }
|
||||
|
||||
[JsonProperty("Position", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Position")]
|
||||
public Vector3? Position { get; set; }
|
||||
|
||||
[JsonProperty("Rotation", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Rotation")]
|
||||
public Vector3? Rotation { get; set; }
|
||||
|
||||
[JsonProperty("IsGroupPosition", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("IsGroupPosition")]
|
||||
public bool? IsGroupPosition { get; set; }
|
||||
|
||||
[JsonProperty("GroupPositions", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("GroupPositions")]
|
||||
public List<GroupPosition>? GroupPositions { get; set; }
|
||||
|
||||
[JsonProperty("IsAlwaysSpawn", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("IsAlwaysSpawn")]
|
||||
public bool? IsAlwaysSpawn { get; set; }
|
||||
|
||||
[JsonProperty("Root")]
|
||||
[JsonPropertyName("Root")]
|
||||
public string? Root { get; set; }
|
||||
|
||||
[JsonProperty("Items", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Items")]
|
||||
public List<Item>? Items { get; set; }
|
||||
|
||||
protected bool Equals(Template other)
|
||||
{
|
||||
return Id == other.Id;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((Template)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (Id != null ? Id.GetHashCode() : 0);
|
||||
}
|
||||
|
||||
public IKey GetKey()
|
||||
{
|
||||
return new FlatUniqueKey(new[] { __ID });
|
||||
}
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new Template
|
||||
{
|
||||
Id = this.Id,
|
||||
IsContainer = this.IsContainer,
|
||||
UseGravity = this.UseGravity,
|
||||
RandomRotation = this.RandomRotation,
|
||||
Position = ProcessorUtil.Copy(this.Position),
|
||||
Rotation = ProcessorUtil.Copy(this.Rotation),
|
||||
IsGroupPosition = this.IsGroupPosition,
|
||||
GroupPositions = ProcessorUtil.Copy(this.GroupPositions),
|
||||
IsAlwaysSpawn = this.IsAlwaysSpawn,
|
||||
Root = this.Root,
|
||||
Items = ProcessorUtil.Copy(this.Items)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
36
Model/Upd.cs
Normal file
36
Model/Upd.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LootDumpProcessor.Process.Processor;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model
|
||||
{
|
||||
public class Upd : ICloneable
|
||||
{
|
||||
[JsonProperty("StackObjectsCount", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("StackObjectsCount")]
|
||||
public int? StackObjectsCount { get; set; }
|
||||
|
||||
[JsonProperty("FireMode", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("FireMode")]
|
||||
public FireMode? FireMode { get; set; }
|
||||
|
||||
[JsonProperty("Foldable", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Foldable")]
|
||||
public Foldable? Foldable { get; set; }
|
||||
|
||||
[JsonProperty("Repairable", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("Repairable")]
|
||||
public Repairable? Repairable { get;set; }
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new Upd
|
||||
{
|
||||
StackObjectsCount = this.StackObjectsCount,
|
||||
FireMode = ProcessorUtil.Copy(this.FireMode),
|
||||
Foldable = ProcessorUtil.Copy(this.Foldable),
|
||||
Repairable = ProcessorUtil.Copy(this.Repairable)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
30
Model/Vector3.cs
Normal file
30
Model/Vector3.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LootDumpProcessor.Model
|
||||
{
|
||||
public class Vector3 : ICloneable
|
||||
{
|
||||
[JsonProperty("x", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("x")]
|
||||
public double? X { get; set; }
|
||||
|
||||
[JsonProperty("y", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("y")]
|
||||
public double? Y { get; set; }
|
||||
|
||||
[JsonProperty("z", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonPropertyName("z")]
|
||||
public double? Z { get; set; }
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new Vector3
|
||||
{
|
||||
X = this.X,
|
||||
Y = this.Y,
|
||||
Z = this.Z
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
10
Process/Collector/CollectorFactory.cs
Normal file
10
Process/Collector/CollectorFactory.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace LootDumpProcessor.Process.Collector;
|
||||
|
||||
public static class CollectorFactory
|
||||
{
|
||||
public static ICollector GetInstance()
|
||||
{
|
||||
// TODO: implement real factory
|
||||
return new HashSetCollector();
|
||||
}
|
||||
}
|
28
Process/Collector/HashSetCollector.cs
Normal file
28
Process/Collector/HashSetCollector.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using LootDumpProcessor.Model.Processing;
|
||||
|
||||
namespace LootDumpProcessor.Process.Collector;
|
||||
|
||||
public class HashSetCollector : ICollector
|
||||
{
|
||||
private HashSet<PartialData> processedDumps = new HashSet<PartialData>();
|
||||
|
||||
private object lockObject = new object();
|
||||
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
}
|
||||
|
||||
public void Hold(PartialData outputData)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
processedDumps.Add(outputData);
|
||||
}
|
||||
}
|
||||
|
||||
public List<PartialData> Retrieve()
|
||||
{
|
||||
return processedDumps.ToList();
|
||||
}
|
||||
}
|
12
Process/Collector/ICollector.cs
Normal file
12
Process/Collector/ICollector.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using LootDumpProcessor.Model.Config;
|
||||
using LootDumpProcessor.Model.Processing;
|
||||
|
||||
namespace LootDumpProcessor.Process.Collector;
|
||||
|
||||
public interface ICollector
|
||||
{
|
||||
void Setup();
|
||||
void Hold(PartialData parsedDump);
|
||||
|
||||
List<PartialData> Retrieve();
|
||||
}
|
6
Process/FilesGatherer.cs
Normal file
6
Process/FilesGatherer.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace LootDumpProcessor.Process;
|
||||
|
||||
public class FilesGatherer
|
||||
{
|
||||
|
||||
}
|
6
Process/IPipeline.cs
Normal file
6
Process/IPipeline.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace LootDumpProcessor.Process;
|
||||
|
||||
public interface IPipeline
|
||||
{
|
||||
void DoProcess();
|
||||
}
|
9
Process/OutputFileType.cs
Normal file
9
Process/OutputFileType.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace LootDumpProcessor.Process;
|
||||
|
||||
public enum OutputFileType
|
||||
{
|
||||
LooseLoot,
|
||||
StaticContainer,
|
||||
StaticLoot,
|
||||
StaticAmmo
|
||||
}
|
10
Process/PipelineFactory.cs
Normal file
10
Process/PipelineFactory.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace LootDumpProcessor.Process;
|
||||
|
||||
public static class PipelineFactory
|
||||
{
|
||||
public static IPipeline GetInstance()
|
||||
{
|
||||
// implement actual factory at some point
|
||||
return new QueuePipeline();
|
||||
}
|
||||
}
|
12
Process/Processor/DumpProcessor/DumpProcessorFactory.cs
Normal file
12
Process/Processor/DumpProcessor/DumpProcessorFactory.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace LootDumpProcessor.Process.Processor.DumpProcessor;
|
||||
|
||||
public static class DumpProcessorFactory
|
||||
{
|
||||
|
||||
public static IDumpProcessor GetInstance()
|
||||
{
|
||||
// Implement real factory
|
||||
return new MultithreadSteppedDumpProcessor();
|
||||
}
|
||||
|
||||
}
|
8
Process/Processor/DumpProcessor/IDumpProcessor.cs
Normal file
8
Process/Processor/DumpProcessor/IDumpProcessor.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using LootDumpProcessor.Model.Processing;
|
||||
|
||||
namespace LootDumpProcessor.Process.Processor.DumpProcessor;
|
||||
|
||||
public interface IDumpProcessor
|
||||
{
|
||||
Dictionary<OutputFileType, object> ProcessDumps(List<PartialData> dumps);
|
||||
}
|
@ -0,0 +1,300 @@
|
||||
using System.Collections.Concurrent;
|
||||
using LootDumpProcessor.Logger;
|
||||
using LootDumpProcessor.Model;
|
||||
using LootDumpProcessor.Model.Input;
|
||||
using LootDumpProcessor.Model.Output.StaticContainer;
|
||||
using LootDumpProcessor.Model.Processing;
|
||||
using LootDumpProcessor.Serializers.Json;
|
||||
using LootDumpProcessor.Storage;
|
||||
using LootDumpProcessor.Storage.Collections;
|
||||
|
||||
namespace LootDumpProcessor.Process.Processor.DumpProcessor;
|
||||
|
||||
public class MultithreadSteppedDumpProcessor : IDumpProcessor
|
||||
{
|
||||
private static IJsonSerializer _jsonSerializer = JsonSerializerFactory.GetInstance();
|
||||
|
||||
private static readonly List<Task> Runners = new();
|
||||
|
||||
private static readonly BlockingCollection<PartialData> _partialDataToProcess = new();
|
||||
|
||||
// if we need to, this variable can be moved to use the factory, but since the factory
|
||||
// needs a locking mechanism to prevent dictionary access exceptions, its better to keep
|
||||
// a reference to use here
|
||||
private static readonly IDataStorage _dataStorage = DataStorageFactory.GetInstance();
|
||||
|
||||
public Dictionary<OutputFileType, object> ProcessDumps(List<PartialData> dumps)
|
||||
{
|
||||
LoggerFactory.GetInstance().Log("Starting final dump processing", LogLevel.Info);
|
||||
var output = new Dictionary<OutputFileType, object>();
|
||||
|
||||
var dumpProcessData = GetDumpProcessData(dumps);
|
||||
LoggerFactory.GetInstance().Log("Heavy processing done!", LogLevel.Info);
|
||||
|
||||
var staticContainers = new Dictionary<string, MapStaticLoot>();
|
||||
var staticContainersLock = new object();
|
||||
// We need to count how many dumps we have for each map
|
||||
var mapDumpCounter = new Dictionary<string, int>();
|
||||
var mapDumpCounterLock = new object();
|
||||
// dictionary of maps, that has a dictionary of template and hit count
|
||||
var mapStaticContainersAggregated = new Dictionary<string, Dictionary<Template, int>>();
|
||||
var mapStaticContainersAggregatedLock = new object();
|
||||
|
||||
Runners.Clear();
|
||||
// BSG changed the map data so static containers are now dynamic, so we need to scan all dumps for the static containers.
|
||||
foreach (var dumped in dumps)
|
||||
{
|
||||
Runners.Add(
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
var data = _jsonSerializer.Deserialize<RootData>(File.ReadAllText(dumped.BasicInfo.FileName));
|
||||
// the if statement below will keep track of how many dumps we have for each map
|
||||
lock (mapDumpCounterLock)
|
||||
{
|
||||
if (mapDumpCounter.ContainsKey(data.Data.Name))
|
||||
mapDumpCounter[data.Data.Name] += 1;
|
||||
else
|
||||
mapDumpCounter.Add(data.Data.Name, 1);
|
||||
}
|
||||
// the if statement below takes care of processing "forced" or real static data for each map, we only need
|
||||
// to do this once per map, so we dont care about doing it again
|
||||
lock (staticContainersLock)
|
||||
{
|
||||
if (!staticContainers.ContainsKey(data.Data.Name))
|
||||
{
|
||||
var mapStaticLoot = StaticLootProcessor.CreateRealStaticContainers(data);
|
||||
staticContainers[mapStaticLoot.Item1] = mapStaticLoot.Item2;
|
||||
}
|
||||
}
|
||||
|
||||
// the section below takes care of finding how many "dynamic static containers" we have on the map
|
||||
Dictionary<Template, int> mapAggregatedData;
|
||||
lock (mapStaticContainersAggregatedLock)
|
||||
{
|
||||
if (!mapStaticContainersAggregated.TryGetValue(data.Data.Name, out mapAggregatedData))
|
||||
{
|
||||
mapAggregatedData = new Dictionary<Template, int>();
|
||||
mapStaticContainersAggregated.Add(data.Data.Name, mapAggregatedData);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var dynamicStaticContainer in StaticLootProcessor.CreateDynamicStaticContainers(data))
|
||||
{
|
||||
lock (mapStaticContainersAggregatedLock)
|
||||
{
|
||||
if (mapAggregatedData.ContainsKey(dynamicStaticContainer))
|
||||
mapAggregatedData[dynamicStaticContainer] += 1;
|
||||
else
|
||||
mapAggregatedData.Add(dynamicStaticContainer, 1);
|
||||
}
|
||||
}
|
||||
|
||||
GCHandler.Collect();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
Task.WaitAll(Runners.ToArray());
|
||||
// Aggregate and calculate the probability of a static container
|
||||
mapStaticContainersAggregated.ToDictionary(
|
||||
kv => kv.Key,
|
||||
kv => kv.Value.Select(
|
||||
td => new StaticDataPoint
|
||||
{
|
||||
Template = td.Key,
|
||||
Probability = Math.Round((double)((decimal)td.Value / (decimal)mapDumpCounter[kv.Key]), 2)
|
||||
}
|
||||
).ToList()
|
||||
).ToList().ForEach(kv => staticContainers[kv.Key].StaticContainers = kv.Value);
|
||||
|
||||
// Static containers
|
||||
output.Add(OutputFileType.StaticContainer, staticContainers);
|
||||
|
||||
// Ammo distribution
|
||||
output.Add(
|
||||
OutputFileType.StaticAmmo,
|
||||
StaticLootProcessor.CreateAmmoDistribution(dumpProcessData.ContainerCounts)
|
||||
);
|
||||
|
||||
// Static loot distribution
|
||||
output.Add(
|
||||
OutputFileType.StaticLoot,
|
||||
StaticLootProcessor.CreateStaticLootDistribution(dumpProcessData.ContainerCounts)
|
||||
);
|
||||
|
||||
// Loose loot distribution
|
||||
var looseLootDistribution = LooseLootProcessor.CreateLooseLootDistribution(
|
||||
dumpProcessData.MapCounts,
|
||||
dumpProcessData.LooseLootCounts
|
||||
);
|
||||
|
||||
var loot = dumpProcessData.MapCounts
|
||||
.Select(mapCount => mapCount.Key)
|
||||
.ToDictionary(mi => mi, mi => looseLootDistribution[mi]);
|
||||
|
||||
output.Add(OutputFileType.LooseLoot, loot);
|
||||
return output;
|
||||
}
|
||||
|
||||
private DumpProcessData GetDumpProcessData(List<PartialData> dumps)
|
||||
{
|
||||
var dumpProcessData = new DumpProcessData();
|
||||
|
||||
dumps.GroupBy(x => x.BasicInfo.Map)
|
||||
.ToList()
|
||||
.ForEach(tuple =>
|
||||
{
|
||||
var mapi = tuple.Key;
|
||||
var g = tuple.ToList();
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"Processing map {mapi}, total dump data to process: {g.Count}",
|
||||
LogLevel.Info
|
||||
);
|
||||
dumpProcessData.MapCounts[mapi] = g.Count;
|
||||
|
||||
var lockObjectContainerCounts = new object();
|
||||
|
||||
var lockObjectCounts = new object();
|
||||
var counts = new LooseLootCounts();
|
||||
|
||||
var lockObjectDictionaryCounts = new object();
|
||||
var dictionaryCounts = new FlatKeyableDictionary<string, int>();
|
||||
counts.Counts = dictionaryCounts.GetKey();
|
||||
|
||||
/*
|
||||
var dictionaryItemCounts = new FlatKeyableDictionary<string, List<string>>();
|
||||
counts.Items = dictionaryItemCounts.GetKey();
|
||||
*/
|
||||
|
||||
var lockObjectDictionaryItemProperties = new object();
|
||||
var dictionaryItemProperties = new FlatKeyableDictionary<string, FlatKeyableList<Template>>();
|
||||
|
||||
var actualDictionaryItemProperties = new FlatKeyableDictionary<string, IKey>();
|
||||
counts.ItemProperties = actualDictionaryItemProperties.GetKey();
|
||||
|
||||
dumpProcessData.LooseLootCounts.Add(mapi, counts.GetKey());
|
||||
// add the items to the queue
|
||||
foreach (var gi in g)
|
||||
{
|
||||
_partialDataToProcess.Add(gi);
|
||||
}
|
||||
|
||||
// Call GC before running threads
|
||||
g = null;
|
||||
tuple = null;
|
||||
GCHandler.Collect();
|
||||
|
||||
// The data storage factory has a lock, we dont want the locks to occur when multithreading
|
||||
|
||||
for (int i = 0; i < LootDumpProcessorContext.GetConfig().Threads; i++)
|
||||
{
|
||||
Runners.Add(
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
while (_partialDataToProcess.TryTake(out var partialData,
|
||||
TimeSpan.FromMilliseconds(5000)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var dumpData = _dataStorage.GetItem<ParsedDump>(partialData.ParsedDumpKey);
|
||||
lock (lockObjectContainerCounts)
|
||||
{
|
||||
dumpProcessData.ContainerCounts.AddRange(dumpData.Containers);
|
||||
}
|
||||
|
||||
// loose loot into ids on files
|
||||
var loadedDictionary =
|
||||
_dataStorage
|
||||
.GetItem<SubdivisionedKeyableDictionary<string, List<Template>>>(
|
||||
dumpData.LooseLoot.ItemProperties
|
||||
);
|
||||
foreach (var (k, v) in loadedDictionary)
|
||||
{
|
||||
var count = dumpData.LooseLoot.Counts[k];
|
||||
lock (lockObjectDictionaryCounts)
|
||||
{
|
||||
if (dictionaryCounts.ContainsKey(k))
|
||||
dictionaryCounts[k] += count;
|
||||
else
|
||||
dictionaryCounts[k] = count;
|
||||
}
|
||||
|
||||
/*
|
||||
var itemList = dumpData.LooseLoot.Items[k];
|
||||
if (!dictionaryItemCounts.TryGetValue(k, out var itemCounts))
|
||||
{
|
||||
itemCounts = new List<string>();
|
||||
dictionaryItemCounts.Add(k, itemCounts);
|
||||
}
|
||||
itemCounts.AddRange(itemList);
|
||||
*/
|
||||
|
||||
lock (lockObjectDictionaryItemProperties)
|
||||
{
|
||||
if (!dictionaryItemProperties.TryGetValue(k, out var values))
|
||||
{
|
||||
values = new FlatKeyableList<Template>();
|
||||
dictionaryItemProperties.Add(k, values);
|
||||
actualDictionaryItemProperties.Add(k, values.GetKey());
|
||||
}
|
||||
|
||||
values.AddRange(v);
|
||||
}
|
||||
}
|
||||
|
||||
lock (lockObjectCounts)
|
||||
{
|
||||
counts.MapSpawnpointCount.AddRange(new List<int>
|
||||
{
|
||||
dumpData.LooseLoot.MapSpawnpointCount
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"ERROR OCCURRED:{e.Message}\n{e.StackTrace}",
|
||||
LogLevel.Error
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
TaskCreationOptions.LongRunning)
|
||||
);
|
||||
}
|
||||
|
||||
// Wait until all runners are done processing
|
||||
while (!Runners.All(r => r.IsCompleted))
|
||||
{
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"One or more file processors are still processing files. Waiting {LootDumpProcessorContext.GetConfig().ThreadPoolingTimeoutMs}ms before checking again",
|
||||
LogLevel.Info
|
||||
);
|
||||
Thread.Sleep(
|
||||
TimeSpan.FromMilliseconds(LootDumpProcessorContext.GetConfig().ThreadPoolingTimeoutMs));
|
||||
}
|
||||
|
||||
foreach (var (_, value) in dictionaryItemProperties)
|
||||
{
|
||||
_dataStorage.Store(value);
|
||||
}
|
||||
|
||||
_dataStorage.Store(dictionaryCounts);
|
||||
dictionaryCounts = null;
|
||||
GCHandler.Collect();
|
||||
/*
|
||||
DataStorageFactory.GetInstance().Store(dictionaryItemCounts);
|
||||
dictionaryItemCounts = null;
|
||||
GC.Collect();
|
||||
*/
|
||||
_dataStorage.Store(actualDictionaryItemProperties);
|
||||
actualDictionaryItemProperties = null;
|
||||
GCHandler.Collect();
|
||||
_dataStorage.Store(counts);
|
||||
counts = null;
|
||||
GCHandler.Collect();
|
||||
});
|
||||
return dumpProcessData;
|
||||
}
|
||||
}
|
52
Process/Processor/FileProcessor/FileProcessor.cs
Normal file
52
Process/Processor/FileProcessor/FileProcessor.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using LootDumpProcessor.Logger;
|
||||
using LootDumpProcessor.Model;
|
||||
using LootDumpProcessor.Model.Processing;
|
||||
using LootDumpProcessor.Process.Processor;
|
||||
using LootDumpProcessor.Storage;
|
||||
|
||||
namespace LootDumpProcessor.Process.Impl;
|
||||
|
||||
public class FileProcessor : IFileProcessor
|
||||
{
|
||||
public PartialData Process(BasicInfo parsedData)
|
||||
{
|
||||
LoggerFactory.GetInstance().Log($"Processing file {parsedData.FileName}...", LogLevel.Info);
|
||||
List<Template> looseLoot = new List<Template>();
|
||||
List<Template> staticLoot = new List<Template>();
|
||||
|
||||
foreach (var item in parsedData.Data.Data.Loot)
|
||||
{
|
||||
if (item.IsContainer ?? false)
|
||||
staticLoot.Add(item);
|
||||
else
|
||||
looseLoot.Add(item);
|
||||
}
|
||||
|
||||
parsedData.Data = null;
|
||||
|
||||
var dumpData = new ParsedDump
|
||||
{
|
||||
BasicInfo = parsedData
|
||||
};
|
||||
|
||||
PartialData data = new PartialData
|
||||
{
|
||||
BasicInfo = parsedData,
|
||||
ParsedDumpKey = (AbstractKey)dumpData.GetKey()
|
||||
};
|
||||
|
||||
if (!DataStorageFactory.GetInstance().Exists(dumpData.GetKey()))
|
||||
{
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"Cached not found for {string.Join("/", dumpData.GetKey().GetLookupIndex())} processing.",
|
||||
LogLevel.Info
|
||||
);
|
||||
dumpData.Containers = StaticLootProcessor.PreProcessStaticLoot(staticLoot);
|
||||
dumpData.LooseLoot = LooseLootProcessor.PreProcessLooseLoot(looseLoot);
|
||||
DataStorageFactory.GetInstance().Store(dumpData);
|
||||
}
|
||||
|
||||
LoggerFactory.GetInstance().Log($"File {parsedData.FileName} finished processing!", LogLevel.Info);
|
||||
return data;
|
||||
}
|
||||
}
|
12
Process/Processor/FileProcessor/FileProcessorFactory.cs
Normal file
12
Process/Processor/FileProcessor/FileProcessorFactory.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using LootDumpProcessor.Process.Impl;
|
||||
|
||||
namespace LootDumpProcessor.Process.Processor;
|
||||
|
||||
public static class FileProcessorFactory
|
||||
{
|
||||
public static IFileProcessor GetInstance()
|
||||
{
|
||||
// implement actual factory someday
|
||||
return new FileProcessor();
|
||||
}
|
||||
}
|
8
Process/Processor/FileProcessor/IFileProcessor.cs
Normal file
8
Process/Processor/FileProcessor/IFileProcessor.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using LootDumpProcessor.Model.Processing;
|
||||
|
||||
namespace LootDumpProcessor.Process;
|
||||
|
||||
public interface IFileProcessor
|
||||
{
|
||||
PartialData Process(BasicInfo parsedData);
|
||||
}
|
262
Process/Processor/LooseLootProcessor.cs
Normal file
262
Process/Processor/LooseLootProcessor.cs
Normal file
@ -0,0 +1,262 @@
|
||||
using LootDumpProcessor.Logger;
|
||||
using LootDumpProcessor.Model;
|
||||
using LootDumpProcessor.Model.Output;
|
||||
using LootDumpProcessor.Model.Output.LooseLoot;
|
||||
using LootDumpProcessor.Model.Processing;
|
||||
using LootDumpProcessor.Storage;
|
||||
using LootDumpProcessor.Storage.Collections;
|
||||
using NumSharp;
|
||||
|
||||
namespace LootDumpProcessor.Process.Processor;
|
||||
|
||||
public class LooseLootProcessor
|
||||
{
|
||||
public static PreProcessedLooseLoot PreProcessLooseLoot(List<Template> looseloot)
|
||||
{
|
||||
var looseloot_ci = new PreProcessedLooseLoot
|
||||
{
|
||||
Counts = new Dictionary<string, int>()
|
||||
};
|
||||
var temporalItemProperties = new SubdivisionedKeyableDictionary<string, List<Template>>();
|
||||
looseloot_ci.ItemProperties = (AbstractKey)temporalItemProperties.GetKey();
|
||||
looseloot_ci.MapSpawnpointCount = looseloot.Count;
|
||||
var uniqueIds = new Dictionary<string, object>();
|
||||
// sometimes the rotation changes very slightly in the dumps for the same location / rotation spawnpoint
|
||||
// use rounding to make sure it is not generated to two spawnpoint
|
||||
|
||||
foreach (var looseLootTemplate in looseloot)
|
||||
{
|
||||
// the bsg ids are insane.
|
||||
// Sometimes the last 7 digits vary but they spawn the same item at the same position
|
||||
// e.g. for the quest item "60a3b65c27adf161da7b6e14" at "loot_bunker_quest (3)555192"
|
||||
// so the first approach was to remove the last digits.
|
||||
// We then saw, that sometimes when the last digits differ for the same string, also the position
|
||||
// differs.
|
||||
// We decided to group over the position/rotation/useGravity since they make out a distinct spot
|
||||
var saneId = looseLootTemplate.GetSaneId();
|
||||
if (!uniqueIds.ContainsKey(saneId))
|
||||
{
|
||||
uniqueIds[saneId] = looseLootTemplate.Id;
|
||||
if (looseloot_ci.Counts.ContainsKey(saneId))
|
||||
looseloot_ci.Counts[saneId]++;
|
||||
else
|
||||
looseloot_ci.Counts[saneId] = 1;
|
||||
}
|
||||
|
||||
if (!temporalItemProperties.TryGetValue(saneId, out var templates))
|
||||
{
|
||||
templates = new FlatKeyableList<Template>();
|
||||
temporalItemProperties.Add(saneId, templates);
|
||||
}
|
||||
|
||||
templates.Add(looseLootTemplate);
|
||||
}
|
||||
|
||||
DataStorageFactory.GetInstance().Store(temporalItemProperties);
|
||||
return looseloot_ci;
|
||||
}
|
||||
|
||||
public static Dictionary<string, LooseLootRoot> CreateLooseLootDistribution(
|
||||
Dictionary<string, int> map_counts,
|
||||
Dictionary<string, IKey> looseloot_counts
|
||||
)
|
||||
{
|
||||
var forcedConfidence = LootDumpProcessorContext.GetConfig().ProcessorConfig.SpawnPointToleranceForForced / 100;
|
||||
var probabilities = new Dictionary<string, Dictionary<string, double>>();
|
||||
var looseLootDistribution = new Dictionary<string, LooseLootRoot>();
|
||||
foreach (var _tup_1 in map_counts)
|
||||
{
|
||||
var mapName = _tup_1.Key;
|
||||
var mapCount = _tup_1.Value;
|
||||
probabilities[mapName] = new Dictionary<string, double>();
|
||||
var looseLootCounts = DataStorageFactory.GetInstance().GetItem<LooseLootCounts>(looseloot_counts[mapName]);
|
||||
|
||||
var counts = DataStorageFactory.GetInstance()
|
||||
.GetItem<FlatKeyableDictionary<string, int>>(looseLootCounts.Counts);
|
||||
foreach (var (idi, cnt) in counts)
|
||||
{
|
||||
probabilities[mapName][idi] = (double)((decimal)cnt / mapCount);
|
||||
}
|
||||
|
||||
// No longer used, dispose
|
||||
counts = null;
|
||||
|
||||
looseLootDistribution[mapName] = new LooseLootRoot
|
||||
{
|
||||
SpawnPointCount = new SpawnPointCount
|
||||
{
|
||||
Mean = np.mean(np.array(looseLootCounts.MapSpawnpointCount)),
|
||||
Std = np.std(np.array(looseLootCounts.MapSpawnpointCount))
|
||||
},
|
||||
SpawnPointsForced = new List<SpawnPointsForced>(),
|
||||
SpawnPoints = new List<SpawnPoint>()
|
||||
};
|
||||
|
||||
var itemProperties = DataStorageFactory.GetInstance()
|
||||
.GetItem<FlatKeyableDictionary<string, IKey>>(looseLootCounts.ItemProperties);
|
||||
foreach (var (spawnPoint, itemList) in itemProperties)
|
||||
{
|
||||
var itemsCounts = new Dictionary<ComposedKey, int>();
|
||||
|
||||
var savedItemProperties = DataStorageFactory.GetInstance().GetItem<FlatKeyableList<Template>>(itemList);
|
||||
foreach (var savedTemplateProperties in savedItemProperties)
|
||||
{
|
||||
var key = new ComposedKey(savedTemplateProperties);
|
||||
if (itemsCounts.ContainsKey(key))
|
||||
itemsCounts[key] += 1;
|
||||
else
|
||||
itemsCounts[key] = 1;
|
||||
}
|
||||
|
||||
// Group by arguments to create possible positions / rotations per spawnpoint
|
||||
|
||||
// check if grouping is unique
|
||||
var itemListSorted = savedItemProperties.Select(template => (template.GetSaneId(), template))
|
||||
.GroupBy(g => g.Item1).ToList();
|
||||
|
||||
if (itemListSorted.Count > 1)
|
||||
{
|
||||
throw new Exception("More than one saneKey found");
|
||||
}
|
||||
|
||||
var spawnPoints = itemListSorted.First().Select(v => v.template).ToList();
|
||||
var locationId = spawnPoints[0].GetLocationId();
|
||||
var template = ProcessorUtil.Copy(spawnPoints[0]);
|
||||
//template.Root = null; // Why do we do this, not null in bsg data
|
||||
var itemDistribution = itemsCounts.Select(kv => new ItemDistribution
|
||||
{
|
||||
ComposedKey = kv.Key,
|
||||
RelativeProbability = kv.Value
|
||||
}).ToList();
|
||||
|
||||
// If any of the items is a quest item or forced loose loot items, or the item normally appreas 99.5%
|
||||
if (itemDistribution.Any(item =>
|
||||
LootDumpProcessorContext.GetTarkovItems().IsQuestItem(item.ComposedKey?.FirstItem?.Tpl) ||
|
||||
LootDumpProcessorContext.GetForcedLooseItems()[mapName].Contains(item.ComposedKey?.FirstItem?.Tpl))
|
||||
)
|
||||
{
|
||||
var spawnPointToAdd = new SpawnPointsForced
|
||||
{
|
||||
LocationId = locationId,
|
||||
Probability = probabilities[mapName][spawnPoint],
|
||||
Template = template
|
||||
};
|
||||
looseLootDistribution[mapName].SpawnPointsForced.Add(spawnPointToAdd);
|
||||
}
|
||||
else if (probabilities[mapName][spawnPoint] > forcedConfidence)
|
||||
{
|
||||
var spawnPointToAdd = new SpawnPointsForced
|
||||
{
|
||||
LocationId = locationId,
|
||||
Probability = probabilities[mapName][spawnPoint],
|
||||
Template = template
|
||||
};
|
||||
looseLootDistribution[mapName].SpawnPointsForced.Add(spawnPointToAdd);
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"Item: {template.Id} has > {LootDumpProcessorContext.GetConfig().ProcessorConfig.SpawnPointToleranceForForced}% spawn chance in spawn point: {spawnPointToAdd.LocationId} but isn't in forced loot, adding to forced",
|
||||
LogLevel.Warning
|
||||
);
|
||||
}
|
||||
else // Normal spawn point, add to non-forced spawnpoint array
|
||||
{
|
||||
var spawnPointToAdd = new SpawnPoint
|
||||
{
|
||||
LocationId = locationId,
|
||||
Probability = probabilities[mapName][spawnPoint],
|
||||
Template = template,
|
||||
ItemDistribution = itemDistribution
|
||||
};
|
||||
|
||||
template.Items = new List<Item>();
|
||||
|
||||
var group = spawnPoints.GroupBy(template => new ComposedKey(template))
|
||||
.ToDictionary(g => g.Key, g => g.ToList());
|
||||
foreach (var distribution in itemDistribution)
|
||||
{
|
||||
if (group.TryGetValue(distribution.ComposedKey, out var items))
|
||||
{
|
||||
// We need to reparent the IDs to match the composed key ID
|
||||
var itemDistributionItemList = items.First().Items;
|
||||
// Find the item with no parent id, this is essentially the "Root" of the actual item
|
||||
var firstItemInTemplate =
|
||||
itemDistributionItemList.Find(i => string.IsNullOrEmpty(i.ParentId));
|
||||
// Save the original ID reference, we need to replace it on child items
|
||||
var originalId = firstItemInTemplate.Id;
|
||||
// Put the composed key instead
|
||||
firstItemInTemplate.Id = distribution.ComposedKey.Key;
|
||||
// Reparent any items with the original id on it
|
||||
itemDistributionItemList.Where(i => i.ParentId == originalId)
|
||||
.ToList()
|
||||
.ForEach(i => i.ParentId = firstItemInTemplate.Id);
|
||||
|
||||
template.Items.AddRange(itemDistributionItemList);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"Item template {distribution.ComposedKey?.FirstItem?.Tpl} was on loose loot distribution for spawn point {template.Id} but the spawn points didnt contain a template matching it.",
|
||||
LogLevel.Error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
looseLootDistribution[mapName].SpawnPoints.Add(spawnPointToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
// # Test for duplicate position
|
||||
// # we removed most of them by "rounding away" the jitter in rotation,
|
||||
// # there are still a few duplicate locations with distinct difference in rotation left though
|
||||
// group_fun = lambda x: (
|
||||
// x["template"]["Position"]["x"],
|
||||
// x["template"]["Position"]["y"],
|
||||
// x["template"]["Position"]["z"],
|
||||
// )
|
||||
// test = sorted(loose_loot_distribution[mi]["spawnpoints"], key=group_fun)
|
||||
// test_grouped = groupby(test, group_fun)
|
||||
// test_len = []
|
||||
// for k, g in test_grouped:
|
||||
// gl = list(g)
|
||||
// test_len.append(len(gl))
|
||||
// if len(gl) > 1:
|
||||
// print(gl)
|
||||
//
|
||||
// print(mi, np.unique(test_len, return_counts=True))
|
||||
looseLootDistribution[mapName].SpawnPoints =
|
||||
looseLootDistribution[mapName].SpawnPoints.OrderBy(x => x.Template.Id).ToList();
|
||||
// Cross check with forced loot in dumps vs items defined in forced_loose.yaml
|
||||
var forcedTplsInConfig = new HashSet<string>(
|
||||
(from forceditem in LootDumpProcessorContext.GetForcedLooseItems()[mapName]
|
||||
select forceditem).ToList());
|
||||
var forcedTplsFound = new HashSet<string>(
|
||||
(from forceditem in looseLootDistribution[mapName].SpawnPointsForced
|
||||
select forceditem.Template.Items[0].Tpl).ToList());
|
||||
|
||||
// All the tpls that are defined in the forced_loose.yaml for this map that are not found as forced
|
||||
foreach (var itemTpl in forcedTplsInConfig)
|
||||
{
|
||||
if (!forcedTplsFound.Contains(itemTpl))
|
||||
{
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"Expected item: {itemTpl} defined in forced_loose.yaml config not found in forced loot",
|
||||
LogLevel.Error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// All the tpls that are found as forced in output file but not in the forced_loose.yaml config
|
||||
foreach (var itemTpl in forcedTplsFound)
|
||||
{
|
||||
if (!forcedTplsInConfig.Contains(itemTpl))
|
||||
{
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"Map: {mapName} Item: {itemTpl} not defined in forced_loose.yaml config but was flagged as forced by code",
|
||||
LogLevel.Warning
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return looseLootDistribution;
|
||||
}
|
||||
}
|
161
Process/Processor/StaticLootProcessor.cs
Normal file
161
Process/Processor/StaticLootProcessor.cs
Normal file
@ -0,0 +1,161 @@
|
||||
using LootDumpProcessor.Model;
|
||||
using LootDumpProcessor.Model.Input;
|
||||
using LootDumpProcessor.Model.Output;
|
||||
using LootDumpProcessor.Model.Output.StaticContainer;
|
||||
using LootDumpProcessor.Model.Processing;
|
||||
|
||||
namespace LootDumpProcessor.Process.Processor;
|
||||
|
||||
public class StaticLootProcessor
|
||||
{
|
||||
public static List<PreProcessedStaticLoot> PreProcessStaticLoot(List<Template> staticloot)
|
||||
{
|
||||
var containers = new List<PreProcessedStaticLoot>();
|
||||
foreach (var li in staticloot)
|
||||
{
|
||||
var tpl = li.Items[0].Tpl;
|
||||
if (!LootDumpProcessorContext.GetStaticWeaponIds().Contains(tpl))
|
||||
{
|
||||
containers.Add(new PreProcessedStaticLoot
|
||||
{
|
||||
Type = tpl,
|
||||
ContainerId = li.Items[0].Id,
|
||||
Items = li.Items.Skip(1).ToList()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return containers;
|
||||
}
|
||||
|
||||
public static Tuple<string, MapStaticLoot> CreateRealStaticContainers(RootData rawMapDump)
|
||||
{
|
||||
List<StaticForced> forcedStaticItems;
|
||||
var mapName = rawMapDump.Data.Name;
|
||||
var staticLootPositions = (from li in rawMapDump.Data.Loot
|
||||
where li.IsContainer ?? false
|
||||
select li).ToList();
|
||||
var staticWeapons = new List<Template>();
|
||||
staticLootPositions = staticLootPositions.OrderBy(x => x.Id).ToList();
|
||||
foreach (var staticLootPosition in staticLootPositions)
|
||||
{
|
||||
var itemTpl = staticLootPosition.Items[0].Tpl;
|
||||
if (LootDumpProcessorContext.GetStaticWeaponIds().Contains(itemTpl))
|
||||
{
|
||||
staticWeapons.Add(ProcessorUtil.Copy(staticLootPosition));
|
||||
}
|
||||
}
|
||||
|
||||
forcedStaticItems = LootDumpProcessorContext.GetForcedItems().ContainsKey(mapName)
|
||||
? LootDumpProcessorContext.GetForcedItems()[mapName]
|
||||
: new List<StaticForced>();
|
||||
|
||||
var mapStaticData = new MapStaticLoot
|
||||
{
|
||||
StaticWeapons = staticWeapons,
|
||||
StaticForced = forcedStaticItems
|
||||
};
|
||||
return Tuple.Create(mapName, mapStaticData);
|
||||
}
|
||||
|
||||
public static List<Template> CreateDynamicStaticContainers(RootData rawMapDump)
|
||||
{
|
||||
return (from li in rawMapDump.Data.Loot
|
||||
where (li.IsContainer ?? false) && (!LootDumpProcessorContext.GetStaticWeaponIds().Contains(li.Id))
|
||||
select li).ToList();
|
||||
}
|
||||
|
||||
public static Dictionary<string, List<AmmoDistribution>> CreateAmmoDistribution(
|
||||
List<PreProcessedStaticLoot> container_counts
|
||||
)
|
||||
{
|
||||
var ammo = new List<string>();
|
||||
foreach (var ci in container_counts)
|
||||
{
|
||||
ammo.AddRange(from item in ci.Items
|
||||
where LootDumpProcessorContext.GetTarkovItems().IsBaseClass(item.Tpl, BaseClasses.Ammo)
|
||||
select item.Tpl);
|
||||
}
|
||||
|
||||
var ammo_counts = new List<CaliberTemplateCount>();
|
||||
ammo_counts.AddRange(
|
||||
ammo.GroupBy(a => a)
|
||||
.Select(g => new CaliberTemplateCount
|
||||
{
|
||||
Caliber = LootDumpProcessorContext.GetTarkovItems().AmmoCaliber(g.Key),
|
||||
Template = g.Key,
|
||||
Count = g.Count()
|
||||
})
|
||||
);
|
||||
ammo_counts = ammo_counts.OrderBy(x => x.Caliber).ToList();
|
||||
var ammo_distribution = new Dictionary<string, List<AmmoDistribution>>();
|
||||
foreach (var _tup_3 in ammo_counts.GroupBy(x => x.Caliber))
|
||||
{
|
||||
var k = _tup_3.Key;
|
||||
var g = _tup_3.ToList();
|
||||
ammo_distribution[k] = (from gi in g
|
||||
select new AmmoDistribution
|
||||
{
|
||||
Tpl = gi.Template,
|
||||
RelativeProbability = gi.Count
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
return ammo_distribution;
|
||||
}
|
||||
|
||||
public static Dictionary<string, StaticItemDistribution> CreateStaticLootDistribution(
|
||||
List<PreProcessedStaticLoot> container_counts
|
||||
)
|
||||
{
|
||||
var static_loot_distribution = new Dictionary<string, StaticItemDistribution>();
|
||||
var types = Enumerable.Distinct((from ci in container_counts
|
||||
select ci.Type).ToList());
|
||||
|
||||
foreach (var typei in types)
|
||||
{
|
||||
var container_counts_selected = (from ci in container_counts
|
||||
where ci.Type == typei
|
||||
select ci).ToList();
|
||||
var itemscounts = new List<int>();
|
||||
foreach (var ci in container_counts_selected)
|
||||
{
|
||||
itemscounts.Add((from cii in ci.Items
|
||||
where cii.ParentId == ci.ContainerId
|
||||
select cii).ToList().Count);
|
||||
}
|
||||
|
||||
static_loot_distribution[typei] = new StaticItemDistribution();
|
||||
static_loot_distribution[typei].ItemCountDistribution = itemscounts.GroupBy(i => i)
|
||||
.Select(g => new ItemCountDistribution
|
||||
{
|
||||
Count = g.Key,
|
||||
RelativeProbability = g.Count()
|
||||
}).ToList();
|
||||
// TODO: Change for different algo that splits items per parent once parentid = containerid, then compose
|
||||
// TODO: key and finally create distribution based on composed Id instead
|
||||
var itemsHitCounts = new Dictionary<string, int>();
|
||||
foreach (var ci in container_counts_selected)
|
||||
{
|
||||
foreach (var cii in ci.Items)
|
||||
{
|
||||
if (cii.ParentId == ci.ContainerId)
|
||||
{
|
||||
if (itemsHitCounts.ContainsKey(cii.Tpl))
|
||||
itemsHitCounts[cii.Tpl] += 1;
|
||||
else
|
||||
itemsHitCounts[cii.Tpl] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static_loot_distribution[typei].ItemDistribution = itemsHitCounts.Select(v => new StaticDistribution
|
||||
{
|
||||
Tpl = v.Key,
|
||||
RelativeProbability = v.Value
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
return static_loot_distribution;
|
||||
}
|
||||
}
|
200
Process/QueuePipeline.cs
Normal file
200
Process/QueuePipeline.cs
Normal file
@ -0,0 +1,200 @@
|
||||
using System.Collections.Concurrent;
|
||||
using LootDumpProcessor.Logger;
|
||||
using LootDumpProcessor.Process.Collector;
|
||||
using LootDumpProcessor.Process.Processor;
|
||||
using LootDumpProcessor.Process.Processor.DumpProcessor;
|
||||
using LootDumpProcessor.Process.Reader;
|
||||
using LootDumpProcessor.Process.Reader.Filters;
|
||||
using LootDumpProcessor.Process.Reader.PreProcess;
|
||||
using LootDumpProcessor.Process.Writer;
|
||||
|
||||
namespace LootDumpProcessor.Process;
|
||||
|
||||
public class QueuePipeline : IPipeline
|
||||
{
|
||||
private static readonly BlockingCollection<string> _filesToProcess = new();
|
||||
private static readonly List<Task> Runners = new();
|
||||
|
||||
private static readonly Dictionary<string, IPreProcessReader> _preProcessReaders;
|
||||
|
||||
static QueuePipeline()
|
||||
{
|
||||
_preProcessReaders = LootDumpProcessorContext.GetConfig()
|
||||
.ReaderConfig
|
||||
.PreProcessorConfig
|
||||
?.PreProcessors
|
||||
?.ToDictionary(
|
||||
t => PreProcessReaderFactory.GetInstance(t).GetHandleExtension().ToLower(),
|
||||
PreProcessReaderFactory.GetInstance
|
||||
) ?? new Dictionary<string, IPreProcessReader>();
|
||||
}
|
||||
|
||||
public void DoProcess()
|
||||
{
|
||||
// Single collector instance to collect results
|
||||
var collector = CollectorFactory.GetInstance();
|
||||
collector.Setup();
|
||||
|
||||
// We add 2 more threads to the total count to account for subprocesses and others
|
||||
int threads = LootDumpProcessorContext.GetConfig().Threads;
|
||||
ThreadPool.SetMaxThreads(threads + 2, threads + 2);
|
||||
|
||||
try
|
||||
{
|
||||
// Gather all files, then add them into the processing queue
|
||||
GatherFiles().ForEach(f => _filesToProcess.Add(f));
|
||||
|
||||
// We startup all the threads and collect them into a runners list
|
||||
for (int i = 0; i < threads; i++)
|
||||
{
|
||||
Runners.Add(
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
while (_filesToProcess.TryTake(out var file, TimeSpan.FromMilliseconds(5000)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var reader = IntakeReaderFactory.GetInstance();
|
||||
var processor = FileProcessorFactory.GetInstance();
|
||||
if (reader.Read(file, out var basicInfo))
|
||||
collector.Hold(processor.Process(basicInfo));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"Error occurred while processing file {file}\n{e.Message}\n{e.StackTrace}",
|
||||
LogLevel.Error);
|
||||
}
|
||||
}
|
||||
},
|
||||
TaskCreationOptions.LongRunning)
|
||||
);
|
||||
}
|
||||
|
||||
// Wait until all runners are done processing
|
||||
while (!Runners.All(r => r.IsCompleted))
|
||||
{
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"One or more file processors are still processing files. Waiting {LootDumpProcessorContext.GetConfig().ThreadPoolingTimeoutMs}ms before checking again",
|
||||
LogLevel.Info);
|
||||
Thread.Sleep(TimeSpan.FromMilliseconds(LootDumpProcessorContext.GetConfig().ThreadPoolingTimeoutMs));
|
||||
}
|
||||
|
||||
// Single writer instance to collect results
|
||||
var writer = WriterFactory.GetInstance();
|
||||
// Single collector instance to collect results
|
||||
var dumpProcessor = DumpProcessorFactory.GetInstance();
|
||||
writer.WriteAll(dumpProcessor.ProcessDumps(collector.Retrieve()));
|
||||
}
|
||||
finally
|
||||
{
|
||||
// use dispose on the preprocessreaders to eliminate any temporary files generated
|
||||
foreach (var (_, value) in _preProcessReaders)
|
||||
{
|
||||
value.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> GatherFiles()
|
||||
{
|
||||
// Read locations
|
||||
var inputPath = LootDumpProcessorContext.GetConfig().ReaderConfig.DumpFilesLocation;
|
||||
|
||||
if (inputPath == null || inputPath.Count == 0)
|
||||
throw new Exception("Reader dumpFilesLocations must be set to a valid value");
|
||||
|
||||
// We gather up all files into a queue
|
||||
var queuedFilesToProcess = GetFileQueue(inputPath);
|
||||
// Then we preprocess the files in the queue and get them ready for processing
|
||||
return PreProcessQueuedFiles(queuedFilesToProcess);
|
||||
}
|
||||
|
||||
private List<string> PreProcessQueuedFiles(Queue<string> queuedFilesToProcess)
|
||||
{
|
||||
var gatheredFiles = new List<string>();
|
||||
|
||||
if (queuedFilesToProcess.Count == 0)
|
||||
throw new Exception("No files matched accepted extension types in configs");
|
||||
|
||||
var fileFilters = GetFileFilters() ?? new Dictionary<string, IFileFilter>();
|
||||
|
||||
while (queuedFilesToProcess.TryDequeue(out var file))
|
||||
{
|
||||
var extension = Path.GetExtension(file)[1..].ToLower();
|
||||
// if there is a preprocessor, call it and preprocess the file, then add them to the queue
|
||||
if (_preProcessReaders.TryGetValue(extension, out var preProcessor))
|
||||
{
|
||||
// if the preprocessor found something new to process or generated new files, add them to the queue
|
||||
if (preProcessor.TryPreProcess(file, out var outputFiles, out var outputDirectories))
|
||||
{
|
||||
// all new directories need to be processed as well
|
||||
GetFileQueue(outputDirectories).ToList()
|
||||
.ForEach(queuedFilesToProcess.Enqueue);
|
||||
// all output files need to be queued as well
|
||||
outputFiles.ForEach(queuedFilesToProcess.Enqueue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if there is no preprocessor for the file, means its ready to filter or accept
|
||||
if (fileFilters.TryGetValue(extension, out var filter))
|
||||
{
|
||||
if (filter.Accept(file))
|
||||
gatheredFiles.Add(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
gatheredFiles.Add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gatheredFiles;
|
||||
}
|
||||
|
||||
private Queue<string> GetFileQueue(List<string> inputPath)
|
||||
{
|
||||
var queuedPathsToProcess = new Queue<string>();
|
||||
var queuedFilesToProcess = new Queue<string>();
|
||||
|
||||
// Accepted file extensions on raw files
|
||||
var acceptedFileExtension = LootDumpProcessorContext.GetConfig()
|
||||
.ReaderConfig
|
||||
.AcceptedFileExtensions
|
||||
.Select(ex => ex.ToLower())
|
||||
.ToHashSet();
|
||||
inputPath.ForEach(p => queuedPathsToProcess.Enqueue(p));
|
||||
|
||||
while (queuedPathsToProcess.TryDequeue(out var path))
|
||||
{
|
||||
// Check the input file to be sure its going to have data on it.
|
||||
if (!Directory.Exists(path))
|
||||
throw new Exception($"Input directory \"{inputPath}\" could not be found");
|
||||
// If we should process subfolder, queue them up as well
|
||||
if (LootDumpProcessorContext.GetConfig().ReaderConfig.ProcessSubFolders)
|
||||
foreach (var directory in Directory.GetDirectories(path))
|
||||
queuedPathsToProcess.Enqueue(directory);
|
||||
|
||||
var files = Directory.GetFiles(path);
|
||||
|
||||
foreach (var file in files)
|
||||
if (acceptedFileExtension.Contains(Path.GetExtension(file)[1..].ToLower()))
|
||||
queuedFilesToProcess.Enqueue(file);
|
||||
}
|
||||
|
||||
return queuedFilesToProcess;
|
||||
}
|
||||
|
||||
private Dictionary<string, IFileFilter>? GetFileFilters()
|
||||
{
|
||||
return LootDumpProcessorContext.GetConfig()
|
||||
.ReaderConfig
|
||||
.FileFilters
|
||||
?.ToDictionary(
|
||||
t => FileFilterFactory.GetInstance(t).GetExtension(),
|
||||
FileFilterFactory.GetInstance
|
||||
);
|
||||
}
|
||||
}
|
25
Process/Reader/Filters/FileFilterFactory.cs
Normal file
25
Process/Reader/Filters/FileFilterFactory.cs
Normal file
@ -0,0 +1,25 @@
|
||||
namespace LootDumpProcessor.Process.Reader.Filters;
|
||||
|
||||
public static class FileFilterFactory
|
||||
{
|
||||
private static readonly Dictionary<FileFilterTypes, IFileFilter> _fileFilters = new();
|
||||
private static object lockObject = new();
|
||||
|
||||
public static IFileFilter GetInstance(FileFilterTypes type)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
if (!_fileFilters.TryGetValue(type, out var filter))
|
||||
{
|
||||
filter = type switch
|
||||
{
|
||||
FileFilterTypes.JsonDump => new JsonDumpFileFilter(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
|
||||
};
|
||||
_fileFilters.Add(type, filter);
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
}
|
6
Process/Reader/Filters/FileFilterTypes.cs
Normal file
6
Process/Reader/Filters/FileFilterTypes.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace LootDumpProcessor.Process.Reader.Filters;
|
||||
|
||||
public enum FileFilterTypes
|
||||
{
|
||||
JsonDump
|
||||
}
|
7
Process/Reader/Filters/IFileFilter.cs
Normal file
7
Process/Reader/Filters/IFileFilter.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace LootDumpProcessor.Process.Reader.Filters;
|
||||
|
||||
public interface IFileFilter
|
||||
{
|
||||
string GetExtension();
|
||||
bool Accept(string filename);
|
||||
}
|
40
Process/Reader/Filters/JsonDumpFileFilter.cs
Normal file
40
Process/Reader/Filters/JsonDumpFileFilter.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using LootDumpProcessor.Logger;
|
||||
|
||||
namespace LootDumpProcessor.Process.Reader.Filters;
|
||||
|
||||
public class JsonDumpFileFilter : IFileFilter
|
||||
{
|
||||
private static Regex FileNameDateRegex = new("([0-9]{4}(-[0-9]{2}){2}_((-){0,1}[0-9]{2}){3})");
|
||||
private static DateTime parsedThresholdDate;
|
||||
|
||||
static JsonDumpFileFilter()
|
||||
{
|
||||
// Calculate parsed date from config threshold
|
||||
if (string.IsNullOrEmpty(LootDumpProcessorContext.GetConfig().ReaderConfig.ThresholdDate))
|
||||
{
|
||||
LoggerFactory.GetInstance()
|
||||
.Log($"ThresholdDate is null or empty in configs, defaulting to current day minus 30 days",
|
||||
LogLevel.Warning);
|
||||
parsedThresholdDate = (DateTime.Now - TimeSpan.FromDays(30));
|
||||
}
|
||||
else
|
||||
{
|
||||
parsedThresholdDate = DateTime.ParseExact(
|
||||
LootDumpProcessorContext.GetConfig().ReaderConfig.ThresholdDate,
|
||||
"yyyy-MM-dd",
|
||||
CultureInfo.InvariantCulture
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetExtension() => "json";
|
||||
|
||||
public bool Accept(string filename)
|
||||
{
|
||||
var unparsedDate = FileNameDateRegex.Match(filename).Groups[1].Value;
|
||||
var date = DateTime.ParseExact(unparsedDate, "yyyy-MM-dd_HH-mm-ss", CultureInfo.InvariantCulture);
|
||||
return date > parsedThresholdDate;
|
||||
}
|
||||
}
|
8
Process/Reader/Intake/IIntakeReader.cs
Normal file
8
Process/Reader/Intake/IIntakeReader.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using LootDumpProcessor.Model.Processing;
|
||||
|
||||
namespace LootDumpProcessor.Process;
|
||||
|
||||
public interface IIntakeReader
|
||||
{
|
||||
bool Read(string file, out BasicInfo basicInfo);
|
||||
}
|
18
Process/Reader/Intake/IntakeReaderFactory.cs
Normal file
18
Process/Reader/Intake/IntakeReaderFactory.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using LootDumpProcessor.Process.Impl;
|
||||
|
||||
namespace LootDumpProcessor.Process.Reader;
|
||||
|
||||
public static class IntakeReaderFactory
|
||||
{
|
||||
public static IIntakeReader GetInstance()
|
||||
{
|
||||
return LootDumpProcessorContext.GetConfig().ReaderConfig.IntakeReaderConfig.IntakeReaderType switch
|
||||
{
|
||||
IntakeReaderTypes.Json => new JsonFileIntakeReader(),
|
||||
_ => throw new ArgumentOutOfRangeException(
|
||||
"IntakeReaderType",
|
||||
"Value was not defined on IntakeReaderConfig"
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
6
Process/Reader/Intake/IntakeReaderTypes.cs
Normal file
6
Process/Reader/Intake/IntakeReaderTypes.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace LootDumpProcessor.Process.Reader;
|
||||
|
||||
public enum IntakeReaderTypes
|
||||
{
|
||||
Json
|
||||
}
|
48
Process/Reader/Intake/JsonFileIntakeReader.cs
Normal file
48
Process/Reader/Intake/JsonFileIntakeReader.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using LootDumpProcessor.Logger;
|
||||
using LootDumpProcessor.Model.Input;
|
||||
using LootDumpProcessor.Model.Processing;
|
||||
using LootDumpProcessor.Process.Processor;
|
||||
using LootDumpProcessor.Serializers.Json;
|
||||
|
||||
namespace LootDumpProcessor.Process.Impl;
|
||||
|
||||
public class JsonFileIntakeReader : IIntakeReader
|
||||
{
|
||||
private static readonly IJsonSerializer _jsonSerializer = JsonSerializerFactory.GetInstance();
|
||||
|
||||
private static readonly HashSet<string>? _ignoredLocations =
|
||||
LootDumpProcessorContext.GetConfig().ReaderConfig.IntakeReaderConfig?.IgnoredDumpLocations.ToHashSet();
|
||||
|
||||
private static Regex FileNameDateRegex = new("([0-9]{4}(-[0-9]{2}){2}_((-){0,1}[0-9]{2}){3})");
|
||||
|
||||
public bool Read(string file, out BasicInfo basicInfo)
|
||||
{
|
||||
var fileData = File.ReadAllText(file);
|
||||
var unparsedDate = FileNameDateRegex.Match(file).Groups[1].Value;
|
||||
var date = DateTime.ParseExact(unparsedDate, "yyyy-MM-dd_HH-mm-ss", CultureInfo.InvariantCulture);
|
||||
|
||||
var fi = _jsonSerializer.Deserialize<RootData>(fileData);
|
||||
if (fi.Data?.Name != null && (!_ignoredLocations?.Contains(fi.Data.Name) ?? true))
|
||||
{
|
||||
basicInfo = new BasicInfo
|
||||
{
|
||||
Map = fi.Data.Name,
|
||||
FileHash = ProcessorUtil.HashFile(fileData),
|
||||
Data = fi,
|
||||
Date = date,
|
||||
FileName = file
|
||||
};
|
||||
LoggerFactory.GetInstance().Log($"File {file} fully read, returning data", LogLevel.Info);
|
||||
return true;
|
||||
}
|
||||
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"File {file} was not eligible for dump data, it did not contain a location name or it was on ignored locations config",
|
||||
LogLevel.Info
|
||||
);
|
||||
basicInfo = null;
|
||||
return false;
|
||||
}
|
||||
}
|
48
Process/Reader/PreProcess/AbstractPreProcessReader.cs
Normal file
48
Process/Reader/PreProcess/AbstractPreProcessReader.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using LootDumpProcessor.Logger;
|
||||
|
||||
namespace LootDumpProcessor.Process.Reader.PreProcess;
|
||||
|
||||
public abstract class AbstractPreProcessReader : IPreProcessReader
|
||||
{
|
||||
protected string _tempFolder;
|
||||
|
||||
public AbstractPreProcessReader()
|
||||
{
|
||||
var tempFolder = LootDumpProcessorContext.GetConfig().ReaderConfig.PreProcessorConfig?.PreProcessorTempFolder;
|
||||
if (string.IsNullOrEmpty(tempFolder))
|
||||
{
|
||||
tempFolder = GetBaseDirectory();
|
||||
LoggerFactory.GetInstance()
|
||||
.Log(
|
||||
$"No temp folder was assigned preProcessorTempFolder in PreProcessorConfig, defaulting to {tempFolder}",
|
||||
LogLevel.Warning
|
||||
);
|
||||
}
|
||||
|
||||
// Cleanup the temp directory before starting the process
|
||||
if (Directory.Exists(tempFolder))
|
||||
{
|
||||
Directory.Delete(tempFolder, true);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(tempFolder);
|
||||
|
||||
_tempFolder = tempFolder;
|
||||
}
|
||||
|
||||
public abstract string GetHandleExtension();
|
||||
public abstract bool TryPreProcess(string file, out List<string> files, out List<string> directories);
|
||||
|
||||
protected string GetBaseDirectory()
|
||||
{
|
||||
return $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}\\SPT\\tmp\\PreProcessor";
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (LootDumpProcessorContext.GetConfig().ReaderConfig.PreProcessorConfig?.CleanupTempFolderAfterProcess ?? true)
|
||||
{
|
||||
Directory.Delete(_tempFolder, true);
|
||||
}
|
||||
}
|
||||
}
|
11
Process/Reader/PreProcess/IPreProcessReader.cs
Normal file
11
Process/Reader/PreProcess/IPreProcessReader.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace LootDumpProcessor.Process.Reader.PreProcess;
|
||||
|
||||
public interface IPreProcessReader
|
||||
{
|
||||
string GetHandleExtension();
|
||||
|
||||
bool TryPreProcess(string file, out List<string> files, out List<string> directories);
|
||||
|
||||
// Custom dispose, not IDisposable
|
||||
void Dispose();
|
||||
}
|
22
Process/Reader/PreProcess/PreProcessReaderFactory.cs
Normal file
22
Process/Reader/PreProcess/PreProcessReaderFactory.cs
Normal file
@ -0,0 +1,22 @@
|
||||
namespace LootDumpProcessor.Process.Reader.PreProcess;
|
||||
|
||||
public static class PreProcessReaderFactory
|
||||
{
|
||||
private static readonly Dictionary<PreProcessReaderTypes, IPreProcessReader> _proProcessReaders = new();
|
||||
private static object lockObject = new object();
|
||||
|
||||
public static IPreProcessReader GetInstance(PreProcessReaderTypes type)
|
||||
{
|
||||
if (!_proProcessReaders.TryGetValue(type, out var preProcessReader))
|
||||
{
|
||||
preProcessReader = type switch
|
||||
{
|
||||
PreProcessReaderTypes.SevenZip => new SevenZipPreProcessReader(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
|
||||
};
|
||||
_proProcessReaders.Add(type, preProcessReader);
|
||||
}
|
||||
|
||||
return preProcessReader;
|
||||
}
|
||||
}
|
6
Process/Reader/PreProcess/PreProcessReaderTypes.cs
Normal file
6
Process/Reader/PreProcess/PreProcessReaderTypes.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace LootDumpProcessor.Process.Reader.PreProcess;
|
||||
|
||||
public enum PreProcessReaderTypes
|
||||
{
|
||||
SevenZip
|
||||
}
|
39
Process/Reader/PreProcess/SevenZipPreProcessReader.cs
Normal file
39
Process/Reader/PreProcess/SevenZipPreProcessReader.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using LootDumpProcessor.Logger;
|
||||
using SevenZip;
|
||||
using SevenZip.Sdk.Compression.Lzma;
|
||||
|
||||
namespace LootDumpProcessor.Process.Reader.PreProcess;
|
||||
|
||||
public class SevenZipPreProcessReader : AbstractPreProcessReader
|
||||
{
|
||||
public override string GetHandleExtension() => "7z";
|
||||
|
||||
static SevenZipPreProcessReader()
|
||||
{
|
||||
SevenZipBase.SetLibraryPath("./x64/7z.dll");
|
||||
}
|
||||
|
||||
public override bool TryPreProcess(string file, out List<string> files, out List<string> directories)
|
||||
{
|
||||
Decoder decoder = new Decoder();
|
||||
|
||||
var fileRaw = Path.GetFileNameWithoutExtension(file);
|
||||
// SevenZip library doesnt like forward slashes for some reason
|
||||
var outPath = $"{_tempFolder}\\{fileRaw}".Replace("/", "\\");
|
||||
LoggerFactory.GetInstance().Log(
|
||||
$"Unzipping {file} into temp path {outPath}, this may take a while...",
|
||||
LogLevel.Info);
|
||||
var extractor = new SevenZipExtractor(file);
|
||||
extractor.Extracting += (sender, args) =>
|
||||
{
|
||||
if (args.PercentDone % 10 == 0)
|
||||
LoggerFactory.GetInstance().Log($"Unzip progress: {args.PercentDone}%", LogLevel.Info);
|
||||
};
|
||||
extractor.ExtractArchive(outPath);
|
||||
LoggerFactory.GetInstance().Log($"Finished unzipping {file} into temp path {outPath}", LogLevel.Info);
|
||||
|
||||
files = Directory.GetFiles(outPath).ToList();
|
||||
directories = Directory.GetDirectories(outPath).ToList();
|
||||
return true;
|
||||
}
|
||||
}
|
45
Process/TarkovItems.cs
Normal file
45
Process/TarkovItems.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using LootDumpProcessor.Model.Tarkov;
|
||||
using LootDumpProcessor.Serializers.Json;
|
||||
|
||||
namespace LootDumpProcessor.Process;
|
||||
|
||||
public class TarkovItems
|
||||
{
|
||||
private static readonly IJsonSerializer _jsonSerializer = JsonSerializerFactory.GetInstance();
|
||||
|
||||
private Dictionary<string, TemplateFileItem> _items;
|
||||
private HandbookRoot _handbook;
|
||||
|
||||
public TarkovItems(string items, string handbook)
|
||||
{
|
||||
_items = _jsonSerializer.Deserialize<Dictionary<string, TemplateFileItem>>(File.ReadAllText(items));
|
||||
_handbook = _jsonSerializer.Deserialize<HandbookRoot>(File.ReadAllText(handbook));
|
||||
}
|
||||
|
||||
public virtual bool IsBaseClass(string tpl, string baseclass_id)
|
||||
{
|
||||
var item_template = _items[tpl];
|
||||
if (string.IsNullOrEmpty(item_template.Parent))
|
||||
return false;
|
||||
|
||||
return item_template.Parent == baseclass_id || IsBaseClass(item_template.Parent, baseclass_id);
|
||||
}
|
||||
|
||||
public virtual bool IsQuestItem(string tpl)
|
||||
{
|
||||
var item_template = _items[tpl];
|
||||
return item_template.Props.QuestItem;
|
||||
}
|
||||
|
||||
public virtual string? MaxDurability(string tpl)
|
||||
{
|
||||
var item_template = _items[tpl];
|
||||
return item_template.Props.MaxDurability?.ToString() ?? "";
|
||||
}
|
||||
|
||||
public virtual string? AmmoCaliber(string tpl)
|
||||
{
|
||||
var item_template = _items[tpl];
|
||||
return item_template.Props.Caliber;
|
||||
}
|
||||
}
|
77
Process/Writer/FileWriter.cs
Normal file
77
Process/Writer/FileWriter.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using LootDumpProcessor.Model.Output;
|
||||
using LootDumpProcessor.Model.Output.LooseLoot;
|
||||
using LootDumpProcessor.Model.Output.StaticContainer;
|
||||
using LootDumpProcessor.Serializers.Json;
|
||||
|
||||
namespace LootDumpProcessor.Process.Impl;
|
||||
|
||||
public class FileWriter : IWriter
|
||||
{
|
||||
private static readonly IJsonSerializer _jsonSerializer = JsonSerializerFactory.GetInstance();
|
||||
private static string _outputPath;
|
||||
|
||||
static FileWriter()
|
||||
{
|
||||
var path = LootDumpProcessorContext.GetConfig().WriterConfig.OutputLocation;
|
||||
if (string.IsNullOrEmpty(path))
|
||||
throw new Exception("Output directory must be set in WriterConfigs");
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
_outputPath = path;
|
||||
}
|
||||
|
||||
public void WriteAll(Dictionary<OutputFileType, object> dumpData)
|
||||
{
|
||||
foreach (var (key, value) in dumpData)
|
||||
{
|
||||
Write(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(
|
||||
OutputFileType type,
|
||||
object data
|
||||
)
|
||||
{
|
||||
if (!Directory.Exists($"{_outputPath}\\loot"))
|
||||
Directory.CreateDirectory($"{_outputPath}\\loot");
|
||||
switch (type)
|
||||
{
|
||||
case OutputFileType.LooseLoot:
|
||||
var looseLootData = (Dictionary<string, LooseLootRoot>)data;
|
||||
foreach (var (key, value) in looseLootData)
|
||||
{
|
||||
foreach (var s in LootDumpProcessorContext.GetDirectoryMappings()[key].Name)
|
||||
{
|
||||
if (!Directory.Exists($"{_outputPath}\\locations\\{s}"))
|
||||
Directory.CreateDirectory($"{_outputPath}\\locations\\{s}");
|
||||
File.WriteAllText($"{_outputPath}\\locations\\{s}\\looseLoot.json",
|
||||
_jsonSerializer.Serialize(value));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case OutputFileType.StaticContainer:
|
||||
var staticContainer = (Dictionary<string, MapStaticLoot>)data;
|
||||
File.WriteAllText($"{_outputPath}\\loot\\staticContainers.json",
|
||||
_jsonSerializer.Serialize(staticContainer));
|
||||
break;
|
||||
case OutputFileType.StaticLoot:
|
||||
var staticLoot = (Dictionary<string, StaticItemDistribution>)data;
|
||||
File.WriteAllText($"{_outputPath}\\loot\\staticLoot.json",
|
||||
_jsonSerializer.Serialize(staticLoot));
|
||||
break;
|
||||
case OutputFileType.StaticAmmo:
|
||||
var staticAmmo = (Dictionary<string, List<AmmoDistribution>>)data;
|
||||
File.WriteAllText($"{_outputPath}\\loot\\staticAmmo.json",
|
||||
_jsonSerializer.Serialize(staticAmmo));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user