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