From c86b372d10d277ccf972492031ece65cfbb6b1e0 Mon Sep 17 00:00:00 2001 From: Vari Date: Thu, 19 Jan 2023 00:14:09 +0000 Subject: [PATCH 01/50] feat(damage-tracker-lib): move functionality to new library project --- .gitignore | 413 +++++++++++++++++- .vs/DamageTrackerUtility/v16/.suo | Bin 0 -> 26112 bytes .../DamageInfo/BodyRegion.cs | 2 +- .../DamageInfo/BoneDamageInfo.cs | 2 +- .../DamageInfo/BoneId.cs | 2 +- .../DamageInfo/DamageGroup.cs | 2 +- .../DamageInfo/DamageType.cs | 3 +- .../DamageInfo/Limb.cs | 2 +- .../DamageInfo/PedDamageInfo.cs | 2 +- .../DamageInfo/WeaponDamageInfo.cs | 2 +- .../DamageInfo/WeaponHash.cs | 3 +- DamageTrackerLib/DamageTrackerLib.csproj | 71 +++ .../Lookups.cs | 11 +- DamageTrackerLib/Process.cs | 51 +++ DamageTrackerLib/Properties/AssemblyInfo.cs | 35 ++ DamageTrackerLib/Wrapper.cs | 42 ++ DamageTrackerLib/packages.config | 4 + DamageTrackerUtility.sln | 6 + DamageTrackerUtility.sln.DotSettings.user | 3 + .../.vs/DamageTrackingFramework/v16/.suo | Bin 0 -> 15360 bytes .../.vs/ProjectSettings.json | 3 + .../.vs/VSWorkspaceState.json | 6 + DamageTrackingFramework/.vs/slnx.sqlite | Bin 0 -> 266240 bytes DamageTrackingFramework/App.config | 22 + DamageTrackingFramework/DamageTracker.cs | 5 +- .../DamageTrackingFramework.csproj | 14 +- DamageTrackingFramework/PipeServer.cs | 2 - DamageTrackingFramework/packages.config | 4 + 28 files changed, 672 insertions(+), 40 deletions(-) create mode 100644 .vs/DamageTrackerUtility/v16/.suo rename {DamageTrackingFramework => DamageTrackerLib}/DamageInfo/BodyRegion.cs (71%) rename {DamageTrackingFramework => DamageTrackerLib}/DamageInfo/BoneDamageInfo.cs (79%) rename {DamageTrackingFramework => DamageTrackerLib}/DamageInfo/BoneId.cs (98%) rename {DamageTrackingFramework => DamageTrackerLib}/DamageInfo/DamageGroup.cs (89%) rename {DamageTrackingFramework => DamageTrackerLib}/DamageInfo/DamageType.cs (88%) rename {DamageTrackingFramework => DamageTrackerLib}/DamageInfo/Limb.cs (78%) rename {DamageTrackingFramework => DamageTrackerLib}/DamageInfo/PedDamageInfo.cs (83%) rename {DamageTrackingFramework => DamageTrackerLib}/DamageInfo/WeaponDamageInfo.cs (80%) rename {DamageTrackingFramework => DamageTrackerLib}/DamageInfo/WeaponHash.cs (99%) create mode 100644 DamageTrackerLib/DamageTrackerLib.csproj rename {DamageTrackingFramework => DamageTrackerLib}/Lookups.cs (98%) create mode 100644 DamageTrackerLib/Process.cs create mode 100644 DamageTrackerLib/Properties/AssemblyInfo.cs create mode 100644 DamageTrackerLib/Wrapper.cs create mode 100644 DamageTrackerLib/packages.config create mode 100644 DamageTrackerUtility.sln.DotSettings.user create mode 100644 DamageTrackingFramework/.vs/DamageTrackingFramework/v16/.suo create mode 100644 DamageTrackingFramework/.vs/ProjectSettings.json create mode 100644 DamageTrackingFramework/.vs/VSWorkspaceState.json create mode 100644 DamageTrackingFramework/.vs/slnx.sqlite create mode 100644 DamageTrackingFramework/App.config create mode 100644 DamageTrackingFramework/packages.config diff --git a/.gitignore b/.gitignore index 3237856..4edc121 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,5 @@ -# Created by https://www.toptal.com/developers/gitignore/api/rider -# Edit at https://www.toptal.com/developers/gitignore?templates=rider - -### Custom ### -DamageTrackingFramework/obj -DamageTrackingFramework/bin -.idea/.idea.DamageTrackerUtility/.idea/*.xml -References +# Created by https://www.toptal.com/developers/gitignore/api/visualstudio,rider +# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudio,rider ### Rider ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider @@ -86,4 +80,405 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser -# End of https://www.toptal.com/developers/gitignore/api/rider +### VisualStudio ### +## 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/ + +# 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 + +# 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 + +### VisualStudio Patch ### +# Additional files built by Visual Studio + +# End of https://www.toptal.com/developers/gitignore/api/visualstudio,rider diff --git a/.vs/DamageTrackerUtility/v16/.suo b/.vs/DamageTrackerUtility/v16/.suo new file mode 100644 index 0000000000000000000000000000000000000000..91af4900d2ea751ed2a9e4199e4572e974f127bf GIT binary patch literal 26112 zcmeI4%X3^u6^E~6OcDYiCc%Ud$i#6HCs>LskDnrr^|TeFSn)`*fq`T+Gm`C$9yL-N zJAnmN6yYymNdZe(QN@M@RTRYrDiALys#0vsnyM_>P(=K`?&+C(ukO8bXU2KVL_Kxp zzPkJL>F#s-oYRk6@9ew%i{Cu_FE13%cze9}x9{;j?R($nyZ7$*yszt-ckgd+Z}W+J z-R_1is)38%x_(<;#+&rkbggKI6f}HB2ASl=3#a#}1 z{eAxCj*I7i|4lvoxyDQvyw`-K;$0Q}z={v^gx*yB2_x>of3M!(CrC?wQE?q#AJ+Z< z`~>KpZ+8jq7Cb8mecm3Zz02sjPw)l71A+$yUli;Yd`a+-;L8G<`YVD*1YZ?=P4K7y zx$&5;2Lz7`4ho(SJSliea7gg9;2FUY0rB_Nu0y&G3O-kR4wrHFIb98WnEXHVN`wFZ zK*vyU{P$t<|FZDz^1rG6I&ULGkOT0Tpa1XC`_BmAH^+OQ)jjbtx_(&v@8ny!SHu6| zce~H&Yk+oa2DCqMXm{$HwqOj0hdOEhjMAr-|LB^GRg68zea0pFB;&%c;HV%gI3_qQ zI3YMGI3+kO7!iC!@SNa`;CX?c?r}X&gx>kTb3dc+vw{}|7X)*Hmjo9DF7ATv7X_CD zmj&Mvd|U7xL0<4(fs5Phn!Xj=kBQ!cmQ$7PQIH-oC7q+9=gqogE_+4A7?);*epojD zo1(&o)6zc}?-{cxMeTLs1-e~?3FTXq4zya!`I6CsN_zXcO0ceSTou-<273dmOHCi> zH~J*{M_T;fQ(XEkA*Y-xMhCMvES<~3xT3dJqXXJ6Hh%d3a2xvHyfV4oZ*#ifElK;G z6}IY*I$ktAIE*p)d_ed=rB}%8wDji`w}xIgE242zzeUkpR;|aibP%t5YDfR|xBr6r z6Iyq{D+zlk)a#;J++ns?=!b3>f?uPbTEXAU9(htV$+*ZkNg1Ls2H&=Ve?ql#T~ZF& z78U4!=+x-o?chJJRxg>lUlT7>)EZNUBWR7PdPTFK`Zsvnt^YB#e9?Q=^#65n+?vWV zQ|k{ChWiSMMNs{>-2N{pN9+_rH2-4EpB7$hC4$p`t(4uY(~dqI zE*qsm{`$jl)j#$Wwp!ZuKd-pR48nv)vl*2FTNC-eu9k3k;KybG{=?Qoo~FfrPH`Rn zApP^I_t(_xw(9~V_N)v{?(@7%8~isZysrO+@sFttWtHJo^|f`? zI%9rPISz?_>~v@+KvT0YrU<{RMGE6b-WFAYW_;&x!2jr=_!iRQA5~oVg%E|`YB?p9 zqGbG0N#%k64B@pun``p_S$&SfkN$-Wg!j=uz?~Ere_F+lt#<%LULj0>1OH9+`6ZR2 zVk5@`wD=jT(ZL8|`lI{5za%!D z`_GDg#*#+`Y4OwcaqVw0Apxx?a#WnKA^i~T8%>zE{-FNXhkp$_DlLB6%E{j`<+v_x zN6J=pP3!k`Wq3sR`}BZ3NsE6;aSzopm>1qn;hhn6P@R+HgT^gm6(q|ZvOxdr*A;hC zTKomYb@jg}tn;Q0DyFyJPzjL3*HxZoyr*m=_xt-`C2Zrg_+L?6SO3$ZJf{}EDa&?P zR%}+f-YHo%qq1Tr^*e5?StW=G?ePE0%8NQ9*#3q8xoAcnJImHImyv^54)6 z?F5@^^M8E9gq-jeYg!O>j?}G6s|xErgLTaa`vg64%cMWk27a^}*Z!^Gr>AatNQi>) zGe&#f**5Sa(XrR=RIoK~|69$|FWF`dU4@z^GAN6Xw%8JXp!YZqB}GYZuc$T*{e92q z>dKG?KYicnA4&Kx2?zRal0G`zM*Z&*erNwD;UBN*qU(~5=TsB)yAA2f1wA|MjQ+=5 z#X$jepi9#L?;$S;Y4JN5g(kdVYTl;D|B}(|(}J}4k=G8tZaWH>-(lo!KO7W41xKJw zFQc9}q~8(A0sfN$v~&_&`r^{*nK!c6e&1?dtA)+2a`pD_+D-r7Ute1I=a1S?-)ec| z;@k1S)P}2)xTt~m^rMy%1XA06*hzZ$xRdnAA<{SU*f^`l)S*-QCugVTQzQETA`UO+ z=AeCSJU4gm$U|%UMsA(|`G5L<`>Qi=|NDn}KOygV-dm8wVJz6x{i5VwRZ=K#bZ2xo zw9*YdU(yvFGH-lH+z}ry4%#L5E%v?j_mJD1Yzr)3ES{uz3&Ma`8vXZXY)o=l5oRzT zpI@(+Cb|T1@dq`sZ;BqfF5%ZddtiEX|GRxZ-mMEsV|+8ToC|OCNUf|(zqzKK0sKHT`3Uxd7kXXKKLNu-}(Hy{0~zkr#bVT=Sqz;}^zqm~uX+8LfHEJdFwy{v10acSQ4EjF=+=?uKE9UdiX;GdYBnTB()^T&-IWGP{;79Ara>~6L^BahY%;W#c!EN{4Q+0cvq ziXSNx!tH8dRyh=vA2Z$S;^i%+-bqtlrHZ3BU#BlGKVdkxL6sbz8amsCa%sq`71cU5 z%d8JANr2i{bnOmmS5;?4(NGlyv|t+Q-V${m$FXZe?Z7;!)sx|mi?w^dmV92+!i9sz zHa=zg^pN6O`t#~*=qg!_7{g6-XxZ+u=vh!ca zeDq%CCy2-TgPk%xIgQoz;(Z&*sqyyi#2D`xNzM)5Z7aDo{4B}&vPQDKd|3nJ{5Q!s z?7GSLdc?N6b3UTvvasH=b9&=-Xa7hXXDPzdVSiO}sW(2RrH-zLI7_%0kG|O>RQhYh zSuCFv+N15b_}+~?cQ#`0*-(s5&Fn2_S1GCqyR_W!?$#g?}1r1=2BUonKwShRcS%2M0D#C7WFo-ISEGnit@l8 zpHqIkWe3lo(x1}*QIpG2UGqxI`~d49Soz2f!N2qX6-CWSFq7eVf9nBitgc&;W#239 zvuXV0P}7Y(!+aUNYg5-^*S1NRiW{0c%=Qd5%r~wYYHoF*1PHf{^*Fn?p7(YS&~#Pf z5A)SXfxq_vJOFYh^*J@R$1+OnUikJYgT%um99%-!%c3^o>uxt5A;6hV(%*Z zQdnDLb-8YoeatIYM8UEdTU{@7&z{#iG+9dNf!$BjPCG(mr3ifik7J4ip(t@H8bi@y zAF)4wD)>0g+r<{z_n}k!nSJ2@)rO>l#|q_>#ieX^V7X9Q8pxh1pBN|%Egu^=GL#)E zmxqUjj-60kq3aZ*ukgCP{hnKC9DJYl37_`;waD$1On!onHV~}~H)W_*&7gmNuCekF z?ugnO(C4+7U~jDfAoWjuC9^2dEs96wxGuMW-5h~A@1OW?Y)4?huA5vhDZbkr!9v8w z<_HcWY;2B*kH@k_|K^D3n6?6z4Tj+62q5*BQ2d*@kL?*9$cpOWwVX}JFggPp}= zeLdBPw}%GA=d)2;w|Y&bdrqgJ5=La9dET4SnkVJaIVlZ#OvNA5-d*mF=r^DkCne2> zbT_L1DaEBShV?zGH=~LWwSdKhYvWGCy?+ZFAwZzqAX7@7f;5{KC=C}Y*Qll$-wXAeQcg93I4 za2^65 z&Ohi7-hFGO3@d5Vh28TXKJxP)%=t&~2Yn??tG%p9(z{I9J^vy7`4fy;cl!K?S*-|J zkR%MBcj4b#QfsQnOFQR(EGs8uIiWF1+4HB`IRD4U_Pdl<+Wv=JGsq+G&r0&_p8rEX zvwIjm=<|QV?H_&qk!!7;*WL5KT0j5htg4aSp@eY#H~260`Cl!cf5^&>1GV$NrliA8 z%09^&s|5SS&Q4G14tr)o&o9?4p`F@+&L1&+5APEUQBD5PdEY<@R7i)PeSWjju-QS$ zsWXkx&iQMcz2p2=?0UrF!`|SOEjSMwg*|)ta$k}qX!mJg&a-cn7>%Iw|5~QsFaMIx ve_?0lnttqkXzU5>oPPF{JNe(Bq`kY{^ItkU|AltImV$HIIe(_p^JD%G5`TLO literal 0 HcmV?d00001 diff --git a/DamageTrackingFramework/DamageInfo/BodyRegion.cs b/DamageTrackerLib/DamageInfo/BodyRegion.cs similarity index 71% rename from DamageTrackingFramework/DamageInfo/BodyRegion.cs rename to DamageTrackerLib/DamageInfo/BodyRegion.cs index be8dfb6..e96ac5f 100644 --- a/DamageTrackingFramework/DamageInfo/BodyRegion.cs +++ b/DamageTrackerLib/DamageInfo/BodyRegion.cs @@ -1,4 +1,4 @@ -namespace DamageTrackingFramework.DamageInfo +namespace DamageTrackerLib.DamageInfo { public enum BodyRegion { diff --git a/DamageTrackingFramework/DamageInfo/BoneDamageInfo.cs b/DamageTrackerLib/DamageInfo/BoneDamageInfo.cs similarity index 79% rename from DamageTrackingFramework/DamageInfo/BoneDamageInfo.cs rename to DamageTrackerLib/DamageInfo/BoneDamageInfo.cs index e220b67..928ae6d 100644 --- a/DamageTrackingFramework/DamageInfo/BoneDamageInfo.cs +++ b/DamageTrackerLib/DamageInfo/BoneDamageInfo.cs @@ -1,6 +1,6 @@ using System; -namespace DamageTrackingFramework.DamageInfo +namespace DamageTrackerLib.DamageInfo { [Serializable] public struct BoneDamageInfo diff --git a/DamageTrackingFramework/DamageInfo/BoneId.cs b/DamageTrackerLib/DamageInfo/BoneId.cs similarity index 98% rename from DamageTrackingFramework/DamageInfo/BoneId.cs rename to DamageTrackerLib/DamageInfo/BoneId.cs index bed73a9..ee75de3 100644 --- a/DamageTrackingFramework/DamageInfo/BoneId.cs +++ b/DamageTrackerLib/DamageInfo/BoneId.cs @@ -1,4 +1,4 @@ -namespace DamageTrackingFramework.DamageInfo +namespace DamageTrackerLib.DamageInfo { public enum BoneId : ushort { diff --git a/DamageTrackingFramework/DamageInfo/DamageGroup.cs b/DamageTrackerLib/DamageInfo/DamageGroup.cs similarity index 89% rename from DamageTrackingFramework/DamageInfo/DamageGroup.cs rename to DamageTrackerLib/DamageInfo/DamageGroup.cs index e37a67a..8dbc61f 100644 --- a/DamageTrackingFramework/DamageInfo/DamageGroup.cs +++ b/DamageTrackerLib/DamageInfo/DamageGroup.cs @@ -1,4 +1,4 @@ -namespace DamageTrackingFramework.DamageInfo +namespace DamageTrackerLib.DamageInfo { public enum DamageGroup { diff --git a/DamageTrackingFramework/DamageInfo/DamageType.cs b/DamageTrackerLib/DamageInfo/DamageType.cs similarity index 88% rename from DamageTrackingFramework/DamageInfo/DamageType.cs rename to DamageTrackerLib/DamageInfo/DamageType.cs index 1a55149..74a2bbf 100644 --- a/DamageTrackingFramework/DamageInfo/DamageType.cs +++ b/DamageTrackerLib/DamageInfo/DamageType.cs @@ -1,5 +1,4 @@ -// ReSharper disable InconsistentNaming -namespace DamageTrackingFramework.DamageInfo +namespace DamageTrackerLib.DamageInfo { public enum DamageType { diff --git a/DamageTrackingFramework/DamageInfo/Limb.cs b/DamageTrackerLib/DamageInfo/Limb.cs similarity index 78% rename from DamageTrackingFramework/DamageInfo/Limb.cs rename to DamageTrackerLib/DamageInfo/Limb.cs index e91728b..8e0db8f 100644 --- a/DamageTrackingFramework/DamageInfo/Limb.cs +++ b/DamageTrackerLib/DamageInfo/Limb.cs @@ -1,4 +1,4 @@ -namespace DamageTrackingFramework.DamageInfo +namespace DamageTrackerLib.DamageInfo { public enum Limb { diff --git a/DamageTrackingFramework/DamageInfo/PedDamageInfo.cs b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs similarity index 83% rename from DamageTrackingFramework/DamageInfo/PedDamageInfo.cs rename to DamageTrackerLib/DamageInfo/PedDamageInfo.cs index 3ae224c..c03ae47 100644 --- a/DamageTrackingFramework/DamageInfo/PedDamageInfo.cs +++ b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs @@ -1,7 +1,7 @@ using System; using Rage; -namespace DamageTrackingFramework.DamageInfo +namespace DamageTrackerLib.DamageInfo { [Serializable] public struct PedDamageInfo diff --git a/DamageTrackingFramework/DamageInfo/WeaponDamageInfo.cs b/DamageTrackerLib/DamageInfo/WeaponDamageInfo.cs similarity index 80% rename from DamageTrackingFramework/DamageInfo/WeaponDamageInfo.cs rename to DamageTrackerLib/DamageInfo/WeaponDamageInfo.cs index e654eb9..db2f670 100644 --- a/DamageTrackingFramework/DamageInfo/WeaponDamageInfo.cs +++ b/DamageTrackerLib/DamageInfo/WeaponDamageInfo.cs @@ -1,6 +1,6 @@ using System; -namespace DamageTrackingFramework.DamageInfo +namespace DamageTrackerLib.DamageInfo { [Serializable] public struct WeaponDamageInfo diff --git a/DamageTrackingFramework/DamageInfo/WeaponHash.cs b/DamageTrackerLib/DamageInfo/WeaponHash.cs similarity index 99% rename from DamageTrackingFramework/DamageInfo/WeaponHash.cs rename to DamageTrackerLib/DamageInfo/WeaponHash.cs index d34dfe6..29a3992 100644 --- a/DamageTrackingFramework/DamageInfo/WeaponHash.cs +++ b/DamageTrackerLib/DamageInfo/WeaponHash.cs @@ -1,5 +1,4 @@ -// ReSharper disable InconsistentNaming -namespace DamageTrackingFramework.DamageInfo +namespace DamageTrackerLib.DamageInfo { public enum WeaponHash : uint { diff --git a/DamageTrackerLib/DamageTrackerLib.csproj b/DamageTrackerLib/DamageTrackerLib.csproj new file mode 100644 index 0000000..db863bd --- /dev/null +++ b/DamageTrackerLib/DamageTrackerLib.csproj @@ -0,0 +1,71 @@ + + + + + Debug + AnyCPU + {8BA678B1-D73D-4B13-8D42-F6750285E52A} + Library + Properties + DamageTrackerLib + DamageTrackerLib + v4.8 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + ..\packages\RagePluginHook.1.98.0\lib\net472\RagePluginHook.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DamageTrackingFramework/Lookups.cs b/DamageTrackerLib/Lookups.cs similarity index 98% rename from DamageTrackingFramework/Lookups.cs rename to DamageTrackerLib/Lookups.cs index c5c317e..22aeb57 100644 --- a/DamageTrackingFramework/Lookups.cs +++ b/DamageTrackerLib/Lookups.cs @@ -1,12 +1,11 @@ using System.Collections.Generic; -using DamageTrackingFramework.DamageInfo; -using WeaponHash = DamageTrackingFramework.DamageInfo.WeaponHash; +using DamageTrackerLib.DamageInfo; -namespace DamageTrackingFramework +namespace DamageTrackerLib { - internal static class Lookups + public static class Lookups { - internal static readonly Dictionary + public static readonly Dictionary BoneLookup = new Dictionary { @@ -69,7 +68,7 @@ internal static class Lookups [BoneId.LeftClavicle] = (Limb.Chest, BodyRegion.Torso), }; - internal static readonly Dictionary + public static readonly Dictionary WeaponLookup = new Dictionary { diff --git a/DamageTrackerLib/Process.cs b/DamageTrackerLib/Process.cs new file mode 100644 index 0000000..e949518 --- /dev/null +++ b/DamageTrackerLib/Process.cs @@ -0,0 +1,51 @@ +using System; +using System.IO.Pipes; +using System.Runtime.Serialization.Formatters.Binary; +using Rage; +using Rage.Attributes; + +[assembly: Plugin("DamageTrackerLib", Description = "A plugin for testing.", + Author = "Variapolis", + PrefersSingleInstance = true)] + +namespace DamageTrackerLib +{ + // ReSharper disable once UnusedType.Global + public static class Process + { + } + + public static class PipeClient + { + private static readonly BinaryFormatter BinaryFormatter = new BinaryFormatter(); + + internal static void Run() + { + var pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.In); + + + Game.LogTrivial("Connecting to server."); + pipeClient.Connect(); + Game.LogTrivial("Connected to server."); + + + // Validate the server's signature string. + try + { + Game.LogTrivial("Attempting to deserialize."); + var shit = (int)BinaryFormatter.Deserialize(pipeClient); // HACK: NEEDS TO BE CAST TO A PED DAMAGE INFO + Game.LogTrivial($"Success! {shit}"); + } + // Catch the IOException that is raised if the pipe is broken or disconnected. + catch (Exception e) + { + Game.LogTrivial($"ERROR: {e.Message}"); + } + finally + { + pipeClient.Close(); + Game.LogTrivial("Client Closed."); + } + } + } +} \ No newline at end of file diff --git a/DamageTrackerLib/Properties/AssemblyInfo.cs b/DamageTrackerLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0fd28bc --- /dev/null +++ b/DamageTrackerLib/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TestRPHPlugin")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestRPHPlugin")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8BA678B1-D73D-4B13-8D42-F6750285E52A")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/DamageTrackerLib/Wrapper.cs b/DamageTrackerLib/Wrapper.cs new file mode 100644 index 0000000..28f3f2e --- /dev/null +++ b/DamageTrackerLib/Wrapper.cs @@ -0,0 +1,42 @@ +namespace DamageTrackerLib +{ + internal static class Wrapper + { + // static Wrapper() => AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve; + // + // [MethodImpl(MethodImplOptions.NoInlining)] + // public static void Start() + // { + // Game.LogTrivial("Started!"); + // var beforeCount = DamageTrackingFramework.DamageTracker.DamageSubCount; + // DamageTrackingFramework.DamageTracker.OnPedTookDamage += OnPlayerTookDamage; + // Game.LogTrivial($"[Start] {beforeCount} to {DamageTrackingFramework.DamageTracker.DamageSubCount}"); + // } + // + // [MethodImpl(MethodImplOptions.NoInlining)] + // public static void Call() + // { + // Game.LogTrivial($"[Call] {DamageTrackingFramework.DamageTracker.DamageSubCount}"); + // // DamageTrackingFramework.EntryPoint.GetPlayer(); + // } + // + // private static void PrintPed(Ped ped, PedDamageInfo info) + // { + // Game.DisplayHelp($"{ped.Model.Name} {info.Damage} {info.WeaponInfo.Hash.ToString()} {info.BoneInfo.BoneId.ToString()}"); + // } + // + // + // private static void OnPlayerTookDamage(Ped ped, PedDamageInfo info) + // { + // Game.LogTrivial("Damaged!"); + // // Game.DisplayHelp($"~r~Player ~w~took damage from ~g~{info.WeaponInfo.Name} ~w~in ~y~{info.BoneInfo.Limb.ToString()}"); + // } + // + // private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) + // { + // if (!args.Name.StartsWith("DamageTrackingFramework")) return null; + // Game.LogTrivial("Resolved!"); + // return Assembly.Load(File.ReadAllBytes(@"DamageTrackingFramework.dll")); + // } + } +} \ No newline at end of file diff --git a/DamageTrackerLib/packages.config b/DamageTrackerLib/packages.config new file mode 100644 index 0000000..8f90e06 --- /dev/null +++ b/DamageTrackerLib/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/DamageTrackerUtility.sln b/DamageTrackerUtility.sln index 82d2dfc..2bd6a9a 100644 --- a/DamageTrackerUtility.sln +++ b/DamageTrackerUtility.sln @@ -2,6 +2,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DamageTrackingFramework", "DamageTrackingFramework\DamageTrackingFramework.csproj", "{94C2148E-3005-4946-9C57-2CC4D8BC250B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DamageTrackerLib", "DamageTrackerLib\DamageTrackerLib.csproj", "{8BA678B1-D73D-4B13-8D42-F6750285E52A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -12,5 +14,9 @@ Global {94C2148E-3005-4946-9C57-2CC4D8BC250B}.Debug|Any CPU.Build.0 = Debug|Any CPU {94C2148E-3005-4946-9C57-2CC4D8BC250B}.Release|Any CPU.ActiveCfg = Release|Any CPU {94C2148E-3005-4946-9C57-2CC4D8BC250B}.Release|Any CPU.Build.0 = Release|Any CPU + {8BA678B1-D73D-4B13-8D42-F6750285E52A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BA678B1-D73D-4B13-8D42-F6750285E52A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BA678B1-D73D-4B13-8D42-F6750285E52A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BA678B1-D73D-4B13-8D42-F6750285E52A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/DamageTrackerUtility.sln.DotSettings.user b/DamageTrackerUtility.sln.DotSettings.user new file mode 100644 index 0000000..09d4d26 --- /dev/null +++ b/DamageTrackerUtility.sln.DotSettings.user @@ -0,0 +1,3 @@ + + True + True \ No newline at end of file diff --git a/DamageTrackingFramework/.vs/DamageTrackingFramework/v16/.suo b/DamageTrackingFramework/.vs/DamageTrackingFramework/v16/.suo new file mode 100644 index 0000000000000000000000000000000000000000..da090903b0eee4f111efbd5c7d557e0974308e7e GIT binary patch literal 15360 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 literal 0 HcmV?d00001 diff --git a/DamageTrackingFramework/App.config b/DamageTrackingFramework/App.config new file mode 100644 index 0000000..7064a37 --- /dev/null +++ b/DamageTrackingFramework/App.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index 95d30f6..1d6ecf7 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using DamageTrackingFramework.DamageInfo; +using DamageTrackerLib; +using DamageTrackerLib.DamageInfo; using Rage; using Rage.Native; -using WeaponHash = DamageTrackingFramework.DamageInfo.WeaponHash; +using WeaponHash = DamageTrackerLib.DamageInfo.WeaponHash; namespace DamageTrackingFramework { diff --git a/DamageTrackingFramework/DamageTrackingFramework.csproj b/DamageTrackingFramework/DamageTrackingFramework.csproj index 82083c0..c48d377 100644 --- a/DamageTrackingFramework/DamageTrackingFramework.csproj +++ b/DamageTrackingFramework/DamageTrackingFramework.csproj @@ -12,6 +12,7 @@ v4.8 512 true + 10 AnyCPU @@ -33,6 +34,9 @@ 4 + + ..\references\DamageTrackerLib.dll + @@ -45,18 +49,8 @@ - - - - - - - - - - diff --git a/DamageTrackingFramework/PipeServer.cs b/DamageTrackingFramework/PipeServer.cs index d1054c0..e6229cd 100644 --- a/DamageTrackingFramework/PipeServer.cs +++ b/DamageTrackingFramework/PipeServer.cs @@ -1,10 +1,8 @@ using System; -using System.Collections; using System.Collections.Generic; using System.IO.Pipes; using System.Runtime.Serialization.Formatters.Binary; using System.Threading; -using DamageTrackingFramework.DamageInfo; using Rage; namespace DamageTrackingFramework diff --git a/DamageTrackingFramework/packages.config b/DamageTrackingFramework/packages.config new file mode 100644 index 0000000..8f90e06 --- /dev/null +++ b/DamageTrackingFramework/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 4a9e0ae7f8e947391730917247652fd955568efe Mon Sep 17 00:00:00 2001 From: Vari Date: Thu, 19 Jan 2023 00:33:21 +0000 Subject: [PATCH 02/50] feat(ipc): remove pipe server functionality in place of shared memory --- DamageTrackerLib/DamageInfo/PedDamageInfo.cs | 2 +- DamageTrackerLib/DamageTrackerLib.csproj | 1 + DamageTrackerLib/Process.cs | 54 +++++---------- DamageTrackingFramework/DamageTracker.cs | 65 ++++++++++--------- .../DamageTrackingFramework.csproj | 3 +- DamageTrackingFramework/Entry.cs | 1 - DamageTrackingFramework/PipeServer.cs | 62 ------------------ 7 files changed, 56 insertions(+), 132 deletions(-) delete mode 100644 DamageTrackingFramework/PipeServer.cs diff --git a/DamageTrackerLib/DamageInfo/PedDamageInfo.cs b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs index c03ae47..4fb29d2 100644 --- a/DamageTrackerLib/DamageInfo/PedDamageInfo.cs +++ b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs @@ -6,7 +6,7 @@ namespace DamageTrackerLib.DamageInfo [Serializable] public struct PedDamageInfo { - public Ped Ped; + public uint PedHandle; public int Damage; public WeaponDamageInfo WeaponInfo; public BoneDamageInfo BoneInfo; diff --git a/DamageTrackerLib/DamageTrackerLib.csproj b/DamageTrackerLib/DamageTrackerLib.csproj index db863bd..e43a81a 100644 --- a/DamageTrackerLib/DamageTrackerLib.csproj +++ b/DamageTrackerLib/DamageTrackerLib.csproj @@ -11,6 +11,7 @@ DamageTrackerLib v4.8 512 + 10 AnyCPU diff --git a/DamageTrackerLib/Process.cs b/DamageTrackerLib/Process.cs index e949518..e702e1d 100644 --- a/DamageTrackerLib/Process.cs +++ b/DamageTrackerLib/Process.cs @@ -1,51 +1,31 @@ using System; -using System.IO.Pipes; +using System.IO; +using System.IO.MemoryMappedFiles; using System.Runtime.Serialization.Formatters.Binary; +using DamageTrackerLib.DamageInfo; using Rage; -using Rage.Attributes; - -[assembly: Plugin("DamageTrackerLib", Description = "A plugin for testing.", - Author = "Variapolis", - PrefersSingleInstance = true)] +using WeaponHash = DamageTrackerLib.DamageInfo.WeaponHash; namespace DamageTrackerLib { // ReSharper disable once UnusedType.Global public static class Process { - } - - public static class PipeClient - { - private static readonly BinaryFormatter BinaryFormatter = new BinaryFormatter(); + public const string Guid = "609a228f-ac5d-4308-849b-34ebafcc9778"; + private static readonly BinaryFormatter binaryFormatter = new(); - internal static void Run() + public static void Run() { - var pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.In); - - - Game.LogTrivial("Connecting to server."); - pipeClient.Connect(); - Game.LogTrivial("Connected to server."); - - - // Validate the server's signature string. - try - { - Game.LogTrivial("Attempting to deserialize."); - var shit = (int)BinaryFormatter.Deserialize(pipeClient); // HACK: NEEDS TO BE CAST TO A PED DAMAGE INFO - Game.LogTrivial($"Success! {shit}"); - } - // Catch the IOException that is raised if the pipe is broken or disconnected. - catch (Exception e) - { - Game.LogTrivial($"ERROR: {e.Message}"); - } - finally - { - pipeClient.Close(); - Game.LogTrivial("Client Closed."); - } + using var mmf = MemoryMappedFile.OpenExisting(Guid); + using var mmfAccessor = mmf.CreateViewAccessor(); + using var stream = new MemoryStream(); + var buffer = new byte[mmfAccessor.Capacity]; + mmfAccessor.ReadArray(0, buffer, 0, buffer.Length); + stream.Write(buffer,0,buffer.Length); + Game.LogTrivial(stream.Length.ToString()); + stream.Position = 0; + var damagedPeds = (PedDamageInfo[])binaryFormatter.Deserialize(stream); + foreach (var ped in damagedPeds) Game.DisplayHelp(Enum.GetName(typeof(WeaponHash), ped.WeaponInfo.Hash), 2); } } } \ No newline at end of file diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index 1d6ecf7..8d4242a 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.IO; +using System.IO.MemoryMappedFiles; using System.Linq; +using System.Runtime.Serialization.Formatters.Binary; using DamageTrackerLib; using DamageTrackerLib.DamageInfo; using Rage; @@ -9,33 +12,50 @@ namespace DamageTrackingFramework { - public static class DamageTracker + internal static class DamageTracker { - public delegate void PedDamagedDelegate(Ped ped, PedDamageInfo pedDamageInfo); + // ReSharper disable once HeapView.ObjectAllocation.Evident + private static readonly Dictionary PedDict = new(); - public static event PedDamagedDelegate OnPedTookDamage; - public static event PedDamagedDelegate OnPlayerTookDamage; + private static readonly List pedDamageList = new() + { + new PedDamageInfo + { + Damage = 0, PedHandle = Game.LocalPlayer.Character.Handle.Value, BoneInfo = new BoneDamageInfo(), + WeaponInfo = new WeaponDamageInfo() + } + }; - // ReSharper disable once HeapView.ObjectAllocation.Evident - private static readonly Dictionary PedDict = new Dictionary(); + private static readonly BinaryFormatter _binaryFormatter = new(); internal static void CheckPedsFiber() { - // var beforeCount = DamageSubCount; - // OnPedTookDamage += Test; - // Game.LogTrivial($"{beforeCount} to {DamageSubCount}"); - PipeServer.Start(); + using var mmf = MemoryMappedFile.CreateOrOpen(Process.Guid, 10000, + MemoryMappedFileAccess.ReadWrite); // TODO: Replace with GUID from Lib + using var mmfAccessor = mmf.CreateViewAccessor(); + using var stream = new MemoryStream(); while (true) { + pedDamageList.Clear(); var peds = World.GetAllPeds(); - foreach (var ped in peds) HandlePed(ped); // TODO: Add peds to pipe queue here - // TODO: Flush ped queue here + foreach (var ped in peds) HandlePed(ped); + SendPedData(mmfAccessor, stream); + Process.Run(); CleanPedDictionary(); GameFiber.Yield(); } // ReSharper disable once FunctionNeverReturns } + private static void SendPedData(MemoryMappedViewAccessor accessor, MemoryStream stream) + { + stream.SetLength(0); + _binaryFormatter.Serialize(stream, pedDamageList.ToArray()); + var buffer = stream.ToArray(); + accessor.WriteArray(0, buffer, 0, buffer.Length); + accessor.Flush(); + } + private static void HandlePed(Ped ped) { if (!ped.Exists()) return; @@ -43,32 +63,19 @@ private static void HandlePed(Ped ped) var previousHealth = PedDict[ped]; if (!TryGetPedDamage(ped, out var damage)) return; - InvokeDamageEvent(ped, GenerateDamageInfo(ped, previousHealth, damage)); + pedDamageList.Add(GenerateDamageInfo(ped, previousHealth, damage)); ClearPedDamage(ped); } - private static void InvokeDamageEvent(Ped ped, PedDamageInfo damageInfo) - { - switch (ped.IsPlayer) - { - case true when OnPlayerTookDamage != null: - OnPlayerTookDamage(ped, damageInfo); - break; - case false when OnPedTookDamage != null: - OnPedTookDamage(ped, damageInfo); - break; - } - } - private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, WeaponDamageInfo damage) { var lastDamagedBone = (BoneId)ped.LastDamageBone; var boneTuple = Lookups.BoneLookup[lastDamagedBone]; - return new PedDamageInfo() + return new PedDamageInfo { Damage = previousHealth - ped.Health, WeaponInfo = damage, - BoneInfo = new BoneDamageInfo() + BoneInfo = new BoneDamageInfo { BoneId = lastDamagedBone, Limb = boneTuple.limb, @@ -103,7 +110,7 @@ private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) !Lookups.WeaponLookup.ContainsKey(*(WeaponHash*)hashAddr)) return false; // May not be necessary. var weaponHash = *(WeaponHash*)hashAddr; var damageTuple = Lookups.WeaponLookup[weaponHash]; - damage = new WeaponDamageInfo() + damage = new WeaponDamageInfo { Hash = weaponHash, Group = damageTuple.DamageGroup, diff --git a/DamageTrackingFramework/DamageTrackingFramework.csproj b/DamageTrackingFramework/DamageTrackingFramework.csproj index c48d377..1cdc466 100644 --- a/DamageTrackingFramework/DamageTrackingFramework.csproj +++ b/DamageTrackingFramework/DamageTrackingFramework.csproj @@ -35,7 +35,7 @@ - ..\references\DamageTrackerLib.dll + ..\DamageTrackerLib\bin\Release\DamageTrackerLib.dll @@ -50,7 +50,6 @@ - diff --git a/DamageTrackingFramework/Entry.cs b/DamageTrackingFramework/Entry.cs index 79f6631..d96bfdc 100644 --- a/DamageTrackingFramework/Entry.cs +++ b/DamageTrackingFramework/Entry.cs @@ -25,7 +25,6 @@ public static void Main() public static void OnUnload(bool Exit) { Game.DisplayNotification("DamageTrackingFramework by Variapolis ~r~ Unloaded"); - PipeServer.Stop(); _gameFiber.Abort(); } } diff --git a/DamageTrackingFramework/PipeServer.cs b/DamageTrackingFramework/PipeServer.cs deleted file mode 100644 index e6229cd..0000000 --- a/DamageTrackingFramework/PipeServer.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO.Pipes; -using System.Runtime.Serialization.Formatters.Binary; -using System.Threading; -using Rage; - -namespace DamageTrackingFramework -{ - public static class PipeServer - { - private static readonly BinaryFormatter BinaryFormatter = new BinaryFormatter(); - private static Thread _thread; - - public static void Start() - { - _thread = new Thread(Run); - _thread.Start(); - } - - public static void Stop() - { - _thread.Abort(); - _thread = null; - } - - private static void Run() - { - NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut); - - - // Wait for a client to connect - Game.LogTrivial("Waiting for client to connect."); - - pipeServer.WaitForConnection(); // TODO: Convert to GameFiber by checking Connected instead. - Game.LogTrivial("Client connected."); - try - { - Queue q = new Queue(); - for (int i = 0; i < q.Count; i++) BinaryFormatter.Serialize(pipeServer, q.Dequeue()); - pipeServer.Flush(); - Game.LogTrivial("Packet sent!"); - } - // Catch the IOException that is raised if the pipe is broken or disconnected. - catch (Exception e) - { - Game.LogTrivial($"ERROR: {e.Message}"); - } - finally - { - pipeServer.Close(); - Game.LogTrivial("Server Closed."); - } - } - - // public PedDamageInfo ReadString() - // { - // var shit = (PedDamageInfo)BinaryFormatter.Deserialize(ioStream); - // return shit; - // } - } -} \ No newline at end of file From 851e654d5985daec732811cbbc5be3411a609712 Mon Sep 17 00:00:00 2001 From: Vari Date: Thu, 19 Jan 2023 00:33:53 +0000 Subject: [PATCH 03/50] build: update assembly title --- DamageTrackerLib/Properties/AssemblyInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DamageTrackerLib/Properties/AssemblyInfo.cs b/DamageTrackerLib/Properties/AssemblyInfo.cs index 0fd28bc..957e3cd 100644 --- a/DamageTrackerLib/Properties/AssemblyInfo.cs +++ b/DamageTrackerLib/Properties/AssemblyInfo.cs @@ -4,11 +4,11 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("TestRPHPlugin")] +[assembly: AssemblyTitle("DamageTrackerLib")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("TestRPHPlugin")] +[assembly: AssemblyProduct("DamageTrackerLib")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] From 6bbea2e7c6a6e36ea691a8e10266dfc8365e9c39 Mon Sep 17 00:00:00 2001 From: Vari Date: Thu, 19 Jan 2023 02:18:35 +0000 Subject: [PATCH 04/50] feat(ipc): make damage tracker use shared memory list correctly --- DamageTrackingFramework/DamageTracker.cs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index 8d4242a..d14374a 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -17,26 +17,19 @@ internal static class DamageTracker // ReSharper disable once HeapView.ObjectAllocation.Evident private static readonly Dictionary PedDict = new(); - private static readonly List pedDamageList = new() - { - new PedDamageInfo - { - Damage = 0, PedHandle = Game.LocalPlayer.Character.Handle.Value, BoneInfo = new BoneDamageInfo(), - WeaponInfo = new WeaponDamageInfo() - } - }; + private static readonly List PedDamageList = new(); - private static readonly BinaryFormatter _binaryFormatter = new(); + private static readonly BinaryFormatter Formatter = new(); internal static void CheckPedsFiber() { - using var mmf = MemoryMappedFile.CreateOrOpen(Process.Guid, 10000, + using var mmf = MemoryMappedFile.CreateOrOpen(Process.Guid, 20000, MemoryMappedFileAccess.ReadWrite); // TODO: Replace with GUID from Lib using var mmfAccessor = mmf.CreateViewAccessor(); using var stream = new MemoryStream(); while (true) { - pedDamageList.Clear(); + PedDamageList.Clear(); var peds = World.GetAllPeds(); foreach (var ped in peds) HandlePed(ped); SendPedData(mmfAccessor, stream); @@ -50,7 +43,7 @@ internal static void CheckPedsFiber() private static void SendPedData(MemoryMappedViewAccessor accessor, MemoryStream stream) { stream.SetLength(0); - _binaryFormatter.Serialize(stream, pedDamageList.ToArray()); + Formatter.Serialize(stream, PedDamageList.ToArray()); var buffer = stream.ToArray(); accessor.WriteArray(0, buffer, 0, buffer.Length); accessor.Flush(); @@ -63,7 +56,7 @@ private static void HandlePed(Ped ped) var previousHealth = PedDict[ped]; if (!TryGetPedDamage(ped, out var damage)) return; - pedDamageList.Add(GenerateDamageInfo(ped, previousHealth, damage)); + PedDamageList.Add(GenerateDamageInfo(ped, previousHealth, damage)); ClearPedDamage(ped); } @@ -73,6 +66,7 @@ private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, Wea var boneTuple = Lookups.BoneLookup[lastDamagedBone]; return new PedDamageInfo { + PedHandle = ped.Handle, Damage = previousHealth - ped.Health, WeaponInfo = damage, BoneInfo = new BoneDamageInfo From 777f737c2ac2f69cd78951889fce5ba9c26d0d56 Mon Sep 17 00:00:00 2001 From: Vari Date: Thu, 19 Jan 2023 02:19:46 +0000 Subject: [PATCH 05/50] refactor(library): cleanup Process.cs --- DamageTrackerLib/Process.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/DamageTrackerLib/Process.cs b/DamageTrackerLib/Process.cs index e702e1d..be217d9 100644 --- a/DamageTrackerLib/Process.cs +++ b/DamageTrackerLib/Process.cs @@ -21,11 +21,13 @@ public static void Run() using var stream = new MemoryStream(); var buffer = new byte[mmfAccessor.Capacity]; mmfAccessor.ReadArray(0, buffer, 0, buffer.Length); - stream.Write(buffer,0,buffer.Length); - Game.LogTrivial(stream.Length.ToString()); + stream.Write(buffer, 0, buffer.Length); stream.Position = 0; var damagedPeds = (PedDamageInfo[])binaryFormatter.Deserialize(stream); - foreach (var ped in damagedPeds) Game.DisplayHelp(Enum.GetName(typeof(WeaponHash), ped.WeaponInfo.Hash), 2); + foreach (var pedDamageInfo in damagedPeds) + { + var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); + } } } } \ No newline at end of file From b68e35477b8534288352b75b87a4154494f672f7 Mon Sep 17 00:00:00 2001 From: Vari Date: Thu, 19 Jan 2023 18:11:39 +0000 Subject: [PATCH 06/50] refactor: clean up files --- DamageTrackerLib/DamageInfo/PedDamageInfo.cs | 1 - DamageTrackerLib/Lookups.cs | 4 ++-- DamageTrackerLib/Process.cs | 4 +--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/DamageTrackerLib/DamageInfo/PedDamageInfo.cs b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs index 4fb29d2..a2e5a0b 100644 --- a/DamageTrackerLib/DamageInfo/PedDamageInfo.cs +++ b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs @@ -1,5 +1,4 @@ using System; -using Rage; namespace DamageTrackerLib.DamageInfo { diff --git a/DamageTrackerLib/Lookups.cs b/DamageTrackerLib/Lookups.cs index 22aeb57..0cbb1c6 100644 --- a/DamageTrackerLib/Lookups.cs +++ b/DamageTrackerLib/Lookups.cs @@ -7,7 +7,7 @@ public static class Lookups { public static readonly Dictionary BoneLookup = - new Dictionary + new() { [BoneId.Root] = (Limb.Stomach, BodyRegion.Torso), [BoneId.LeftThumb1] = (Limb.LeftArm, BodyRegion.Arms), @@ -70,7 +70,7 @@ public static class Lookups public static readonly Dictionary WeaponLookup = - new Dictionary + new() { [WeaponHash.Antique_Cavalry_Dagger] = ("Antique Cavalry Dagger", DamageGroup.Melee, DamageType.MeleeStab), diff --git a/DamageTrackerLib/Process.cs b/DamageTrackerLib/Process.cs index be217d9..f2ea547 100644 --- a/DamageTrackerLib/Process.cs +++ b/DamageTrackerLib/Process.cs @@ -1,10 +1,8 @@ -using System; -using System.IO; +using System.IO; using System.IO.MemoryMappedFiles; using System.Runtime.Serialization.Formatters.Binary; using DamageTrackerLib.DamageInfo; using Rage; -using WeaponHash = DamageTrackerLib.DamageInfo.WeaponHash; namespace DamageTrackerLib { From 48e27c712c4ef5a8b7f859ccfa2191d1d93abb59 Mon Sep 17 00:00:00 2001 From: Vari Date: Thu, 19 Jan 2023 21:26:01 +0000 Subject: [PATCH 07/50] fix: add useless native to main function to warm up jit --- DamageTrackingFramework/Entry.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DamageTrackingFramework/Entry.cs b/DamageTrackingFramework/Entry.cs index d96bfdc..c7c9286 100644 --- a/DamageTrackingFramework/Entry.cs +++ b/DamageTrackingFramework/Entry.cs @@ -1,5 +1,6 @@ using Rage; using Rage.Attributes; +using Rage.Native; [assembly: Plugin("DamageTrackingFramework", Description = "A damage tracking utility for GTA V mods.", Author = "Variapolis", PrefersSingleInstance = true)] @@ -14,6 +15,7 @@ public class EntryPoint // ReSharper disable once UnusedMember.Global public static void Main() { + NativeFunction.Natives.x5BA652A0CD14DF2F(); // HACK: Fixes stuttering issue by warming up JIT with a useless native. _gameFiber = GameFiber.StartNew(DamageTracker.CheckPedsFiber); Game.LogTrivial("GameFiber started!"); Game.DisplayNotification("DamageTrackerFramework by Variapolis ~g~Successfully Loaded"); From 076903700749e8c43b700543da2a05a343f7e00f Mon Sep 17 00:00:00 2001 From: Vari Date: Thu, 19 Jan 2023 23:55:03 +0000 Subject: [PATCH 08/50] refactor(damage-tracker-lib): rename classes to reflect the use case --- DamageTrackerLib/DamageTrackerLib.csproj | 4 ++-- DamageTrackerLib/{Lookups.cs => DamageTrackerLookups.cs} | 2 +- DamageTrackerLib/{Process.cs => DamageTrackerService.cs} | 2 +- DamageTrackingFramework/DamageTracker.cs | 9 ++++----- 4 files changed, 8 insertions(+), 9 deletions(-) rename DamageTrackerLib/{Lookups.cs => DamageTrackerLookups.cs} (99%) rename DamageTrackerLib/{Process.cs => DamageTrackerService.cs} (96%) diff --git a/DamageTrackerLib/DamageTrackerLib.csproj b/DamageTrackerLib/DamageTrackerLib.csproj index e43a81a..d809342 100644 --- a/DamageTrackerLib/DamageTrackerLib.csproj +++ b/DamageTrackerLib/DamageTrackerLib.csproj @@ -52,8 +52,8 @@ - - + + diff --git a/DamageTrackerLib/Lookups.cs b/DamageTrackerLib/DamageTrackerLookups.cs similarity index 99% rename from DamageTrackerLib/Lookups.cs rename to DamageTrackerLib/DamageTrackerLookups.cs index 0cbb1c6..e3850a1 100644 --- a/DamageTrackerLib/Lookups.cs +++ b/DamageTrackerLib/DamageTrackerLookups.cs @@ -3,7 +3,7 @@ namespace DamageTrackerLib { - public static class Lookups + public static class DamageTrackerLookups { public static readonly Dictionary BoneLookup = diff --git a/DamageTrackerLib/Process.cs b/DamageTrackerLib/DamageTrackerService.cs similarity index 96% rename from DamageTrackerLib/Process.cs rename to DamageTrackerLib/DamageTrackerService.cs index f2ea547..a1d4ef0 100644 --- a/DamageTrackerLib/Process.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -7,7 +7,7 @@ namespace DamageTrackerLib { // ReSharper disable once UnusedType.Global - public static class Process + public static class DamageTrackerService { public const string Guid = "609a228f-ac5d-4308-849b-34ebafcc9778"; private static readonly BinaryFormatter binaryFormatter = new(); diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index d14374a..62b87fa 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -23,7 +23,7 @@ internal static class DamageTracker internal static void CheckPedsFiber() { - using var mmf = MemoryMappedFile.CreateOrOpen(Process.Guid, 20000, + using var mmf = MemoryMappedFile.CreateOrOpen(DamageTrackerService.Guid, 20000, MemoryMappedFileAccess.ReadWrite); // TODO: Replace with GUID from Lib using var mmfAccessor = mmf.CreateViewAccessor(); using var stream = new MemoryStream(); @@ -33,7 +33,6 @@ internal static void CheckPedsFiber() var peds = World.GetAllPeds(); foreach (var ped in peds) HandlePed(ped); SendPedData(mmfAccessor, stream); - Process.Run(); CleanPedDictionary(); GameFiber.Yield(); } @@ -63,7 +62,7 @@ private static void HandlePed(Ped ped) private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, WeaponDamageInfo damage) { var lastDamagedBone = (BoneId)ped.LastDamageBone; - var boneTuple = Lookups.BoneLookup[lastDamagedBone]; + var boneTuple = DamageTrackerLookups.BoneLookup[lastDamagedBone]; return new PedDamageInfo { PedHandle = ped.Handle, @@ -101,9 +100,9 @@ private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) var hashAddr = damageHandler + 8; if (hashAddr == IntPtr.Zero || *(WeaponHash*)hashAddr == 0 || - !Lookups.WeaponLookup.ContainsKey(*(WeaponHash*)hashAddr)) return false; // May not be necessary. + !DamageTrackerLookups.WeaponLookup.ContainsKey(*(WeaponHash*)hashAddr)) return false; // May not be necessary. var weaponHash = *(WeaponHash*)hashAddr; - var damageTuple = Lookups.WeaponLookup[weaponHash]; + var damageTuple = DamageTrackerLookups.WeaponLookup[weaponHash]; damage = new WeaponDamageInfo { Hash = weaponHash, From 0dc90645a2815707289f8af61518d8587013c8f8 Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 20 Jan 2023 00:05:50 +0000 Subject: [PATCH 09/50] feat(damage-tracker-lib): add events --- DamageTrackerLib/DamageTrackerService.cs | 37 +++++++++++++++++++----- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index a1d4ef0..04d8100 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -10,22 +10,43 @@ namespace DamageTrackerLib public static class DamageTrackerService { public const string Guid = "609a228f-ac5d-4308-849b-34ebafcc9778"; + public delegate void PedTookDamageDelegate(Ped ped, PedDamageInfo damageInfo); + public static event PedTookDamageDelegate OnPedTookDamage; + public static event PedTookDamageDelegate OnPlayerTookDamage; + private static readonly BinaryFormatter binaryFormatter = new(); + private static readonly GameFiber _gameFiber = new(Run); + public static void Start() => _gameFiber.Start(); - public static void Run() + public static void Stop() => _gameFiber.Abort(); + + private static void Run() { using var mmf = MemoryMappedFile.OpenExisting(Guid); using var mmfAccessor = mmf.CreateViewAccessor(); using var stream = new MemoryStream(); - var buffer = new byte[mmfAccessor.Capacity]; - mmfAccessor.ReadArray(0, buffer, 0, buffer.Length); - stream.Write(buffer, 0, buffer.Length); - stream.Position = 0; - var damagedPeds = (PedDamageInfo[])binaryFormatter.Deserialize(stream); - foreach (var pedDamageInfo in damagedPeds) + while (true) { - var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); + var buffer = new byte[mmfAccessor.Capacity]; + mmfAccessor.ReadArray(0, buffer, 0, buffer.Length); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; + var damagedPeds = (PedDamageInfo[])binaryFormatter.Deserialize(stream); + foreach (var pedDamageInfo in damagedPeds) + { + var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); + switch (ped.IsPlayer) + { + case true when OnPlayerTookDamage != null: + OnPlayerTookDamage(ped, pedDamageInfo); + break; + case false when OnPedTookDamage != null: + OnPedTookDamage(ped, pedDamageInfo); + break; + } + } } + // ReSharper disable once FunctionNeverReturns } } } \ No newline at end of file From d795776eae9b6147b880c6e48e8288d901e841be Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 20 Jan 2023 00:12:25 +0000 Subject: [PATCH 10/50] chore: delete Wrapper.cs --- DamageTrackerLib/DamageTrackerLib.csproj | 1 - DamageTrackerLib/Wrapper.cs | 42 ------------------------ 2 files changed, 43 deletions(-) delete mode 100644 DamageTrackerLib/Wrapper.cs diff --git a/DamageTrackerLib/DamageTrackerLib.csproj b/DamageTrackerLib/DamageTrackerLib.csproj index d809342..88f059e 100644 --- a/DamageTrackerLib/DamageTrackerLib.csproj +++ b/DamageTrackerLib/DamageTrackerLib.csproj @@ -55,7 +55,6 @@ - diff --git a/DamageTrackerLib/Wrapper.cs b/DamageTrackerLib/Wrapper.cs deleted file mode 100644 index 28f3f2e..0000000 --- a/DamageTrackerLib/Wrapper.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace DamageTrackerLib -{ - internal static class Wrapper - { - // static Wrapper() => AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve; - // - // [MethodImpl(MethodImplOptions.NoInlining)] - // public static void Start() - // { - // Game.LogTrivial("Started!"); - // var beforeCount = DamageTrackingFramework.DamageTracker.DamageSubCount; - // DamageTrackingFramework.DamageTracker.OnPedTookDamage += OnPlayerTookDamage; - // Game.LogTrivial($"[Start] {beforeCount} to {DamageTrackingFramework.DamageTracker.DamageSubCount}"); - // } - // - // [MethodImpl(MethodImplOptions.NoInlining)] - // public static void Call() - // { - // Game.LogTrivial($"[Call] {DamageTrackingFramework.DamageTracker.DamageSubCount}"); - // // DamageTrackingFramework.EntryPoint.GetPlayer(); - // } - // - // private static void PrintPed(Ped ped, PedDamageInfo info) - // { - // Game.DisplayHelp($"{ped.Model.Name} {info.Damage} {info.WeaponInfo.Hash.ToString()} {info.BoneInfo.BoneId.ToString()}"); - // } - // - // - // private static void OnPlayerTookDamage(Ped ped, PedDamageInfo info) - // { - // Game.LogTrivial("Damaged!"); - // // Game.DisplayHelp($"~r~Player ~w~took damage from ~g~{info.WeaponInfo.Name} ~w~in ~y~{info.BoneInfo.Limb.ToString()}"); - // } - // - // private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) - // { - // if (!args.Name.StartsWith("DamageTrackingFramework")) return null; - // Game.LogTrivial("Resolved!"); - // return Assembly.Load(File.ReadAllBytes(@"DamageTrackingFramework.dll")); - // } - } -} \ No newline at end of file From 8176d5e2de1721a7e4e3f80425385c5bb47a62f9 Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 20 Jan 2023 01:58:18 +0000 Subject: [PATCH 11/50] fix(damage-tracker-lib): fix shared memory not being read properly --- DamageTrackerLib/DamageInfo/DamageType.cs | 2 +- DamageTrackerLib/DamageTrackerService.cs | 24 +++++++++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/DamageTrackerLib/DamageInfo/DamageType.cs b/DamageTrackerLib/DamageInfo/DamageType.cs index 74a2bbf..e840afb 100644 --- a/DamageTrackerLib/DamageInfo/DamageType.cs +++ b/DamageTrackerLib/DamageInfo/DamageType.cs @@ -19,7 +19,7 @@ public enum DamageType Misc = 14, NonDamaging = 15, WaterCannon = 16, - Medical = 17, + Medical = 17, // I.E. Bleeding Drowning = 18, Animal = 19, Vehicle = 20, diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 04d8100..f79003d 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -9,14 +9,24 @@ namespace DamageTrackerLib // ReSharper disable once UnusedType.Global public static class DamageTrackerService { - public const string Guid = "609a228f-ac5d-4308-849b-34ebafcc9778"; + public const string Guid = "609a228f"; + public delegate void PedTookDamageDelegate(Ped ped, PedDamageInfo damageInfo); + public static event PedTookDamageDelegate OnPedTookDamage; public static event PedTookDamageDelegate OnPlayerTookDamage; - + private static readonly BinaryFormatter binaryFormatter = new(); - private static readonly GameFiber _gameFiber = new(Run); - public static void Start() => _gameFiber.Start(); + private static GameFiber _gameFiber; + public static void Start() + { + if (_gameFiber != null) + { + Game.LogTrivial("Tried to start DamageTrackerService while already running!"); + return; + } + _gameFiber = GameFiber.StartNew(Run); + } public static void Stop() => _gameFiber.Abort(); @@ -27,6 +37,7 @@ private static void Run() using var stream = new MemoryStream(); while (true) { + stream.SetLength(0); var buffer = new byte[mmfAccessor.Capacity]; mmfAccessor.ReadArray(0, buffer, 0, buffer.Length); stream.Write(buffer, 0, buffer.Length); @@ -38,13 +49,14 @@ private static void Run() switch (ped.IsPlayer) { case true when OnPlayerTookDamage != null: - OnPlayerTookDamage(ped, pedDamageInfo); + OnPlayerTookDamage.Invoke(ped, pedDamageInfo); break; case false when OnPedTookDamage != null: - OnPedTookDamage(ped, pedDamageInfo); + OnPedTookDamage.Invoke(ped, pedDamageInfo); break; } } + GameFiber.Yield(); } // ReSharper disable once FunctionNeverReturns } From a574c0db82d052c7e59c51dc262426c366733ca3 Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 20 Jan 2023 21:44:44 +0000 Subject: [PATCH 12/50] fix(damage-tracker-lib): fix crash if dependent plugin loads before or without framework --- DamageTrackerLib/DamageTrackerService.cs | 16 ++++++++++++++-- DamageTrackerUtility.sln.DotSettings.user | 5 ++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index f79003d..1a1e186 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -18,6 +18,7 @@ public static class DamageTrackerService private static readonly BinaryFormatter binaryFormatter = new(); private static GameFiber _gameFiber; + public static void Start() { if (_gameFiber != null) @@ -25,6 +26,7 @@ public static void Start() Game.LogTrivial("Tried to start DamageTrackerService while already running!"); return; } + _gameFiber = GameFiber.StartNew(Run); } @@ -32,16 +34,19 @@ public static void Start() private static void Run() { - using var mmf = MemoryMappedFile.OpenExisting(Guid); + using var mmf = MemoryMappedFile.CreateOrOpen(Guid, 20000, MemoryMappedFileAccess.ReadWrite); using var mmfAccessor = mmf.CreateViewAccessor(); using var stream = new MemoryStream(); while (true) { + GameFiber.Yield(); stream.SetLength(0); var buffer = new byte[mmfAccessor.Capacity]; mmfAccessor.ReadArray(0, buffer, 0, buffer.Length); + if (IsByteArrayZero(buffer)) continue; stream.Write(buffer, 0, buffer.Length); stream.Position = 0; + if(stream.Length <= 0) continue; var damagedPeds = (PedDamageInfo[])binaryFormatter.Deserialize(stream); foreach (var pedDamageInfo in damagedPeds) { @@ -56,9 +61,16 @@ private static void Run() break; } } - GameFiber.Yield(); } // ReSharper disable once FunctionNeverReturns } + + private static bool IsByteArrayZero(byte[] array) + { + foreach (var element in array) + if (element != 0) + return false; + return true; + } } } \ No newline at end of file diff --git a/DamageTrackerUtility.sln.DotSettings.user b/DamageTrackerUtility.sln.DotSettings.user index 09d4d26..230426c 100644 --- a/DamageTrackerUtility.sln.DotSettings.user +++ b/DamageTrackerUtility.sln.DotSettings.user @@ -1,3 +1,6 @@  True - True \ No newline at end of file + True + <AssemblyExplorer> + <Assembly Path="D:\Users\Vari\Desktop\Work\Forks\DamageTrackerPlugin\DamageTrackerUtility\packages\RagePluginHook.1.98.0\lib\net472\RagePluginHook.dll" /> +</AssemblyExplorer> \ No newline at end of file From 312d5b8a0a9772d89a787885cc4477c6571247a6 Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 20 Jan 2023 21:53:34 +0000 Subject: [PATCH 13/50] chore: add comments to DamageTrackerService.cs --- DamageTrackerLib/DamageTrackerService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 1a1e186..7dea3b5 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -43,10 +43,10 @@ private static void Run() stream.SetLength(0); var buffer = new byte[mmfAccessor.Capacity]; mmfAccessor.ReadArray(0, buffer, 0, buffer.Length); - if (IsByteArrayZero(buffer)) continue; + if (IsByteArrayZero(buffer)) continue; // TODO: Add error message stream.Write(buffer, 0, buffer.Length); stream.Position = 0; - if(stream.Length <= 0) continue; + if (stream.Length <= 0) continue; // TODO: Add error message var damagedPeds = (PedDamageInfo[])binaryFormatter.Deserialize(stream); foreach (var pedDamageInfo in damagedPeds) { From 652b06679ff1c3795613240645e2c465a03cde70 Mon Sep 17 00:00:00 2001 From: Vari Date: Sun, 22 Jan 2023 20:08:17 +0000 Subject: [PATCH 14/50] feat(damage-tracker): add check if ped is human --- DamageTrackingFramework/DamageTracker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index 62b87fa..7710193 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -50,7 +50,7 @@ private static void SendPedData(MemoryMappedViewAccessor accessor, MemoryStream private static void HandlePed(Ped ped) { - if (!ped.Exists()) return; + if (!ped.Exists() || !ped.IsHuman) return; if (!PedDict.ContainsKey(ped)) PedDict.Add(ped, ped.Health); var previousHealth = PedDict[ped]; From e7a72e3691e2814e2b5db3a50c183a81494de5ad Mon Sep 17 00:00:00 2001 From: Vari Date: Sun, 22 Jan 2023 20:08:40 +0000 Subject: [PATCH 15/50] docs: add todo comments --- DamageTrackingFramework/DamageTracker.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index 7710193..c2875dd 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -3,6 +3,7 @@ using System.IO; using System.IO.MemoryMappedFiles; using System.Linq; +using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; using DamageTrackerLib; using DamageTrackerLib.DamageInfo; @@ -39,8 +40,10 @@ internal static void CheckPedsFiber() // ReSharper disable once FunctionNeverReturns } - private static void SendPedData(MemoryMappedViewAccessor accessor, MemoryStream stream) + private static void SendPedData(MemoryMappedViewAccessor accessor, MemoryStream stream) // TODO: Resize file if ped count is too small or send less. { + // var requiredSize = Marshal.SizeOf(PedDamageList) + (PedDamageList.Count * Marshal.SizeOf()) + 2000; + // if(requiredSize > accessor.Capacity) stream.SetLength(0); Formatter.Serialize(stream, PedDamageList.ToArray()); var buffer = stream.ToArray(); @@ -83,7 +86,7 @@ private static void ClearPedDamage(Ped ped) NativeFunction.Natives.xAC678E40BE7C74D2(ped); } - private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) + private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) // BUG: Fire doesn't damage per tick { var pedAddr = ped.MemoryAddress; damage = default; From 0327d606519c4eb10cf4826490e654104074ecc4 Mon Sep 17 00:00:00 2001 From: Vari Date: Tue, 7 Feb 2023 00:37:13 +0000 Subject: [PATCH 16/50] refactor: clean up lookup dictionary and rename medical damage type to bodily --- DamageTrackerLib/DamageInfo/DamageGroup.cs | 2 +- DamageTrackerLib/DamageInfo/DamageType.cs | 2 +- DamageTrackerLib/DamageTrackerLookups.cs | 576 ++++++++------------- 3 files changed, 231 insertions(+), 349 deletions(-) diff --git a/DamageTrackerLib/DamageInfo/DamageGroup.cs b/DamageTrackerLib/DamageInfo/DamageGroup.cs index 8dbc61f..ed4515f 100644 --- a/DamageTrackerLib/DamageInfo/DamageGroup.cs +++ b/DamageTrackerLib/DamageInfo/DamageGroup.cs @@ -15,7 +15,7 @@ public enum DamageGroup Environmental = 11, Gas = 12, WaterCannon = 13, - Medical = 14, + Bodily = 14, Drowning = 15 } } \ No newline at end of file diff --git a/DamageTrackerLib/DamageInfo/DamageType.cs b/DamageTrackerLib/DamageInfo/DamageType.cs index e840afb..fd25ed4 100644 --- a/DamageTrackerLib/DamageInfo/DamageType.cs +++ b/DamageTrackerLib/DamageInfo/DamageType.cs @@ -19,7 +19,7 @@ public enum DamageType Misc = 14, NonDamaging = 15, WaterCannon = 16, - Medical = 17, // I.E. Bleeding + Bodily = 17, // Bleeding, Exhaustion Drowning = 18, Animal = 19, Vehicle = 20, diff --git a/DamageTrackerLib/DamageTrackerLookups.cs b/DamageTrackerLib/DamageTrackerLookups.cs index e3850a1..5a4c666 100644 --- a/DamageTrackerLib/DamageTrackerLookups.cs +++ b/DamageTrackerLib/DamageTrackerLookups.cs @@ -68,356 +68,238 @@ public static class DamageTrackerLookups [BoneId.LeftClavicle] = (Limb.Chest, BodyRegion.Torso), }; - public static readonly Dictionary + public static readonly Dictionary WeaponLookup = new() { - [WeaponHash.Antique_Cavalry_Dagger] = - ("Antique Cavalry Dagger", DamageGroup.Melee, DamageType.MeleeStab), - [WeaponHash.Baseball_Bat] = ("Baseball Bat", DamageGroup.Melee, DamageType.MeleeBlunt), - [WeaponHash.Bottle] = ("Bottle", DamageGroup.Melee, DamageType.MeleeStab), - [WeaponHash.Crowbar] = ("Crowbar", DamageGroup.Melee, DamageType.MeleeBlunt), - [WeaponHash.Fist] = ("Fist", DamageGroup.Melee, DamageType.Unarmed), - [WeaponHash.Flashlight] = ("Flashlight", DamageGroup.Melee, DamageType.MeleeBlunt), - [WeaponHash.Golf_Club] = ("Golf Club", DamageGroup.Melee, DamageType.MeleeBlunt), - [WeaponHash.Hammer] = ("Hammer", DamageGroup.Melee, DamageType.MeleeBlunt), - [WeaponHash.Hatchet] = ("Hatchet", DamageGroup.Melee, DamageType.MeleeStab), - [WeaponHash.Knuckle] = ("Knuckle", DamageGroup.Melee, DamageType.MeleeBlunt), - [WeaponHash.Knife] = ("Knife", DamageGroup.Melee, DamageType.MeleeStab), - [WeaponHash.Machete] = ("Machete", DamageGroup.Melee, DamageType.MeleeStab), - [WeaponHash.Switchblade] = ("Switchblade", DamageGroup.Melee, DamageType.MeleeStab), - [WeaponHash.Nightstick] = ("Nightstick", DamageGroup.Melee, DamageType.MeleeBlunt), - [WeaponHash.Pipe_Wrench] = ("Pipe Wrench", DamageGroup.Melee, DamageType.MeleeBlunt), - [WeaponHash.Battle_Axe] = ("Battle Axe", DamageGroup.Melee, DamageType.MeleeStab), - [WeaponHash.Pool_Cue] = ("Pool Cue", DamageGroup.Melee, DamageType.MeleeBlunt), - [WeaponHash.Stone_Hatchet] = ("Stone Hatchet", DamageGroup.Melee, DamageType.MeleeStab), - [WeaponHash.Pistol] = ("Pistol", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Pistol_MK2] = ("Pistol MK2", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Combat_Pistol] = ("Combat Pistol", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.APPistol] = ("AP Pistol", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Stun_Gun] = ("Stun Gun", DamageGroup.LessThanLethal, DamageType.LessThanLethal), - [WeaponHash.Pistol50] = ("Pistol .50", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.SNSPistol] = ("SNS Pistol", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.SNSPistol_MK2] = ("SNS Pistol MK2", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Heavy_Pistol] = ("Heavy Pistol", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Vintage_Pistol] = ("Vintage Pistol", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Flare_Gun] = ("Flare Gun", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Marksman_Pistol] = ("Marksman Pistol", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Heavy_Revolver] = ("Heavy Revolver", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Heavy_Revolver_MK2] = ("Heavy Revolver MK2", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Double_Action] = ("Double Action", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Up_n_Atomizer] = ("Up-n-Atomizer", DamageGroup.Bullet, DamageType.Pistol), - [WeaponHash.Micro_SMG] = ("Micro SMG", DamageGroup.Bullet, DamageType.SMG), - [WeaponHash.SMG] = ("SMG", DamageGroup.Bullet, DamageType.SMG), - [WeaponHash.SMGMK2] = ("SMG MK2", DamageGroup.Bullet, DamageType.SMG), - [WeaponHash.Assault_SMG] = ("Assault SMG", DamageGroup.Bullet, DamageType.SMG), - [WeaponHash.Combat_PDW] = ("Combat PDW", DamageGroup.Bullet, DamageType.SMG), - [WeaponHash.Machine_Pistol] = ("Machine Pistol", DamageGroup.Bullet, DamageType.SMG), - [WeaponHash.Mini_SMG] = ("Mini SMG", DamageGroup.Bullet, DamageType.SMG), - [WeaponHash.Unholy_Hellbringer] = ("Unholy Hellbringer", DamageGroup.Bullet, DamageType.MG), - [WeaponHash.Pump_Shotgun] = ("Pump Shotgun", DamageGroup.Bullet, DamageType.Shotgun), - [WeaponHash.Pump_Shotgun_MK2] = ("Pump Shotgun MK2", DamageGroup.Bullet, DamageType.Shotgun), - [WeaponHash.Sawed_Off_Shotgun] = ("Sawed-Off Shotgun", DamageGroup.Bullet, DamageType.Shotgun), - [WeaponHash.Assault_Shotgun] = ("Assault Shotgun", DamageGroup.Bullet, DamageType.Shotgun), - [WeaponHash.Bullpup_Shotgun] = ("Bullpup Shotgun", DamageGroup.Bullet, DamageType.Shotgun), - [WeaponHash.Musket] = ("Musket", DamageGroup.Bullet, DamageType.Sniper), - [WeaponHash.Heavy_Shotgun] = ("Heavy Shotgun", DamageGroup.Bullet, DamageType.Shotgun), - [WeaponHash.Double_Barrel_Shotgun] = - ("Double Barrel Shotgun", DamageGroup.Bullet, DamageType.Shotgun), - [WeaponHash.Sweeper_Shotgun] = ("Sweeper Shotgun", DamageGroup.Bullet, DamageType.Shotgun), - [WeaponHash.Assault_Rifle] = ("Assault Rifle", DamageGroup.Bullet, DamageType.Rifle), - [WeaponHash.Assault_Rifle_MK2] = ("Assault Rifle MK2", DamageGroup.Bullet, DamageType.Rifle), - [WeaponHash.Carbine_Rifle] = ("Carbine Rifle", DamageGroup.Bullet, DamageType.Rifle), - [WeaponHash.Carbine_Rifle_MK2] = ("Carbine Rifle MK2", DamageGroup.Bullet, DamageType.Rifle), - [WeaponHash.Advanced_Rifle] = ("Advanced Rifle", DamageGroup.Bullet, DamageType.Rifle), - [WeaponHash.Special_Carbine] = ("Special Carbine", DamageGroup.Bullet, DamageType.Rifle), - [WeaponHash.Special_Carbine_MK2] = ("Special Carbine MK2", DamageGroup.Bullet, DamageType.Rifle), - [WeaponHash.Bullpup_Rifle] = ("Bullpup Rifle", DamageGroup.Bullet, DamageType.Rifle), - [WeaponHash.Bullpup_Rifle_MK2] = ("Bullpup Rifle MK2", DamageGroup.Bullet, DamageType.Rifle), - [WeaponHash.Compact_Rifle] = ("Compact Rifle", DamageGroup.Bullet, DamageType.Rifle), - [WeaponHash.MG] = ("MG", DamageGroup.Bullet, DamageType.MG), - [WeaponHash.Combat_MG] = ("Combat MG", DamageGroup.Bullet, DamageType.MG), - [WeaponHash.Combat_MGMK2] = ("Combat MG MK2", DamageGroup.Bullet, DamageType.MG), - [WeaponHash.Gusenberg_Sweeper] = ("Gusenberg Sweeper", DamageGroup.Bullet, DamageType.MG), - [WeaponHash.Sniper_Rifle] = ("Sniper Rifle", DamageGroup.Bullet, DamageType.Sniper), - [WeaponHash.Heavy_Sniper] = ("Heavy Sniper", DamageGroup.Bullet, DamageType.Sniper), - [WeaponHash.Heavy_Sniper_MK2] = ("Heavy Sniper MK2", DamageGroup.Bullet, DamageType.Sniper), - [WeaponHash.Marksman_Rifle] = ("Marksman Rifle", DamageGroup.Bullet, DamageType.Sniper), - [WeaponHash.Marksman_Rifle_MK2] = ("Marksman Rifle MK2", DamageGroup.Bullet, DamageType.Sniper), - [WeaponHash.RPG] = ("RPG", DamageGroup.Explosion, DamageType.Launcher), - [WeaponHash.Grenade_Launcher] = ("Grenade Launcher", DamageGroup.Explosion, DamageType.Launcher), - [WeaponHash.Smoke_Grenade_Launcher] = ("Smoke Grenade Launcher", DamageGroup.NonDamaging, - DamageType.Launcher), - [WeaponHash.Minigun] = ("Minigun", DamageGroup.Bullet, DamageType.Launcher), - [WeaponHash.Firework_Launcher] = ("Firework Launcher", DamageGroup.Explosion, DamageType.Launcher), - [WeaponHash.Railgun] = ("Railgun", DamageGroup.Explosion, DamageType.Launcher), - [WeaponHash.Homing_Launcher] = ("Homing Launcher", DamageGroup.Explosion, DamageType.Launcher), - [WeaponHash.Compact_Grenade_Launcher] = ("Compact Grenade Launcher", DamageGroup.Explosion, - DamageType.Launcher), - [WeaponHash.Ray_Minigun] = ("Ray Minigun", DamageGroup.Bullet, DamageType.Launcher), - [WeaponHash.Grenade] = ("Grenade", DamageGroup.Explosion, DamageType.Explosive), - [WeaponHash.BZGas] = ("BZ Gas", DamageGroup.Gas, DamageType.Gas), - [WeaponHash.Smoke_Grenade] = - ("Smoke Grenade", DamageGroup.NonDamaging, DamageType.ThrowableNonLethal), - [WeaponHash.Flare] = ("Flare", DamageGroup.NonDamaging, DamageType.ThrowableNonLethal), - [WeaponHash.Molotov] = ("Molotov", DamageGroup.Fire, DamageType.Fire), - [WeaponHash.Sticky_Bomb] = ("Sticky Bomb", DamageGroup.Explosion, DamageType.Explosive), - [WeaponHash.Proximity_Mine] = ("Proximity Mine", DamageGroup.Explosion, DamageType.Explosive), - [WeaponHash.Snowball] = ("Snowball", DamageGroup.NonDamaging, DamageType.ThrowableNonLethal), - [WeaponHash.Pipe_Bomb] = ("Pipe Bomb", DamageGroup.Explosion, DamageType.Explosive), - [WeaponHash.Baseball] = ("Baseball", DamageGroup.NonDamaging, DamageType.ThrowableNonLethal), - [WeaponHash.Jerry_Can] = ("Jerry Can", DamageGroup.NonDamaging, DamageType.Misc), - [WeaponHash.Fire_Extinguisher] = ("Fire Extinguisher", DamageGroup.NonDamaging, DamageType.Misc), - [WeaponHash.Parachute] = ("Parachute", DamageGroup.Unknown, DamageType.Unknown), - [WeaponHash.Electric_Fence] = ("Electric Fence", DamageGroup.Environmental, DamageType.Electric), - [WeaponHash.Hitby_Water_Cannon] = - ("Hit by Water Cannon", DamageGroup.WaterCannon, DamageType.WaterCannon), - [WeaponHash.Rammedby_Car] = ("Rammed by Car", DamageGroup.Vehicle, DamageType.Vehicle), - [WeaponHash.Run_Overby_Car] = ("Run Over by Car", DamageGroup.Vehicle, DamageType.Vehicle), - [WeaponHash.Fall] = ("Fall", DamageGroup.Fall, DamageType.Fall), - [WeaponHash.Animal] = ("Animal", DamageGroup.Animal, DamageType.Animal), - [WeaponHash.Airstrike_Rocket] = ("Airstrike Rocket", DamageGroup.Explosion, DamageType.Launcher), - [WeaponHash.Bleeding] = ("Bleeding", DamageGroup.Medical, DamageType.Medical), - [WeaponHash.Briefcase] = ("Briefcase", DamageGroup.Unknown, DamageType.Unknown), - [WeaponHash.Briefcase02] = ("Briefcase 02", DamageGroup.Unknown, DamageType.Unknown), - [WeaponHash.Cougar] = ("Cougar", DamageGroup.Animal, DamageType.Animal), - [WeaponHash.Barbed_Wire] = ("Barbed Wire", DamageGroup.Environmental, DamageType.BarbedWire), - [WeaponHash.Drowning] = ("Drowning", DamageGroup.Drowning, DamageType.Drowning), - [WeaponHash.Drowning_In_Vehicle] = - ("Drowning In Vehicle", DamageGroup.Drowning, DamageType.Drowning), - [WeaponHash.Explosion] = ("Explosion", DamageGroup.Explosion, DamageType.Explosive), - [WeaponHash.Exhaustion] = ("Exhaustion", DamageGroup.Medical, DamageType.Medical), - [WeaponHash.Fire] = ("Fire", DamageGroup.Fire, DamageType.Fire), - [WeaponHash.Heli_Crash] = ("Heli Crash", DamageGroup.Explosion, DamageType.Explosive), - [WeaponHash.Vehicle_Rocket] = ("Rocket", DamageGroup.Explosion, DamageType.Launcher), - [WeaponHash.Vehicle_Akula_Barrage] = ("Akula Barrage", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Akula_Minigun] = ("Akula Minigun", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Akula_Missile] = ("Akula Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Akula_Turret_Dual] = ("Akula Turret Dual", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Akula_Turret_Single] = ("Akula Turret Single", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_APCCannon] = ("APC Cannon", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_APCMG] = ("APC MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_APCMissile] = ("APC Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Ardent_MG] = - ("Ardent MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Avenger_Cannon] = ("Avenger Cannon", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Barrage_Rear_GL] = ("Barrage Rear GL", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Barrage_Rear_MG] = ("Barrage Rear MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Barrage_Rear_Minigun] = ("Barrage Rear Minigun", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Barrage_Top_MG] = ("Barrage Top MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Barrage_Top_Minigun] = ("Barrage Top Minigun", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Bombushka_Cannon] = ("Bombushka Cannon", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Bombushka_Dual_MG] = ("Bombushka Dual MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Cannon_Blazer] = ("Cannon Blazer", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Caracara_MG] = - ("Caracara MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Caracara_Minigun] = ("Caracara Minigun", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Cherno_Missile] = ("Cherno Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Comet_MG] = ("Comet MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Deluxo_MG] = - ("Deluxo MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Deluxo_Missile] = ("Deluxo Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Dogfighter_MG] = ("Dogfighter MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Dogfighter_Missile] = ("Dogfighter Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Dune_Grenade_Launcher] = ("Dune Grenade Launcher", - DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Dune_MG] = ("Dune MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Dune_Minigun] = - ("Dune Minigun", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Enemy_Laser] = ("Enemy Laser", DamageGroup.Unknown, DamageType.Unknown), - [WeaponHash.Vehicle_Hacker_Missile] = ("Hacker Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Hacker_Missile_Homing] = ("Hacker Missile Homing", - DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Halftrack_Dual_MG] = ("Halftrack Dual MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Halftrack_Quad_MG] = ("Halftrack Quad MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Havok_Minigun] = ("Havok Minigun", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Hunter_Barrage] = ("Hunter Barrage", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Hunter_Cannon] = ("Hunter Cannon", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Hunter_MG] = - ("Hunter MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Hunter_Missile] = ("Hunter Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Insurgent_Minigun] = ("Insurgent Minigun", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Khanjali_Cannon] = ("Khanjali Cannon", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Khanjali_Cannon_Heavy] = ("Khanjali Cannon Heavy", - DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Khanjali_GL] = ("Khanjali GL", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Khanjali_MG] = - ("Khanjali MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Menacer_MG] = - ("Menacer MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Microlight_MG] = ("Microlight MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Mobileops_Cannon] = ("Mobileops Cannon", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Mogul_Dual_Nose] = ("Mogul Dual Nose", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Mogul_Dual_Turret] = ("Mogul Dual Turret", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Mogul_Nose] = - ("Mogul Nose", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Mogul_Turret] = - ("Mogul Turret", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Mule4MG] = ("Mule4 MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Mule4Missile] = ("Mule4 Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Mule4Turret_GL] = ("Mule4 Turret GL", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Nightshark_MG] = ("Nightshark MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Nose_Turret_Valkyrie] = ("Nose Turret Valkyrie", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Oppressor_MG] = - ("Oppressor MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Oppressor_Missile] = ("Oppressor Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Oppressor2Cannon] = ("Oppressor2 Cannon", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Oppressor2MG] = ("Oppressor2 MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Oppressor2Missile] = ("Oppressor2 Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Plane_Rocket] = ("Plane Rocket", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Player_Buzzard] = ("Player Buzzard", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Player_Lazer] = ("Player Lazer", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Player_Savage] = ("Player Savage", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Pounder2Barrage] = ("Pounder2 Barrage", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Pounder2GL] = ("Pounder2 GL", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Pounder2Mini] = ("Pounder2 Mini", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Pounder2Missile] = ("Pounder2 Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Radar] = ("Radar", DamageGroup.NonDamaging, DamageType.NonDamaging), - [WeaponHash.Vehicle_Revolter_MG] = - ("Revolter MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Rogue_Cannon] = ("Rogue Cannon", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Rogue_MG] = ("Rogue MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Rogue_Missile] = ("Rogue Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Ruiner_Bullet] = ("Ruiner Bullet", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Ruiner_Rocket] = ("Ruiner Rocket", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Savestra_MG] = - ("Savestra MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Scramjet_MG] = - ("Scramjet MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Scramjet_Missile] = ("Scramjet Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Seabreeze_MG] = - ("Seabreeze MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Searchlight] = ("Searchlight", DamageGroup.NonDamaging, - DamageType.NonDamaging), - [WeaponHash.Vehicle_Space_Rocket] = ("Space Rocket", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Speedo4MG] = - ("Speedo4 MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Speedo4Turret_MG] = ("Speedo4 Turret MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Speedo4Turret_Mini] = ("Speedo4 Turret Mini", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Strikeforce_Barrage] = ("Strikeforce Barrage", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Strikeforce_Cannon] = ("Strikeforce Cannon", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Strikeforce_Missile] = ("Strikeforce Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Subcar_MG] = - ("Subcar MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Subcar_Missile] = ("Subcar Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Subcar_Torpedo] = ("Subcar Torpedo", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Tampa_Dual_Minigun] = ("Tampa Dual Minigun", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Tampa_Fixed_Minigun] = ("Tampa Fixed Minigun", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Tampa_Missile] = ("Tampa Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Tampa_Mortar] = ("Tampa Mortar", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Tank] = ("Tank", DamageGroup.Explosion, DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Technical_Minigun] = ("Technical Minigun", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Thruster_MG] = - ("Thruster MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Thruster_Missile] = ("Thruster Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Trailer_Dualaa] = ("Trailer Dualaa", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Trailer_Missile] = ("Trailer Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Trailer_Quad_MG] = ("Trailer Quad MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Tula_Dual_MG] = - ("Tula Dual MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Tula_MG] = ("Tula MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Tula_Minigun] = - ("Tula Minigun", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Tula_Nose_MG] = - ("Tula Nose MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Turret_Boxville] = ("Turret Boxville", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Turret_Insurgent] = ("Turret Insurgent", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Turret_Limo] = - ("Turret Limo", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Turret_Technical] = ("Turret Technical", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Turret_Valkyrie] = ("Turret Valkyrie", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Vigilante_MG] = - ("Vigilante MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Vigilante_Missile] = ("Vigilante Missile", DamageGroup.Explosion, - DamageType.VehicleLauncher), - [WeaponHash.Vehicle_Viseris_MG] = - ("Viseris MG", DamageGroup.Bullet, DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Volatol_Dual_MG] = ("Volatol Dual MG", DamageGroup.Bullet, - DamageType.VehicleFirearm), - [WeaponHash.Vehicle_Water_Cannon] = ("Water Cannon", DamageGroup.WaterCannon, - DamageType.WaterCannon), - [WeaponHash.Vehicle_Helicopter_Rotors] = - ("Helicopter Rotors", DamageGroup.Vehicle, DamageType.Vehicle) + [WeaponHash.Antique_Cavalry_Dagger] = (DamageGroup.Melee, DamageType.MeleeStab), + [WeaponHash.Baseball_Bat] = (DamageGroup.Melee, DamageType.MeleeBlunt), + [WeaponHash.Bottle] = (DamageGroup.Melee, DamageType.MeleeStab), + [WeaponHash.Crowbar] = (DamageGroup.Melee, DamageType.MeleeBlunt), + [WeaponHash.Fist] = (DamageGroup.Melee, DamageType.Unarmed), + [WeaponHash.Flashlight] = (DamageGroup.Melee, DamageType.MeleeBlunt), + [WeaponHash.Golf_Club] = (DamageGroup.Melee, DamageType.MeleeBlunt), + [WeaponHash.Hammer] = (DamageGroup.Melee, DamageType.MeleeBlunt), + [WeaponHash.Hatchet] = (DamageGroup.Melee, DamageType.MeleeStab), + [WeaponHash.Knuckle] = (DamageGroup.Melee, DamageType.MeleeBlunt), + [WeaponHash.Knife] = (DamageGroup.Melee, DamageType.MeleeStab), + [WeaponHash.Machete] = (DamageGroup.Melee, DamageType.MeleeStab), + [WeaponHash.Switchblade] = (DamageGroup.Melee, DamageType.MeleeStab), + [WeaponHash.Nightstick] = (DamageGroup.Melee, DamageType.MeleeBlunt), + [WeaponHash.Pipe_Wrench] = (DamageGroup.Melee, DamageType.MeleeBlunt), + [WeaponHash.Battle_Axe] = (DamageGroup.Melee, DamageType.MeleeStab), + [WeaponHash.Pool_Cue] = (DamageGroup.Melee, DamageType.MeleeBlunt), + [WeaponHash.Stone_Hatchet] = (DamageGroup.Melee, DamageType.MeleeStab), + [WeaponHash.Pistol] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Pistol_MK2] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Combat_Pistol] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.APPistol] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Stun_Gun] = (DamageGroup.LessThanLethal, DamageType.LessThanLethal), + [WeaponHash.Pistol50] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.SNSPistol] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.SNSPistol_MK2] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Heavy_Pistol] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Vintage_Pistol] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Flare_Gun] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Marksman_Pistol] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Heavy_Revolver] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Heavy_Revolver_MK2] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Double_Action] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Up_n_Atomizer] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Micro_SMG] = (DamageGroup.Bullet, DamageType.SMG), + [WeaponHash.SMG] = (DamageGroup.Bullet, DamageType.SMG), + [WeaponHash.SMGMK2] = (DamageGroup.Bullet, DamageType.SMG), + [WeaponHash.Assault_SMG] = (DamageGroup.Bullet, DamageType.SMG), + [WeaponHash.Combat_PDW] = (DamageGroup.Bullet, DamageType.SMG), + [WeaponHash.Machine_Pistol] = (DamageGroup.Bullet, DamageType.SMG), + [WeaponHash.Mini_SMG] = (DamageGroup.Bullet, DamageType.SMG), + [WeaponHash.Unholy_Hellbringer] = (DamageGroup.Bullet, DamageType.MG), + [WeaponHash.Pump_Shotgun] = (DamageGroup.Bullet, DamageType.Shotgun), + [WeaponHash.Pump_Shotgun_MK2] = (DamageGroup.Bullet, DamageType.Shotgun), + [WeaponHash.Sawed_Off_Shotgun] = (DamageGroup.Bullet, DamageType.Shotgun), + [WeaponHash.Assault_Shotgun] = (DamageGroup.Bullet, DamageType.Shotgun), + [WeaponHash.Bullpup_Shotgun] = (DamageGroup.Bullet, DamageType.Shotgun), + [WeaponHash.Musket] = (DamageGroup.Bullet, DamageType.Sniper), + [WeaponHash.Heavy_Shotgun] = (DamageGroup.Bullet, DamageType.Shotgun), + [WeaponHash.Double_Barrel_Shotgun] = (DamageGroup.Bullet, DamageType.Shotgun), + [WeaponHash.Sweeper_Shotgun] = (DamageGroup.Bullet, DamageType.Shotgun), + [WeaponHash.Assault_Rifle] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Assault_Rifle_MK2] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Carbine_Rifle] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Carbine_Rifle_MK2] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Advanced_Rifle] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Special_Carbine] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Special_Carbine_MK2] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Bullpup_Rifle] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Bullpup_Rifle_MK2] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Compact_Rifle] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.MG] = (DamageGroup.Bullet, DamageType.MG), + [WeaponHash.Combat_MG] = (DamageGroup.Bullet, DamageType.MG), + [WeaponHash.Combat_MGMK2] = (DamageGroup.Bullet, DamageType.MG), + [WeaponHash.Gusenberg_Sweeper] = (DamageGroup.Bullet, DamageType.MG), + [WeaponHash.Sniper_Rifle] = (DamageGroup.Bullet, DamageType.Sniper), + [WeaponHash.Heavy_Sniper] = (DamageGroup.Bullet, DamageType.Sniper), + [WeaponHash.Heavy_Sniper_MK2] = (DamageGroup.Bullet, DamageType.Sniper), + [WeaponHash.Marksman_Rifle] = (DamageGroup.Bullet, DamageType.Sniper), + [WeaponHash.Marksman_Rifle_MK2] = (DamageGroup.Bullet, DamageType.Sniper), + [WeaponHash.RPG] = (DamageGroup.Explosion, DamageType.Launcher), + [WeaponHash.Grenade_Launcher] = (DamageGroup.Explosion, DamageType.Launcher), + [WeaponHash.Smoke_Grenade_Launcher] = (DamageGroup.NonDamaging, DamageType.Launcher), + [WeaponHash.Minigun] = (DamageGroup.Bullet, DamageType.Launcher), + [WeaponHash.Firework_Launcher] = (DamageGroup.Explosion, DamageType.Launcher), + [WeaponHash.Railgun] = (DamageGroup.Explosion, DamageType.Launcher), + [WeaponHash.Homing_Launcher] = (DamageGroup.Explosion, DamageType.Launcher), + [WeaponHash.Compact_Grenade_Launcher] = (DamageGroup.Explosion, DamageType.Launcher), + [WeaponHash.Ray_Minigun] = (DamageGroup.Bullet, DamageType.Launcher), + [WeaponHash.Grenade] = (DamageGroup.Explosion, DamageType.Explosive), + [WeaponHash.BZGas] = (DamageGroup.Gas, DamageType.Gas), + [WeaponHash.Smoke_Grenade] = (DamageGroup.NonDamaging, DamageType.ThrowableNonLethal), + [WeaponHash.Flare] = (DamageGroup.NonDamaging, DamageType.ThrowableNonLethal), + [WeaponHash.Molotov] = (DamageGroup.Fire, DamageType.Fire), + [WeaponHash.Sticky_Bomb] = (DamageGroup.Explosion, DamageType.Explosive), + [WeaponHash.Proximity_Mine] = (DamageGroup.Explosion, DamageType.Explosive), + [WeaponHash.Snowball] = (DamageGroup.NonDamaging, DamageType.ThrowableNonLethal), + [WeaponHash.Pipe_Bomb] = (DamageGroup.Explosion, DamageType.Explosive), + [WeaponHash.Baseball] = (DamageGroup.NonDamaging, DamageType.ThrowableNonLethal), + [WeaponHash.Jerry_Can] = (DamageGroup.NonDamaging, DamageType.Misc), + [WeaponHash.Fire_Extinguisher] = (DamageGroup.NonDamaging, DamageType.Misc), + [WeaponHash.Parachute] = (DamageGroup.Unknown, DamageType.Unknown), + [WeaponHash.Electric_Fence] = (DamageGroup.Environmental, DamageType.Electric), + [WeaponHash.Hitby_Water_Cannon] = (DamageGroup.WaterCannon, DamageType.WaterCannon), + [WeaponHash.Rammedby_Car] = (DamageGroup.Vehicle, DamageType.Vehicle), + [WeaponHash.Run_Overby_Car] = (DamageGroup.Vehicle, DamageType.Vehicle), + [WeaponHash.Fall] = (DamageGroup.Fall, DamageType.Fall), + [WeaponHash.Animal] = (DamageGroup.Animal, DamageType.Animal), + [WeaponHash.Airstrike_Rocket] = (DamageGroup.Explosion, DamageType.Launcher), + [WeaponHash.Bleeding] = (DamageGroup.Bodily, DamageType.Bodily), + [WeaponHash.Briefcase] = (DamageGroup.Unknown, DamageType.Unknown), + [WeaponHash.Briefcase02] = (DamageGroup.Unknown, DamageType.Unknown), + [WeaponHash.Cougar] = (DamageGroup.Animal, DamageType.Animal), + [WeaponHash.Barbed_Wire] = (DamageGroup.Environmental, DamageType.BarbedWire), + [WeaponHash.Drowning] = (DamageGroup.Drowning, DamageType.Drowning), + [WeaponHash.Drowning_In_Vehicle] = (DamageGroup.Drowning, DamageType.Drowning), + [WeaponHash.Explosion] = (DamageGroup.Explosion, DamageType.Explosive), + [WeaponHash.Exhaustion] = (DamageGroup.Bodily, DamageType.Bodily), + [WeaponHash.Fire] = (DamageGroup.Fire, DamageType.Fire), + [WeaponHash.Heli_Crash] = (DamageGroup.Explosion, DamageType.Explosive), + [WeaponHash.Vehicle_Rocket] = (DamageGroup.Explosion, DamageType.Launcher), + [WeaponHash.Vehicle_Akula_Barrage] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Akula_Minigun] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Akula_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Akula_Turret_Dual] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Akula_Turret_Single] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_APCCannon] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_APCMG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_APCMissile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Ardent_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Avenger_Cannon] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Barrage_Rear_GL] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Barrage_Rear_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Barrage_Rear_Minigun] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Barrage_Top_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Barrage_Top_Minigun] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Bombushka_Cannon] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Bombushka_Dual_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Cannon_Blazer] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Caracara_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Caracara_Minigun] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Cherno_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Comet_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Deluxo_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Deluxo_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Dogfighter_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Dogfighter_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Dune_Grenade_Launcher] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Dune_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Dune_Minigun] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Enemy_Laser] = (DamageGroup.Unknown, DamageType.Unknown), + [WeaponHash.Vehicle_Hacker_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Hacker_Missile_Homing] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Halftrack_Dual_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Halftrack_Quad_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Havok_Minigun] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Hunter_Barrage] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Hunter_Cannon] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Hunter_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Hunter_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Insurgent_Minigun] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Khanjali_Cannon] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Khanjali_Cannon_Heavy] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Khanjali_GL] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Khanjali_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Menacer_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Microlight_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Mobileops_Cannon] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Mogul_Dual_Nose] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Mogul_Dual_Turret] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Mogul_Nose] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Mogul_Turret] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Mule4MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Mule4Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Mule4Turret_GL] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Nightshark_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Nose_Turret_Valkyrie] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Oppressor_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Oppressor_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Oppressor2Cannon] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Oppressor2MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Oppressor2Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Plane_Rocket] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Player_Buzzard] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Player_Lazer] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Player_Savage] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Pounder2Barrage] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Pounder2GL] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Pounder2Mini] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Pounder2Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Radar] = (DamageGroup.NonDamaging, DamageType.NonDamaging), + [WeaponHash.Vehicle_Revolter_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Rogue_Cannon] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Rogue_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Rogue_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Ruiner_Bullet] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Ruiner_Rocket] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Savestra_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Scramjet_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Scramjet_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Seabreeze_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Searchlight] = (DamageGroup.NonDamaging, DamageType.NonDamaging), + [WeaponHash.Vehicle_Space_Rocket] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Speedo4MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Speedo4Turret_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Speedo4Turret_Mini] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Strikeforce_Barrage] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Strikeforce_Cannon] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Strikeforce_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Subcar_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Subcar_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Subcar_Torpedo] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Tampa_Dual_Minigun] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Tampa_Fixed_Minigun] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Tampa_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Tampa_Mortar] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Tank] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Technical_Minigun] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Thruster_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Thruster_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Trailer_Dualaa] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Trailer_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Trailer_Quad_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Tula_Dual_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Tula_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Tula_Minigun] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Tula_Nose_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Turret_Boxville] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Turret_Insurgent] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Turret_Limo] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Turret_Technical] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Turret_Valkyrie] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Vigilante_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Vigilante_Missile] = (DamageGroup.Explosion, DamageType.VehicleLauncher), + [WeaponHash.Vehicle_Viseris_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Volatol_Dual_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), + [WeaponHash.Vehicle_Water_Cannon] = (DamageGroup.WaterCannon, DamageType.WaterCannon), + [WeaponHash.Vehicle_Helicopter_Rotors] = (DamageGroup.Vehicle, DamageType.Vehicle) }; }; } \ No newline at end of file From 46fcf71adb2127ad63cc91aa0c32630062154ab8 Mon Sep 17 00:00:00 2001 From: Vari Date: Tue, 7 Feb 2023 00:37:31 +0000 Subject: [PATCH 17/50] feat(damage-info): add attacker handle to damage info struct --- DamageTrackerLib/DamageInfo/PedDamageInfo.cs | 1 + DamageTrackerLib/DamageTrackerService.cs | 7 ++++--- DamageTrackingFramework/DamageTracker.cs | 16 ++++++++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/DamageTrackerLib/DamageInfo/PedDamageInfo.cs b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs index a2e5a0b..cb74bbd 100644 --- a/DamageTrackerLib/DamageInfo/PedDamageInfo.cs +++ b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs @@ -6,6 +6,7 @@ namespace DamageTrackerLib.DamageInfo public struct PedDamageInfo { public uint PedHandle; + public uint AttackerPedHandle; public int Damage; public WeaponDamageInfo WeaponInfo; public BoneDamageInfo BoneInfo; diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 7dea3b5..b09b847 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -11,7 +11,7 @@ public static class DamageTrackerService { public const string Guid = "609a228f"; - public delegate void PedTookDamageDelegate(Ped ped, PedDamageInfo damageInfo); + public delegate void PedTookDamageDelegate(Ped victimPed, Ped attackerPed, PedDamageInfo damageInfo); public static event PedTookDamageDelegate OnPedTookDamage; public static event PedTookDamageDelegate OnPlayerTookDamage; @@ -51,13 +51,14 @@ private static void Run() foreach (var pedDamageInfo in damagedPeds) { var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); + var attackerPed = pedDamageInfo.AttackerPedHandle == 0 ? null : World.GetEntityByHandle(pedDamageInfo.AttackerPedHandle); switch (ped.IsPlayer) { case true when OnPlayerTookDamage != null: - OnPlayerTookDamage.Invoke(ped, pedDamageInfo); + OnPlayerTookDamage.Invoke(ped, attackerPed, pedDamageInfo); break; case false when OnPedTookDamage != null: - OnPedTookDamage.Invoke(ped, pedDamageInfo); + OnPedTookDamage.Invoke(ped, attackerPed, pedDamageInfo); break; } } diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index c2875dd..f5d6f8e 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -40,7 +40,9 @@ internal static void CheckPedsFiber() // ReSharper disable once FunctionNeverReturns } - private static void SendPedData(MemoryMappedViewAccessor accessor, MemoryStream stream) // TODO: Resize file if ped count is too small or send less. + private static void + SendPedData(MemoryMappedViewAccessor accessor, + MemoryStream stream) // TODO: Resize file if ped count is too small or send less. { // var requiredSize = Marshal.SizeOf(PedDamageList) + (PedDamageList.Count * Marshal.SizeOf()) + 2000; // if(requiredSize > accessor.Capacity) @@ -66,9 +68,18 @@ private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, Wea { var lastDamagedBone = (BoneId)ped.LastDamageBone; var boneTuple = DamageTrackerLookups.BoneLookup[lastDamagedBone]; + PoolHandle attackerPed = 0; + if (ped.HasBeenDamagedByAnyPed) + foreach (var otherPed in PedDict.Keys) + { + if (!otherPed.IsValid() || !ped.HasBeenDamagedBy(otherPed)) continue; + attackerPed = otherPed.Handle; + break; + } return new PedDamageInfo { PedHandle = ped.Handle, + AttackerPedHandle = attackerPed, Damage = previousHealth - ped.Health, WeaponInfo = damage, BoneInfo = new BoneDamageInfo @@ -103,7 +114,8 @@ private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) // BUG var hashAddr = damageHandler + 8; if (hashAddr == IntPtr.Zero || *(WeaponHash*)hashAddr == 0 || - !DamageTrackerLookups.WeaponLookup.ContainsKey(*(WeaponHash*)hashAddr)) return false; // May not be necessary. + !DamageTrackerLookups.WeaponLookup.ContainsKey(*(WeaponHash*)hashAddr)) + return false; // May not be necessary. var weaponHash = *(WeaponHash*)hashAddr; var damageTuple = DamageTrackerLookups.WeaponLookup[weaponHash]; damage = new WeaponDamageInfo From ef89432b6ecf1d68db2c951c7f5abddbf45b7955 Mon Sep 17 00:00:00 2001 From: Vari Date: Tue, 7 Feb 2023 00:49:25 +0000 Subject: [PATCH 18/50] docs: add documentation comments --- DamageTrackerLib/DamageInfo/BoneDamageInfo.cs | 3 +++ DamageTrackerLib/DamageInfo/BoneId.cs | 3 +++ DamageTrackerLib/DamageInfo/PedDamageInfo.cs | 3 +++ .../DamageInfo/WeaponDamageInfo.cs | 3 +++ DamageTrackerLib/DamageInfo/WeaponHash.cs | 3 +++ DamageTrackerLib/DamageTrackerLookups.cs | 7 +++++++ DamageTrackerLib/DamageTrackerService.cs | 21 ++++++++++++++++++- DamageTrackerUtility.sln.DotSettings.user | 3 ++- 8 files changed, 44 insertions(+), 2 deletions(-) diff --git a/DamageTrackerLib/DamageInfo/BoneDamageInfo.cs b/DamageTrackerLib/DamageInfo/BoneDamageInfo.cs index 928ae6d..06d28e8 100644 --- a/DamageTrackerLib/DamageInfo/BoneDamageInfo.cs +++ b/DamageTrackerLib/DamageInfo/BoneDamageInfo.cs @@ -2,6 +2,9 @@ namespace DamageTrackerLib.DamageInfo { + /// + /// Holds info on the Bone that was damaged on the Ped. + /// [Serializable] public struct BoneDamageInfo { diff --git a/DamageTrackerLib/DamageInfo/BoneId.cs b/DamageTrackerLib/DamageInfo/BoneId.cs index ee75de3..55d3818 100644 --- a/DamageTrackerLib/DamageInfo/BoneId.cs +++ b/DamageTrackerLib/DamageInfo/BoneId.cs @@ -1,5 +1,8 @@ namespace DamageTrackerLib.DamageInfo { + /// + /// Complete set of BoneIds. Should be cast-able to RagePluginHook BoneIds however, RPH has no "Root" bone which is 0. + /// public enum BoneId : ushort { LeftThumb1 = 4089, // 0x0FF9 diff --git a/DamageTrackerLib/DamageInfo/PedDamageInfo.cs b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs index cb74bbd..2ff43c5 100644 --- a/DamageTrackerLib/DamageInfo/PedDamageInfo.cs +++ b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs @@ -2,6 +2,9 @@ namespace DamageTrackerLib.DamageInfo { + /// + /// Holds all info for a Ped's damage. + /// [Serializable] public struct PedDamageInfo { diff --git a/DamageTrackerLib/DamageInfo/WeaponDamageInfo.cs b/DamageTrackerLib/DamageInfo/WeaponDamageInfo.cs index db2f670..807550e 100644 --- a/DamageTrackerLib/DamageInfo/WeaponDamageInfo.cs +++ b/DamageTrackerLib/DamageInfo/WeaponDamageInfo.cs @@ -2,6 +2,9 @@ namespace DamageTrackerLib.DamageInfo { + /// + /// Holds info on the Weapon/Thing that damaged the Ped. + /// [Serializable] public struct WeaponDamageInfo { diff --git a/DamageTrackerLib/DamageInfo/WeaponHash.cs b/DamageTrackerLib/DamageInfo/WeaponHash.cs index 29a3992..6fa280f 100644 --- a/DamageTrackerLib/DamageInfo/WeaponHash.cs +++ b/DamageTrackerLib/DamageInfo/WeaponHash.cs @@ -1,5 +1,8 @@ namespace DamageTrackerLib.DamageInfo { + /// + /// Complete set of Weapon Hashes. + /// public enum WeaponHash : uint { Unknown = 0, diff --git a/DamageTrackerLib/DamageTrackerLookups.cs b/DamageTrackerLib/DamageTrackerLookups.cs index 5a4c666..d55ab58 100644 --- a/DamageTrackerLib/DamageTrackerLookups.cs +++ b/DamageTrackerLib/DamageTrackerLookups.cs @@ -5,6 +5,9 @@ namespace DamageTrackerLib { public static class DamageTrackerLookups { + /// + /// Lookups for the Bones. It is not recommended to change/use these values. + /// public static readonly Dictionary BoneLookup = new() @@ -68,6 +71,10 @@ public static class DamageTrackerLookups [BoneId.LeftClavicle] = (Limb.Chest, BodyRegion.Torso), }; + + /// + /// Lookups for the Weapons. It is not recommended to change/use these values. + /// public static readonly Dictionary WeaponLookup = new() diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index b09b847..707b48e 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -11,14 +11,27 @@ public static class DamageTrackerService { public const string Guid = "609a228f"; + /// + /// Delegate to be used for TookDamage events. + /// public delegate void PedTookDamageDelegate(Ped victimPed, Ped attackerPed, PedDamageInfo damageInfo); + /// + /// Event invoked when a Ped takes damage. This event excludes the Player. + /// public static event PedTookDamageDelegate OnPedTookDamage; + + /// + /// Event invoked when the Player takes damage ONLY. + /// public static event PedTookDamageDelegate OnPlayerTookDamage; private static readonly BinaryFormatter binaryFormatter = new(); private static GameFiber _gameFiber; + /// + /// Starts a GameFiber that collects incoming damage data from the DamageTracker plugin and turns them into events. + /// public static void Start() { if (_gameFiber != null) @@ -30,6 +43,10 @@ public static void Start() _gameFiber = GameFiber.StartNew(Run); } + + /// + /// Stops DamageTrackerService GameFiber. + /// public static void Stop() => _gameFiber.Abort(); private static void Run() @@ -51,7 +68,9 @@ private static void Run() foreach (var pedDamageInfo in damagedPeds) { var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); - var attackerPed = pedDamageInfo.AttackerPedHandle == 0 ? null : World.GetEntityByHandle(pedDamageInfo.AttackerPedHandle); + var attackerPed = pedDamageInfo.AttackerPedHandle == 0 + ? null + : World.GetEntityByHandle(pedDamageInfo.AttackerPedHandle); switch (ped.IsPlayer) { case true when OnPlayerTookDamage != null: diff --git a/DamageTrackerUtility.sln.DotSettings.user b/DamageTrackerUtility.sln.DotSettings.user index 230426c..8036555 100644 --- a/DamageTrackerUtility.sln.DotSettings.user +++ b/DamageTrackerUtility.sln.DotSettings.user @@ -3,4 +3,5 @@ True <AssemblyExplorer> <Assembly Path="D:\Users\Vari\Desktop\Work\Forks\DamageTrackerPlugin\DamageTrackerUtility\packages\RagePluginHook.1.98.0\lib\net472\RagePluginHook.dll" /> -</AssemblyExplorer> \ No newline at end of file +</AssemblyExplorer> + True \ No newline at end of file From 4f88ef4ac847356f71b4309822a02cf46cc65dde Mon Sep 17 00:00:00 2001 From: Vari Date: Tue, 7 Feb 2023 23:10:16 +0000 Subject: [PATCH 19/50] feat: add damage logging to DamageTrackerService.cs --- DamageTrackerLib/DamageTrackerService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 707b48e..2306dc8 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -68,6 +68,7 @@ private static void Run() foreach (var pedDamageInfo in damagedPeds) { var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); + Game.LogTrivial($"DamageTrackerService: Ped {ped.Model.Name} was damaged."); var attackerPed = pedDamageInfo.AttackerPedHandle == 0 ? null : World.GetEntityByHandle(pedDamageInfo.AttackerPedHandle); From 1a7cf6bdce94a0d681691117169969ac6fd18108 Mon Sep 17 00:00:00 2001 From: Vari Date: Mon, 20 Feb 2023 17:35:14 +0000 Subject: [PATCH 20/50] fix(damage-tracker): make armour damage tracked --- DamageTrackerLib/DamageInfo/PedDamageInfo.cs | 1 + DamageTrackingFramework/DamageTracker.cs | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/DamageTrackerLib/DamageInfo/PedDamageInfo.cs b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs index 2ff43c5..c9514e3 100644 --- a/DamageTrackerLib/DamageInfo/PedDamageInfo.cs +++ b/DamageTrackerLib/DamageInfo/PedDamageInfo.cs @@ -11,6 +11,7 @@ public struct PedDamageInfo public uint PedHandle; public uint AttackerPedHandle; public int Damage; + public int ArmourDamage; public WeaponDamageInfo WeaponInfo; public BoneDamageInfo BoneInfo; } diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index f5d6f8e..4f94af6 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -16,7 +16,7 @@ namespace DamageTrackingFramework internal static class DamageTracker { // ReSharper disable once HeapView.ObjectAllocation.Evident - private static readonly Dictionary PedDict = new(); + private static readonly Dictionary PedDict = new(); private static readonly List PedDamageList = new(); @@ -56,15 +56,15 @@ private static void private static void HandlePed(Ped ped) { if (!ped.Exists() || !ped.IsHuman) return; - if (!PedDict.ContainsKey(ped)) PedDict.Add(ped, ped.Health); + if (!PedDict.ContainsKey(ped)) PedDict.Add(ped, (ped.Health, ped.Armor)); var previousHealth = PedDict[ped]; if (!TryGetPedDamage(ped, out var damage)) return; - PedDamageList.Add(GenerateDamageInfo(ped, previousHealth, damage)); + PedDamageList.Add(GenerateDamageInfo(ped, previousHealth.health, previousHealth.armour, damage)); ClearPedDamage(ped); } - private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, WeaponDamageInfo damage) + private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, int previousArmour, WeaponDamageInfo damage) { var lastDamagedBone = (BoneId)ped.LastDamageBone; var boneTuple = DamageTrackerLookups.BoneLookup[lastDamagedBone]; @@ -81,6 +81,7 @@ private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, Wea PedHandle = ped.Handle, AttackerPedHandle = attackerPed, Damage = previousHealth - ped.Health, + ArmourDamage = previousArmour - ped.Armor, WeaponInfo = damage, BoneInfo = new BoneDamageInfo { @@ -106,9 +107,10 @@ private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) // BUG var damageHandler = *(IntPtr*)(pedAddr + 648); if (damageHandler == IntPtr.Zero) return false; var damageArray = *(int*)(damageHandler + 72); - if (ped.Health >= PedDict[ped] || damageArray <= 0) + var previousHealth = PedDict[ped]; + if (ped.Health >= previousHealth.health || ped.Armor >= previousHealth.armour || damageArray <= 0) { - PedDict[ped] = ped.Health; + PedDict[ped] = (ped.Health, ped.Armor); return false; } From d9616b0184631c0fff337e3d0c0c0eb1ff5a99ae Mon Sep 17 00:00:00 2001 From: Vari Date: Mon, 20 Feb 2023 19:12:53 +0000 Subject: [PATCH 21/50] fix(damage-tracker): fix armour check changes ignoring all damage --- DamageTrackingFramework/DamageTracker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index 4f94af6..61359ed 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -108,7 +108,7 @@ private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) // BUG if (damageHandler == IntPtr.Zero) return false; var damageArray = *(int*)(damageHandler + 72); var previousHealth = PedDict[ped]; - if (ped.Health >= previousHealth.health || ped.Armor >= previousHealth.armour || damageArray <= 0) + if (ped.Health > previousHealth.health || ped.Armor > previousHealth.armour || damageArray <= 0) { PedDict[ped] = (ped.Health, ped.Armor); return false; From 153aff00e44bd08908fe7fa44a16d2992deec485 Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 24 Feb 2023 13:37:32 +0000 Subject: [PATCH 22/50] feat: add version checking --- DamageTrackingFramework/DamageTracker.cs | 1 - .../DamageTrackingFramework.csproj | 1 + DamageTrackingFramework/Entry.cs | 9 ++-- .../Properties/AssemblyInfo.cs | 4 +- DamageTrackingFramework/VersionChecker.cs | 41 +++++++++++++++++++ 5 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 DamageTrackingFramework/VersionChecker.cs diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index 61359ed..d7db7fc 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -3,7 +3,6 @@ using System.IO; using System.IO.MemoryMappedFiles; using System.Linq; -using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; using DamageTrackerLib; using DamageTrackerLib.DamageInfo; diff --git a/DamageTrackingFramework/DamageTrackingFramework.csproj b/DamageTrackingFramework/DamageTrackingFramework.csproj index 1cdc466..ccdfab5 100644 --- a/DamageTrackingFramework/DamageTrackingFramework.csproj +++ b/DamageTrackingFramework/DamageTrackingFramework.csproj @@ -52,6 +52,7 @@ + diff --git a/DamageTrackingFramework/Entry.cs b/DamageTrackingFramework/Entry.cs index c7c9286..5ca1ef6 100644 --- a/DamageTrackingFramework/Entry.cs +++ b/DamageTrackingFramework/Entry.cs @@ -15,10 +15,11 @@ public class EntryPoint // ReSharper disable once UnusedMember.Global public static void Main() { - NativeFunction.Natives.x5BA652A0CD14DF2F(); // HACK: Fixes stuttering issue by warming up JIT with a useless native. + NativeFunction.Natives + .x5BA652A0CD14DF2F(); // HACK: Fixes stuttering issue by warming up JIT with a useless native. _gameFiber = GameFiber.StartNew(DamageTracker.CheckPedsFiber); Game.LogTrivial("GameFiber started!"); - Game.DisplayNotification("DamageTrackerFramework by Variapolis ~g~Successfully Loaded"); + VersionChecker.CheckForUpdates(); GameFiber.Hibernate(); } @@ -26,7 +27,9 @@ public static void Main() // ReSharper disable once UnusedParameter.Global public static void OnUnload(bool Exit) { - Game.DisplayNotification("DamageTrackingFramework by Variapolis ~r~ Unloaded"); + Game.DisplayNotification("commonmenu", "card_suit_hearts", + $"DamageTrackerFramework {VersionChecker.CurrentVersion}", + "~o~Unloaded", $"By Variapolis"); _gameFiber.Abort(); } } diff --git a/DamageTrackingFramework/Properties/AssemblyInfo.cs b/DamageTrackingFramework/Properties/AssemblyInfo.cs index a95402b..ffd62d3 100644 --- a/DamageTrackingFramework/Properties/AssemblyInfo.cs +++ b/DamageTrackingFramework/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file +[assembly: AssemblyVersion("0.9.5")] +[assembly: AssemblyFileVersion("0.9.5")] \ No newline at end of file diff --git a/DamageTrackingFramework/VersionChecker.cs b/DamageTrackingFramework/VersionChecker.cs new file mode 100644 index 0000000..efa9510 --- /dev/null +++ b/DamageTrackingFramework/VersionChecker.cs @@ -0,0 +1,41 @@ +using System.Net; +using System.Reflection; +using Rage; + +namespace DamageTrackingFramework; + +internal static class VersionChecker +{ + internal static string CurrentVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString(3); + + internal static void CheckForUpdates() + { + var webClient = new WebClient(); + var upToDate = false; + try + { + var receivedVersion = webClient + .DownloadString( + "https://www.lcpdfr.com/applications/downloadsng/interface/api.php?do=checkForUpdates&fileId=42767&textOnly=1") + .Trim(); + Game.LogTrivial( + $"DamageTrackerFramework loaded successfully. Online Version: {receivedVersion} | Local Version: {CurrentVersion}"); + upToDate = receivedVersion == CurrentVersion; + } + catch (WebException) + { + Game.DisplayNotification("commonmenu", "mp_alerttriangle", "~y~DamageTrackerFramework Version Check", + "Version check ~r~Failed.", + "Please ensure you are ~o~online~w~."); + } + finally + { + if (!upToDate) + Game.LogTrivial( + "[VERSION OUTDATED] Please update to latest version here: https://www.lcpdfr.com/downloads/gta5mods/scripts/42767-damage-tracker-framework/"); + Game.DisplayNotification("commonmenu", "card_suit_hearts", $"DamageTrackerFramework {CurrentVersion}", + "~g~Successfully Loaded", + $"By Variapolis \nVersion is {(upToDate ? "~g~Up To Date" : "~r~Out Of Date")}"); + } + } +} \ No newline at end of file From 8424d584664fde4dab9157a5c906425a1723dd05 Mon Sep 17 00:00:00 2001 From: Vari Date: Sat, 25 Feb 2023 17:12:06 +0000 Subject: [PATCH 23/50] feat: add version mismatch checking --- DamageTrackerLib/DamageTrackerLib.csproj | 1 + DamageTrackerLib/DamageTrackerService.cs | 3 +++ DamageTrackerLib/Properties/AssemblyInfo.cs | 4 +-- .../Properties/AssemblyVersion.cs | 5 ++++ .../DamageTrackingFramework.csproj | 3 +++ .../Properties/AssemblyInfo.cs | 4 +-- DamageTrackingFramework/VersionChecker.cs | 27 ++++++++++++++----- 7 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 DamageTrackerLib/Properties/AssemblyVersion.cs diff --git a/DamageTrackerLib/DamageTrackerLib.csproj b/DamageTrackerLib/DamageTrackerLib.csproj index 88f059e..41afc04 100644 --- a/DamageTrackerLib/DamageTrackerLib.csproj +++ b/DamageTrackerLib/DamageTrackerLib.csproj @@ -55,6 +55,7 @@ + diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 2306dc8..79f6f81 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -1,5 +1,6 @@ using System.IO; using System.IO.MemoryMappedFiles; +using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; using DamageTrackerLib.DamageInfo; using Rage; @@ -9,6 +10,8 @@ namespace DamageTrackerLib // ReSharper disable once UnusedType.Global public static class DamageTrackerService { + public static string CurrentVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString(3); + public const string Guid = "609a228f"; /// diff --git a/DamageTrackerLib/Properties/AssemblyInfo.cs b/DamageTrackerLib/Properties/AssemblyInfo.cs index 957e3cd..cec2526 100644 --- a/DamageTrackerLib/Properties/AssemblyInfo.cs +++ b/DamageTrackerLib/Properties/AssemblyInfo.cs @@ -30,6 +30,4 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file +// [assembly: AssemblyVersion("1.0.*")] \ No newline at end of file diff --git a/DamageTrackerLib/Properties/AssemblyVersion.cs b/DamageTrackerLib/Properties/AssemblyVersion.cs new file mode 100644 index 0000000..4b4b084 --- /dev/null +++ b/DamageTrackerLib/Properties/AssemblyVersion.cs @@ -0,0 +1,5 @@ +using System.Reflection; + +[assembly: AssemblyVersion("0.9.6")] +[assembly: AssemblyFileVersion("0.9.6")] + diff --git a/DamageTrackingFramework/DamageTrackingFramework.csproj b/DamageTrackingFramework/DamageTrackingFramework.csproj index ccdfab5..b4612a1 100644 --- a/DamageTrackingFramework/DamageTrackingFramework.csproj +++ b/DamageTrackingFramework/DamageTrackingFramework.csproj @@ -49,6 +49,9 @@ + + Properties\AssemblyVersion.cs + diff --git a/DamageTrackingFramework/Properties/AssemblyInfo.cs b/DamageTrackingFramework/Properties/AssemblyInfo.cs index ffd62d3..a8758d9 100644 --- a/DamageTrackingFramework/Properties/AssemblyInfo.cs +++ b/DamageTrackingFramework/Properties/AssemblyInfo.cs @@ -30,6 +30,4 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.9.5")] -[assembly: AssemblyFileVersion("0.9.5")] \ No newline at end of file +// [assembly: AssemblyVersion("1.0.*")] \ No newline at end of file diff --git a/DamageTrackingFramework/VersionChecker.cs b/DamageTrackingFramework/VersionChecker.cs index efa9510..149f160 100644 --- a/DamageTrackingFramework/VersionChecker.cs +++ b/DamageTrackingFramework/VersionChecker.cs @@ -1,5 +1,6 @@ using System.Net; using System.Reflection; +using DamageTrackerLib; using Rage; namespace DamageTrackingFramework; @@ -7,20 +8,25 @@ namespace DamageTrackingFramework; internal static class VersionChecker { internal static string CurrentVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString(3); + internal static string LibraryVersion => + Assembly.GetAssembly(typeof(DamageTrackerService)).GetName().Version.ToString(3); internal static void CheckForUpdates() { var webClient = new WebClient(); - var upToDate = false; + var frameworkUpToDate = false; + var libraryVersionMatch = false; try { var receivedVersion = webClient .DownloadString( "https://www.lcpdfr.com/applications/downloadsng/interface/api.php?do=checkForUpdates&fileId=42767&textOnly=1") .Trim(); + Game.LogTrivial( - $"DamageTrackerFramework loaded successfully. Online Version: {receivedVersion} | Local Version: {CurrentVersion}"); - upToDate = receivedVersion == CurrentVersion; + $"DamageTrackerFramework loaded successfully. Online Version: {receivedVersion} | Local DamageTrackerFramework Version: {CurrentVersion} | Local DamageTrackerLib Version: {LibraryVersion}"); + frameworkUpToDate = receivedVersion == CurrentVersion; + libraryVersionMatch = LibraryVersion == CurrentVersion; } catch (WebException) { @@ -30,12 +36,19 @@ internal static void CheckForUpdates() } finally { - if (!upToDate) - Game.LogTrivial( - "[VERSION OUTDATED] Please update to latest version here: https://www.lcpdfr.com/downloads/gta5mods/scripts/42767-damage-tracker-framework/"); Game.DisplayNotification("commonmenu", "card_suit_hearts", $"DamageTrackerFramework {CurrentVersion}", "~g~Successfully Loaded", - $"By Variapolis \nVersion is {(upToDate ? "~g~Up To Date" : "~r~Out Of Date")}"); + $"By Variapolis \nVersion is {(frameworkUpToDate ? "~g~Up To Date" : "~r~Out Of Date")}"); + if (!frameworkUpToDate) + Game.LogTrivial( + "[VERSION OUTDATED] Please update to latest version here: https://www.lcpdfr.com/downloads/gta5mods/scripts/42767-damage-tracker-framework/"); + if (!libraryVersionMatch) + { + Game.LogTrivial( + "[VERSION MISMATCH] DamageTrackerLib version does not match DamageTrackerFramework. Ensure both DLLs are up to date."); + Game.DisplayNotification( + "~r~WARNING: ~w~Version Mismatch for DamageTrackerLib.dll! ~o~Ensure both DLL files are up to date."); + } } } } \ No newline at end of file From f12e1c1d084818b20ad35222963a6576592ac771 Mon Sep 17 00:00:00 2001 From: Vari Date: Sat, 25 Feb 2023 17:14:33 +0000 Subject: [PATCH 24/50] fix: add notification for version check fail --- DamageTrackingFramework/VersionChecker.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/DamageTrackingFramework/VersionChecker.cs b/DamageTrackingFramework/VersionChecker.cs index 149f160..5193620 100644 --- a/DamageTrackingFramework/VersionChecker.cs +++ b/DamageTrackingFramework/VersionChecker.cs @@ -8,6 +8,7 @@ namespace DamageTrackingFramework; internal static class VersionChecker { internal static string CurrentVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString(3); + internal static string LibraryVersion => Assembly.GetAssembly(typeof(DamageTrackerService)).GetName().Version.ToString(3); @@ -16,17 +17,19 @@ internal static void CheckForUpdates() var webClient = new WebClient(); var frameworkUpToDate = false; var libraryVersionMatch = false; + var webSuccess = false; try { var receivedVersion = webClient .DownloadString( "https://www.lcpdfr.com/applications/downloadsng/interface/api.php?do=checkForUpdates&fileId=42767&textOnly=1") .Trim(); - + Game.LogTrivial( $"DamageTrackerFramework loaded successfully. Online Version: {receivedVersion} | Local DamageTrackerFramework Version: {CurrentVersion} | Local DamageTrackerLib Version: {LibraryVersion}"); frameworkUpToDate = receivedVersion == CurrentVersion; libraryVersionMatch = LibraryVersion == CurrentVersion; + webSuccess = true; } catch (WebException) { @@ -38,7 +41,7 @@ internal static void CheckForUpdates() { Game.DisplayNotification("commonmenu", "card_suit_hearts", $"DamageTrackerFramework {CurrentVersion}", "~g~Successfully Loaded", - $"By Variapolis \nVersion is {(frameworkUpToDate ? "~g~Up To Date" : "~r~Out Of Date")}"); + $"By Variapolis \nVersion is {(webSuccess ? frameworkUpToDate ? "~g~Up To Date" : "~r~Out Of Date" : "~o~Version Check Failed")}"); if (!frameworkUpToDate) Game.LogTrivial( "[VERSION OUTDATED] Please update to latest version here: https://www.lcpdfr.com/downloads/gta5mods/scripts/42767-damage-tracker-framework/"); From 4c357b37681142ae881fe269bb81ecc83b5e0066 Mon Sep 17 00:00:00 2001 From: Vari Date: Sun, 26 Feb 2023 21:41:36 +0000 Subject: [PATCH 25/50] fix: check for mismatch even if web request fails. --- DamageTrackingFramework/VersionChecker.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/DamageTrackingFramework/VersionChecker.cs b/DamageTrackingFramework/VersionChecker.cs index 5193620..6219fde 100644 --- a/DamageTrackingFramework/VersionChecker.cs +++ b/DamageTrackingFramework/VersionChecker.cs @@ -20,15 +20,14 @@ internal static void CheckForUpdates() var webSuccess = false; try { + libraryVersionMatch = LibraryVersion == CurrentVersion; var receivedVersion = webClient .DownloadString( "https://www.lcpdfr.com/applications/downloadsng/interface/api.php?do=checkForUpdates&fileId=42767&textOnly=1") .Trim(); - Game.LogTrivial( $"DamageTrackerFramework loaded successfully. Online Version: {receivedVersion} | Local DamageTrackerFramework Version: {CurrentVersion} | Local DamageTrackerLib Version: {LibraryVersion}"); frameworkUpToDate = receivedVersion == CurrentVersion; - libraryVersionMatch = LibraryVersion == CurrentVersion; webSuccess = true; } catch (WebException) From fb68d036736e182eee0374fc1f7c4cae995ea4b3 Mon Sep 17 00:00:00 2001 From: Vari Date: Mon, 27 Feb 2023 00:46:50 +0000 Subject: [PATCH 26/50] fix: fix damage coalescing --- .../Properties/AssemblyVersion.cs | 4 ++-- DamageTrackingFramework/DamageTracker.cs | 20 +++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/DamageTrackerLib/Properties/AssemblyVersion.cs b/DamageTrackerLib/Properties/AssemblyVersion.cs index 4b4b084..3903d40 100644 --- a/DamageTrackerLib/Properties/AssemblyVersion.cs +++ b/DamageTrackerLib/Properties/AssemblyVersion.cs @@ -1,5 +1,5 @@ using System.Reflection; -[assembly: AssemblyVersion("0.9.6")] -[assembly: AssemblyFileVersion("0.9.6")] +[assembly: AssemblyVersion("0.9.7")] +[assembly: AssemblyFileVersion("0.9.7")] diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index d7db7fc..33e3e88 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -95,6 +95,7 @@ private static void ClearPedDamage(Ped ped) { ped.ClearLastDamageBone(); NativeFunction.Natives.xAC678E40BE7C74D2(ped); + PedDict[ped] = (ped.Health, ped.Armor); } private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) // BUG: Fire doesn't damage per tick @@ -106,17 +107,12 @@ private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) // BUG var damageHandler = *(IntPtr*)(pedAddr + 648); if (damageHandler == IntPtr.Zero) return false; var damageArray = *(int*)(damageHandler + 72); - var previousHealth = PedDict[ped]; - if (ped.Health > previousHealth.health || ped.Armor > previousHealth.armour || damageArray <= 0) - { - PedDict[ped] = (ped.Health, ped.Armor); - return false; - } - + if (damageArray == 0) return false; + if (!WasDamaged(ped, PedDict[ped])) return false; var hashAddr = damageHandler + 8; if (hashAddr == IntPtr.Zero || *(WeaponHash*)hashAddr == 0 || !DamageTrackerLookups.WeaponLookup.ContainsKey(*(WeaponHash*)hashAddr)) - return false; // May not be necessary. + return false; // May not be necessary. TODO: Default value for unknown hashes and 0 var weaponHash = *(WeaponHash*)hashAddr; var damageTuple = DamageTrackerLookups.WeaponLookup[weaponHash]; damage = new WeaponDamageInfo @@ -129,6 +125,14 @@ private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) // BUG } } + private static bool WasDamaged(Ped ped, (int health, int armour) previousHealth) + { + var wasDamaged = ped.Health < previousHealth.health || ped.Armor < previousHealth.armour; + if (ped.Health > previousHealth.health) PedDict[ped] = (ped.Health, PedDict[ped].armour); + if (ped.Armor > previousHealth.armour) PedDict[ped] = (PedDict[ped].health, ped.Armor); + return wasDamaged; + } + private static void CleanPedDictionary() { foreach (var ped in PedDict.Keys.ToList()) From 61017ff798e6186b7edb49c5b3ec21fed3fb02d5 Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 5 May 2023 04:09:30 +0100 Subject: [PATCH 27/50] fix(damage-tracker-service): log when dts fiber is null and add optional logging to damage events --- DamageTrackerLib/DamageTrackerService.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 79f6f81..a525410 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -35,7 +35,7 @@ public static class DamageTrackerService /// /// Starts a GameFiber that collects incoming damage data from the DamageTracker plugin and turns them into events. /// - public static void Start() + public static void Start(bool enableLogging = false) { if (_gameFiber != null) { @@ -43,16 +43,24 @@ public static void Start() return; } - _gameFiber = GameFiber.StartNew(Run); + _gameFiber = GameFiber.StartNew(() => Run(enableLogging)); } /// /// Stops DamageTrackerService GameFiber. /// - public static void Stop() => _gameFiber.Abort(); + public static void Stop() + { + if (_gameFiber == null) + { + Game.LogTrivial("Tried to stop DamageTrackerService while it was not running"); + return; + } + _gameFiber.Abort(); + } - private static void Run() + private static void Run(bool enableLogging) { using var mmf = MemoryMappedFile.CreateOrOpen(Guid, 20000, MemoryMappedFileAccess.ReadWrite); using var mmfAccessor = mmf.CreateViewAccessor(); @@ -71,7 +79,7 @@ private static void Run() foreach (var pedDamageInfo in damagedPeds) { var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); - Game.LogTrivial($"DamageTrackerService: Ped {ped.Model.Name} was damaged."); + if (enableLogging) Game.LogTrivial($"DamageTrackerService: Ped {ped.Model.Name} was damaged."); var attackerPed = pedDamageInfo.AttackerPedHandle == 0 ? null : World.GetEntityByHandle(pedDamageInfo.AttackerPedHandle); From 95c044dd074b56f8f529880340dadecf0730b4d4 Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 5 May 2023 04:23:14 +0100 Subject: [PATCH 28/50] feat(damage-tracker-service): add start and stop logging --- DamageTrackerLib/DamageTrackerService.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index a525410..f1c938c 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -42,7 +42,7 @@ public static void Start(bool enableLogging = false) Game.LogTrivial("Tried to start DamageTrackerService while already running!"); return; } - + Game.LogTrivial("DamageTrackerService Started"); _gameFiber = GameFiber.StartNew(() => Run(enableLogging)); } @@ -57,6 +57,7 @@ public static void Stop() Game.LogTrivial("Tried to stop DamageTrackerService while it was not running"); return; } + Game.LogTrivial("DamageTrackerService Stopped"); _gameFiber.Abort(); } @@ -79,6 +80,7 @@ private static void Run(bool enableLogging) foreach (var pedDamageInfo in damagedPeds) { var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); + if (!ped) continue; if (enableLogging) Game.LogTrivial($"DamageTrackerService: Ped {ped.Model.Name} was damaged."); var attackerPed = pedDamageInfo.AttackerPedHandle == 0 ? null From c86c1cf2efe468dc25e39162e5cb16147c794d3c Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 5 May 2023 04:30:36 +0100 Subject: [PATCH 29/50] fix(damage-tracker-service): fix crash for outdated plugins starting service --- DamageTrackerLib/DamageTrackerService.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index f1c938c..94d7c97 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -35,7 +35,12 @@ public static class DamageTrackerService /// /// Starts a GameFiber that collects incoming damage data from the DamageTracker plugin and turns them into events. /// - public static void Start(bool enableLogging = false) + public static void Start() => Start(false); + + /// + /// Starts a GameFiber that collects incoming damage data from the DamageTracker plugin and turns them into events. Takes a boolean parameter that will enable logging damage. + /// + public static void Start(bool enableLogging) { if (_gameFiber != null) { From ac1bb7f9ab4e728a7b2cc5d0aa6da1eb75c83dbd Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 5 May 2023 04:33:17 +0100 Subject: [PATCH 30/50] refactor(damage-tracker-service): make damage logging more verbose --- DamageTrackerLib/DamageTrackerService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 94d7c97..3d014d8 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -86,7 +86,7 @@ private static void Run(bool enableLogging) { var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); if (!ped) continue; - if (enableLogging) Game.LogTrivial($"DamageTrackerService: Ped {ped.Model.Name} was damaged."); + if (enableLogging) Game.LogTrivial($"DamageTrackerService: Ped {ped.Model.Name} damaged by {pedDamageInfo.WeaponInfo.Hash}."); var attackerPed = pedDamageInfo.AttackerPedHandle == 0 ? null : World.GetEntityByHandle(pedDamageInfo.AttackerPedHandle); From 061171b6dd617ee76d1c944e09e9333b7ed9a390 Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 5 May 2023 04:45:31 +0100 Subject: [PATCH 31/50] feat(damage-tracker-service): add IsRunning property to DamageTrackerService.cs --- DamageTrackerLib/DamageTrackerService.cs | 2 ++ DamageTrackerLib/Properties/AssemblyVersion.cs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 3d014d8..209e2e0 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -32,6 +32,8 @@ public static class DamageTrackerService private static readonly BinaryFormatter binaryFormatter = new(); private static GameFiber _gameFiber; + public static bool IsRunning => _gameFiber != null; + /// /// Starts a GameFiber that collects incoming damage data from the DamageTracker plugin and turns them into events. /// diff --git a/DamageTrackerLib/Properties/AssemblyVersion.cs b/DamageTrackerLib/Properties/AssemblyVersion.cs index 3903d40..f663283 100644 --- a/DamageTrackerLib/Properties/AssemblyVersion.cs +++ b/DamageTrackerLib/Properties/AssemblyVersion.cs @@ -1,5 +1,5 @@ using System.Reflection; -[assembly: AssemblyVersion("0.9.7")] -[assembly: AssemblyFileVersion("0.9.7")] +[assembly: AssemblyVersion("0.9.8")] +[assembly: AssemblyFileVersion("0.9.8")] From a9bddb5ba06c1f1aa0dc9ce00377105c18384574 Mon Sep 17 00:00:00 2001 From: Vari Date: Sun, 14 May 2023 02:34:55 +0100 Subject: [PATCH 32/50] build: update copyright --- DamageTrackerLib/Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DamageTrackerLib/Properties/AssemblyInfo.cs b/DamageTrackerLib/Properties/AssemblyInfo.cs index cec2526..ca90b94 100644 --- a/DamageTrackerLib/Properties/AssemblyInfo.cs +++ b/DamageTrackerLib/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("DamageTrackerLib")] -[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyCopyright("Copyright © 2022 Variapolis")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] From aa0747876773b80b2ae70b2de174777cd59cabdc Mon Sep 17 00:00:00 2001 From: Vari Date: Tue, 16 May 2023 10:00:08 +0100 Subject: [PATCH 33/50] feat(hashes): update hashes --- DamageTrackerLib/DamageInfo/WeaponHash.cs | 16 ++++++++++++++++ DamageTrackerLib/DamageTrackerLookups.cs | 19 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/DamageTrackerLib/DamageInfo/WeaponHash.cs b/DamageTrackerLib/DamageInfo/WeaponHash.cs index 6fa280f..de744bc 100644 --- a/DamageTrackerLib/DamageInfo/WeaponHash.cs +++ b/DamageTrackerLib/DamageInfo/WeaponHash.cs @@ -234,5 +234,21 @@ public enum WeaponHash : uint Vehicle_Volatol_Dual_MG = 1150790720, Vehicle_Water_Cannon = 1741783703, Vehicle_Helicopter_Rotors = 2971687502, + + // 0.9.9 + Military_Rifle = 0x9D1F17E6, + Heavy_Rifle = 0xC78D71B4, + Service_Carbine = 3520460075, + Precision_Rifle = 1853742572, + Combat_Shotgun = 94989220, + Compact_EMP_Launcher = 3676729658, + Railgun_XM3 = 4272043364, + Stun_Gun_MP = 1171102963, + Perico_Pistol = 1470379660, + WM29_Pistol = 465894841, + Navy_Revolver = 2441047180, + Ceramic_Pistol = 727643628, + Candy_Cane = 1703483498, + Custom = 694201337, } } \ No newline at end of file diff --git a/DamageTrackerLib/DamageTrackerLookups.cs b/DamageTrackerLib/DamageTrackerLookups.cs index d55ab58..e6b95d9 100644 --- a/DamageTrackerLib/DamageTrackerLookups.cs +++ b/DamageTrackerLib/DamageTrackerLookups.cs @@ -71,7 +71,7 @@ public static class DamageTrackerLookups [BoneId.LeftClavicle] = (Limb.Chest, BodyRegion.Torso), }; - + /// /// Lookups for the Weapons. It is not recommended to change/use these values. /// @@ -79,6 +79,7 @@ public static class DamageTrackerLookups WeaponLookup = new() { + [WeaponHash.Unknown] = (DamageGroup.Unknown, DamageType.Unknown), [WeaponHash.Antique_Cavalry_Dagger] = (DamageGroup.Melee, DamageType.MeleeStab), [WeaponHash.Baseball_Bat] = (DamageGroup.Melee, DamageType.MeleeBlunt), [WeaponHash.Bottle] = (DamageGroup.Melee, DamageType.MeleeStab), @@ -306,7 +307,21 @@ public static class DamageTrackerLookups [WeaponHash.Vehicle_Viseris_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), [WeaponHash.Vehicle_Volatol_Dual_MG] = (DamageGroup.Bullet, DamageType.VehicleFirearm), [WeaponHash.Vehicle_Water_Cannon] = (DamageGroup.WaterCannon, DamageType.WaterCannon), - [WeaponHash.Vehicle_Helicopter_Rotors] = (DamageGroup.Vehicle, DamageType.Vehicle) + [WeaponHash.Vehicle_Helicopter_Rotors] = (DamageGroup.Vehicle, DamageType.Vehicle), + // 0.9.9 + [WeaponHash.Military_Rifle] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Heavy_Rifle] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Service_Carbine] = (DamageGroup.Bullet, DamageType.Rifle), + [WeaponHash.Precision_Rifle] = (DamageGroup.Bullet, DamageType.Sniper), + [WeaponHash.Combat_Shotgun] = (DamageGroup.Bullet, DamageType.Shotgun), + [WeaponHash.Compact_EMP_Launcher] = (DamageGroup.Explosion, DamageType.Launcher), + [WeaponHash.Railgun_XM3] = (DamageGroup.Explosion, DamageType.Launcher), + [WeaponHash.Stun_Gun_MP] = (DamageGroup.LessThanLethal, DamageType.LessThanLethal), + [WeaponHash.Perico_Pistol] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.WM29_Pistol] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Navy_Revolver] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Ceramic_Pistol] = (DamageGroup.Bullet, DamageType.Pistol), + [WeaponHash.Candy_Cane] = (DamageGroup.Melee, DamageType.MeleeBlunt), }; }; } \ No newline at end of file From bc96112862c36ff6aeb4e9f4657554a61ec04bf1 Mon Sep 17 00:00:00 2001 From: Vari Date: Tue, 16 May 2023 10:00:56 +0100 Subject: [PATCH 34/50] feat(damage-tracker): make tracker send unknown damage --- DamageTrackingFramework/DamageTracker.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index 33e3e88..a7a1a56 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -110,10 +110,11 @@ private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) // BUG if (damageArray == 0) return false; if (!WasDamaged(ped, PedDict[ped])) return false; var hashAddr = damageHandler + 8; - if (hashAddr == IntPtr.Zero || *(WeaponHash*)hashAddr == 0 || - !DamageTrackerLookups.WeaponLookup.ContainsKey(*(WeaponHash*)hashAddr)) - return false; // May not be necessary. TODO: Default value for unknown hashes and 0 - var weaponHash = *(WeaponHash*)hashAddr; + if (hashAddr == IntPtr.Zero || *(WeaponHash*)hashAddr == 0) return false; // May not be necessary. + var weaponHash = DamageTrackerLookups.WeaponLookup.ContainsKey(*(WeaponHash*)hashAddr) ? *(WeaponHash*)hashAddr : WeaponHash.Unknown; + if (weaponHash == WeaponHash.Unknown) + Game.LogTrivial( + $"WARNING: {*(uint*)hashAddr} Hash is unknown. Please notify DamageTracker Developer at: https://www.lcpdfr.com/downloads/gta5mods/scripts/42767-damage-tracker-framework/"); var damageTuple = DamageTrackerLookups.WeaponLookup[weaponHash]; damage = new WeaponDamageInfo { From ce894fdc2e3c82a20d0ce7296bcee1c9cd0e8a62 Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 19 May 2023 23:20:49 +0100 Subject: [PATCH 35/50] refactor(damage-tracker): make damage tracker use ped memory components as damage booleans The Damage Tracker used to use health changes to determine whether damage was received. However, with the way Rockstar designed the damage system, the "damageArray", which I'm not sure the real purpose of, is often 0 after the damage history is cleared, allowing for us to check if damage was received by checking that value instead. --- DamageTrackingFramework/DamageTracker.cs | 100 +++++++++++++---------- 1 file changed, 58 insertions(+), 42 deletions(-) diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index a7a1a56..0987262 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -15,8 +15,7 @@ namespace DamageTrackingFramework internal static class DamageTracker { // ReSharper disable once HeapView.ObjectAllocation.Evident - private static readonly Dictionary PedDict = new(); - + private static readonly Dictionary PedHealthDict = new(); private static readonly List PedDamageList = new(); private static readonly BinaryFormatter Formatter = new(); @@ -33,7 +32,7 @@ internal static void CheckPedsFiber() var peds = World.GetAllPeds(); foreach (var ped in peds) HandlePed(ped); SendPedData(mmfAccessor, stream); - CleanPedDictionary(); + CleanPedDictionaries(); GameFiber.Yield(); } // ReSharper disable once FunctionNeverReturns @@ -43,8 +42,6 @@ private static void SendPedData(MemoryMappedViewAccessor accessor, MemoryStream stream) // TODO: Resize file if ped count is too small or send less. { - // var requiredSize = Marshal.SizeOf(PedDamageList) + (PedDamageList.Count * Marshal.SizeOf()) + 2000; - // if(requiredSize > accessor.Capacity) stream.SetLength(0); Formatter.Serialize(stream, PedDamageList.ToArray()); var buffer = stream.ToArray(); @@ -55,33 +52,34 @@ private static void private static void HandlePed(Ped ped) { if (!ped.Exists() || !ped.IsHuman) return; - if (!PedDict.ContainsKey(ped)) PedDict.Add(ped, (ped.Health, ped.Armor)); + if (!PedHealthDict.ContainsKey(ped)) PedHealthDict.Add(ped, (ped.Health, ped.Armor)); - var previousHealth = PedDict[ped]; + var previousHealth = PedHealthDict[ped]; if (!TryGetPedDamage(ped, out var damage)) return; PedDamageList.Add(GenerateDamageInfo(ped, previousHealth.health, previousHealth.armour, damage)); ClearPedDamage(ped); } - private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, int previousArmour, WeaponDamageInfo damage) + private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, int previousArmour, + WeaponHash damageHash) { var lastDamagedBone = (BoneId)ped.LastDamageBone; var boneTuple = DamageTrackerLookups.BoneLookup[lastDamagedBone]; - PoolHandle attackerPed = 0; - if (ped.HasBeenDamagedByAnyPed) - foreach (var otherPed in PedDict.Keys) - { - if (!otherPed.IsValid() || !ped.HasBeenDamagedBy(otherPed)) continue; - attackerPed = otherPed.Handle; - break; - } + var weaponTuple = DamageTrackerLookups.WeaponLookup[damageHash]; + var attackerPed = GetAttackerPed(ped); + return new PedDamageInfo { PedHandle = ped.Handle, AttackerPedHandle = attackerPed, Damage = previousHealth - ped.Health, ArmourDamage = previousArmour - ped.Armor, - WeaponInfo = damage, + WeaponInfo = + { + Hash = damageHash, + Type = weaponTuple.DamageType, + Group = weaponTuple.DamageGroup + }, BoneInfo = new BoneDamageInfo { BoneId = lastDamagedBone, @@ -91,54 +89,72 @@ private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, int }; } - private static void ClearPedDamage(Ped ped) + private static PoolHandle GetAttackerPed(Ped ped) { - ped.ClearLastDamageBone(); - NativeFunction.Natives.xAC678E40BE7C74D2(ped); - PedDict[ped] = (ped.Health, ped.Armor); + PoolHandle attackerPed = 0; + if (!ped.HasBeenDamagedByAnyPed) return attackerPed; + foreach (var otherPed in PedHealthDict.Keys) + { + if (!otherPed.IsValid() || !ped.HasBeenDamagedBy(otherPed)) continue; + attackerPed = otherPed.Handle; + break; + } + + return attackerPed; } - private static bool TryGetPedDamage(Ped ped, out WeaponDamageInfo damage) // BUG: Fire doesn't damage per tick + private static bool TryGetPedDamage(Ped ped, out WeaponHash damageHash) { var pedAddr = ped.MemoryAddress; - damage = default; + damageHash = default; unsafe { var damageHandler = *(IntPtr*)(pedAddr + 648); - if (damageHandler == IntPtr.Zero) return false; + if (damageHandler == IntPtr.Zero) // Always true if the Ped has never taken damage. + { + if (!WasDamaged(ped)) return false; + damageHash = WeaponHash.Fall; // Triggers damage event if health went down due to falling. + return true; + } + var damageArray = *(int*)(damageHandler + 72); - if (damageArray == 0) return false; - if (!WasDamaged(ped, PedDict[ped])) return false; + if (damageArray == 0) // true unless the ped took damage since LastDamage was cleared (Except Falling). + { + if (!WasDamaged(ped)) return false; + damageHash = WeaponHash.Fall; // Triggers damage event if health went down due to falling. + return true; + } + var hashAddr = damageHandler + 8; - if (hashAddr == IntPtr.Zero || *(WeaponHash*)hashAddr == 0) return false; // May not be necessary. - var weaponHash = DamageTrackerLookups.WeaponLookup.ContainsKey(*(WeaponHash*)hashAddr) ? *(WeaponHash*)hashAddr : WeaponHash.Unknown; - if (weaponHash == WeaponHash.Unknown) + damageHash = DamageTrackerLookups.WeaponLookup.ContainsKey(*(WeaponHash*)hashAddr) + ? *(WeaponHash*)hashAddr + : WeaponHash.Unknown; + if (damageHash == WeaponHash.Unknown) Game.LogTrivial( $"WARNING: {*(uint*)hashAddr} Hash is unknown. Please notify DamageTracker Developer at: https://www.lcpdfr.com/downloads/gta5mods/scripts/42767-damage-tracker-framework/"); - var damageTuple = DamageTrackerLookups.WeaponLookup[weaponHash]; - damage = new WeaponDamageInfo - { - Hash = weaponHash, - Group = damageTuple.DamageGroup, - Type = damageTuple.DamageType - }; return true; } } - private static bool WasDamaged(Ped ped, (int health, int armour) previousHealth) + private static bool WasDamaged(Ped ped) { + var previousHealth = PedHealthDict[ped]; var wasDamaged = ped.Health < previousHealth.health || ped.Armor < previousHealth.armour; - if (ped.Health > previousHealth.health) PedDict[ped] = (ped.Health, PedDict[ped].armour); - if (ped.Armor > previousHealth.armour) PedDict[ped] = (PedDict[ped].health, ped.Armor); return wasDamaged; } - private static void CleanPedDictionary() + private static void ClearPedDamage(Ped ped) + { + ped.ClearLastDamageBone(); + NativeFunction.Natives.xAC678E40BE7C74D2(ped); + PedHealthDict[ped] = (ped.Health, ped.Armor); + } + + private static void CleanPedDictionaries() { - foreach (var ped in PedDict.Keys.ToList()) + foreach (var ped in PedHealthDict.Keys.ToList()) if (!ped.Exists()) - PedDict.Remove(ped); + PedHealthDict.Remove(ped); } } } \ No newline at end of file From 4e374b402027c32fe465b08a1fcc4f48bda6bbe4 Mon Sep 17 00:00:00 2001 From: Vari Date: Fri, 19 May 2023 23:29:05 +0100 Subject: [PATCH 36/50] build: bump version to 1.0.0 --- DamageTrackerLib/Properties/AssemblyVersion.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DamageTrackerLib/Properties/AssemblyVersion.cs b/DamageTrackerLib/Properties/AssemblyVersion.cs index f663283..1496ec4 100644 --- a/DamageTrackerLib/Properties/AssemblyVersion.cs +++ b/DamageTrackerLib/Properties/AssemblyVersion.cs @@ -1,5 +1,5 @@ using System.Reflection; -[assembly: AssemblyVersion("0.9.8")] -[assembly: AssemblyFileVersion("0.9.8")] +[assembly: AssemblyVersion("1.0.0")] +[assembly: AssemblyFileVersion("1.0.0")] From bc83a6a44840dae3d259051406112541d28db42c Mon Sep 17 00:00:00 2001 From: Sam <72755263+Variapolis@users.noreply.github.com> Date: Fri, 19 May 2023 23:42:46 +0100 Subject: [PATCH 37/50] Create README.md --- README.md | 494 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 494 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..59428fd --- /dev/null +++ b/README.md @@ -0,0 +1,494 @@ +# DamageTrackerFramework Documentation + +DamageTrackerFramework is a GTA V Plugin that provides a framework and API for developers to get performant, reliable, and detailed events for when Peds are damaged. + +## Installation +The DamageTrackerFramework release can be downloaded from the [LSPDFR Website](https://www.lcpdfr.com/downloads/gta5mods/scripts/42767-damage-tracker-framework/) + +For installation, the users MUST do the following: + +1. Install DamageTrackerLib.dll to their GTA V directory. +2. Install DamageTrackerFramework.dll to their plugins folder. +3. DamageTrackerFramework ********MUST******** be started in RagePluginHook. + +## Usage + +### Plugin Examples + +Usage for the plugin is pretty simple. + +1. Ensure that you have a reference to the DamageTrackerLib.dll. You ************DO NOT************ need a reference to the DamageTrackerFramework, but it **MUST** be installed and running in GTA V when your plugin is running. +2. When your plugin is loaded you must start the DamageTrackerService with `DamageTrackerService.Start()` (You must also have a `using DamageTrackerLib;` statement at the top of the file.) +3. Subscribe to the events with a custom function. I.E: `DamageTrackerService.OnPedTookDamage += MyCustomFunction;` and `DamageTrackerService.OnPlayerTookDamage += MyCustomFunction;` Custom function must be in the form of the [Event Delegate](#event-delegate) +4. Unsubscribe to the events when the plugin is unloaded. I.E: `DamageTrackerService.OnPedTookDamage -= MyCustomFunction;` and `DamageTrackerService.OnPlayerTookDamage -= MyCustomFunction;` +5. Stop the DamageTrackerService when the plugin is unloaded with `DamageTrackerService.Stop()` + +Below are two example plugins, the full source code for them can be found here: [Variapolis/DamageTrackerExample](https://github.com/Variapolis/DamageTrackerExample) + +#### RPH Plugin +```csharp +using DamageTrackerLib; +using DamageTrackerLib.DamageInfo; +using Rage; +using Rage.Attributes; + +[assembly: Plugin("DamageTrackerExample", Description = "A plugin for testing.", + Author = "Variapolis", + PrefersSingleInstance = true)] + +namespace TestCallouts +{ + // ReSharper disable once UnusedType.Global + public class EntryPoint + { + private static GameFiber GameFiber; + + // ReSharper disable once UnusedMember.Global + public static void Main() + { + Game.DisplayNotification("DamageTrackerExample by Variapolis ~g~Successfully Loaded"); + DamageTrackerService.Start(); + DamageTrackerService.OnPedTookDamage += HandleDamage; // C# Event from DamageTrackerService + DamageTrackerService.OnPlayerTookDamage += HandleDamage; // C# Event from DamageTrackerService + GameFiber.Hibernate(); + } + + // ReSharper disable once UnusedMember.Global + public static void OnUnload(bool Exit) + { + DamageTrackerService.Stop(); + Game.DisplayNotification("DamageTrackerExample by Variapolis ~r~ Unloaded"); + } + + // This uses a delegate function from DamageTrackerLib - public delegate void PedTookDamageDelegate(Ped victimPed, Ped attackerPed, PedDamageInfo damageInfo) + private static void HandleDamage(Ped victim, Ped attacker, PedDamageInfo damageInfo) => + Game.DisplayHelp($"~w~Ped: {victim.Model.Name} (~r~{damageInfo.Damage} ~b~{damageInfo.ArmourDamage} ~w~Dmg ({(victim.IsAlive ? "~g~Alive" : "~r~Dead")}~w~) " + + $"\n~w~Health: ~g~{victim.Health}/{victim.MaxHealth} Armor: ~b~{victim.Armor})" + + $"\n~w~Attacker: ~r~{attacker?.Model.Name ?? "None"}" + + $"\n~w~Weapon: ~y~{damageInfo.WeaponInfo.Hash.ToString()} {damageInfo.WeaponInfo.Type.ToString()} {damageInfo.WeaponInfo.Group.ToString()}" + + $"\n~w~Bone: ~r~{damageInfo.BoneInfo.BoneId.ToString()} {damageInfo.BoneInfo.Limb.ToString()} {damageInfo.BoneInfo.BodyRegion.ToString()}"); + } +} +``` +#### LSPDFR Plugin + +```csharp +using DamageTrackerLib; +using DamageTrackerLib.DamageInfo; +using LSPD_First_Response.Mod.API; +using Rage; + +namespace DamageTrackerLSPDFRExample +{ + public class Main : Plugin + { + public override void Initialize() + { + Functions.OnOnDutyStateChanged += HandleDutyChanged; + Game.DisplayNotification("DTF LSPDFR Example Loaded."); + } + + private void HandleDutyChanged(bool onduty) + { + if (onduty) + { + DamageTrackerService.Start(); + DamageTrackerService.OnPedTookDamage += HandleDamage; + DamageTrackerService.OnPlayerTookDamage += HandleDamage; + } + else + { + DamageTrackerService.Stop(); + DamageTrackerService.OnPedTookDamage -= HandleDamage; + DamageTrackerService.OnPlayerTookDamage -= HandleDamage; + } + } + + private static void HandleDamage(Ped victim, Ped attacker, PedDamageInfo damageInfo) => + Game.DisplayHelp($"~w~Ped: {victim.Model.Name} (~r~{damageInfo.Damage} ~b~{damageInfo.ArmourDamage} ~w~Dmg ({(victim.IsAlive ? "~g~Alive" : "~r~Dead")}~w~) " + + $"\n~w~Health: ~g~{victim.Health}/{victim.MaxHealth} Armor: ~b~{victim.Armor})" + + $"\n~w~Attacker: ~r~{attacker?.Model.Name ?? "None"}" + + $"\n~w~Weapon: ~y~{damageInfo.WeaponInfo.Hash.ToString()} {damageInfo.WeaponInfo.Type.ToString()} {damageInfo.WeaponInfo.Group.ToString()}" + + $"\n~w~Bone: ~r~{damageInfo.BoneInfo.BoneId.ToString()} {damageInfo.BoneInfo.Limb.ToString()} {damageInfo.BoneInfo.BodyRegion.ToString()}"); + + public override void Finally() => Game.DisplayNotification("DTF LSPDFR Example Unloaded."); + } +} +``` + + +## Documentation + +### DamageTrackerService Start() and Stop() + +`DamageTrackerService.Start()` and `DamageTrackerService.Stop()` are used to start and stop a GameFiber which collects data sent by the DamageTrackerFramework. This GameFiber will not start if it is already running, however, it is recommended to stop it when unloading a plugin to prevent any potential memory leaks. + +### Event Delegate + +This is the event delegate that is used by the DamageTrackerService. It is a template of what the function that is being subscribed to the event should look like. + +```csharp +public delegate void PedTookDamageDelegate(Ped victimPed, Ped attackerPed, PedDamageInfo damageInfo); +``` + +### Damage Info + +Damage info about peds is provided via a PedDamageInfo struct. This holds all the information about how a ped was damaged, including the handle for the ped, the handle for the attacker, and the damage received to health, as well as damage to armor. + +```csharp +[Serializable] +public struct PedDamageInfo +{ + public uint PedHandle; // Reference to Ped is provided via the event. + public uint AttackerPedHandle; // Reference to AttackerPed is provided via the event. + public int Damage; + public int ArmourDamage; + public WeaponDamageInfo WeaponInfo; + public BoneDamageInfo BoneInfo; +} +``` + +WeaponDamageInfo provides information on what kind of weapon was used to damage the Ped. This can include firearms and other environmental things such as falling. `WeaponHashes` are grouped into categories such as `DamageType` and `DamageGroup`. The relationships can be found in [Weapon Lookups](#weapon-lookups) + +```csharp +[Serializable] +public struct WeaponDamageInfo +{ + public WeaponHash Hash; + public DamageType Type; + public DamageGroup Group; +} +``` + +BoneDamageInfo provides information on what part of the body the Ped was damaged on. `BoneIds` have been grouped into categories such as `Limb` and `BodyRegion`. The relationships can be found in [Bone Lookups](#bone-lookups) + +```csharp +[Serializable] +public struct BoneDamageInfo +{ + public BoneId BoneId; + public Limb Limb; + public BodyRegion BodyRegion; +} +``` + +### Bone Lookups + +- Lookup Table + + + | BoneId | Limb | BodyRegion | + | --- | --- | --- | + | BoneId.Root | Limb.Stomach | BodyRegion.Torso | + | BoneId.LeftThumb1 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftThumb2 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftRingFinger1 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftRingFinger2 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftPinky1 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftPinky2 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftIndexFinger1 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftIndexFinger2 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftMiddleFinger1 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftMiddleFinger2 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.RightClavicle | Limb.Chest | BodyRegion.Torso | + | BoneId.Pelvis | Limb.Stomach | BodyRegion.Torso | + | BoneId.LeftFoot | Limb.LeftLeg | BodyRegion.Legs | + | BoneId.LeftHand | Limb.LeftArm | BodyRegion.Arms | + | BoneId.Spine | Limb.Stomach | BodyRegion.Torso | + | BoneId.RightPhFoot | Limb.RightLeg | BodyRegion.Legs | + | BoneId.Spine1 | Limb.Stomach | BodyRegion.Torso | + | BoneId.Spine2 | Limb.Chest | BodyRegion.Torso | + | BoneId.Spine3 | Limb.Chest | BodyRegion.Torso | + | BoneId.LeftThumb0 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftIndexFinger0 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftMiddleFinger0 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftRingFinger0 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftPinky0 | Limb.LeftArm | BodyRegion.Arms | + | BoneId.RightForearm | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightPhHand | Limb.RightArm | BodyRegion.Arms | + | BoneId.Head | Limb.Head | BodyRegion.Head | + | BoneId.RightCalf | Limb.RightLeg | BodyRegion.Legs | + | BoneId.Neck | Limb.Head | BodyRegion.Head | + | BoneId.RightUpperArm | Limb.RightArm | BodyRegion.Arms | + | BoneId.LeftUpperArm | Limb.LeftArm | BodyRegion.Arms | + | BoneId.RightThigh | Limb.RightLeg | BodyRegion.Legs | + | BoneId.RightFoot | Limb.RightLeg | BodyRegion.Legs | + | BoneId.RightHand | Limb.RightArm | BodyRegion.Arms | + | BoneId.SpineRoot | Limb.Stomach | BodyRegion.Torso | + | BoneId.LeftPhFoot | Limb.LeftLeg | BodyRegion.Arms | + | BoneId.LeftThigh | Limb.LeftLeg | BodyRegion.Legs | + | BoneId.RightThumb0 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightIndexFinger0 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightMiddleFinger0 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightRingFinger0 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightPinky0 | Limb.RightArm | BodyRegion.Arms | + | BoneId.LeftPhHand | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftForeArm | Limb.LeftArm | BodyRegion.Arms | + | BoneId.LeftCalf | Limb.LeftLeg | BodyRegion.Legs | + | BoneId.RightThumb1 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightThumb2 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightRingFinger1 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightRingFinger2 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightPinky1 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightPinky2 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightIndexFinger1 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightIndexFinger2 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightMiddleFinger1 | Limb.RightArm | BodyRegion.Arms | + | BoneId.RightMiddleFinger2 | Limb.RightArm | BodyRegion.Arms | + | BoneId.LeftClavicle | Limb.Chest | BodyRegion.Torso | + +### Weapon Lookups + +- Lookup Table + + + | WeaponHash | DamageGroup | DamageType | + | --- | --- | --- | + | WeaponHash.Unknown | DamageGroup.Unknown | DamageType.Unknown | + | WeaponHash.Antique_Cavalry_Dagger | DamageGroup.Melee | DamageType.MeleeStab | + | WeaponHash.Baseball_Bat | DamageGroup.Melee | DamageType.MeleeBlunt | + | WeaponHash.Bottle | DamageGroup.Melee | DamageType.MeleeStab | + | WeaponHash.Crowbar | DamageGroup.Melee | DamageType.MeleeBlunt | + | WeaponHash.Fist | DamageGroup.Melee | DamageType.Unarmed | + | WeaponHash.Flashlight | DamageGroup.Melee | DamageType.MeleeBlunt | + | WeaponHash.Golf_Club | DamageGroup.Melee | DamageType.MeleeBlunt | + | WeaponHash.Hammer | DamageGroup.Melee | DamageType.MeleeBlunt | + | WeaponHash.Hatchet | DamageGroup.Melee | DamageType.MeleeStab | + | WeaponHash.Knuckle | DamageGroup.Melee | DamageType.MeleeBlunt | + | WeaponHash.Knife | DamageGroup.Melee | DamageType.MeleeStab | + | WeaponHash.Machete | DamageGroup.Melee | DamageType.MeleeStab | + | WeaponHash.Switchblade | DamageGroup.Melee | DamageType.MeleeStab | + | WeaponHash.Nightstick | DamageGroup.Melee | DamageType.MeleeBlunt | + | WeaponHash.Pipe_Wrench | DamageGroup.Melee | DamageType.MeleeBlunt | + | WeaponHash.Battle_Axe | DamageGroup.Melee | DamageType.MeleeStab | + | WeaponHash.Pool_Cue | DamageGroup.Melee | DamageType.MeleeBlunt | + | WeaponHash.Stone_Hatchet | DamageGroup.Melee | DamageType.MeleeStab | + | WeaponHash.Pistol | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Pistol_MK2 | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Combat_Pistol | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.APPistol | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Stun_Gun | DamageGroup.LessThanLethal | DamageType.LessThanLethal | + | WeaponHash.Pistol50 | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.SNSPistol | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.SNSPistol_MK2 | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Heavy_Pistol | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Vintage_Pistol | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Flare_Gun | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Marksman_Pistol | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Heavy_Revolver | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Heavy_Revolver_MK2 | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Double_Action | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Up_n_Atomizer | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Micro_SMG | DamageGroup.Bullet | DamageType.SMG | + | WeaponHash.SMG | DamageGroup.Bullet | DamageType.SMG | + | WeaponHash.SMGMK2 | DamageGroup.Bullet | DamageType.SMG | + | WeaponHash.Assault_SMG | DamageGroup.Bullet | DamageType.SMG | + | WeaponHash.Combat_PDW | DamageGroup.Bullet | DamageType.SMG | + | WeaponHash.Machine_Pistol | DamageGroup.Bullet | DamageType.SMG | + | WeaponHash.Mini_SMG | DamageGroup.Bullet | DamageType.SMG | + | WeaponHash.Unholy_Hellbringer | DamageGroup.Bullet | DamageType.MG | + | WeaponHash.Pump_Shotgun | DamageGroup.Bullet | DamageType.Shotgun | + | WeaponHash.Pump_Shotgun_MK2 | DamageGroup.Bullet | DamageType.Shotgun | + | WeaponHash.Sawed_Off_Shotgun | DamageGroup.Bullet | DamageType.Shotgun | + | WeaponHash.Assault_Shotgun | DamageGroup.Bullet | DamageType.Shotgun | + | WeaponHash.Bullpup_Shotgun | DamageGroup.Bullet | DamageType.Shotgun | + | WeaponHash.Musket | DamageGroup.Bullet | DamageType.Sniper | + | WeaponHash.Heavy_Shotgun | DamageGroup.Bullet | DamageType.Shotgun | + | WeaponHash.Double_Barrel_Shotgun | DamageGroup.Bullet | DamageType.Shotgun | + | WeaponHash.Sweeper_Shotgun | DamageGroup.Bullet | DamageType.Shotgun | + | WeaponHash.Assault_Rifle | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Assault_Rifle_MK2 | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Carbine_Rifle | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Carbine_Rifle_MK2 | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Advanced_Rifle | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Special_Carbine | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Special_Carbine_MK2 | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Bullpup_Rifle | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Bullpup_Rifle_MK2 | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Compact_Rifle | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.MG | DamageGroup.Bullet | DamageType.MG | + | WeaponHash.Combat_MG | DamageGroup.Bullet | DamageType.MG | + | WeaponHash.Combat_MGMK2 | DamageGroup.Bullet | DamageType.MG | + | WeaponHash.Gusenberg_Sweeper | DamageGroup.Bullet | DamageType.MG | + | WeaponHash.Sniper_Rifle | DamageGroup.Bullet | DamageType.Sniper | + | WeaponHash.Heavy_Sniper | DamageGroup.Bullet | DamageType.Sniper | + | WeaponHash.Heavy_Sniper_MK2 | DamageGroup.Bullet | DamageType.Sniper | + | WeaponHash.Marksman_Rifle | DamageGroup.Bullet | DamageType.Sniper | + | WeaponHash.Marksman_Rifle_MK2 | DamageGroup.Bullet | DamageType.Sniper | + | WeaponHash.RPG | DamageGroup.Explosion | DamageType.Launcher | + | WeaponHash.Grenade_Launcher | DamageGroup.Explosion | DamageType.Launcher | + | WeaponHash.Smoke_Grenade_Launcher | DamageGroup.NonDamaging | DamageType.Launcher | + | WeaponHash.Minigun | DamageGroup.Bullet | DamageType.Launcher | + | WeaponHash.Firework_Launcher | DamageGroup.Explosion | DamageType.Launcher | + | WeaponHash.Railgun | DamageGroup.Explosion | DamageType.Launcher | + | WeaponHash.Homing_Launcher | DamageGroup.Explosion | DamageType.Launcher | + | WeaponHash.Compact_Grenade_Launcher | DamageGroup.Explosion | DamageType.Launcher | + | WeaponHash.Ray_Minigun | DamageGroup.Bullet | DamageType.Launcher | + | WeaponHash.Grenade | DamageGroup.Explosion | DamageType.Explosive | + | WeaponHash.BZGas | DamageGroup.Gas | DamageType.Gas | + | WeaponHash.Smoke_Grenade | DamageGroup.NonDamaging | DamageType.ThrowableNonLethal | + | WeaponHash.Flare | DamageGroup.NonDamaging | DamageType.ThrowableNonLethal | + | WeaponHash.Molotov | DamageGroup.Fire | DamageType.Fire | + | WeaponHash.Sticky_Bomb | DamageGroup.Explosion | DamageType.Explosive | + | WeaponHash.Proximity_Mine | DamageGroup.Explosion | DamageType.Explosive | + | WeaponHash.Snowball | DamageGroup.NonDamaging | DamageType.ThrowableNonLethal | + | WeaponHash.Pipe_Bomb | DamageGroup.Explosion | DamageType.Explosive | + | WeaponHash.Baseball | DamageGroup.NonDamaging | DamageType.ThrowableNonLethal | + | WeaponHash.Jerry_Can | DamageGroup.NonDamaging | DamageType.Misc | + | WeaponHash.Fire_Extinguisher | DamageGroup.NonDamaging | DamageType.Misc | + | WeaponHash.Parachute | DamageGroup.Unknown | DamageType.Unknown | + | WeaponHash.Electric_Fence | DamageGroup.Environmental | DamageType.Electric | + | WeaponHash.Hitby_Water_Cannon | DamageGroup.WaterCannon | DamageType.WaterCannon | + | WeaponHash.Rammedby_Car | DamageGroup.Vehicle | DamageType.Vehicle | + | WeaponHash.Run_Overby_Car | DamageGroup.Vehicle | DamageType.Vehicle | + | WeaponHash.Fall | DamageGroup.Fall | DamageType.Fall | + | WeaponHash.Animal | DamageGroup.Animal | DamageType.Animal | + | WeaponHash.Airstrike_Rocket | DamageGroup.Explosion | DamageType.Launcher | + | WeaponHash.Bleeding | DamageGroup.Bodily | DamageType.Bodily | + | WeaponHash.Briefcase | DamageGroup.Unknown | DamageType.Unknown | + | WeaponHash.Briefcase02 | DamageGroup.Unknown | DamageType.Unknown | + | WeaponHash.Cougar | DamageGroup.Animal | DamageType.Animal | + | WeaponHash.Barbed_Wire | DamageGroup.Environmental | DamageType.BarbedWire | + | WeaponHash.Drowning | DamageGroup.Drowning | DamageType.Drowning | + | WeaponHash.Drowning_In_Vehicle | DamageGroup.Drowning | DamageType.Drowning | + | WeaponHash.Explosion | DamageGroup.Explosion | DamageType.Explosive | + | WeaponHash.Exhaustion | DamageGroup.Bodily | DamageType.Bodily | + | WeaponHash.Fire | DamageGroup.Fire | DamageType.Fire | + | WeaponHash.Heli_Crash | DamageGroup.Explosion | DamageType.Explosive | + | WeaponHash.Vehicle_Rocket | DamageGroup.Explosion | DamageType.Launcher | + | WeaponHash.Vehicle_Akula_Barrage | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Akula_Minigun | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Akula_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Akula_Turret_Dual | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Akula_Turret_Single | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_APCCannon | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_APCMG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_APCMissile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Ardent_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Avenger_Cannon | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Barrage_Rear_GL | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Barrage_Rear_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Barrage_Rear_Minigun | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Barrage_Top_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Barrage_Top_Minigun | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Bombushka_Cannon | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Bombushka_Dual_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Cannon_Blazer | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Caracara_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Caracara_Minigun | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Cherno_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Comet_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Deluxo_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Deluxo_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Dogfighter_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Dogfighter_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Dune_Grenade_Launcher | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Dune_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Dune_Minigun | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Enemy_Laser | DamageGroup.Unknown | DamageType.Unknown | + | WeaponHash.Vehicle_Hacker_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Hacker_Missile_Homing | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Halftrack_Dual_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Halftrack_Quad_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Havok_Minigun | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Hunter_Barrage | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Hunter_Cannon | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Hunter_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Hunter_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Insurgent_Minigun | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Khanjali_Cannon | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Khanjali_Cannon_Heavy | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Khanjali_GL | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Khanjali_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Menacer_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Microlight_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Mobileops_Cannon | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Mogul_Dual_Nose | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Mogul_Dual_Turret | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Mogul_Nose | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Mogul_Turret | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Mule4MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Mule4Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Mule4Turret_GL | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Nightshark_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Nose_Turret_Valkyrie | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Oppressor_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Oppressor_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Oppressor2Cannon | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Oppressor2MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Oppressor2Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Plane_Rocket | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Player_Buzzard | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Player_Lazer | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Player_Savage | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Pounder2Barrage | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Pounder2GL | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Pounder2Mini | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Pounder2Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Radar | DamageGroup.NonDamaging | DamageType.NonDamaging | + | WeaponHash.Vehicle_Revolter_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Rogue_Cannon | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Rogue_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Rogue_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Ruiner_Bullet | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Ruiner_Rocket | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Savestra_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Scramjet_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Scramjet_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Seabreeze_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Searchlight | DamageGroup.NonDamaging | DamageType.NonDamaging | + | WeaponHash.Vehicle_Space_Rocket | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Speedo4MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Speedo4Turret_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Speedo4Turret_Mini | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Strikeforce_Barrage | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Strikeforce_Cannon | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Strikeforce_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Subcar_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Subcar_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Subcar_Torpedo | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Tampa_Dual_Minigun | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Tampa_Fixed_Minigun | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Tampa_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Tampa_Mortar | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Tank | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Technical_Minigun | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Thruster_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Thruster_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Trailer_Dualaa | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Trailer_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Trailer_Quad_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Tula_Dual_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Tula_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Tula_Minigun | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Tula_Nose_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Turret_Boxville | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Turret_Insurgent | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Turret_Limo | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Turret_Technical | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Turret_Valkyrie | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Vigilante_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Vigilante_Missile | DamageGroup.Explosion | DamageType.VehicleLauncher | + | WeaponHash.Vehicle_Viseris_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Volatol_Dual_MG | DamageGroup.Bullet | DamageType.VehicleFirearm | + | WeaponHash.Vehicle_Water_Cannon | DamageGroup.WaterCannon | DamageType.WaterCannon | + | WeaponHash.Vehicle_Helicopter_Rotors | DamageGroup.Vehicle | DamageType.Vehicle | + | WeaponHash.Military_Rifle | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Heavy_Rifle | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Service_Carbine | DamageGroup.Bullet | DamageType.Rifle | + | WeaponHash.Precision_Rifle | DamageGroup.Bullet | DamageType.Sniper | + | WeaponHash.Combat_Shotgun | DamageGroup.Bullet | DamageType.Shotgun | + | WeaponHash.Compact_EMP_Launcher | DamageGroup.Explosion| DamageType.Launcher | + | WeaponHash.Railgun_XM3 | DamageGroup.Explosion | DamageType.Launcher | + | WeaponHash.Stun_Gun_MP | DamageGroup.LessThanLethal | DamageType.LessThanLethal | + | WeaponHash.Perico_Pistol | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.WM29_Pistol | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Navy_Revolver | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Ceramic_Pistol | DamageGroup.Bullet | DamageType.Pistol | + | WeaponHash.Candy_Cane | DamageGroup.Melee | DamageType.MeleeBlunt | + + Planned: + | WeaponHash | DamageGroup | DamageType | + | --- | --- | --- | + | WeaponHash.Custom | Currently Unused | Currently Unused | + From d15daf43ddc03a267dbeb55723536ce98a076d73 Mon Sep 17 00:00:00 2001 From: Sam <72755263+Variapolis@users.noreply.github.com> Date: Mon, 22 May 2023 14:49:41 +0100 Subject: [PATCH 38/50] Create License.txt --- License.txt | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 License.txt diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/License.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From 3e00d78e238aec21f6cd003392b1609a08fa93fb Mon Sep 17 00:00:00 2001 From: Sam <72755263+Variapolis@users.noreply.github.com> Date: Mon, 22 May 2023 14:59:25 +0100 Subject: [PATCH 39/50] Update License.txt --- License.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/License.txt b/License.txt index f288702..8e76fd8 100644 --- a/License.txt +++ b/License.txt @@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + DamageTrackerUtility is a free framework to allow for tracking damage events for NPCs in Grand Theft Auto V. + Copyright (C) 2023 Variapolis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Copyright (C) + DamageTrackerUtility Copyright (C) 2023 Variapolis This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. From 55068bc061ecb05908f3818ab8f99681c7b05fab Mon Sep 17 00:00:00 2001 From: Sam <72755263+Variapolis@users.noreply.github.com> Date: Mon, 22 May 2023 15:21:00 +0100 Subject: [PATCH 40/50] Update License.txt Switched to EPL v2.0 from GPL v3.0 --- License.txt | 953 +++++++++++++++------------------------------------- 1 file changed, 279 insertions(+), 674 deletions(-) diff --git a/License.txt b/License.txt index 8e76fd8..de059c3 100644 --- a/License.txt +++ b/License.txt @@ -1,674 +1,279 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - DamageTrackerUtility is a free framework to allow for tracking damage events for NPCs in Grand Theft Auto V. - Copyright (C) 2023 Variapolis - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - DamageTrackerUtility Copyright (C) 2023 Variapolis - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. +Copyright (c) Variapolis 2023 + +Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + +"Contributor" means any person or entity that Distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which +are necessarily infringed by the use or sale of its Contribution alone +or when combined with the Program. + +"Program" means the Contributions Distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement +or any Secondary License (as applicable), including Contributors. + +"Derivative Works" shall mean any work, whether in Source Code or other +form, that is based on (or derived from) the Program and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. + +"Modified Works" shall mean any work in Source Code or other form that +results from an addition to, deletion from, or modification of the +contents of the Program, including, for purposes of clarity any new file +in Source Code form that contains any contents of the Program. Modified +Works shall not include works that contain only declarations, +interfaces, types, classes, structures, or files of the Program solely +in each case in order to link to, bind by name, or subclass the Program +or Modified Works thereof. + +"Distribute" means the acts of a) distributing or b) making available +in any manner that enables the transfer of a copy. + +"Source Code" means the form of a Program preferred for making +modifications, including but not limited to software source code, +documentation source, and configuration files. + +"Secondary License" means either the GNU General Public License, +Version 2.0, or any later versions of that license, including any +exceptions or additional permissions as identified by the initial +Contributor. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + +3. REQUIREMENTS + +3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + +3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + +3.3 Contributors may not remove or alter any copyright, patent, +trademark, attribution notices, disclaimers of warranty, or limitations +of liability ("notices") contained within the Program from any copy of +the Program which they Distribute, provided that Contributors may add +their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities +with respect to end users, business partners and the like. While this +license is intended to facilitate the commercial use of the Program, +the Contributor who includes the Program in a commercial product +offering should do so in a manner which does not create potential +liability for other Contributors. Therefore, if a Contributor includes +the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and indemnify every +other Contributor ("Indemnified Contributor") against any losses, +damages and costs (collectively "Losses") arising from claims, lawsuits +and other legal actions brought by a third party against the Indemnified +Contributor to the extent caused by the acts or omissions of such +Commercial Contributor in connection with its distribution of the Program +in a commercial product offering. The obligations in this section do not +apply to any claims or Losses relating to any actual or alleged +intellectual property infringement. In order to qualify, an Indemnified +Contributor must: a) promptly notify the Commercial Contributor in +writing of such claim, and b) allow the Commercial Contributor to control, +and cooperate with the Commercial Contributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those performance +claims and warranties, and if a court requires any other Contributor to +pay any damages as a result, the Commercial Contributor must pay +those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF +TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR +PURPOSE. Each Recipient is solely responsible for determining the +appropriateness of using and distributing the Program and assumes all +risks associated with its exercise of rights under this Agreement, +including but not limited to the risks and costs of program errors, +compliance with applicable laws, damage to or loss of data, programs +or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS +SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE +EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software +or hardware) infringes such Recipient's patent(s), then such Recipient's +rights granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of +time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use +and distribution of the Program as soon as reasonably practicable. +However, Recipient's obligations under this Agreement and any licenses +granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, +but in order to avoid inconsistency the Agreement is copyrighted and +may only be modified in the following manner. The Agreement Steward +reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement +Steward has the right to modify this Agreement. The Eclipse Foundation +is the initial Agreement Steward. The Eclipse Foundation may assign the +responsibility to serve as the Agreement Steward to a suitable separate +entity. Each new version of the Agreement will be given a distinguishing +version number. The Program (including Contributions) may always be +Distributed subject to the version of the Agreement under which it was +received. In addition, after a new version of the Agreement is published, +Contributor may elect to Distribute the Program (including its +Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient +receives no rights or licenses to the intellectual property of any +Contributor under this Agreement, whether expressly, by implication, +estoppel or otherwise. All rights in the Program not expressly granted +under this Agreement are reserved. Nothing in this Agreement is intended +to be enforceable by any entity that is not a Contributor or Recipient. +No third-party beneficiary rights are created under this Agreement. + +Exhibit A - Form of Secondary Licenses Notice + +"This Source Code may also be made available under the following +Secondary Licenses when the conditions for such availability set forth +in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), +version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. From dbd64e951ca18078a07f5241ce114e44d93ff527 Mon Sep 17 00:00:00 2001 From: Vari <72755263+Variapolis@users.noreply.github.com> Date: Mon, 22 May 2023 19:20:33 +0100 Subject: [PATCH 41/50] Update README.md Add Requirements. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 59428fd..e5c480d 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ For installation, the users MUST do the following: 2. Install DamageTrackerFramework.dll to their plugins folder. 3. DamageTrackerFramework ********MUST******** be started in RagePluginHook. +## Requirements +- [RagePluginHook](https://ragepluginhook.net/) ## Usage ### Plugin Examples From 4868f0b38ea86c824d97e5a5110b89500ee23901 Mon Sep 17 00:00:00 2001 From: Vari Date: Thu, 25 May 2023 00:36:32 +0100 Subject: [PATCH 42/50] refactor(damage-tracker-service): split up run method in DamageTrackerService.cs --- DamageTrackerLib/DamageTrackerService.cs | 39 +++++++++++++----------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 209e2e0..cde28d6 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -84,28 +84,31 @@ private static void Run(bool enableLogging) stream.Position = 0; if (stream.Length <= 0) continue; // TODO: Add error message var damagedPeds = (PedDamageInfo[])binaryFormatter.Deserialize(stream); - foreach (var pedDamageInfo in damagedPeds) - { - var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); - if (!ped) continue; - if (enableLogging) Game.LogTrivial($"DamageTrackerService: Ped {ped.Model.Name} damaged by {pedDamageInfo.WeaponInfo.Hash}."); - var attackerPed = pedDamageInfo.AttackerPedHandle == 0 - ? null - : World.GetEntityByHandle(pedDamageInfo.AttackerPedHandle); - switch (ped.IsPlayer) - { - case true when OnPlayerTookDamage != null: - OnPlayerTookDamage.Invoke(ped, attackerPed, pedDamageInfo); - break; - case false when OnPedTookDamage != null: - OnPedTookDamage.Invoke(ped, attackerPed, pedDamageInfo); - break; - } - } + foreach (var pedDamageInfo in damagedPeds) InvokeDamageEvent(pedDamageInfo, enableLogging); } // ReSharper disable once FunctionNeverReturns } + private static void InvokeDamageEvent(PedDamageInfo pedDamageInfo, bool enableLogging) + { + var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); + if (!ped) return; + if (enableLogging) + Game.LogTrivial($"DamageTrackerService: Ped {ped.Model.Name} damaged by {pedDamageInfo.WeaponInfo.Hash}."); + var attackerPed = pedDamageInfo.AttackerPedHandle == 0 + ? null + : World.GetEntityByHandle(pedDamageInfo.AttackerPedHandle); + switch (ped.IsPlayer) + { + case true when OnPlayerTookDamage != null: + OnPlayerTookDamage.Invoke(ped, attackerPed, pedDamageInfo); + break; + case false when OnPedTookDamage != null: + OnPedTookDamage.Invoke(ped, attackerPed, pedDamageInfo); + break; + } + } + private static bool IsByteArrayZero(byte[] array) { foreach (var element in array) From 4227d3caf51e9f6e10a88bfcc2860ce86fa62b21 Mon Sep 17 00:00:00 2001 From: Vari Date: Thu, 25 May 2023 00:37:40 +0100 Subject: [PATCH 43/50] refactor(damage-tracker-service): clean up DamageTrackerService.cs --- DamageTrackerLib/DamageTrackerService.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index cde28d6..40ea41a 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -10,6 +10,7 @@ namespace DamageTrackerLib // ReSharper disable once UnusedType.Global public static class DamageTrackerService { + // ReSharper disable once UnusedMember.Global public static string CurrentVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString(3); public const string Guid = "609a228f"; @@ -22,26 +23,31 @@ public static class DamageTrackerService /// /// Event invoked when a Ped takes damage. This event excludes the Player. /// + // ReSharper disable once EventNeverSubscribedTo.Global public static event PedTookDamageDelegate OnPedTookDamage; /// /// Event invoked when the Player takes damage ONLY. /// + // ReSharper disable once EventNeverSubscribedTo.Global public static event PedTookDamageDelegate OnPlayerTookDamage; - private static readonly BinaryFormatter binaryFormatter = new(); + private static readonly BinaryFormatter BinaryFormatter = new(); private static GameFiber _gameFiber; + // ReSharper disable once UnusedMember.Global public static bool IsRunning => _gameFiber != null; /// /// Starts a GameFiber that collects incoming damage data from the DamageTracker plugin and turns them into events. /// + // ReSharper disable once UnusedMember.Global public static void Start() => Start(false); /// /// Starts a GameFiber that collects incoming damage data from the DamageTracker plugin and turns them into events. Takes a boolean parameter that will enable logging damage. /// + // ReSharper disable once MemberCanBePrivate.Global public static void Start(bool enableLogging) { if (_gameFiber != null) @@ -57,6 +63,7 @@ public static void Start(bool enableLogging) /// /// Stops DamageTrackerService GameFiber. /// + // ReSharper disable once UnusedMember.Global public static void Stop() { if (_gameFiber == null) @@ -83,7 +90,7 @@ private static void Run(bool enableLogging) stream.Write(buffer, 0, buffer.Length); stream.Position = 0; if (stream.Length <= 0) continue; // TODO: Add error message - var damagedPeds = (PedDamageInfo[])binaryFormatter.Deserialize(stream); + var damagedPeds = (PedDamageInfo[])BinaryFormatter.Deserialize(stream); foreach (var pedDamageInfo in damagedPeds) InvokeDamageEvent(pedDamageInfo, enableLogging); } // ReSharper disable once FunctionNeverReturns From 81fea5a5bd1b4ae2e45d7374ecf51477c7c6ff68 Mon Sep 17 00:00:00 2001 From: Vari Date: Sat, 27 May 2023 22:35:01 +0100 Subject: [PATCH 44/50] fix(damage-tracker-service): fix crash caused by invalid ped handle --- DamageTrackerLib/DamageTrackerService.cs | 37 +++++++++++++++---- .../Properties/AssemblyVersion.cs | 4 +- DamageTrackingFramework/DamageTracker.cs | 2 +- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 40ea41a..31df81c 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -1,9 +1,11 @@ -using System.IO; +using System; +using System.IO; using System.IO.MemoryMappedFiles; using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; using DamageTrackerLib.DamageInfo; using Rage; +using Rage.Native; namespace DamageTrackerLib { @@ -12,7 +14,7 @@ public static class DamageTrackerService { // ReSharper disable once UnusedMember.Global public static string CurrentVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString(3); - + public const string Guid = "609a228f"; /// @@ -25,7 +27,7 @@ public static class DamageTrackerService /// // ReSharper disable once EventNeverSubscribedTo.Global public static event PedTookDamageDelegate OnPedTookDamage; - + /// /// Event invoked when the Player takes damage ONLY. /// @@ -55,6 +57,7 @@ public static void Start(bool enableLogging) Game.LogTrivial("Tried to start DamageTrackerService while already running!"); return; } + Game.LogTrivial("DamageTrackerService Started"); _gameFiber = GameFiber.StartNew(() => Run(enableLogging)); } @@ -71,6 +74,7 @@ public static void Stop() Game.LogTrivial("Tried to stop DamageTrackerService while it was not running"); return; } + Game.LogTrivial("DamageTrackerService Stopped"); _gameFiber.Abort(); } @@ -98,13 +102,14 @@ private static void Run(bool enableLogging) private static void InvokeDamageEvent(PedDamageInfo pedDamageInfo, bool enableLogging) { - var ped = World.GetEntityByHandle(pedDamageInfo.PedHandle); + var ped = TryGetPedByHandle(pedDamageInfo.PedHandle); if (!ped) return; if (enableLogging) - Game.LogTrivial($"DamageTrackerService: Ped {ped.Model.Name} damaged by {pedDamageInfo.WeaponInfo.Hash}."); - var attackerPed = pedDamageInfo.AttackerPedHandle == 0 + Game.LogTrivial( + $"DamageTrackerService: Ped {ped.Model.Name} damaged by {pedDamageInfo.WeaponInfo.Hash}."); + var attackerPed = pedDamageInfo.AttackerPedHandle == default ? null - : World.GetEntityByHandle(pedDamageInfo.AttackerPedHandle); + : TryGetPedByHandle(pedDamageInfo.AttackerPedHandle); switch (ped.IsPlayer) { case true when OnPlayerTookDamage != null: @@ -116,6 +121,24 @@ private static void InvokeDamageEvent(PedDamageInfo pedDamageInfo, bool enableLo } } + private static Ped TryGetPedByHandle(PoolHandle handle) + { + if (!NativeFunction.Natives.DOES_ENTITY_EXIST(handle)) + { + Game.LogTrivial($"DamageTrackerService Warning: Ped Handle {handle.ToString()} does not exist."); + return null; + } + try + { + return World.GetEntityByHandle(handle); + } + catch (ArgumentException) + { + Game.LogTrivial($"DamageTrackerService Exception Caught: Ped Handle ({handle.ToString()}) did not return an Entity."); + } + return null; + } + private static bool IsByteArrayZero(byte[] array) { foreach (var element in array) diff --git a/DamageTrackerLib/Properties/AssemblyVersion.cs b/DamageTrackerLib/Properties/AssemblyVersion.cs index 1496ec4..8afa7f0 100644 --- a/DamageTrackerLib/Properties/AssemblyVersion.cs +++ b/DamageTrackerLib/Properties/AssemblyVersion.cs @@ -1,5 +1,5 @@ using System.Reflection; -[assembly: AssemblyVersion("1.0.0")] -[assembly: AssemblyFileVersion("1.0.0")] +[assembly: AssemblyVersion("1.0.1")] +[assembly: AssemblyFileVersion("1.0.1")] diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index 0987262..99a02ea 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -91,7 +91,7 @@ private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, int private static PoolHandle GetAttackerPed(Ped ped) { - PoolHandle attackerPed = 0; + PoolHandle attackerPed = default; if (!ped.HasBeenDamagedByAnyPed) return attackerPed; foreach (var otherPed in PedHealthDict.Keys) { From c85a54d67613157b304ed69cdc108f0b1c458a05 Mon Sep 17 00:00:00 2001 From: Vari Date: Sun, 28 May 2023 01:27:28 +0100 Subject: [PATCH 45/50] fix(damage-tracker-service): make entity exists check cast handle to uint --- DamageTrackerLib/DamageTrackerService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 31df81c..4a9091e 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -123,7 +123,7 @@ private static void InvokeDamageEvent(PedDamageInfo pedDamageInfo, bool enableLo private static Ped TryGetPedByHandle(PoolHandle handle) { - if (!NativeFunction.Natives.DOES_ENTITY_EXIST(handle)) + if (!NativeFunction.Natives.DOES_ENTITY_EXIST((uint)handle)) { Game.LogTrivial($"DamageTrackerService Warning: Ped Handle {handle.ToString()} does not exist."); return null; From ad09a74b00f5bc44847002268b772010ffaec03c Mon Sep 17 00:00:00 2001 From: Vari Date: Sun, 28 May 2023 22:46:47 +0100 Subject: [PATCH 46/50] fix(damage-tracker-service): make DamageTrackerService warm up JIT. --- DamageTrackerLib/DamageTrackerService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 4a9091e..9a097b6 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -57,7 +57,8 @@ public static void Start(bool enableLogging) Game.LogTrivial("Tried to start DamageTrackerService while already running!"); return; } - + NativeFunction.Natives + .x5BA652A0CD14DF2F(); // HACK: Fixes stuttering issue by warming up JIT with a useless native. Game.LogTrivial("DamageTrackerService Started"); _gameFiber = GameFiber.StartNew(() => Run(enableLogging)); } From c16bbd3619c7e0019e08c7f706173cc792383bee Mon Sep 17 00:00:00 2001 From: Vari <72755263+variapolis@users.noreply.github.com> Date: Thu, 24 Aug 2023 01:14:22 +0100 Subject: [PATCH 47/50] feat: add damage hooking --- DamageTrackerLib/DamageInfo/WeaponHash.cs | 2 +- DamageTrackerLib/DamageTrackerLib.csproj | 1 + DamageTrackerLib/DamageTrackerLookups.cs | 2 +- DamageTrackerLib/DamageTrackerService.cs | 22 +-- DamageTrackerLib/HandleUtility.cs | 26 +++ DamageTrackerUtility.sln.DotSettings.user | 1 + DamageTrackingFramework/DamageTracker.cs | 155 ++++++++++-------- .../DamageTrackingFramework.csproj | 9 + DamageTrackingFramework/Entry.cs | 1 + 9 files changed, 127 insertions(+), 92 deletions(-) create mode 100644 DamageTrackerLib/HandleUtility.cs diff --git a/DamageTrackerLib/DamageInfo/WeaponHash.cs b/DamageTrackerLib/DamageInfo/WeaponHash.cs index de744bc..d200473 100644 --- a/DamageTrackerLib/DamageInfo/WeaponHash.cs +++ b/DamageTrackerLib/DamageInfo/WeaponHash.cs @@ -87,7 +87,7 @@ public enum WeaponHash : uint Ray_Minigun = 3056410471, Grenade = 2481070269, BZGas = 2694266206, - Smoke_Grenade = 4256991824, + Tear_Gas = 4256991824, Flare = 1233104067, Molotov = 615608432, Sticky_Bomb = 741814745, diff --git a/DamageTrackerLib/DamageTrackerLib.csproj b/DamageTrackerLib/DamageTrackerLib.csproj index 41afc04..296e85b 100644 --- a/DamageTrackerLib/DamageTrackerLib.csproj +++ b/DamageTrackerLib/DamageTrackerLib.csproj @@ -54,6 +54,7 @@ + diff --git a/DamageTrackerLib/DamageTrackerLookups.cs b/DamageTrackerLib/DamageTrackerLookups.cs index e6b95d9..94e5df0 100644 --- a/DamageTrackerLib/DamageTrackerLookups.cs +++ b/DamageTrackerLib/DamageTrackerLookups.cs @@ -161,7 +161,7 @@ public static class DamageTrackerLookups [WeaponHash.Ray_Minigun] = (DamageGroup.Bullet, DamageType.Launcher), [WeaponHash.Grenade] = (DamageGroup.Explosion, DamageType.Explosive), [WeaponHash.BZGas] = (DamageGroup.Gas, DamageType.Gas), - [WeaponHash.Smoke_Grenade] = (DamageGroup.NonDamaging, DamageType.ThrowableNonLethal), + [WeaponHash.Tear_Gas] = (DamageGroup.NonDamaging, DamageType.ThrowableNonLethal), [WeaponHash.Flare] = (DamageGroup.NonDamaging, DamageType.ThrowableNonLethal), [WeaponHash.Molotov] = (DamageGroup.Fire, DamageType.Fire), [WeaponHash.Sticky_Bomb] = (DamageGroup.Explosion, DamageType.Explosive), diff --git a/DamageTrackerLib/DamageTrackerService.cs b/DamageTrackerLib/DamageTrackerService.cs index 9a097b6..5c4e5c2 100644 --- a/DamageTrackerLib/DamageTrackerService.cs +++ b/DamageTrackerLib/DamageTrackerService.cs @@ -103,14 +103,14 @@ private static void Run(bool enableLogging) private static void InvokeDamageEvent(PedDamageInfo pedDamageInfo, bool enableLogging) { - var ped = TryGetPedByHandle(pedDamageInfo.PedHandle); + var ped = HandleUtility.TryGetPedByHandle(pedDamageInfo.PedHandle); if (!ped) return; if (enableLogging) Game.LogTrivial( $"DamageTrackerService: Ped {ped.Model.Name} damaged by {pedDamageInfo.WeaponInfo.Hash}."); var attackerPed = pedDamageInfo.AttackerPedHandle == default ? null - : TryGetPedByHandle(pedDamageInfo.AttackerPedHandle); + : HandleUtility.TryGetPedByHandle(pedDamageInfo.AttackerPedHandle); switch (ped.IsPlayer) { case true when OnPlayerTookDamage != null: @@ -122,24 +122,6 @@ private static void InvokeDamageEvent(PedDamageInfo pedDamageInfo, bool enableLo } } - private static Ped TryGetPedByHandle(PoolHandle handle) - { - if (!NativeFunction.Natives.DOES_ENTITY_EXIST((uint)handle)) - { - Game.LogTrivial($"DamageTrackerService Warning: Ped Handle {handle.ToString()} does not exist."); - return null; - } - try - { - return World.GetEntityByHandle(handle); - } - catch (ArgumentException) - { - Game.LogTrivial($"DamageTrackerService Exception Caught: Ped Handle ({handle.ToString()}) did not return an Entity."); - } - return null; - } - private static bool IsByteArrayZero(byte[] array) { foreach (var element in array) diff --git a/DamageTrackerLib/HandleUtility.cs b/DamageTrackerLib/HandleUtility.cs new file mode 100644 index 0000000..048911c --- /dev/null +++ b/DamageTrackerLib/HandleUtility.cs @@ -0,0 +1,26 @@ +using System; +using Rage; +using Rage.Native; + +namespace DamageTrackerLib; + +public static class HandleUtility +{ + public static Ped TryGetPedByHandle(PoolHandle handle) + { + if (!NativeFunction.Natives.DOES_ENTITY_EXIST((uint)handle)) + { + Game.LogTrivial($"DamageTrackerService Warning: Ped Handle {handle.ToString()} does not exist."); + return null; + } + try + { + return NativeFunction.Natives.IS_ENTITY_A_PED((uint)handle) ? World.GetEntityByHandle(handle) : null; + } + catch (ArgumentException) + { + Game.LogTrivial($"Exception Caught: Ped Handle ({handle.ToString()}) did not return an Entity."); + } + return null; + } +} \ No newline at end of file diff --git a/DamageTrackerUtility.sln.DotSettings.user b/DamageTrackerUtility.sln.DotSettings.user index 8036555..7ee935c 100644 --- a/DamageTrackerUtility.sln.DotSettings.user +++ b/DamageTrackerUtility.sln.DotSettings.user @@ -1,6 +1,7 @@  True True + True <AssemblyExplorer> <Assembly Path="D:\Users\Vari\Desktop\Work\Forks\DamageTrackerPlugin\DamageTrackerUtility\packages\RagePluginHook.1.98.0\lib\net472\RagePluginHook.dll" /> </AssemblyExplorer> diff --git a/DamageTrackingFramework/DamageTracker.cs b/DamageTrackingFramework/DamageTracker.cs index 99a02ea..90d0ada 100644 --- a/DamageTrackingFramework/DamageTracker.cs +++ b/DamageTrackingFramework/DamageTracker.cs @@ -1,27 +1,58 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.IO.MemoryMappedFiles; using System.Linq; +using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; using DamageTrackerLib; using DamageTrackerLib.DamageInfo; using Rage; +using Rage.Attributes; using Rage.Native; using WeaponHash = DamageTrackerLib.DamageInfo.WeaponHash; namespace DamageTrackingFramework { + internal struct HookDamageData + { + internal readonly PoolHandle VictimHandle; + internal readonly PoolHandle? AttackerHandle; + internal readonly uint WeaponHash; + + public HookDamageData(PoolHandle victimHandle, PoolHandle? attackerHandle, uint weaponHash) + { + VictimHandle = victimHandle; + AttackerHandle = attackerHandle; + WeaponHash = weaponHash; + } + } + internal static class DamageTracker { // ReSharper disable once HeapView.ObjectAllocation.Evident private static readonly Dictionary PedHealthDict = new(); private static readonly List PedDamageList = new(); - + private static readonly List HookData = new(); + public static EasyHook.LocalHook hook; private static readonly BinaryFormatter Formatter = new(); + public delegate void EntityLogDamageDelegate(IntPtr victim, IntPtr culprit, uint weapon, uint time, bool a5); + + public delegate uint GetScriptGuidForEntityDelegate(IntPtr fwEntity); + + public static GetScriptGuidForEntityDelegate GetScriptGuidForEntity; + public static EntityLogDamageDelegate origEntityLogDamage; + internal static void CheckPedsFiber() { + IntPtr addr = Game.FindPattern("48 F7 F9 49 8B 48 08 48 63 D0 C1 E0 08 0F B6 1C 11 03 D8"); + if (addr == IntPtr.Zero) return; + addr -= 0x68; + GetScriptGuidForEntity = Marshal.GetDelegateForFunctionPointer(addr); + Hook(); + using var mmf = MemoryMappedFile.CreateOrOpen(DamageTrackerService.Guid, 20000, MemoryMappedFileAccess.ReadWrite); // TODO: Replace with GUID from Lib using var mmfAccessor = mmf.CreateViewAccessor(); @@ -29,8 +60,8 @@ internal static void CheckPedsFiber() while (true) { PedDamageList.Clear(); - var peds = World.GetAllPeds(); - foreach (var ped in peds) HandlePed(ped); + CreateDamageInfo(); + CachePedHealth(); SendPedData(mmfAccessor, stream); CleanPedDictionaries(); GameFiber.Yield(); @@ -38,26 +69,29 @@ internal static void CheckPedsFiber() // ReSharper disable once FunctionNeverReturns } - private static void - SendPedData(MemoryMappedViewAccessor accessor, - MemoryStream stream) // TODO: Resize file if ped count is too small or send less. + public static void Hook() { - stream.SetLength(0); - Formatter.Serialize(stream, PedDamageList.ToArray()); - var buffer = stream.ToArray(); - accessor.WriteArray(0, buffer, 0, buffer.Length); - accessor.Flush(); + IntPtr addr = Game.FindPattern("21 4D D8 21 4D DC 41 8B D8"); + + if (addr == IntPtr.Zero) throw new EntryPointNotFoundException("Pattern could not be found"); + + addr -= 0x1F; + origEntityLogDamage = Marshal.GetDelegateForFunctionPointer(addr); + EntityLogDamageDelegate detour = EntityLogDamageDetour; + hook = EasyHook.LocalHook.Create(addr, detour, null); + hook.ThreadACL.SetExclusiveACL(new[] { 0 }); + Game.DisplaySubtitle("Hooked"); } - private static void HandlePed(Ped ped) + private static void CreateDamageInfo() { - if (!ped.Exists() || !ped.IsHuman) return; - if (!PedHealthDict.ContainsKey(ped)) PedHealthDict.Add(ped, (ped.Health, ped.Armor)); - - var previousHealth = PedHealthDict[ped]; - if (!TryGetPedDamage(ped, out var damage)) return; - PedDamageList.Add(GenerateDamageInfo(ped, previousHealth.health, previousHealth.armour, damage)); - ClearPedDamage(ped); + foreach (var data in HookData) + { + var victim = HandleUtility.TryGetPedByHandle(data.VictimHandle); + // if (victim == null) continue; + // Game.DisplaySubtitle(victim?.Model.Name ?? "Nothing"); + // PedDamageList.Add(GenerateDamageInfo(data)); + } } private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, int previousArmour, @@ -66,12 +100,11 @@ private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, int var lastDamagedBone = (BoneId)ped.LastDamageBone; var boneTuple = DamageTrackerLookups.BoneLookup[lastDamagedBone]; var weaponTuple = DamageTrackerLookups.WeaponLookup[damageHash]; - var attackerPed = GetAttackerPed(ped); return new PedDamageInfo { PedHandle = ped.Handle, - AttackerPedHandle = attackerPed, + AttackerPedHandle = default, Damage = previousHealth - ped.Health, ArmourDamage = previousArmour - ped.Armor, WeaponInfo = @@ -89,65 +122,36 @@ private static PedDamageInfo GenerateDamageInfo(Ped ped, int previousHealth, int }; } - private static PoolHandle GetAttackerPed(Ped ped) + private static void CachePedHealth() { - PoolHandle attackerPed = default; - if (!ped.HasBeenDamagedByAnyPed) return attackerPed; - foreach (var otherPed in PedHealthDict.Keys) - { - if (!otherPed.IsValid() || !ped.HasBeenDamagedBy(otherPed)) continue; - attackerPed = otherPed.Handle; - break; - } - - return attackerPed; + foreach (var ped in World.EnumeratePeds()) PedHealthDict[ped] = (ped.Health, ped.Armor); } - private static bool TryGetPedDamage(Ped ped, out WeaponHash damageHash) + private static void EntityLogDamageDetour(IntPtr victim, IntPtr culprit, uint weapon, uint time, bool a5) { - var pedAddr = ped.MemoryAddress; - damageHash = default; - unsafe + if (victim != IntPtr.Zero) // Check if victim is null { - var damageHandler = *(IntPtr*)(pedAddr + 648); - if (damageHandler == IntPtr.Zero) // Always true if the Ped has never taken damage. - { - if (!WasDamaged(ped)) return false; - damageHash = WeaponHash.Fall; // Triggers damage event if health went down due to falling. - return true; - } - - var damageArray = *(int*)(damageHandler + 72); - if (damageArray == 0) // true unless the ped took damage since LastDamage was cleared (Except Falling). - { - if (!WasDamaged(ped)) return false; - damageHash = WeaponHash.Fall; // Triggers damage event if health went down due to falling. - return true; - } - - var hashAddr = damageHandler + 8; - damageHash = DamageTrackerLookups.WeaponLookup.ContainsKey(*(WeaponHash*)hashAddr) - ? *(WeaponHash*)hashAddr - : WeaponHash.Unknown; - if (damageHash == WeaponHash.Unknown) - Game.LogTrivial( - $"WARNING: {*(uint*)hashAddr} Hash is unknown. Please notify DamageTracker Developer at: https://www.lcpdfr.com/downloads/gta5mods/scripts/42767-damage-tracker-framework/"); - return true; + var victimHandle = new PoolHandle(GetScriptGuidForEntity(victim)); + PoolHandle? attackerHandle = + culprit == IntPtr.Zero ? null : new PoolHandle(GetScriptGuidForEntity(culprit)); + HookData.Add(new HookDamageData(victimHandle, attackerHandle, weapon)); + var ped = HandleUtility.TryGetPedByHandle(victimHandle); + if (ped != null) Game.LogTrivial(ped.Health.ToString()); } - } - private static bool WasDamaged(Ped ped) - { - var previousHealth = PedHealthDict[ped]; - var wasDamaged = ped.Health < previousHealth.health || ped.Armor < previousHealth.armour; - return wasDamaged; + origEntityLogDamage(victim, culprit, weapon, time, a5); } - private static void ClearPedDamage(Ped ped) + + private static void + SendPedData(MemoryMappedViewAccessor accessor, + MemoryStream stream) // TODO: Resize file if ped count is too small or send less. { - ped.ClearLastDamageBone(); - NativeFunction.Natives.xAC678E40BE7C74D2(ped); - PedHealthDict[ped] = (ped.Health, ped.Armor); + stream.SetLength(0); + Formatter.Serialize(stream, PedDamageList.ToArray()); + var buffer = stream.ToArray(); + accessor.WriteArray(0, buffer, 0, buffer.Length); + accessor.Flush(); } private static void CleanPedDictionaries() @@ -155,6 +159,17 @@ private static void CleanPedDictionaries() foreach (var ped in PedHealthDict.Keys.ToList()) if (!ped.Exists()) PedHealthDict.Remove(ped); + HookData.Clear(); + } + + public static void Dispose() => hook.Dispose(); + + [ConsoleCommand] + public static void DeformAdvancedFromVehicle(Vector3 relativeVehicleOffset) + { + var vehicle = Game.LocalPlayer.Character.CurrentVehicle; + var offset = vehicle.GetOffsetPosition(relativeVehicleOffset); + NativeFunction.Natives.SET_VEHICLE_DAMAGE(vehicle, offset.X, offset.Y, offset.Z, 100f, 100f, false); } } } \ No newline at end of file diff --git a/DamageTrackingFramework/DamageTrackingFramework.csproj b/DamageTrackingFramework/DamageTrackingFramework.csproj index b4612a1..9cb0043 100644 --- a/DamageTrackingFramework/DamageTrackingFramework.csproj +++ b/DamageTrackingFramework/DamageTrackingFramework.csproj @@ -37,6 +37,9 @@ ..\DamageTrackerLib\bin\Release\DamageTrackerLib.dll + + G:\SteamLibrary\steamapps\common\Grand Theft Auto V\EasyHook.dll + @@ -61,6 +64,12 @@ + + + {8ba678b1-d73d-4b13-8d42-f6750285e52a} + DamageTrackerLib + +