Compare commits

...

228 Commits

Author SHA1 Message Date
Dawid Bepierszcz
d9adaa4cd5 Merge pull request #311 from daffyyyy/main
2.6a
2024-10-18 21:36:58 +02:00
Dawid Bepierszcz
c91141516e Update build.yml 2024-10-18 21:34:23 +02:00
Dawid Bepierszcz
399a56be12 Update build.yml 2024-10-18 21:32:24 +02:00
Dawid Bepierszcz
692fcc905a Update build.yml 2024-10-18 21:31:41 +02:00
Dawid Bepierszcz
3c4f06c4e2 2.6a
- New method to refresh weapons
- Dynamic menu type
- Multilang files
- Command list
2024-10-18 21:31:06 +02:00
Dawid Bepierszcz
a5723a4462 Update build.yml 2024-10-18 19:18:20 +02:00
Dawid Bepierszcz
e9f47e9237 Merge pull request #310 from stefanx111/stickers-and-charms
feat: Stickers and Charms
2024-10-18 19:11:32 +02:00
StefanX
e209b12829 mistake 2024-10-18 19:54:21 +03:00
StefanX
c55a40ecb1 stickers, charms, nametag 2024-10-18 19:48:42 +03:00
Nereziel
b6cac17197 Update gamedata for windows 2024-10-06 16:09:58 +02:00
Nereziel
683f9f2a1c fix deagle thingy 2024-10-05 00:02:17 +02:00
Nereziel
a70e2f771e Update README.md 2024-10-04 13:16:14 +02:00
Nereziel
f4e6a4338d Update README.md 2024-10-04 13:15:26 +02:00
Nereziel
edd3733940 updated new skins and added optional languages
to use another lang just rename it to skins.json
2024-10-04 10:36:37 +02:00
Nereziel
492b8a7976 Merge pull request #303 from stefanx111/fix-armory-update
fix gamedata
2024-10-04 01:10:31 +02:00
Dawid Bepierszcz
6db3d00893 Update weaponpaints.json 2024-10-04 00:02:40 +02:00
StefanX
fc79381e1e fix gamedata 2024-10-04 00:34:59 +03:00
Nereziel
7b12d29227 Merge pull request #299 from originalaidn/main
fixing latest skins size & editing every weapon, knife and glove defa…
2024-10-01 21:48:38 +02:00
AiDN™
abff60a1db fixing latest skins size & editing every weapon, knife and glove default images 2024-09-16 23:11:26 +02:00
Nereziel
edb848b4f9 Merge pull request #298 from originalaidn/main
adding missing skins & missing agent #282
2024-09-11 21:55:17 +02:00
AiDN™
694cc548c8 adding missing skins & missing agent #282 2024-09-11 21:34:57 +02:00
Nereziel
201f723a3c Update README.md 2024-06-21 22:38:18 +02:00
Dawid Bepierszcz
d6384f4ecf Merge pull request #270 from stefanx111/fix-sig
fix wildcard
2024-06-01 12:47:09 +02:00
StefanX
85fc0bd4bc fix wildcard 2024-06-01 13:44:33 +03:00
Dawid Bepierszcz
5c7df833cc Merge pull request #269 from stefanx111/fix-win
win sig mistake
2024-05-31 12:15:23 +02:00
StefanX
5640919b09 win sig mistake 2024-05-31 03:18:17 +03:00
Dawid Bepierszcz
0550ef68f4 Merge pull request #267 from stefanx111/sig-workground
sig workground
2024-05-31 01:08:58 +02:00
Dawid Bepierszcz
c0d42a3d9c Merge branch 'main' into sig-workground 2024-05-31 01:06:58 +02:00
StefanX
5636b401ea sig workground 2024-05-31 00:20:48 +03:00
Dawid Bepierszcz
06cfda21f2 Fix for gameupdate - linux only 2024-05-30 00:38:16 +02:00
Dawid Bepierszcz
771a832ae8 Update weaponpaints.json 2024-05-25 20:58:48 +02:00
Dawid Bepierszcz
323c74b49c Merge pull request #261 from daffyyyy/main
2.5a
2024-05-25 15:32:04 +02:00
Dawid Bepierszcz
ee1dffa06b Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-05-25 15:30:49 +02:00
Dawid Bepierszcz
d90055ad89 2.5a
- Minor changes
- New gloves applied only on spawn (probably new cs2 update issue)
2024-05-25 15:30:47 +02:00
Dawid Bepierszcz
48854c4eaf Merge pull request #253 from daffyyyy/main
2.4e
2024-04-28 02:20:36 +02:00
Dawid Bepierszcz
c06f7ae3be Merge branch 'Nereziel:main' into main 2024-04-28 02:18:14 +02:00
Dawid Bepierszcz
29461e9de2 2.4e
- Minor changes
2024-04-28 02:17:24 +02:00
Dawid Bepierszcz
74ec584d9a Merge pull request #241 from daffyyyy/main
2.4d
2024-04-26 10:07:05 +02:00
Dawid Bepierszcz
ec0d4f4d5a 2.4d
- Updated for latest css
2024-04-26 10:02:32 +02:00
Dawid Bepierszcz
a8ba645292 Merge branch 'Nereziel:main' into main 2024-04-14 22:10:17 +02:00
Dawid Bepierszcz
e04dd312e8 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-04-14 22:09:55 +02:00
Dawid Bepierszcz
702dea9450 2.4c
- Disable hooking giveitemfunc on windows (counterstrikesharp issue) (fix)
2024-04-14 22:09:53 +02:00
Dawid Bepierszcz
c594cd534e Merge pull request #237 from daffyyyy/main
2.4b
2024-04-08 21:31:43 +02:00
Dawid Bepierszcz
5aaf0e6f62 Merge branch 'Nereziel:main' into main 2024-04-08 21:30:46 +02:00
Dawid Bepierszcz
942e776688 2.4b
- Nothing big ;P
2024-04-08 21:30:22 +02:00
Dawid Bepierszcz
36046fee2d Merge pull request #231 from daffyyyy/main
2.4a
2024-04-03 01:35:07 +02:00
Dawid Bepierszcz
d6de0ce6c8 Merge branch 'Nereziel:main' into main 2024-04-03 01:33:52 +02:00
Dawid Bepierszcz
d2c19d8af8 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-04-03 01:32:27 +02:00
Dawid Bepierszcz
0f6d334621 2.4a
- .NET8
- Mysql queries optimization
- CounterStrikeSharp updated
2024-04-03 01:32:24 +02:00
Dawid Bepierszcz
f99c9b2767 Merge pull request #226 from daffyyyy/main
2.3c
2024-03-27 23:20:43 +01:00
Dawid Bepierszcz
6a2d28c303 Merge branch 'Nereziel:main' into main 2024-03-27 23:19:42 +01:00
Dawid Bepierszcz
27a2ae5be9 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-03-27 23:19:26 +01:00
Dawid Bepierszcz
0af9177f07 2.3c
- Small change for mysql performance
2024-03-27 23:19:24 +01:00
Dawid Bepierszcz
cfb49e1498 Merge pull request #222 from daffyyyy/main
2.3b
2024-03-21 01:13:14 +01:00
Dawid Bepierszcz
bbdb4b82ce Merge branch 'Nereziel:main' into main 2024-03-21 01:12:08 +01:00
Dawid Bepierszcz
bfb7defcaa 2.3b
- Fixed agent team bug
- Minor changes
2024-03-21 01:09:45 +01:00
Dawid Bepierszcz
5626c32d30 Merge pull request #213 from daffyyyy/main
2.3a
2024-03-12 14:19:05 +01:00
Dawid Bepierszcz
a6575e9ab2 Music images 2024-03-12 14:17:56 +01:00
Dawid Bepierszcz
683efbd0ae Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-03-12 14:17:02 +01:00
Dawid Bepierszcz
3bc9123a71 Update build.yml 2024-03-12 14:16:52 +01:00
Dawid Bepierszcz
f75ea76deb Merge branch 'Nereziel:main' into main 2024-03-12 14:15:42 +01:00
Dawid Bepierszcz
bf0deda5d7 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-03-12 14:14:52 +01:00
Dawid Bepierszcz
548fdb642d 2.3a
- Added music kits
- Minor changes
2024-03-12 14:14:50 +01:00
Dawid Bepierszcz
8cb9563994 Merge pull request #211 from daffyyyy/main
2.2e
2024-03-11 11:19:41 +01:00
Dawid Bepierszcz
e45714cb9a Merge branch 'Nereziel:main' into main 2024-03-11 11:16:45 +01:00
Dawid Bepierszcz
97e73bfd53 2.2e 2024-03-11 11:16:18 +01:00
Dawid Bepierszcz
6dc047477c Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-03-11 11:10:28 +01:00
Dawid Bepierszcz
ced010645d 2.2e
- Changed data loading to non-block main thread
- Additional check for empty agent
2024-03-11 11:10:25 +01:00
Dawid Bepierszcz
b030d5c7e1 Merge pull request #206 from daffyyyy/main
2.2d
2024-03-09 18:47:02 +01:00
Dawid Bepierszcz
90771f76c7 Merge branch 'Nereziel:main' into main 2024-03-09 18:46:39 +01:00
Dawid Bepierszcz
ad8e51a403 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-03-09 18:46:23 +01:00
Dawid Bepierszcz
8c1edddd1e 2.2d
- Fixed skins
2024-03-09 18:46:12 +01:00
Dawid Bepierszcz
6f86cddd13 Merge pull request #204 from daffyyyy/main
2.2c
2024-03-09 12:03:20 +01:00
Dawid Bepierszcz
24801e814b Merge branch 'Nereziel:main' into main 2024-03-09 12:02:55 +01:00
Dawid Bepierszcz
77def8a305 2.2c
- Minor changes
- Updated translations
- Updated css
2024-03-09 12:01:25 +01:00
Dawid Bepierszcz
651fae4d23 Merge pull request #191 from daffyyyy/main
2.2b
2024-03-05 12:28:48 +01:00
Dawid Bepierszcz
692c22f7d1 Merge branch 'Nereziel:main' into main 2024-03-05 12:27:46 +01:00
Dawid Bepierszcz
cf07106641 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-03-05 12:27:21 +01:00
Dawid Bepierszcz
44177f18fe 2.2b
- Small fixes 🍕
2024-03-05 12:27:19 +01:00
Dawid Bepierszcz
88274d78d8 Merge pull request #188 from daffyyyy/main
2.2a

- Updated languages
- Added agents
- Minor changes
- Updated readme
- Gloves small fix
- Fixed showimage
2024-03-05 02:24:48 +01:00
Dawid Bepierszcz
5cef723674 Merge branch 'Nereziel:main' into main 2024-03-05 02:23:07 +01:00
Dawid Bepierszcz
5f83645867 2.2a
- Added agents images
2024-03-05 02:22:02 +01:00
Dawid Bepierszcz
89005fdd4b Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-03-05 02:20:42 +01:00
Dawid Bepierszcz
4f432cddf5 2.2a
- Updated languages
- Added agents
- Minor changes
- Updated readme
- Gloves small fix
- Fixed showimage
2024-03-05 02:20:33 +01:00
Dawid Bepierszcz
ee1259846d Merge pull request #187 from daffyyyy/main
2.1a
2024-03-04 23:52:42 +01:00
Dawid Bepierszcz
485dd1e9dd Merge branch 'Nereziel:main' into main 2024-03-04 23:51:32 +01:00
Dawid Bepierszcz
666de9e2d2 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-03-04 23:51:10 +01:00
Dawid Bepierszcz
77409269d0 2.1a
- FINALLY WINDOWS SUPPORT
- Fixed visual bug (no skin)
2024-03-04 23:51:08 +01:00
Dawid Bepierszcz
09d9de2a2a Merge pull request #186 from daffyyyy/main
2.0a
2024-03-04 21:50:42 +01:00
Dawid Bepierszcz
362084c503 Merge branch 'Nereziel:main' into main 2024-03-04 21:49:41 +01:00
Dawid Bepierszcz
8cf175d336 2.0a
- New knife method
- Minor commands changes
- Remove OnTick event
- Changed save place
- New skins saving method
- New gamedata file

**IMPORTANT UPDATE**
2024-03-04 21:47:54 +01:00
Nereziel
84adfa8085 Update FUNDING.yml 2024-03-01 15:16:54 +01:00
Nereziel
286d97d125 Create FUNDING.yml 2024-03-01 15:14:07 +01:00
Dawid Bepierszcz
4d3db5b34f Merge pull request #174 from daffyyyy/main
1.9c
2024-02-25 13:20:57 +01:00
Dawid Bepierszcz
85d4e11f26 Merge branch 'Nereziel:main' into main 2024-02-25 13:19:55 +01:00
Dawid Bepierszcz
34b086a140 1.9c
- Some changes
2024-02-25 12:55:44 +01:00
Dawid Bepierszcz
ad73e0a85d Merge pull request #171 from daffyyyy/main
Some fixes
2024-02-23 02:58:01 +01:00
Dawid Bepierszcz
25c205e53d Merge branch 'Nereziel:main' into main 2024-02-23 02:56:42 +01:00
Dawid Bepierszcz
1366e141a7 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-23 02:46:00 +01:00
Dawid Bepierszcz
5465b982b7 Some fixes 2024-02-23 02:45:58 +01:00
Dawid Bepierszcz
ead5ae23a3 Merge pull request #170 from daffyyyy/main
1.9b
2024-02-22 22:46:31 +01:00
Dawid Bepierszcz
ff2e7ffd6b Merge branch 'Nereziel:main' into main 2024-02-22 22:43:46 +01:00
Dawid Bepierszcz
c9a1fad496 1.9b 2024-02-22 22:43:25 +01:00
Dawid Bepierszcz
0d4d01800d Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-22 22:41:34 +01:00
Dawid Bepierszcz
19d004c21d 1.9b
- Fixed weapons on retake
- FIxed saving
2024-02-22 22:41:32 +01:00
Dawid Bepierszcz
391efd5cac Merge pull request #169 from daffyyyy/main
1.9a
2024-02-22 21:12:33 +01:00
Dawid Bepierszcz
3cf9a67ee2 Merge branch 'Nereziel:main' into main 2024-02-22 21:10:26 +01:00
Dawid Bepierszcz
ddb4fb7cba Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-22 21:09:00 +01:00
Dawid Bepierszcz
e75d48bd0d 1.9a
- Removed GlobalShare
- More stability
2024-02-22 21:07:52 +01:00
Dawid Bepierszcz
959123344f Merge pull request #165 from daffyyyy/main
1.8d
2024-02-21 12:06:08 +01:00
Dawid Bepierszcz
14b0b8153f Merge branch 'Nereziel:main' into main 2024-02-21 12:04:41 +01:00
Dawid Bepierszcz
fa48245b34 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-21 12:03:52 +01:00
Dawid Bepierszcz
5d5e0f2bd1 1.8d
- Small changes
- Fixed gloves command
2024-02-21 12:03:48 +01:00
Dawid Bepierszcz
726e67865c Merge pull request #163 from daffyyyy/main
1.8c
2024-02-20 12:54:31 +01:00
Dawid Bepierszcz
868e6c8746 Merge branch 'Nereziel:main' into main 2024-02-20 12:52:33 +01:00
Dawid Bepierszcz
a1285bef26 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-20 12:51:15 +01:00
Dawid Bepierszcz
b1920f312c 1.8c
- Better gloves operations
- Changed gloves table
2024-02-20 12:51:14 +01:00
Dawid Bepierszcz
5e9850bece Merge pull request #162 from daffyyyy/main
1.8b
2024-02-20 01:57:01 +01:00
Dawid Bepierszcz
e1802fd0f0 Merge branch 'Nereziel:main' into main 2024-02-20 01:55:45 +01:00
Dawid Bepierszcz
267de3c4de 1.8b
- Fixed gloves changing?
2024-02-20 01:54:54 +01:00
Dawid Bepierszcz
9f24fbf3ef test 2024-02-20 01:51:25 +01:00
Dawid Bepierszcz
9c23545173 test 2024-02-20 01:48:41 +01:00
Dawid Bepierszcz
40d1088ee6 test 2024-02-20 01:46:41 +01:00
Dawid Bepierszcz
e7f546ed58 test 2024-02-20 01:43:27 +01:00
Dawid Bepierszcz
beab940ebb test 2024-02-20 01:38:22 +01:00
Dawid Bepierszcz
7dc78e7706 test 2024-02-20 01:30:09 +01:00
Dawid Bepierszcz
02208095f0 test 2024-02-20 01:28:25 +01:00
Dawid Bepierszcz
63f4b4c43d Merge pull request #161 from daffyyyy/main
1.8a
2024-02-19 14:02:02 +01:00
Dawid Bepierszcz
a6821b85b4 Merge branch 'Nereziel:main' into main 2024-02-19 14:00:14 +01:00
Dawid Bepierszcz
a37f4e9e58 1.8a
- Gloves?

Currently only in plugin, website update soon
2024-02-19 13:59:26 +01:00
Dawid Bepierszcz
fb4340cc1d Merge pull request #157 from daffyyyy/main
1.7a
2024-02-16 15:58:14 +01:00
Dawid Bepierszcz
bbbf27a751 Merge branch 'Nereziel:main' into main 2024-02-16 14:05:29 +01:00
Dawid Bepierszcz
c9d8bb9b5f 1.7a
- Fixed hotreloading
- Minor changes
2024-02-16 14:04:36 +01:00
Dawid Bepierszcz
1109c0cf56 Merge pull request #148 from daffyyyy/main
1.6c
2024-02-11 04:00:07 +01:00
Dawid Bepierszcz
63869f4c94 Merge branch 'Nereziel:main' into main 2024-02-11 03:58:49 +01:00
Dawid Bepierszcz
fa284678e8 1.6c
- Fix for invalid players
2024-02-11 03:58:32 +01:00
Dawid Bepierszcz
558f3178f2 Update WeaponAction.cs 2024-02-10 15:34:34 +01:00
Dawid Bepierszcz
c5f9cc6429 Merge pull request #145 from daffyyyy/main
1.6b
2024-02-10 13:00:48 +01:00
Dawid Bepierszcz
4087d3d016 Merge branch 'Nereziel:main' into main 2024-02-10 13:00:04 +01:00
Dawid Bepierszcz
e7919bb468 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-10 12:59:45 +01:00
Dawid Bepierszcz
33bd83d0a1 1.6b
- Closing menu
2024-02-10 12:59:41 +01:00
Dawid Bepierszcz
73d989c0ce Merge pull request #144 from daffyyyy/main
1.6b
2024-02-10 12:25:38 +01:00
Dawid Bepierszcz
f1cecfc73e Merge branch 'Nereziel:main' into main 2024-02-10 12:24:35 +01:00
Dawid Bepierszcz
aae6f7e260 1.6b
- Minor changes
- Fixed tables creation
2024-02-10 12:23:56 +01:00
Dawid Bepierszcz
171d520cc0 Merge pull request #136 from daffyyyy/main
1.6a
2024-02-08 19:37:40 +01:00
Dawid Bepierszcz
deac9bab97 Merge branch 'Nereziel:main' into main 2024-02-08 19:35:57 +01:00
Dawid Bepierszcz
8a76530302 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-08 19:35:40 +01:00
Dawid Bepierszcz
d1cbecaecb 1.6a
- Major changes
- Better sql stuff
- Temp fix for crashes on skins reload
2024-02-08 19:35:29 +01:00
Dawid Bepierszcz
ebc932e47c Merge pull request #135 from daffyyyy/main
Updated min. css version
2024-02-08 10:53:34 +01:00
Dawid Bepierszcz
e258ed8c92 Merge branch 'Nereziel:main' into main 2024-02-08 10:53:08 +01:00
Dawid Bepierszcz
e44af369bb Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-08 10:52:32 +01:00
Dawid Bepierszcz
47055ad6f7 Updated min. css version 2024-02-08 10:52:22 +01:00
Dawid Bepierszcz
d9166253b3 Merge pull request #134 from daffyyyy/main
1.5a
2024-02-08 10:51:44 +01:00
Dawid Bepierszcz
4e90506645 Merge branch 'Nereziel:main' into main 2024-02-08 10:50:08 +01:00
Dawid Bepierszcz
bd93936fab 1.5a
- Minor changes
- New skins
2024-02-08 10:49:53 +01:00
Dawid Bepierszcz
63403dfc8e new skins
New skins
2024-02-07 22:08:26 +01:00
Nereziel
b24a2bd04e Update README.md 2024-02-03 20:27:29 +01:00
Dawid Bepierszcz
dbc652a68c Merge pull request #129 from daffyyyy/main
1.4c
2024-02-03 17:26:12 +01:00
Dawid Bepierszcz
a59ce8f1a5 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-03 17:24:46 +01:00
Dawid Bepierszcz
baaa47d837 1.4c 2024-02-03 17:24:26 +01:00
Dawid Bepierszcz
7dcfea3e17 Merge branch 'Nereziel:main' into main 2024-02-03 17:23:44 +01:00
Dawid Bepierszcz
4eab8f0a87 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-03 17:23:16 +01:00
Dawid Bepierszcz
236c79c4b9 1.4c
- Minor changes
- Better loading skins
2024-02-03 17:23:12 +01:00
Nereziel
83084452df Update README.md 2024-02-03 16:51:13 +01:00
Nereziel
43e7a3183e Update README.md
Before using website, make sure the plugin is correctly loaded in cs2 server!
2024-01-29 19:36:30 +01:00
Dawid Bepierszcz
60c592aa54 Merge pull request #121 from daffyyyy/main
1.4b
2024-01-26 17:54:35 +01:00
Dawid Bepierszcz
2568f263d9 Merge branch 'Nereziel:main' into main 2024-01-26 17:53:45 +01:00
Dawid Bepierszcz
14e285d44f 1.4b
- Probably fixed empty skin
2024-01-26 17:53:11 +01:00
Nereziel
97b8840ac4 Update README.md 2024-01-22 15:07:18 +01:00
Nereziel
f820c7d251 Merge pull request #115 from daffyyyy/main
1.4a
Updated css version
Probably not needed SkinVisibilityFix anymore
2024-01-20 20:20:44 +01:00
Dawid Bepierszcz
6e5d595c0f Merge branch 'Nereziel:main' into main 2024-01-20 18:05:40 +01:00
Dawid Bepierszcz
71d57eb3ad Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-01-20 18:04:52 +01:00
Dawid Bepierszcz
620b067991 1.4a
- Probably not needed `SkinsVisibilityFix` anymore
2024-01-20 18:04:50 +01:00
Nereziel
89c425c170 Merge pull request #112 from daffyyyy/main
1.3i, update css, minor changes
2024-01-18 09:55:55 +01:00
Dawid Bepierszcz
c744f2898b Merge branch 'Nereziel:main' into main 2024-01-18 01:36:39 +01:00
Dawid Bepierszcz
d04bc0879a 1.3i
- Updated css
- Minor changes
2024-01-18 01:36:05 +01:00
Nereziel
4417b093dd Update README.md 2024-01-06 17:41:32 +01:00
Nereziel
3f8533ab94 Merge pull request #107 from daffyyyy/main
1.3h
2023-12-25 20:07:56 +01:00
Dawid Bepierszcz
55905ccc33 Update WeaponPaints.cs 2023-12-25 15:47:40 +01:00
Dawid Bepierszcz
24fcfa0222 1.3h
- Changed knife remove method
- Fixed (?) exception with cooldown
2023-12-25 15:45:32 +01:00
Nereziel
cd059c6bfb Merge pull request #104 from daffyyyy/main
Small website optimization
2023-12-18 12:50:52 +01:00
daffyyyy
e338bebaec Small website optimization 2023-12-18 01:51:24 +01:00
Dawid Bepierszcz
efd7f5dbef Merge branch 'Nereziel:main' into main 2023-12-18 00:55:56 +01:00
Nereziel
6bd002cdec Merge pull request #102 from panikajo/main
add Ukraine Language
2023-12-17 12:16:12 +01:00
panikajo
3a1adf8d4a add Ukraine Language
added Ukrainian translation
2023-12-17 13:05:50 +02:00
Nereziel
7c3fa6469b Merge pull request #99 from himenekocn/main
Add zh-cn.json
2023-12-15 20:13:36 +01:00
LynchMus
52962518fe Create zh-cn.json 2023-12-14 12:13:31 +08:00
Nereziel
7e12b89a9e fix logout 2023-12-13 20:02:01 +01:00
Nereziel
ae56b18a3c Merge pull request #97 from daffyyyy/some-changes
Fix for F
2023-12-13 19:52:59 +01:00
daffyyyy
c907911cd1 Fix for F 2023-12-13 19:49:47 +01:00
Nereziel
1aa486cd7d Merge branch 'main' of https://github.com/Nereziel/cs2-WeaponPaints 2023-12-13 19:42:43 +01:00
Nereziel
5e62c7c597 Update preview.png 2023-12-13 19:36:37 +01:00
Nereziel
819ac6233c Update README.md 2023-12-13 19:31:47 +01:00
Nereziel
ed24eb0dfc add config for darkmode
lazy to make toggle for player
2023-12-13 19:25:13 +01:00
Nereziel
1a9f7ad108 Merge pull request #91 from exababy/patch-1
Wear & Seed Support
2023-12-13 19:22:20 +01:00
Nereziel
6f1a29bb39 Merge pull request #96 from snowhp/main
pt-PT and pt-BR translations added
2023-12-13 08:28:33 +01:00
Nereziel
9e64cdcd43 Merge pull request #95 from exababy/patch-2
turkish language
2023-12-13 08:27:23 +01:00
Nereziel
da86756092 Merge pull request #94 from rcon420/patch-2
latvian lang added
2023-12-13 08:26:35 +01:00
Tiago Machado
22880070cd Merge pull request #1 from crashzk/patch-1
Update pt-BR.json
2023-12-12 23:02:44 +00:00
crashzk
208cbe1aef Update pt-BR.json 2023-12-12 19:53:34 -03:00
Tiago Machado
c0cf9210dc Create pt-BR.json 2023-12-12 22:00:51 +00:00
Tiago Machado
5f61254b4e Create pt-PT.json 2023-12-12 22:00:18 +00:00
Nilsu Derinder
6cd1bb3bf5 fix 2 2023-12-12 23:46:11 +03:00
Nilsu Derinder
4f94b831c2 fix 2023-12-12 23:40:53 +03:00
Nilsu Derinder
969d40b970 Button Update
the button will not work if the skin is not selected which fixes possible bugs in the plugin.
2023-12-12 23:33:05 +03:00
Nilsu Derinder
0cd36a7877 turkish language 2023-12-12 23:21:33 +03:00
rcon_password
a3306b5f8f latvian lang added
latvian lang added
2023-12-12 22:13:05 +02:00
Nereziel
379c2f797c Merge pull request #93 from daffyyyy/some-changes
CSS 121, languages and more
2023-12-12 20:55:21 +01:00
Nilsu Derinder
7f41607d54 Update & Fix
now selected wear appears 
and pulls the value from the database.
2023-12-12 22:44:08 +03:00
daffyyyy
fc42190701 CSS 121, languages and more 2023-12-12 20:09:39 +01:00
Nilsu Derinder
928c1e1466 bootstrap update 2023-12-11 18:46:34 +03:00
Nilsu Derinder
78649f5dcf Update
wear has been updated and settings have been moved into modal and added settings button
2023-12-11 11:32:40 +03:00
Nilsu Derinder
4e72f10326 Seed Update
seed was converted to box instead of range and only numbers can be entered.
2023-12-08 17:56:28 +03:00
Nilsu Derinder
3ddbf7e11e Advanced wear 2023-12-06 22:25:19 +03:00
Nilsu Derinder
ee770fd8c2 Seed support 2023-12-06 22:03:52 +03:00
Nilsu Derinder
72c5df53b5 fix 2023-12-06 20:50:39 +03:00
Nilsu Derinder
d0ed0f4c0b Wear Support 2023-12-06 19:42:18 +03:00
Nereziel
643beaad46 Merge pull request #90 from daffyyyy/some-changes
!skins thread-safe and checking version
2023-12-06 17:18:06 +01:00
daffyyyy
6d44e582be !skins thread-safe and checking version 2023-12-06 14:47:26 +01:00
Nereziel
813a9abcc8 Merge pull request #89 from daffyyyy/some-changes
Small fixes cssharp >= 101
2023-12-05 19:32:00 +01:00
daffyyyy
b0790729be Small fixes 2023-12-05 19:30:10 +01:00
Nereziel
74a6dff114 Merge pull request #88 from daffyyyy/some-changes
Update for cssharp 101
2023-12-04 21:03:07 +01:00
daffyyyy
e37f111f1b Update WeaponPaints.csproj 2023-12-04 21:01:36 +01:00
daffyyyy
5e6286b667 Update for cssharp 101 2023-12-04 21:00:24 +01:00
Dawid Bepierszcz
a8cf33d404 Merge branch 'Nereziel:main' into main 2023-11-25 22:39:40 +01:00
Dawid Bepierszcz
1c026c018e Merge branch 'Nereziel:main' into main 2023-11-22 23:16:15 +01:00
Dawid Bepierszcz
4a410fd0d8 Update build.yml 2023-11-21 22:19:25 +01:00
Dawid Bepierszcz
bb08e88371 Update build.yml 2023-11-21 22:14:51 +01:00
3724 changed files with 2712 additions and 1160 deletions

14
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: nereziel # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
custom: ['https://steamcommunity.com/tradeoffer/new/?partner=41515647&token=gW2W-nXE'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -58,14 +58,10 @@ jobs:
${{ env.OUTPUT_PATH }}/McMaster.NETCore.Plugins.dll \
${{ env.OUTPUT_PATH }}/Microsoft.DotNet.PlatformAbstractions.dll \
${{ env.OUTPUT_PATH }}/Microsoft.Extensions.DependencyModel.dll \
- name: Copy skins.json
run: cp website/data/skins.json ${{ env.OUTPUT_PATH }}/skins.json
- name: Copy skins
run: cp -R website/data ${{ env.OUTPUT_PATH }}
- name: Zip
uses: thedoctor0/zip-release@0.7.5
with:
type: 'zip'
filename: '${{ env.PROJECT_NAME }}.zip'
path: ${{ env.OUTPUT_PATH }}
run: zip -r "${{ env.PROJECT_NAME }}.zip" "${{ env.OUTPUT_PATH }}" gamedata/
- name: Clean files Website
run: |
rm -rf website/img/

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.vs/
bin/
obj/
website/getskins.php
.idea/

BIN
3rd_party/MenuManagerApi.dll vendored Normal file

Binary file not shown.

View File

@@ -1,6 +1,7 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Menu;
using Newtonsoft.Json.Linq;
namespace WeaponPaints
{
@@ -8,35 +9,48 @@ namespace WeaponPaints
{
private void OnCommandRefresh(CCSPlayerController? player, CommandInfo command)
{
if (!Config.Additional.CommandWpEnabled || !Config.Additional.SkinEnabled || !g_bCommandsAllowed) return;
if (!Config.Additional.CommandWpEnabled || !Config.Additional.SkinEnabled || !_gBCommandsAllowed) return;
if (!Utility.IsPlayerValid(player)) return;
string temp = "";
if (player == null || player.Index <= 0) return;
int playerIndex = (int)player!.Index;
if (playerIndex != 0 && DateTime.UtcNow >= commandCooldown[playerIndex].AddSeconds(Config.CmdRefreshCooldownSeconds))
{
commandCooldown[playerIndex] = DateTime.UtcNow;
if (weaponSync != null)
Task.Run(async () => await weaponSync.GetWeaponPaintsFromDatabase(playerIndex));
if (Config.Additional.KnifeEnabled)
{
if (weaponSync != null)
Task.Run(async () => await weaponSync.GetKnifeFromDatabase(playerIndex));
RefreshWeapons(player);
}
if (!string.IsNullOrEmpty(Config.Messages.SuccessRefreshCommand))
{
temp = $" {Config.Prefix} {Config.Messages.SuccessRefreshCommand}";
player.PrintToChat(Utility.ReplaceTags(temp));
}
return;
}
if (!string.IsNullOrEmpty(Config.Messages.CooldownRefreshCommand))
if (player == null || !player.IsValid || player.UserId == null || player.IsBot) return;
PlayerInfo? playerInfo = new PlayerInfo
{
temp = $" {Config.Prefix} {Config.Messages.CooldownRefreshCommand}";
player.PrintToChat(Utility.ReplaceTags(temp));
UserId = player.UserId,
Slot = player.Slot,
Index = (int)player.Index,
SteamId = player?.SteamID.ToString(),
Name = player?.PlayerName,
IpAddress = player?.IpAddress?.Split(":")[0]
};
try
{
if (player != null && !CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
player != null && DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{
CommandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
if (WeaponSync != null)
{
_ = Task.Run(async () => await WeaponSync.GetPlayerData(playerInfo));
GivePlayerGloves(player);
RefreshWeapons(player);
}
if (!string.IsNullOrEmpty(Localizer["wp_command_refresh_done"]))
{
player.Print(Localizer["wp_command_refresh_done"]);
}
return;
}
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{
player!.Print(Localizer["wp_command_cooldown"]);
}
}
catch (Exception) { }
}
private void OnCommandWS(CCSPlayerController? player, CommandInfo command)
@@ -44,232 +58,639 @@ namespace WeaponPaints
if (!Config.Additional.SkinEnabled) return;
if (!Utility.IsPlayerValid(player)) return;
string temp;
if (!string.IsNullOrEmpty(Config.Messages.WebsiteMessageCommand))
if (!string.IsNullOrEmpty(Localizer["wp_info_website"]))
{
temp = $" {Config.Prefix} {Config.Messages.WebsiteMessageCommand}";
player!.PrintToChat(Utility.ReplaceTags(temp));
player!.Print(Localizer["wp_info_website", Config.Website]);
}
if (!string.IsNullOrEmpty(Config.Messages.SynchronizeMessageCommand))
if (!string.IsNullOrEmpty(Localizer["wp_info_refresh"]))
{
temp = $" {Config.Prefix} {Config.Messages.SynchronizeMessageCommand}";
player!.PrintToChat(Utility.ReplaceTags(temp));
player!.Print(Localizer["wp_info_refresh"]);
}
if (Config.Additional.GloveEnabled)
if (!string.IsNullOrEmpty(Localizer["wp_info_glove"]))
{
player!.Print(Localizer["wp_info_glove"]);
}
if (Config.Additional.AgentEnabled)
if (!string.IsNullOrEmpty(Localizer["wp_info_agent"]))
{
player!.Print(Localizer["wp_info_agent"]);
}
if (Config.Additional.MusicEnabled)
if (!string.IsNullOrEmpty(Localizer["wp_info_music"]))
{
player!.Print(Localizer["wp_info_music"]);
}
if (!Config.Additional.KnifeEnabled) return;
if (!string.IsNullOrEmpty(Config.Messages.KnifeMessageCommand))
if (!string.IsNullOrEmpty(Localizer["wp_info_knife"]))
{
temp = $" {Config.Prefix} {Config.Messages.KnifeMessageCommand}";
player!.PrintToChat(Utility.ReplaceTags(temp));
player!.Print(Localizer["wp_info_knife"]);
}
}
private void RegisterCommands()
{
AddCommand($"css_{Config.Additional.CommandSkin}", "Skins info", (player, info) =>
_config.Additional.CommandSkin.ForEach(c =>
{
if (!Utility.IsPlayerValid(player)) return;
OnCommandWS(player, info);
AddCommand($"css_{c}", "Skins info", (player, info) =>
{
if (!Utility.IsPlayerValid(player)) return;
OnCommandWS(player, info);
});
});
AddCommand($"css_{Config.Additional.CommandRefresh}", "Skins refresh", (player, info) =>
_config.Additional.CommandRefresh.ForEach(c =>
{
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
OnCommandRefresh(player, info);
AddCommand($"css_{c}", "Skins refresh", (player, info) =>
{
if (!Utility.IsPlayerValid(player)) return;
OnCommandRefresh(player, info);
});
});
if (Config.Additional.CommandKillEnabled)
{
AddCommand($"css_{Config.Additional.CommandKill}", "kill yourself", (player, info) =>
_config.Additional.CommandKill.ForEach(c =>
{
if (player == null || !Utility.IsPlayerValid(player) || player.PlayerPawn.Value == null || !player!.PlayerPawn.IsValid) return;
AddCommand($"css_{c}", "kill yourself", (player, _) =>
{
if (player == null || !Utility.IsPlayerValid(player) || player.PlayerPawn.Value == null || !player.PlayerPawn.IsValid) return;
player.PlayerPawn.Value.CommitSuicide(true, false);
player.PlayerPawn.Value.CommitSuicide(true, false);
});
});
}
}
private void SetupKnifeMenu()
{
if (!Config.Additional.KnifeEnabled || !g_bCommandsAllowed) return;
if (!Config.Additional.KnifeEnabled || !_gBCommandsAllowed) return;
var knivesOnly = weaponList
var knivesOnly = WeaponList
.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet"))
.ToDictionary(pair => pair.Key, pair => pair.Value);
var giveItemMenu = new ChatMenu(Utility.ReplaceTags($" {Config.Messages.KnifeMenuTitle}"));
var handleGive = (CCSPlayerController? player, ChatMenuOption option) =>
var giveItemMenu = MenuApi?.NewMenu(Localizer["wp_knife_menu_title"]);
var handleGive = (CCSPlayerController player, ChatMenuOption option) =>
{
if (Utility.IsPlayerValid(player))
if (!Utility.IsPlayerValid(player)) return;
var knifeName = option.Text;
var knifeKey = knivesOnly.FirstOrDefault(x => x.Value == knifeName).Key;
if (string.IsNullOrEmpty(knifeKey)) return;
if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_select"]))
{
var knifeName = option.Text;
var knifeKey = knivesOnly.FirstOrDefault(x => x.Value == knifeName).Key;
if (!string.IsNullOrEmpty(knifeKey))
{
string temp = "";
if (!string.IsNullOrEmpty(Config.Messages.ChosenKnifeMenu))
{
temp = $" {Config.Prefix} {Config.Messages.ChosenKnifeMenu}".Replace("{KNIFE}", knifeName);
player!.PrintToChat(Utility.ReplaceTags(temp));
}
if (!string.IsNullOrEmpty(Config.Messages.ChosenKnifeMenuKill) && Config.Additional.CommandKillEnabled)
{
temp = $" {Config.Prefix} {Config.Messages.ChosenKnifeMenuKill}";
player!.PrintToChat(Utility.ReplaceTags(temp));
}
g_playersKnife[(int)player!.Index] = knifeKey;
if (player!.PawnIsAlive && g_bCommandsAllowed)
{
RefreshWeapons(player);
}
if (weaponSync != null)
Task.Run(() => weaponSync.SyncKnifeToDatabase((int)player.Index, knifeKey));
}
player.Print(Localizer["wp_knife_menu_select", knifeName]);
}
if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_kill"]) && Config.Additional.CommandKillEnabled)
{
player.Print(Localizer["wp_knife_menu_kill"]);
}
PlayerInfo playerInfo = new PlayerInfo
{
UserId = player.UserId,
Slot = player.Slot,
Index = (int)player.Index,
SteamId = player.SteamID.ToString(),
Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0]
};
GPlayersKnife[player.Slot] = knifeKey;
if (_gBCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE)
RefreshWeapons(player);
if (WeaponSync != null)
_ = Task.Run(async () => await WeaponSync.SyncKnifeToDatabase(playerInfo, knifeKey));
};
foreach (var knifePair in knivesOnly)
{
giveItemMenu.AddMenuOption(knifePair.Value, handleGive);
giveItemMenu?.AddMenuOption(knifePair.Value, handleGive);
}
AddCommand($"css_{Config.Additional.CommandKnife}", "Knife Menu", (player, info) =>
_config.Additional.CommandKnife.ForEach(c =>
{
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
int playerIndex = (int)player!.Index;
AddCommand($"css_{c}", "Knife Menu", (player, _) =>
{
if (giveItemMenu == null) return;
if (!Utility.IsPlayerValid(player) || !_gBCommandsAllowed) return;
if (commandCooldown != null && DateTime.UtcNow >= commandCooldown[playerIndex].AddSeconds(Config.CmdRefreshCooldownSeconds))
{
commandCooldown[playerIndex] = DateTime.UtcNow;
ChatMenus.OpenMenu(player, giveItemMenu);
return;
}
if (!string.IsNullOrEmpty(Config.Messages.CooldownRefreshCommand))
{
string temp = $" {Config.Prefix} {Config.Messages.CooldownRefreshCommand}";
player.PrintToChat(Utility.ReplaceTags(temp));
}
if (player == null || player.UserId == null) return;
if (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{
CommandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
giveItemMenu.PostSelectAction = PostSelectAction.Close;
giveItemMenu.Open(player);
return;
}
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{
player.Print(Localizer["wp_command_cooldown"]);
}
});
});
}
private void SetupSkinsMenu()
{
var classNamesByWeapon = weaponList.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
var weaponSelectionMenu = new ChatMenu(Utility.ReplaceTags($" {Config.Messages.WeaponMenuTitle}"));
// var classNamesByWeapon = WeaponList.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
var classNamesByWeapon = WeaponList
.Except([new KeyValuePair<string, string>("weapon_knife", "Default Knife")])
.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
var weaponSelectionMenu = MenuApi?.NewMenu(Localizer["wp_skin_menu_weapon_title"]);
// Function to handle skin selection for a specific weapon
var handleWeaponSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{
if (!Utility.IsPlayerValid(player)) return;
int playerIndex = (int)player!.Index;
string selectedWeapon = option.Text;
if (classNamesByWeapon.TryGetValue(selectedWeapon, out string? selectedWeaponClassname))
{
if (selectedWeaponClassname == null) return;
var skinsForSelectedWeapon = skinsList?.Where(skin =>
skin != null &&
var selectedWeapon = option.Text;
if (!classNamesByWeapon.TryGetValue(selectedWeapon, out var selectedWeaponClassname)) return;
var skinsForSelectedWeapon = SkinsList?.Where(skin =>
skin.TryGetValue("weapon_name", out var weaponName) &&
weaponName?.ToString() == selectedWeaponClassname
)?.ToList();
var skinSubMenu = new ChatMenu(Utility.ReplaceTags($" {Config.Messages.SkinMenuTitle}").Replace("{WEAPON}", selectedWeapon));
var skinSubMenu = MenuApi?.NewMenu(Localizer["wp_skin_menu_skin_title", selectedWeapon]);
// Function to handle skin selection for the chosen weapon
var handleSkinSelection = (CCSPlayerController? p, ChatMenuOption opt) =>
// Function to handle skin selection for the chosen weapon
var handleSkinSelection = (CCSPlayerController p, ChatMenuOption opt) =>
{
if (!Utility.IsPlayerValid(p)) return;
var steamId = p.SteamID.ToString();
var firstSkin = SkinsList?.FirstOrDefault(skin =>
{
if (p == null || !p.IsValid || p.Index <= 0) return;
playerIndex = (int)p.Index;
if (p.AuthorizedSteamID == null) return;
string steamId = p.AuthorizedSteamID.SteamId64.ToString();
var firstSkin = skinsList?.FirstOrDefault(skin =>
if (skin.TryGetValue("weapon_name", out var weaponName))
{
if (skin != null && skin.TryGetValue("weapon_name", out var weaponName))
{
return weaponName?.ToString() == selectedWeaponClassname;
}
return false;
});
string selectedSkin = opt.Text;
string selectedPaintID = selectedSkin.Split('(')[1].Trim(')').Trim();
if (firstSkin != null &&
firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) &&
weaponDefIndexObj != null &&
int.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) &&
int.TryParse(selectedPaintID, out var paintID))
{
string temp = $" {Config.Prefix} {Config.Messages.ChosenSkinMenu}".Replace("{SKIN}", selectedSkin);
p.PrintToChat(Utility.ReplaceTags(temp));
if (!gPlayerWeaponsInfo[playerIndex].ContainsKey(weaponDefIndex))
{
gPlayerWeaponsInfo[playerIndex][weaponDefIndex] = new WeaponInfo();
}
gPlayerWeaponsInfo[playerIndex][weaponDefIndex].Paint = paintID;
gPlayerWeaponsInfo[playerIndex][weaponDefIndex].Wear = 0.0f;
gPlayerWeaponsInfo[playerIndex][weaponDefIndex].Seed = 0;
if (!Config.GlobalShare)
{
if (weaponSync == null) return;
Task.Run(async () =>
{
await weaponSync.SyncWeaponPaintsToDatabase(p);
});
}
return weaponName?.ToString() == selectedWeaponClassname;
}
};
return false;
});
// Add skin options to the submenu for the selected weapon
if (skinsForSelectedWeapon != null)
var selectedSkin = opt.Text;
var selectedPaintId = selectedSkin[(selectedSkin.LastIndexOf('(') + 1)..].Trim(')');
if (firstSkin == null ||
!firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) ||
!int.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) ||
!int.TryParse(selectedPaintId, out var paintId)) return;
{
foreach (var skin in skinsForSelectedWeapon.Where(s => s != null))
if (Config.Additional.ShowSkinImage && SkinsList != null)
{
if (skin.TryGetValue("paint_name", out var paintNameObj) && skin.TryGetValue("paint", out var paintObj))
{
var paintName = paintNameObj?.ToString();
var paint = paintObj?.ToString();
var foundSkin = SkinsList.FirstOrDefault(skin =>
((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex &&
((int?)skin?["paint"] ?? 0) == paintId &&
skin?["image"] != null
);
var image = foundSkin?["image"]?.ToString() ?? "";
_playerWeaponImage[p.Slot] = image;
AddTimer(2.0f, () => _playerWeaponImage.Remove(p.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
}
if (!string.IsNullOrEmpty(paintName) && !string.IsNullOrEmpty(paint))
{
skinSubMenu.AddMenuOption($"{paintName} ({paint})", handleSkinSelection);
}
}
p.Print(Localizer["wp_skin_menu_select", selectedSkin]);
if (!GPlayerWeaponsInfo[p.Slot].TryGetValue(weaponDefIndex, out var value))
{
value = new WeaponInfo();
GPlayerWeaponsInfo[p.Slot][weaponDefIndex] = value;
}
value.Paint = paintId;
value.Wear = 0.01f;
value.Seed = 0;
PlayerInfo playerInfo = new PlayerInfo
{
UserId = p.UserId,
Slot = p.Slot,
Index = (int)p.Index,
SteamId = p.SteamID.ToString(),
Name = p.PlayerName,
IpAddress = p.IpAddress?.Split(":")[0]
};
if (!_gBCommandsAllowed || (LifeState_t)p.LifeState != LifeState_t.LIFE_ALIVE ||
WeaponSync == null) return;
RefreshWeapons(player);
try
{
_ = Task.Run(async () => await WeaponSync.SyncWeaponPaintsToDatabase(playerInfo));
}
catch (Exception ex)
{
Utility.Log($"Error syncing weapon paints: {ex.Message}");
}
}
};
// Open the submenu for skin selection of the chosen weapon
ChatMenus.OpenMenu(player, skinSubMenu);
// Add skin options to the submenu for the selected weapon
if (skinsForSelectedWeapon != null)
{
foreach (var skin in skinsForSelectedWeapon)
{
if (!skin.TryGetValue("paint_name", out var paintNameObj) ||
!skin.TryGetValue("paint", out var paintObj)) continue;
var paintName = paintNameObj?.ToString();
var paint = paintObj?.ToString();
if (!string.IsNullOrEmpty(paintName) && !string.IsNullOrEmpty(paint))
{
skinSubMenu?.AddMenuOption($"{paintName} ({paint})", handleSkinSelection);
}
}
}
if (player != null && Utility.IsPlayerValid(player))
skinSubMenu?.Open(player);
};
// Add weapon options to the weapon selection menu
foreach (var weaponName in WeaponList
.Where(kvp => kvp.Key != "weapon_knife")
.Select(kvp => kvp.Value))
{
weaponSelectionMenu?.AddMenuOption(weaponName, handleWeaponSelection);
}
// Command to open the weapon selection menu for players
_config.Additional.CommandSkinSelection.ForEach(c =>
{
AddCommand($"css_{c}", "Skins selection menu", (player, _) =>
{
if (!Utility.IsPlayerValid(player)) return;
if (player == null || player.UserId == null) return;
if (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{
CommandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
weaponSelectionMenu?.Open(player);
return;
}
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{
player.Print(Localizer["wp_command_cooldown"]);
}
});
});
}
private void SetupGlovesMenu()
{
var glovesSelectionMenu = MenuApi?.NewMenu(Localizer["wp_glove_menu_title"]);
if (glovesSelectionMenu == null) return;
glovesSelectionMenu.PostSelectAction = PostSelectAction.Close;
var handleGloveSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{
if (!Utility.IsPlayerValid(player) || player is null) return;
var selectedPaintName = option.Text;
var selectedGlove = GlovesList.FirstOrDefault(g => g.ContainsKey("paint_name") && g["paint_name"]?.ToString() == selectedPaintName);
var image = selectedGlove?["image"]?.ToString() ?? "";
if (selectedGlove == null ||
!selectedGlove.ContainsKey("weapon_defindex") ||
!selectedGlove.ContainsKey("paint") ||
!int.TryParse(selectedGlove["weapon_defindex"]?.ToString(), out var weaponDefindex) ||
!int.TryParse(selectedGlove["paint"]?.ToString(), out var paint)) return;
if (Config.Additional.ShowSkinImage)
{
_playerWeaponImage[player.Slot] = image;
AddTimer(2.0f, () => _playerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
}
PlayerInfo playerInfo = new PlayerInfo
{
UserId = player.UserId,
Slot = player.Slot,
Index = (int)player.Index,
SteamId = player.SteamID.ToString(),
Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0]
};
if (paint != 0)
{
GPlayersGlove[player.Slot] = (ushort)weaponDefindex;
if (!GPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefindex))
{
WeaponInfo weaponInfo = new()
{
Paint = paint
};
GPlayerWeaponsInfo[player.Slot][weaponDefindex] = weaponInfo;
}
}
else
{
GPlayersGlove.TryRemove(player.Slot, out _);
}
if (!string.IsNullOrEmpty(Localizer["wp_glove_menu_select"]))
{
player.Print(Localizer["wp_glove_menu_select", selectedPaintName]);
}
if (WeaponSync == null) return;
_ = Task.Run(async () =>
{
await WeaponSync.SyncGloveToDatabase(playerInfo, weaponDefindex);
if (!GPlayerWeaponsInfo[playerInfo.Slot].TryGetValue(weaponDefindex, out var value))
{
value = new WeaponInfo();
GPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex] = value;
}
value.Paint = paint;
value.Wear = 0.00f;
value.Seed = 0;
await WeaponSync.SyncWeaponPaintsToDatabase(playerInfo);
});
AddTimer(0.1f, () => GivePlayerGloves(player));
AddTimer(0.25f, () => GivePlayerGloves(player));
};
// Add weapon options to the weapon selection menu
foreach (var weaponClass in weaponList.Keys)
foreach (var paintName in GlovesList.Select(gloveObject => gloveObject["paint_name"]?.ToString() ?? "").Where(paintName => paintName.Length > 0))
{
string weaponName = weaponList[weaponClass];
weaponSelectionMenu.AddMenuOption(weaponName, handleWeaponSelection);
glovesSelectionMenu.AddMenuOption(paintName, handleGloveSelection);
}
// Command to open the weapon selection menu for players
AddCommand($"css_{Config.Additional.CommandSkinSelection}", "Skins selection menu", (player, info) =>
{
if (!Utility.IsPlayerValid(player)) return;
int playerIndex = (int)player!.Index;
if (commandCooldown != null && DateTime.UtcNow >= commandCooldown[playerIndex].AddSeconds(Config.CmdRefreshCooldownSeconds) && playerIndex > 0 && playerIndex < commandCooldown.Length)
// Command to open the weapon selection menu for players
_config.Additional.CommandGlove.ForEach(c =>
{
AddCommand($"css_{c}", "Gloves selection menu", (player, info) =>
{
commandCooldown[playerIndex] = DateTime.UtcNow;
ChatMenus.OpenMenu(player, weaponSelectionMenu);
return;
}
if (!string.IsNullOrEmpty(Config.Messages.CooldownRefreshCommand))
if (!Utility.IsPlayerValid(player) || !_gBCommandsAllowed) return;
if (player == null || player.UserId == null) return;
if (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{
CommandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
glovesSelectionMenu?.Open(player);
return;
}
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{
player.Print(Localizer["wp_command_cooldown"]);
}
});
});
}
private void SetupAgentsMenu()
{
var handleAgentSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{
if (!Utility.IsPlayerValid(player) || player is null) return;
var selectedPaintName = option.Text;
var selectedAgent = AgentsList.FirstOrDefault(g =>
g.ContainsKey("agent_name") &&
g["agent_name"] != null && g["agent_name"]!.ToString() == selectedPaintName &&
g["team"] != null && (int)(g["team"]!) == player.TeamNum);
if (selectedAgent == null) return;
if (
selectedAgent.ContainsKey("model")
)
{
string temp = $"{Config.Prefix} {Config.Messages.CooldownRefreshCommand}";
player.PrintToChat(Utility.ReplaceTags(temp));
PlayerInfo playerInfo = new PlayerInfo
{
UserId = player.UserId,
Slot = player.Slot,
Index = (int)player.Index,
SteamId = player.SteamID.ToString(),
Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0]
};
if (Config.Additional.ShowSkinImage)
{
var image = selectedAgent["image"]?.ToString() ?? "";
_playerWeaponImage[player.Slot] = image;
AddTimer(2.0f, () => _playerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
}
if (!string.IsNullOrEmpty(Localizer["wp_agent_menu_select"]))
{
player.Print(Localizer["wp_agent_menu_select", selectedPaintName]);
}
if (player.TeamNum == 3)
{
GPlayersAgent.AddOrUpdate(player.Slot,
key => (selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString(), null),
(key, oldValue) => (selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString(), oldValue.T));
}
else
{
GPlayersAgent.AddOrUpdate(player.Slot,
key => (null, selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString()),
(key, oldValue) => (oldValue.CT, selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString())
);
}
if (WeaponSync != null)
{
_ = Task.Run(async () =>
{
await WeaponSync.SyncAgentToDatabase(playerInfo);
});
}
};
};
// Command to open the weapon selection menu for players
_config.Additional.CommandAgent.ForEach(c =>
{
AddCommand($"css_{c}", "Agents selection menu", (player, info) =>
{
if (!Utility.IsPlayerValid(player) || !_gBCommandsAllowed) return;
if (player == null || player.UserId == null) return;
if (!CommandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{
var agentsSelectionMenu = MenuApi?.NewMenu(Localizer["wp_agent_menu_title"]);
if (agentsSelectionMenu == null) return;
agentsSelectionMenu.PostSelectAction = PostSelectAction.Close;
var filteredAgents = AgentsList.Where(agentObject =>
{
if (agentObject["team"]?.Value<int>() is { } teamNum)
{
return teamNum == player.TeamNum;
}
else
{
return false;
}
});
// Add weapon options to the weapon selection menu
foreach (var agentObject in filteredAgents)
{
var paintName = agentObject["agent_name"]?.ToString() ?? "";
if (paintName.Length > 0)
agentsSelectionMenu.AddMenuOption(paintName, handleAgentSelection);
}
CommandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
agentsSelectionMenu.Open(player);
return;
}
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{
player.Print(Localizer["wp_command_cooldown"]);
}
});
});
}
private void SetupMusicMenu()
{
var musicSelectionMenu = MenuApi?.NewMenu(Localizer["wp_music_menu_title"]);
if (musicSelectionMenu == null) return;
musicSelectionMenu.PostSelectAction = PostSelectAction.Close;
var handleMusicSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{
if (!Utility.IsPlayerValid(player) || player is null) return;
var selectedPaintName = option.Text;
var selectedMusic = MusicList.FirstOrDefault(g => g.ContainsKey("name") && g["name"]?.ToString() == selectedPaintName);
if (selectedMusic != null)
{
if (!selectedMusic.ContainsKey("id") ||
!selectedMusic.ContainsKey("name") ||
!int.TryParse(selectedMusic["id"]?.ToString(), out var paint)) return;
var image = selectedMusic["image"]?.ToString() ?? "";
if (Config.Additional.ShowSkinImage)
{
_playerWeaponImage[player.Slot] = image;
AddTimer(2.0f, () => _playerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
}
PlayerInfo playerInfo = new PlayerInfo
{
UserId = player.UserId,
Slot = player.Slot,
Index = (int)player.Index,
SteamId = player.SteamID.ToString(),
Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0]
};
if (paint != 0)
{
GPlayersMusic[player.Slot] = (ushort)paint;
}
else
{
GPlayersMusic[player.Slot] = 0;
}
if (!string.IsNullOrEmpty(Localizer["wp_music_menu_select"]))
{
player.Print(Localizer["wp_music_menu_select", selectedPaintName]);
}
if (WeaponSync != null)
{
_ = Task.Run(async () =>
{
await WeaponSync.SyncMusicToDatabase(playerInfo, (ushort)paint);
});
}
//RefreshGloves(player);
}
else
{
PlayerInfo playerInfo = new PlayerInfo
{
UserId = player.UserId,
Slot = player.Slot,
Index = (int)player.Index,
SteamId = player.SteamID.ToString(),
Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0]
};
GPlayersMusic[player.Slot] = 0;
if (!string.IsNullOrEmpty(Localizer["wp_music_menu_select"]))
{
player.Print(Localizer["wp_music_menu_select", Localizer["None"]]);
}
if (WeaponSync != null)
{
_ = Task.Run(async () =>
{
await WeaponSync.SyncMusicToDatabase(playerInfo, 0);
});
}
}
};
musicSelectionMenu.AddMenuOption(Localizer["None"], handleMusicSelection);
// Add weapon options to the weapon selection menu
foreach (var paintName in MusicList.Select(musicObject => musicObject["name"]?.ToString() ?? "").Where(paintName => paintName.Length > 0))
{
musicSelectionMenu.AddMenuOption(paintName, handleMusicSelection);
}
// Command to open the weapon selection menu for players
_config.Additional.CommandMusic.ForEach(c =>
{
AddCommand($"css_{c}", "Music selection menu", (player, info) =>
{
if (!Utility.IsPlayerValid(player) || !_gBCommandsAllowed) return;
if (player == null || player.UserId == null) return;
if (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{
CommandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
musicSelectionMenu.Open(player);
return;
}
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{
player.Print(Localizer["wp_command_cooldown"]);
}
});
});
}
}

View File

@@ -3,40 +3,20 @@ using System.Text.Json.Serialization;
namespace WeaponPaints
{
public class Messages
{
[JsonPropertyName("WebsiteMessageCommand")]
public string WebsiteMessageCommand { get; set; } = "Visit {WEBSITE} where you can change skins.";
[JsonPropertyName("SynchronizeMessageCommand")]
public string SynchronizeMessageCommand { get; set; } = "Type !wp to synchronize chosen skins.";
[JsonPropertyName("KnifeMessageCommand")]
public string KnifeMessageCommand { get; set; } = "Type !knife to open knife menu.";
[JsonPropertyName("CooldownRefreshCommand")]
public string CooldownRefreshCommand { get; set; } = "You can't refresh weapon paints right now.";
[JsonPropertyName("SuccessRefreshCommand")]
public string SuccessRefreshCommand { get; set; } = "Refreshing weapon paints.";
[JsonPropertyName("ChosenKnifeMenu")]
public string ChosenKnifeMenu { get; set; } = "You have chosen {KNIFE} as your knife.";
[JsonPropertyName("ChosenSkinMenu")]
public string ChosenSkinMenu { get; set; } = "You have chosen {SKIN} as your skin.";
[JsonPropertyName("ChosenKnifeMenuKill")]
public string ChosenKnifeMenuKill { get; set; } = "To correctly apply skin for knife, you need to type !kill.";
[JsonPropertyName("KnifeMenuTitle")]
public string KnifeMenuTitle { get; set; } = "Knife Menu.";
[JsonPropertyName("WeaponMenuTitle")]
public string WeaponMenuTitle { get; set; } = "Weapon Menu.";
[JsonPropertyName("SkinMenuTitle")]
public string SkinMenuTitle { get; set; } = "Select skin for {WEAPON}";
}
public class Additional
{
[JsonPropertyName("SkinVisibilityFix")]
public bool SkinVisibilityFix { get; set; } = true;
[JsonPropertyName("KnifeEnabled")]
public bool KnifeEnabled { get; set; } = true;
[JsonPropertyName("GloveEnabled")]
public bool GloveEnabled { get; set; } = true;
[JsonPropertyName("MusicEnabled")]
public bool MusicEnabled { get; set; } = true;
[JsonPropertyName("AgentEnabled")]
public bool AgentEnabled { get; set; } = true;
[JsonPropertyName("SkinEnabled")]
public bool SkinEnabled { get; set; } = true;
@@ -47,30 +27,45 @@ namespace WeaponPaints
public bool CommandKillEnabled { get; set; } = true;
[JsonPropertyName("CommandKnife")]
public string CommandKnife { get; set; } = "knife";
public List<string> CommandKnife { get; set; } = ["knife"];
[JsonPropertyName("CommandMusic")]
public List<string> CommandMusic { get; set; } = ["music"];
[JsonPropertyName("CommandGlove")]
public List<string> CommandGlove { get; set; } = ["gloves"];
[JsonPropertyName("CommandAgent")]
public List<string> CommandAgent { get; set; } = ["agents"];
[JsonPropertyName("CommandSkin")]
public string CommandSkin { get; set; } = "ws";
public List<string> CommandSkin { get; set; } = ["ws"];
[JsonPropertyName("CommandSkinSelection")]
public string CommandSkinSelection { get; set; } = "skins";
public List<string> CommandSkinSelection { get; set; } = ["skins"];
[JsonPropertyName("CommandRefresh")]
public string CommandRefresh { get; set; } = "wp";
public List<string> CommandRefresh { get; set; } = ["wp"];
[JsonPropertyName("CommandKill")]
public string CommandKill { get; set; } = "kill";
public List<string> CommandKill { get; set; } = ["kill"];
[JsonPropertyName("GiveRandomKnife")]
public bool GiveRandomKnife { get; set; } = false;
[JsonPropertyName("GiveRandomSkin")]
public bool GiveRandomSkin { get; set; } = false;
[JsonPropertyName("ShowSkinImage")]
public bool ShowSkinImage { get; set; } = true;
}
public class WeaponPaintsConfig : BasePluginConfig
{
public override int Version { get; set; } = 4;
[JsonPropertyName("ConfigVersion")] public override int Version { get; set; } = 7;
[JsonPropertyName("SkinsLanguage")]
public string SkinsLanguage { get; set; } = "en";
[JsonPropertyName("DatabaseHost")]
public string DatabaseHost { get; set; } = "";
@@ -87,23 +82,13 @@ namespace WeaponPaints
[JsonPropertyName("DatabaseName")]
public string DatabaseName { get; set; } = "";
[JsonPropertyName("GlobalShare")]
public bool GlobalShare { get; set; } = false;
[JsonPropertyName("CmdRefreshCooldownSeconds")]
public int CmdRefreshCooldownSeconds { get; set; } = 60;
[JsonPropertyName("Prefix")]
public string Prefix { get; set; } = "[WeaponPaints]";
public int CmdRefreshCooldownSeconds { get; set; } = 10;
[JsonPropertyName("Website")]
public string Website { get; set; } = "example.com/skins";
[JsonPropertyName("Messages")]
public Messages Messages { get; set; } = new Messages();
[JsonPropertyName("Additional")]
public Additional Additional { get; set; } = new Additional();
[JsonPropertyName("Additionalss")]
public Additional Additional { get; set; } = new();
}
}
}

23
Database.cs Normal file
View File

@@ -0,0 +1,23 @@
using Microsoft.Extensions.Logging;
using MySqlConnector;
namespace WeaponPaints
{
public class Database(string dbConnectionString)
{
public async Task<MySqlConnection> GetConnectionAsync()
{
try
{
var connection = new MySqlConnection(dbConnectionString);
await connection.OpenAsync();
return connection;
}
catch (Exception ex)
{
WeaponPaints.Instance.Logger.LogError($"Unable to connect to database: {ex.Message}");
throw;
}
}
}
}

367
Events.cs
View File

@@ -1,229 +1,250 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using System.Runtime.InteropServices;
namespace WeaponPaints
{
public partial class WeaponPaints
{
private void OnClientAuthorized(int playerSlot, SteamID steamID)
{
int playerIndex = playerSlot + 1;
CCSPlayerController? player = Utilities.GetPlayerFromIndex(playerIndex);
if (player == null || !player.IsValid || player.IsBot || player.IsHLTV) return;
if (Config.Additional.SkinEnabled && weaponSync != null)
_ = weaponSync.GetWeaponPaintsFromDatabase(playerIndex);
if (Config.Additional.KnifeEnabled && weaponSync != null)
_ = weaponSync.GetKnifeFromDatabase(playerIndex);
}
private void OnClientDisconnect(int playerSlot)
{
CCSPlayerController player = Utilities.GetPlayerFromSlot(playerSlot);
if (player == null || !player.IsValid || player.IsBot || player.IsHLTV) return;
if (Config.Additional.KnifeEnabled)
g_playersKnife.Remove((int)player.Index);
if (Config.Additional.SkinEnabled)
gPlayerWeaponsInfo.Remove((int)player.Index);
}
private void OnEntitySpawned(CEntityInstance entity)
{
if (!Config.Additional.SkinEnabled) return;
var designerName = entity.DesignerName;
if (!weaponList.ContainsKey(designerName)) return;
bool isKnife = false;
var weapon = new CBasePlayerWeapon(entity.Handle);
if (designerName.Contains("knife") || designerName.Contains("bayonet"))
{
isKnife = true;
}
Server.NextFrame(() =>
{
try
{
if (!weapon.IsValid) return;
if (weapon.OwnerEntity.Value == null) return;
if (weapon.OwnerEntity.Index <= 0) return;
int weaponOwner = (int)weapon.OwnerEntity.Index;
var pawn = new CBasePlayerPawn(NativeAPI.GetEntityFromIndex(weaponOwner));
if (!pawn.IsValid) return;
var playerIndex = (int)pawn.Controller.Index;
var player = Utilities.GetPlayerFromIndex(playerIndex);
if (!Utility.IsPlayerValid(player)) return;
ChangeWeaponAttributes(weapon, player, isKnife);
}
catch (Exception) { }
});
}
private HookResult OnEventItemPurchasePost(EventItemPurchase @event, GameEventInfo info)
[GameEventHandler]
public HookResult OnClientFullConnect(EventPlayerConnectFull @event, GameEventInfo info)
{
CCSPlayerController? player = @event.Userid;
if (player == null || !player.IsValid) return HookResult.Continue;
if (player is null || !player.IsValid || player.IsBot ||
WeaponSync == null || Database == null) return HookResult.Continue;
if (Config.Additional.SkinVisibilityFix)
AddTimer(0.2f, () => RefreshSkins(player));
return HookResult.Continue;
}
private HookResult OnItemPickup(EventItemPickup @event, GameEventInfo info)
{
if (@event.Defindex == 42 || @event.Defindex == 59)
var playerInfo = new PlayerInfo
{
CCSPlayerController? player = @event.Userid;
if (!Utility.IsPlayerValid(player) || !player.PawnIsAlive || g_knifePickupCount[(int)player.Index] >= 2) return HookResult.Continue;
UserId = player.UserId,
Slot = player.Slot,
Index = (int)player.Index,
SteamId = player.SteamID.ToString(),
Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0]
};
if (g_playersKnife.ContainsKey((int)player.Index)
&&
g_playersKnife[(int)player.Index] != "weapon_knife")
try
{
_ = Task.Run(async () => await WeaponSync.GetPlayerData(playerInfo));
/*
if (Config.Additional.SkinEnabled)
{
g_knifePickupCount[(int)player.Index]++;
RemovePlayerKnife(player, true);
AddTimer(0.3f, () => GiveKnifeToPlayer(player));
_ = Task.Run(async () => await weaponSync.GetWeaponPaintsFromDatabase(playerInfo));
}
if (Config.Additional.KnifeEnabled)
{
_ = Task.Run(async () => await weaponSync.GetKnifeFromDatabase(playerInfo));
}
if (Config.Additional.GloveEnabled)
{
_ = Task.Run(async () => await weaponSync.GetGloveFromDatabase(playerInfo));
}
if (Config.Additional.AgentEnabled)
{
_ = Task.Run(async () => await weaponSync.GetAgentFromDatabase(playerInfo));
}
if (Config.Additional.MusicEnabled)
{
_ = Task.Run(async () => await weaponSync.GetMusicFromDatabase(playerInfo));
}
*/
}
catch
{
}
return HookResult.Continue;
}
[GameEventHandler]
public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
{
CCSPlayerController? player = @event.Userid;
if (player is null || !player.IsValid || player.IsBot) return HookResult.Continue;
if (Config.Additional.SkinEnabled)
{
GPlayerWeaponsInfo.TryRemove(player.Slot, out _);
}
if (Config.Additional.KnifeEnabled)
{
GPlayersKnife.TryRemove(player.Slot, out _);
}
if (Config.Additional.GloveEnabled)
{
GPlayersGlove.TryRemove(player.Slot, out _);
}
if (Config.Additional.AgentEnabled)
{
GPlayersAgent.TryRemove(player.Slot, out _);
}
if (Config.Additional.MusicEnabled)
{
GPlayersMusic.TryRemove(player.Slot, out _);
}
_temporaryPlayerWeaponWear.TryRemove(player.Slot, out _);
CommandsCooldown.Remove(player.Slot);
return HookResult.Continue;
}
private void OnMapStart(string mapName)
{
if (!Config.Additional.KnifeEnabled) return;
// TODO
// needed for now
AddTimer(2.0f, () =>
{
NativeAPI.IssueServerCommand("mp_t_default_melee \"\"");
NativeAPI.IssueServerCommand("mp_ct_default_melee \"\"");
NativeAPI.IssueServerCommand("mp_equipment_reset_rounds 0");
if (Config.Additional is { KnifeEnabled: false, SkinEnabled: false, GloveEnabled: false }) return;
if (Config.GlobalShare)
GlobalShareConnect();
});
g_hTimerCheckSkinsData = AddTimer(10.0f, () =>
{
List<CCSPlayerController> players = Utilities.GetPlayers();
foreach (CCSPlayerController player in players)
{
if (player == null || !player.IsValid || player.IsBot || player.IsHLTV || player.AuthorizedSteamID == null) continue;
if (gPlayerWeaponsInfo.ContainsKey((int)player.Index)) continue;
if (Config.Additional.SkinEnabled && weaponSync != null)
_ = weaponSync.GetWeaponPaintsFromDatabase((int)player.Index);
if (Config.Additional.KnifeEnabled && weaponSync != null)
_ = weaponSync.GetKnifeFromDatabase((int)player.Index);
}
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE | CounterStrikeSharp.API.Modules.Timers.TimerFlags.REPEAT);
}
private HookResult OnPlayerConnectFull(EventPlayerConnectFull @event, GameEventInfo info)
{
CCSPlayerController? player = @event.Userid;
if (player == null || !player.IsValid || player.IsBot || player.IsHLTV) return HookResult.Continue;
if (!gPlayerWeaponsInfo.ContainsKey((int)player.Index))
{
Console.WriteLine($"[WeaponPaints] Retrying to retrieve player {player.PlayerName} skins");
if (Config.Additional.SkinEnabled && weaponSync != null)
_ = weaponSync.GetWeaponPaintsFromDatabase((int)player.Index);
if (Config.Additional.KnifeEnabled && weaponSync != null)
_ = weaponSync.GetKnifeFromDatabase((int)player.Index);
}
return HookResult.Continue;
if (Database != null)
WeaponSync = new WeaponSynchronization(Database, Config);
}
private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info)
{
CCSPlayerController? player = @event.Userid;
if (player == null || !player.IsValid)
{
if (player is null || !player.IsValid || Config.Additional is { KnifeEnabled: false, GloveEnabled: false })
return HookResult.Continue;
}
if (Config.Additional.KnifeEnabled)
{
g_knifePickupCount[(int)player.Index] = 0;
if (!PlayerHasKnife(player))
GiveKnifeToPlayer(player);
}
CCSPlayerPawn? pawn = player.PlayerPawn.Value;
if (Config.Additional.SkinVisibilityFix)
{
AddTimer(0.3f, () => RefreshSkins(player));
}
if (pawn == null || !pawn.IsValid)
return HookResult.Continue;
GivePlayerMusicKit(player);
GivePlayerAgent(player);
GivePlayerGloves(player);
return HookResult.Continue;
}
private HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info)
{
g_bCommandsAllowed = false;
_gBCommandsAllowed = false;
return HookResult.Continue;
}
private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info)
{
NativeAPI.IssueServerCommand("mp_t_default_melee \"\"");
NativeAPI.IssueServerCommand("mp_ct_default_melee \"\"");
NativeAPI.IssueServerCommand("mp_equipment_reset_rounds 0");
_gBCommandsAllowed = true;
return HookResult.Continue;
}
g_bCommandsAllowed = true;
public HookResult OnGiveNamedItemPost(DynamicHook hook)
{
try
{
var itemServices = hook.GetParam<CCSPlayer_ItemServices>(0);
var weapon = hook.GetReturn<CBasePlayerWeapon>();
if (!weapon.DesignerName.Contains("weapon"))
return HookResult.Continue;
var player = GetPlayerFromItemServices(itemServices);
if (player != null)
GivePlayerWeaponSkin(player, weapon);
}
catch { }
return HookResult.Continue;
}
public void OnEntityCreated(CEntityInstance entity)
{
var designerName = entity.DesignerName;
if (designerName.Contains("weapon"))
{
Server.NextFrame(() =>
{
var weapon = new CBasePlayerWeapon(entity.Handle);
if (!weapon.IsValid) return;
try
{
SteamID? steamid = null;
if (weapon.OriginalOwnerXuidLow > 0)
steamid = new SteamID(weapon.OriginalOwnerXuidLow);
CCSPlayerController? player;
if (steamid != null && steamid.IsValid())
{
player = Utilities.GetPlayers().FirstOrDefault(p => p.IsValid && p.SteamID == steamid.SteamId64);
if (player == null)
player = Utilities.GetPlayerFromSteamId(weapon.OriginalOwnerXuidLow);
}
else
{
CCSWeaponBaseGun gun = weapon.As<CCSWeaponBaseGun>();
player = Utilities.GetPlayerFromIndex((int)weapon.OwnerEntity.Index) ?? Utilities.GetPlayerFromIndex((int)gun.OwnerEntity.Value!.Index);
}
if (string.IsNullOrEmpty(player?.PlayerName)) return;
if (!Utility.IsPlayerValid(player)) return;
GivePlayerWeaponSkin(player, weapon);
}
catch (Exception)
{
}
});
}
}
private void OnTick()
{
if (!Config.Additional.ShowSkinImage) return;
foreach (var player in Utilities.GetPlayers().Where(p =>
p is { IsValid: true, PlayerPawn.IsValid: true } &&
(LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE
&& !p.IsBot && p is { Connected: PlayerConnectedState.PlayerConnected }
)
)
{
if (_playerWeaponImage.TryGetValue(player.Slot, out var value) && !string.IsNullOrEmpty(value))
{
player.PrintToCenterHtml("<img src='{PATH}'</img>".Replace("{PATH}", value));
}
}
}
[GameEventHandler]
public HookResult OnItemPickup(EventItemPickup @event, GameEventInfo _)
{
if (!IsWindows) return HookResult.Continue;
var player = @event.Userid;
if (player != null && player is { IsValid: true, Connected: PlayerConnectedState.PlayerConnected, PawnIsAlive: true, PlayerPawn.IsValid: true })
{
GiveOnItemPickup(player);
}
return HookResult.Continue;
}
private void RegisterListeners()
{
RegisterListener<Listeners.OnEntitySpawned>(OnEntitySpawned);
RegisterListener<Listeners.OnClientAuthorized>(OnClientAuthorized);
RegisterListener<Listeners.OnClientDisconnect>(OnClientDisconnect);
RegisterListener<Listeners.OnMapStart>(OnMapStart);
RegisterEventHandler<EventPlayerConnectFull>(OnPlayerConnectFull);
RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn);
RegisterEventHandler<EventRoundStart>(OnRoundStart, HookMode.Pre);
RegisterEventHandler<EventRoundStart>(OnRoundStart);
RegisterEventHandler<EventRoundEnd>(OnRoundEnd);
RegisterEventHandler<EventItemPurchase>(OnEventItemPurchasePost);
RegisterEventHandler<EventItemPickup>(OnItemPickup);
RegisterListener<Listeners.OnEntityCreated>(OnEntityCreated);
if (Config.Additional.ShowSkinImage)
RegisterListener<Listeners.OnTick>(OnTick);
if (!IsWindows)
VirtualFunctions.GiveNamedItemFunc.Hook(OnGiveNamedItemPost, HookMode.Post);
}
/* WORKAROUND FOR CLIENTS WITHOUT STEAMID ON AUTHORIZATION */
/*private HookResult OnPlayerConnectFull(EventPlayerConnectFull @event, GameEventInfo info)
{
CCSPlayerController? player = @event.Userid;
if (player == null || !player.IsValid || !player.EntityIndex.HasValue || player.IsHLTV) return HookResult.Continue;
int playerIndex = (int)player.EntityIndex.Value.Value;
if (Config.Additional.SkinEnabled && weaponSync != null)
_ = weaponSync.GetWeaponPaintsFromDatabase(playerIndex);
if (Config.Additional.KnifeEnabled && weaponSync != null)
_ = weaponSync.GetKnifeFromDatabase(playerIndex);
Task.Run(async () =>
{
if (Config.Additional.SkinEnabled && weaponSync != null)
if (Config.Additional.KnifeEnabled && weaponSync != null)
});
return HookResult.Continue;
}
*/
}
}

16
PlayerExtensions.cs Normal file
View File

@@ -0,0 +1,16 @@
using CounterStrikeSharp.API.Core;
using System.Text;
namespace WeaponPaints;
public static class PlayerExtensions
{
public static void Print(this CCSPlayerController controller, string message)
{
if (WeaponPaints._localizer == null) return;
StringBuilder _message = new(WeaponPaints._localizer["wp_prefix"]);
_message.Append(message);
controller.PrintToChat(_message.ToString());
}
}

12
PlayerInfo.cs Normal file
View File

@@ -0,0 +1,12 @@
namespace WeaponPaints
{
public class PlayerInfo
{
public int Index { get; set; }
public int Slot { get; init; }
public int? UserId { get; set; }
public string? SteamId { get; init; }
public string? Name { get; set; }
public string? IpAddress { get; set; }
}
}

View File

@@ -1,38 +1,50 @@
# CS2 Weapon Paints
## Description
Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin for **[CSSharp](https://docs.cssharp.dev/)**.
Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin for **[CSSharp](https://docs.cssharp.dev/docs/guides/getting-started.html)**.
## Created [Discord server](https://discord.gg/d9CvaYPSFe) where you can discus about plugin.
## Created [Discord server](https://discord.gg/d9CvaYPSFe) where you can discuss about plugin.
### Consider to donate instead of buying from unknown sources.
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/E1E2G0P2O) or [![Donate on Steam](https://github.com/Nereziel/cs2-WeaponPaints/assets/32937653/a0d53822-4ca7-4caf-83b4-e1a9b5f8c94e)](https://steamcommunity.com/tradeoffer/new/?partner=41515647&token=gW2W-nXE)
## Features
- Changes only paint, seed and wear on weapons and knives;
- MySQL based or global website at [weaponpaints.fun](https://weaponpaints.fun/), so you dont need MySQL/Website;
- Data sync on player connect;
- Added command **`!wp`** to refresh skins; ***(with cooldown in second can be configured)***
- Added command **`!ws`** to show website;
- Added command **`!knife`** to show menu with knives;
- Knife change is now limited to have these cvars empty **`mp_t_default_melee ""`** and **`mp_ct_default_melee ""`**;
- Changes only paint, seed and wear on weapons, knives, gloves and agents
- MySQL based
- Data syncs on player connect
- Added command **`!wp`** to refresh skins ***(with cooldown in seconds can be configured)***
- Added command **`!ws`** to show website
- Added command **`!knife`** to show menu with knives
- Added command **`!gloves`** to show menu with gloves
- Added command **`!agents`** to show menu with agents
- Translations support, submit a PR if you want to share your translation
## ⚙️ Requirements
**Ensure all the following dependencies are installed before proceeding**
- [CounterStrikeSharp](https://github.com/roflmuffin/CounterStrikeSharp)
- [PlayerSettings](https://github.com/NickFox007/PlayerSettingsCS2) - Required by MenuManagerCS2
- [AnyBaseLibCS2](https://github.com/NickFox007/AnyBaseLibCS2) - Required by PlayerSettings
- [MenuManagerCS2](https://github.com/NickFox007/MenuManagerCS2)
- MySQL database
## CS2 Server
- Compile and copy plugin to plugins, [more info here](https://docs.cssharp.dev/guides/hello-world-plugin/);
- Setup **`addons/counterstrikesharp/configs/plugins/WeaponPaints/WeaponPaints.json`** set **`GlobalShare`** to **`true`** for global, or include database credentials;
- in **`addons/counterstrikesharp/configs/core.json`** set **FollowCS2ServerGuidelines** to **`false`**;
- Have working CounterStrikeSharp (**with RUNTIME!**)
- Download from Release and copy plugin to plugins
- Run server with plugin, **it will generate config if installed correctly!**
- Edit `addons/counterstrikesharp/configs/`**`plugins/WeaponPaints/WeaponPaints.json`** include database credentials
- In `addons/counterstrikesharp/configs/`**`core.json`** set **FollowCS2ServerGuidelines** to **`false`**
- Copy from plugins folder gamedata file **`weaponpaints.json`** to folder **`addons/counterstrikesharp/gamedata/`**
## Plugin Configuration
<details>
<summary>Click to expand</summary>
<code><pre>{
"Version": 4, // Don't touch
"DatabaseHost": "", // MySQL host (required if GlobalShare = false)
"DatabasePort": 3306, // MySQL port (required if GlobalShare = false)
"DatabaseUser": "", // MySQL username (required if GlobalShare = false)
"DatabasePassword": "", // MySQL user password (required if GlobalShare = false)
"DatabaseName": "", // MySQL database name (required if GlobalShare = false)
"GlobalShare": false, // Enable or disable GlobalShare, plugin can work without mysql credentials but with shared website at weaponpaints.fun
"DatabaseHost": "", // MySQL host
"DatabasePort": 3306, // MySQL port
"DatabaseUser": "", // MySQL username
"DatabasePassword": "", // MySQL user password
"DatabaseName": "", // MySQL database name
"CmdRefreshCooldownSeconds": 60, // Cooldown time in refreshing skins (!wp command)
"Prefix": "[WeaponPaints]", // Prefix every chat message
"Website": "example.com/skins", // Website used in WebsiteMessageCommand (!ws command)
@@ -50,7 +62,6 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
"SkinMenuTitle": "Select skin for {WEAPON}" // Menu title (!skins menu, after weapon select)
},
"Additional": {
"SkinVisibilityFix": true, // Enable or disable fix for skin visibility
"KnifeEnabled": true, // Enable or disable knife feature
"SkinEnabled": true, // Enable or disable skin feature
"CommandWpEnabled": true, // Enable or disable refreshing command
@@ -63,21 +74,31 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
"GiveRandomKnife": false, // Give random knife to players if they didn't choose
"GiveRandomSkins": false // Give random skins to players if they didn't choose
},
"ConfigVersion": 4 // Don't touch
}</pre></code>
</pre></code>
</details>
## Web install
Disregard if the config is **`GlobalShare = true`**;
- Requires PHP >= 7.4; ***(Tested on php ver **`8.2.3`** and nginx webserver)***
- Copy website to web server; ***(Folder `img` not needed)***
- Get [Steam API Key](https://steamcommunity.com/dev/apikey);
- Fill in database credentials and api key in `class/config.php`;
- Visit website and login via steam;
- Requires PHP >= 7.4 with curl and pdo_mysql ***(Tested on php ver **`8.2.3`** and nginx webserver)***
- **Before using website, make sure the plugin is correctly loaded in cs2 server!** Mysql tables are created by plugin not by website.
- Copy website to web server ***(Folder `img` not needed)***
- Get [Steam API Key](https://steamcommunity.com/dev/apikey)
- Fill in database credentials and api key in `class/config.php`
- Visit website and login via steam
## Known issues
- Issue on Windows servers, no knives are given.
## Web Features
- Basic website
- Steam login/logout
- Change knife, paint, seed and wear
## Troubleshooting
<details>
**Skins are not changing:**
Set FollowCSGOGuidelines to false in cssharps core.jcon config
**Database error table does not exists:**
Plugin is not loaded or configured with mysql credentials. Tables are auto-created by plugin.
</details>
### Use this plugin at your own risk! Using this may lead to GSLT ban or something else Valve come with. [Valve Server guidelines](https://blog.counter-strike.net/index.php/server_guidelines/)

View File

@@ -1,10 +1,9 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using CounterStrikeSharp.API.Core.Translations;
using Dapper;
using MySqlConnector;
using Newtonsoft.Json.Linq;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Reflection;
using Newtonsoft.Json.Linq;
namespace WeaponPaints
{
@@ -12,37 +11,69 @@ namespace WeaponPaints
{
internal static WeaponPaintsConfig? Config { get; set; }
internal static string BuildDatabaseConnectionString()
internal static async Task CheckDatabaseTables()
{
if (Config == null) return string.Empty;
var builder = new MySqlConnectionStringBuilder
{
Server = Config.DatabaseHost,
UserID = Config.DatabaseUser,
Password = Config.DatabasePassword,
Database = Config.DatabaseName,
Port = (uint)Config.DatabasePort,
};
if (WeaponPaints.Database is null) return;
return builder.ConnectionString;
}
internal static async void CheckDatabaseTables()
{
try
{
using var connection = new MySqlConnection(BuildDatabaseConnectionString());
await connection.OpenAsync();
await using var connection = await WeaponPaints.Database.GetConnectionAsync();
using var transaction = await connection.BeginTransactionAsync();
await using var transaction = await connection.BeginTransactionAsync();
try
{
string createTable1 = "CREATE TABLE IF NOT EXISTS `wp_player_skins` (`steamid` varchar(64) NOT NULL, `weapon_defindex` int(6) NOT NULL, `weapon_paint_id` int(6) NOT NULL, `weapon_wear` float NOT NULL DEFAULT 0.000001, `weapon_seed` int(16) NOT NULL DEFAULT 0) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci";
string createTable2 = "CREATE TABLE IF NOT EXISTS `wp_player_knife` (`steamid` varchar(64) NOT NULL, `knife` varchar(64) NOT NULL, UNIQUE (`steamid`)) ENGINE = InnoDB";
string[] createTableQueries =
[
"""
CREATE TABLE IF NOT EXISTS `wp_player_skins` (
`steamid` varchar(18) NOT NULL,
`weapon_defindex` int(6) NOT NULL,
`weapon_paint_id` int(6) NOT NULL,
`weapon_wear` float NOT NULL DEFAULT 0.000001,
`weapon_seed` int(16) NOT NULL DEFAULT 0,
`weapon_nametag` VARCHAR(128) DEFAULT NULL,
`weapon_sticker_0` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
`weapon_sticker_1` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
`weapon_sticker_2` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
`weapon_sticker_3` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
`weapon_sticker_4` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
`weapon_keychain`VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0' COMMENT 'id;x;y;z;seed'
) ENGINE=InnoDB
""",
@"CREATE TABLE IF NOT EXISTS `wp_player_knife` (
`steamid` varchar(18) NOT NULL,
`knife` varchar(64) NOT NULL,
UNIQUE (`steamid`)
) ENGINE = InnoDB",
"""
CREATE TABLE IF NOT EXISTS `wp_player_gloves` (
`steamid` varchar(18) NOT NULL,
`weapon_defindex` int(11) NOT NULL,
UNIQUE (`steamid`)
) ENGINE=InnoDB
""",
"""
CREATE TABLE IF NOT EXISTS `wp_player_agents` (
`steamid` varchar(18) NOT NULL,
`agent_ct` varchar(64) DEFAULT NULL,
`agent_t` varchar(64) DEFAULT NULL,
UNIQUE (`steamid`)
) ENGINE=InnoDB
""",
"""
CREATE TABLE IF NOT EXISTS `wp_player_music` (
`steamid` varchar(64) NOT NULL,
`music_id` int(11) NOT NULL,
UNIQUE (`steamid`)
) ENGINE=InnoDB
""",
];
await connection.ExecuteAsync(createTable1, transaction: transaction);
await connection.ExecuteAsync(createTable2, transaction: transaction);
foreach (var query in createTableQueries)
{
await connection.ExecuteAsync(query, transaction: transaction);
}
await transaction.CommitAsync();
}
@@ -54,25 +85,70 @@ namespace WeaponPaints
}
catch (Exception ex)
{
throw new Exception("[WeaponPaints] Unknown mysql exception! " + ex.Message);
throw new Exception("[WeaponPaints] Unknown MySQL exception! " + ex.Message);
}
}
internal static bool IsPlayerValid(CCSPlayerController? player)
{
return (player != null && player.IsValid && !player.IsBot && !player.IsHLTV && player.AuthorizedSteamID != null);
if (player is null || WeaponPaints.WeaponSync is null) return false;
return player is { IsValid: true, IsBot: false, IsHLTV: false, UserId: not null };
}
internal static void LoadSkinsFromFile(string filePath)
internal static void LoadSkinsFromFile(string filePath, ILogger logger)
{
if (File.Exists(filePath))
var json = File.ReadAllText(filePath);
try
{
string json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.skinsList = deserializedSkins ?? new List<JObject>();
WeaponPaints.SkinsList = deserializedSkins ?? [];
}
else
catch (FileNotFoundException)
{
throw new FileNotFoundException("File not found.", filePath);
logger?.LogError("Not found \"skins.json\" file");
}
}
internal static void LoadGlovesFromFile(string filePath, ILogger logger)
{
try
{
var json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.GlovesList = deserializedSkins ?? [];
}
catch (FileNotFoundException)
{
logger?.LogError("Not found \"gloves.json\" file");
}
}
internal static void LoadAgentsFromFile(string filePath, ILogger logger)
{
try
{
var json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.AgentsList = deserializedSkins ?? [];
}
catch (FileNotFoundException)
{
logger?.LogError("Not found \"agents.json\" file");
}
}
internal static void LoadMusicFromFile(string filePath, ILogger logger)
{
try
{
var json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.MusicList = deserializedSkins ?? [];
}
catch (FileNotFoundException)
{
logger?.LogError("Not found \"music.json\" file");
}
}
@@ -86,25 +162,50 @@ namespace WeaponPaints
internal static string ReplaceTags(string message)
{
if (message.Contains('{'))
return message.ReplaceColorTags();
}
internal static async Task CheckVersion(string version, ILogger logger)
{
using HttpClient client = new();
try
{
string modifiedValue = message;
if (Config != null)
var response = await client.GetAsync("https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/VERSION").ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
modifiedValue = modifiedValue.Replace("{WEBSITE}", Config.Website);
}
foreach (FieldInfo field in typeof(ChatColors).GetFields())
{
string pattern = $"{{{field.Name}}}";
if (message.Contains(pattern, StringComparison.OrdinalIgnoreCase))
var remoteVersion = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
remoteVersion = remoteVersion.Trim();
var comparisonResult = string.CompareOrdinal(version, remoteVersion);
switch (comparisonResult)
{
modifiedValue = modifiedValue.Replace(pattern, field.GetValue(null)!.ToString(), StringComparison.OrdinalIgnoreCase);
case < 0:
logger.LogWarning("Plugin is outdated! Check https://github.com/Nereziel/cs2-WeaponPaints");
break;
case > 0:
logger.LogInformation("Probably dev version detected");
break;
default:
logger.LogInformation("Plugin is up to date");
break;
}
}
return modifiedValue;
else
{
logger.LogWarning("Failed to check version");
}
}
catch (HttpRequestException ex)
{
logger.LogError(ex, "Failed to connect to the version server.");
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred while checking version.");
}
return message;
}
internal static void ShowAd(string moduleVersion)
@@ -121,24 +222,5 @@ namespace WeaponPaints
Console.WriteLine(" >> GitHub: https://github.com/Nereziel/cs2-WeaponPaints");
Console.WriteLine(" ");
}
internal static void TestDatabaseConnection()
{
try
{
using var connection = new MySqlConnection(BuildDatabaseConnectionString());
connection.Open();
if (connection.State != System.Data.ConnectionState.Open)
{
throw new Exception("[WeaponPaints] Unable connect to database!");
}
}
catch (Exception ex)
{
throw new Exception("[WeaponPaints] Unknown mysql exception! " + ex.Message);
}
CheckDatabaseTables();
}
}
}

1
VERSION Normal file
View File

@@ -0,0 +1 @@
2.6a

165
Variables.cs Normal file
View File

@@ -0,0 +1,165 @@
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Capabilities;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using MenuManager;
using Microsoft.Extensions.Localization;
using Newtonsoft.Json.Linq;
namespace WeaponPaints;
public partial class WeaponPaints
{
private static readonly Dictionary<string, string> WeaponList = new()
{
{"weapon_deagle", "Desert Eagle"},
{"weapon_elite", "Dual Berettas"},
{"weapon_fiveseven", "Five-SeveN"},
{"weapon_glock", "Glock-18"},
{"weapon_ak47", "AK-47"},
{"weapon_aug", "AUG"},
{"weapon_awp", "AWP"},
{"weapon_famas", "FAMAS"},
{"weapon_g3sg1", "G3SG1"},
{"weapon_galilar", "Galil AR"},
{"weapon_m249", "M249"},
{"weapon_m4a1", "M4A1"},
{"weapon_mac10", "MAC-10"},
{"weapon_p90", "P90"},
{"weapon_mp5sd", "MP5-SD"},
{"weapon_ump45", "UMP-45"},
{"weapon_xm1014", "XM1014"},
{"weapon_bizon", "PP-Bizon"},
{"weapon_mag7", "MAG-7"},
{"weapon_negev", "Negev"},
{"weapon_sawedoff", "Sawed-Off"},
{"weapon_tec9", "Tec-9"},
{"weapon_taser", "Zeus x27"},
{"weapon_hkp2000", "P2000"},
{"weapon_mp7", "MP7"},
{"weapon_mp9", "MP9"},
{"weapon_nova", "Nova"},
{"weapon_p250", "P250"},
{"weapon_scar20", "SCAR-20"},
{"weapon_sg556", "SG 553"},
{"weapon_ssg08", "SSG 08"},
{"weapon_m4a1_silencer", "M4A1-S"},
{"weapon_usp_silencer", "USP-S"},
{"weapon_cz75a", "CZ75-Auto"},
{"weapon_revolver", "R8 Revolver"},
{ "weapon_knife", "Default Knife" },
{ "weapon_knife_m9_bayonet", "M9 Bayonet" },
{ "weapon_knife_karambit", "Karambit" },
{ "weapon_bayonet", "Bayonet" },
{ "weapon_knife_survival_bowie", "Bowie Knife" },
{ "weapon_knife_butterfly", "Butterfly Knife" },
{ "weapon_knife_falchion", "Falchion Knife" },
{ "weapon_knife_flip", "Flip Knife" },
{ "weapon_knife_gut", "Gut Knife" },
{ "weapon_knife_tactical", "Huntsman Knife" },
{ "weapon_knife_push", "Shadow Daggers" },
{ "weapon_knife_gypsy_jackknife", "Navaja Knife" },
{ "weapon_knife_stiletto", "Stiletto Knife" },
{ "weapon_knife_widowmaker", "Talon Knife" },
{ "weapon_knife_ursus", "Ursus Knife" },
{ "weapon_knife_css", "Classic Knife" },
{ "weapon_knife_cord", "Paracord Knife" },
{ "weapon_knife_canis", "Survival Knife" },
{ "weapon_knife_outdoor", "Nomad Knife" },
{ "weapon_knife_skeleton", "Skeleton Knife" },
{ "weapon_knife_kukri", "Kukri Knife" }
};
public static IStringLocalizer? _localizer;
internal static readonly ConcurrentDictionary<int, string> GPlayersKnife = new();
internal static readonly ConcurrentDictionary<int, ushort> GPlayersGlove = new();
internal static readonly ConcurrentDictionary<int, ushort> GPlayersMusic = new();
public static readonly ConcurrentDictionary<int, (string? CT, string? T)> GPlayersAgent = new();
internal static readonly ConcurrentDictionary<int, ConcurrentDictionary<int, WeaponInfo>> GPlayerWeaponsInfo = new();
internal static List<JObject> SkinsList = [];
internal static List<JObject> GlovesList = [];
internal static List<JObject> AgentsList = [];
internal static List<JObject> MusicList = [];
internal static WeaponSynchronization? WeaponSync;
private static bool _gBCommandsAllowed = true;
private readonly Dictionary<int, string> _playerWeaponImage = new();
private static readonly Dictionary<int, DateTime> CommandsCooldown = new();
internal static Database? Database;
private static readonly MemoryFunctionVoid<nint, string, float> CAttributeListSetOrAddAttributeValueByName = new(GameData.GetSignature("CAttributeList_SetOrAddAttributeValueByName"));
private static readonly MemoryFunctionWithReturn<nint, string, int, int> SetBodygroupFunc = new(
GameData.GetSignature("CBaseModelEntity_SetBodygroup"));
private static readonly Func<nint, string, int, int> SetBodygroup = SetBodygroupFunc.Invoke;
private static Dictionary<int, string> WeaponDefindex { get; } = new()
{
{ 1, "weapon_deagle" },
{ 2, "weapon_elite" },
{ 3, "weapon_fiveseven" },
{ 4, "weapon_glock" },
{ 7, "weapon_ak47" },
{ 8, "weapon_aug" },
{ 9, "weapon_awp" },
{ 10, "weapon_famas" },
{ 11, "weapon_g3sg1" },
{ 13, "weapon_galilar" },
{ 14, "weapon_m249" },
{ 16, "weapon_m4a1" },
{ 17, "weapon_mac10" },
{ 19, "weapon_p90" },
{ 23, "weapon_mp5sd" },
{ 24, "weapon_ump45" },
{ 25, "weapon_xm1014" },
{ 26, "weapon_bizon" },
{ 27, "weapon_mag7" },
{ 28, "weapon_negev" },
{ 29, "weapon_sawedoff" },
{ 30, "weapon_tec9" },
{ 31, "weapon_taser" },
{ 32, "weapon_hkp2000" },
{ 33, "weapon_mp7" },
{ 34, "weapon_mp9" },
{ 35, "weapon_nova" },
{ 36, "weapon_p250" },
{ 38, "weapon_scar20" },
{ 39, "weapon_sg556" },
{ 40, "weapon_ssg08" },
{ 60, "weapon_m4a1_silencer" },
{ 61, "weapon_usp_silencer" },
{ 63, "weapon_cz75a" },
{ 64, "weapon_revolver" },
{ 500, "weapon_bayonet" },
{ 503, "weapon_knife_css" },
{ 505, "weapon_knife_flip" },
{ 506, "weapon_knife_gut" },
{ 507, "weapon_knife_karambit" },
{ 508, "weapon_knife_m9_bayonet" },
{ 509, "weapon_knife_tactical" },
{ 512, "weapon_knife_falchion" },
{ 514, "weapon_knife_survival_bowie" },
{ 515, "weapon_knife_butterfly" },
{ 516, "weapon_knife_push" },
{ 517, "weapon_knife_cord" },
{ 518, "weapon_knife_canis" },
{ 519, "weapon_knife_ursus" },
{ 520, "weapon_knife_gypsy_jackknife" },
{ 521, "weapon_knife_outdoor" },
{ 522, "weapon_knife_stiletto" },
{ 523, "weapon_knife_widowmaker" },
{ 525, "weapon_knife_skeleton" },
{ 526, "weapon_knife_kukri" }
};
private const ulong MinimumCustomItemId = 65578;
private ulong _nextItemId = MinimumCustomItemId;
private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
private readonly ConcurrentDictionary<int, ConcurrentDictionary<int, float>> _temporaryPlayerWeaponWear = new();
internal static IMenuApi? MenuApi;
private static readonly PluginCapability<IMenuApi> MenuCapability = new("menu:nfcore");
}

View File

@@ -1,83 +1,200 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.Utils;
using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Runtime.InteropServices;
namespace WeaponPaints
{
public partial class WeaponPaints
{
internal static void ChangeWeaponAttributes(CBasePlayerWeapon? weapon, CCSPlayerController? player, bool isKnife = false)
private void GivePlayerWeaponSkin(CCSPlayerController player, CBasePlayerWeapon weapon)
{
if (player == null || weapon == null || !weapon.IsValid || !Utility.IsPlayerValid(player)) return;
if (!Config.Additional.SkinEnabled) return;
if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return;
int playerIndex = (int)player.Index;
bool isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet");
if (!gPlayerWeaponsInfo.ContainsKey(playerIndex)) return;
if (isKnife && !GPlayersKnife.ContainsKey(player.Slot) || isKnife && GPlayersKnife[player.Slot] == "weapon_knife") return;
if (isKnife && !g_playersKnife.ContainsKey(playerIndex) || isKnife && g_playersKnife[playerIndex] == "weapon_knife") return;
int[] newPaints = { 106, 112, 113, 114, 115, 117, 118, 120, 121, 123, 126, 127, 128, 129, 130, 131, 133, 134, 137, 138, 139, 140, 142, 144, 145, 146, 152, 160, 161, 163, 173, 239, 292, 324, 331, 412, 461, 513, 766, 768, 770, 773, 774, 830, 831, 832, 834, 874, 875, 877, 878, 882, 883, 901, 912, 936, 937, 938, 939, 940, 1054, 1062, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1177, 1178, 1179, 1180 };
if (isKnife)
{
var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == GPlayersKnife[player.Slot]);
if (newDefIndex.Key == 0) return;
if (weapon.AttributeManager.Item.ItemDefinitionIndex != newDefIndex.Key)
{
SubclassChange(weapon, (ushort)newDefIndex.Key);
}
weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)newDefIndex.Key;
weapon.AttributeManager.Item.EntityQuality = 3;
}
UpdatePlayerEconItemId(weapon.AttributeManager.Item);
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
int fallbackPaintKit = 0;
weapon.AttributeManager.Item.AccountID = (uint)player.SteamID;
if (_config.Additional.GiveRandomSkin &&
!gPlayerWeaponsInfo[playerIndex].ContainsKey(weaponDefIndex))
!GPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex))
{
// Random skins
weapon.AttributeManager.Item.ItemID = 16384;
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32;
weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex);
weapon.FallbackSeed = 0;
weapon.FallbackWear = 0.000001f;
if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null)
{
var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode);
skeleton.ModelState.MeshGroupMask = 2;
}
weapon.FallbackWear = 0.01f;
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Attributes.RemoveAll();
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", GetRandomPaint(weaponDefIndex));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture seed", 0);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture wear", 0.01f);
weapon.AttributeManager.Item.AttributeList.Attributes.RemoveAll();
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture prefab", GetRandomPaint(weaponDefIndex));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture seed", 0);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture wear", 0.01f);
fallbackPaintKit = weapon.FallbackPaintKit;
if (fallbackPaintKit == 0)
return;
if (isKnife) return;
UpdatePlayerWeaponMeshGroupMask(player, weapon, !newPaints.Contains(fallbackPaintKit));
return;
}
if (!gPlayerWeaponsInfo[playerIndex].ContainsKey(weaponDefIndex)) return;
WeaponInfo weaponInfo = gPlayerWeaponsInfo[playerIndex][weaponDefIndex];
if (!GPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefIndex, out var value) || value.Paint == 0) return;
var weaponInfo = value;
//Log($"Apply on {weapon.DesignerName}({weapon.AttributeManager.Item.ItemDefinitionIndex}) paint {gPlayerWeaponPaints[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} seed {gPlayerWeaponSeed[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} wear {gPlayerWeaponWear[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]}");
weapon.AttributeManager.Item.ItemID = 16384;
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32;
weapon.AttributeManager.Item.CustomName = weaponInfo.Nametag;
weapon.FallbackPaintKit = weaponInfo.Paint;
weapon.FallbackSeed = weaponInfo.Seed;
weapon.FallbackWear = weaponInfo.Wear;
if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null)
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit);
fallbackPaintKit = weapon.FallbackPaintKit;
if (fallbackPaintKit == 0)
return;
if (isKnife) return;
if (weaponInfo.Stickers.Count > 0) SetStickers(player, weapon);
if (weaponInfo.KeyChain != null) SetKeychain(player, weapon);
UpdatePlayerWeaponMeshGroupMask(player, weapon, !newPaints.Contains(fallbackPaintKit));
}
// silly method to update sticker when call RefreshWeapons()
private void IncrementWearForWeaponWithStickers(CCSPlayerController player, CBasePlayerWeapon weapon)
{
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out var playerWeapons) ||
!playerWeapons.TryGetValue(weaponDefIndex, out var weaponInfo) ||
weaponInfo.Stickers.Count <= 0) return;
float wearIncrement = 0.001f;
float currentWear = weaponInfo.Wear;
var playerWear = _temporaryPlayerWeaponWear.GetOrAdd(player.Slot, _ => new ConcurrentDictionary<int, float>());
float incrementedWear = playerWear.AddOrUpdate(
weaponDefIndex,
currentWear + wearIncrement,
(_, oldWear) => Math.Min(oldWear + wearIncrement, 1.0f)
);
weapon.FallbackWear = incrementedWear;
}
private void SetStickers(CCSPlayerController? player, CBasePlayerWeapon weapon)
{
if (player == null || !player.IsValid) return;
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out var playerWeapons) ||
!playerWeapons.TryGetValue(weaponDefIndex, out var weaponInfo))
{
var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode);
skeleton.ModelState.MeshGroupMask = 2;
return;
}
foreach (var sticker in weaponInfo.Stickers)
{
int stickerSlot = weaponInfo.Stickers.IndexOf(sticker);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} id", ViewAsFloat(sticker.Id));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} schema", sticker.Schema);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} offset x", sticker.OffsetX);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} offset y", sticker.OffsetY);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} wear", sticker.Wear);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} scale", sticker.Scale);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} rotation", sticker.Rotation);
}
if (_temporaryPlayerWeaponWear.TryGetValue(player.Slot, out var playerWear) &&
playerWear.TryGetValue(weaponDefIndex, out float storedWear))
{
weapon.FallbackWear = storedWear;
}
}
internal static void GiveKnifeToPlayer(CCSPlayerController? player)
private void SetKeychain(CCSPlayerController? player, CBasePlayerWeapon weapon)
{
if (player == null || !player.IsValid) return;
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out var playerWeaponsInfo) ||
!playerWeaponsInfo.TryGetValue(weaponDefIndex, out var value) ||
value.KeyChain == null) return;
var keyChain = value.KeyChain;
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
"keychain slot 0 id", ViewAsFloat(keyChain.Id));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
"keychain slot 0 offset x", keyChain.OffsetX);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
"keychain slot 0 offset y", keyChain.OffsetY);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
"keychain slot 0 offset z", keyChain.OffsetZ);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
"keychain slot 0 seed", keyChain.Seed);
}
private static void GiveKnifeToPlayer(CCSPlayerController? player)
{
if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return;
if (g_playersKnife.TryGetValue((int)player.Index, out var knife))
{
player.GiveNamedItem(knife);
}
else if (_config.Additional.GiveRandomKnife)
{
var knifeTypes = weaponList.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet")).ToDictionary(pair => pair.Key, pair => pair.Value);
Random random = new();
int index = random.Next(knifeTypes.Count);
var randomKnifeClass = knifeTypes.Keys.ElementAt(index);
if (PlayerHasKnife(player)) return;
player.GiveNamedItem(randomKnifeClass);
}
else
{
var defaultKnife = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife";
player.GiveNamedItem(defaultKnife);
}
//string knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife";
player.GiveNamedItem(CsItem.Knife);
}
internal static bool PlayerHasKnife(CCSPlayerController? player)
private static bool PlayerHasKnife(CCSPlayerController? player)
{
if (!_config.Additional.KnifeEnabled) return false;
@@ -86,224 +203,316 @@ namespace WeaponPaints
return false;
}
if (player.PlayerPawn?.Value == null || player.PlayerPawn?.Value.WeaponServices == null || player.PlayerPawn?.Value.ItemServices == null)
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null)
return false;
var weapons = player.PlayerPawn.Value.WeaponServices?.MyWeapons;
if (weapons == null) return false;
foreach (var weapon in weapons)
{
if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid)
if (!weapon.IsValid || weapon.Value == null || !weapon.Value.IsValid) continue;
if (weapon.Value.DesignerName.Contains("knife") || weapon.Value.DesignerName.Contains("bayonet"))
{
if (weapon.Value.DesignerName.Contains("knife") || weapon.Value.DesignerName.Contains("bayonet"))
{
return true;
}
return true;
}
}
return false;
}
internal void RefreshPlayerKnife(CCSPlayerController? player)
private void RefreshWeapons(CCSPlayerController? player)
{
if (player == null || !player.IsValid || player.PlayerPawn.Value == null || !player.PawnIsAlive) return;
if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null) return;
if (!_gBCommandsAllowed) return;
if (player == null || !player.IsValid || player.PlayerPawn.Value == null || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE)
return;
if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null)
return;
var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons;
if (weapons != null && weapons.Count > 0)
if (weapons.Count == 0)
return;
if (player.Team is CsTeam.None or CsTeam.Spectator)
return;
int playerTeam = player.TeamNum;
Dictionary<string, List<(int, int)>> weaponsWithAmmo = [];
foreach (var weapon in weapons)
{
CCSPlayer_ItemServices service = new(player.PlayerPawn.Value.ItemServices.Handle);
//var dropWeapon = VirtualFunction.CreateVoid<nint, nint>(service.Handle, GameData.GetOffset("CCSPlayer_ItemServices_DropActivePlayerWeapon"));
if (!weapon.IsValid || weapon.Value == null ||
!weapon.Value.IsValid || !weapon.Value.DesignerName.Contains("weapon_"))
continue;
foreach (var weapon in weapons)
CCSWeaponBaseGun gun = weapon.Value.As<CCSWeaponBaseGun>();
if (weapon.Value.Entity == null) continue;
if (!weapon.Value.OwnerEntity.IsValid) continue;
if (gun.Entity == null) continue;
if (!gun.IsValid) continue;
if (!gun.VisibleinPVS) continue;
try
{
if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid)
CCSWeaponBaseVData? weaponData = weapon.Value.As<CCSWeaponBase>().VData;
if (weaponData == null) continue;
if (weaponData.GearSlot is gear_slot_t.GEAR_SLOT_RIFLE or gear_slot_t.GEAR_SLOT_PISTOL)
{
//if (weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 42 || weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 59)
if (weapon.Value.DesignerName.Contains("knife") || weapon.Value.DesignerName.Contains("bayonet"))
if (!WeaponDefindex.TryGetValue(weapon.Value.AttributeManager.Item.ItemDefinitionIndex, out var weaponByDefindex))
continue;
int clip1 = weapon.Value.Clip1;
int reservedAmmo = weapon.Value.ReserveAmmo[0];
if (!weaponsWithAmmo.TryGetValue(weaponByDefindex, out var value))
{
if (weapon.Index <= 0) return;
int weaponEntityIndex = (int)weapon.Index;
NativeAPI.IssueClientCommand((int)player.Index - 1, "slot3");
AddTimer(0.22f, () =>
{
if (player.PlayerPawn.Value.WeaponServices.ActiveWeapon.Value!.DesignerName.Contains("knife")
||
player.PlayerPawn.Value.WeaponServices.ActiveWeapon.Value!.DesignerName.Contains("bayonet")
)
{
if (player.PawnIsAlive)
{
NativeAPI.IssueClientCommand((int)player.Index - 1, "slot3");
service.DropActivePlayerWeapon(weapon.Value);
GiveKnifeToPlayer(player);
}
}
});
Task.Delay(TimeSpan.FromSeconds(3.5)).ContinueWith(_ =>
{
try
{
CEntityInstance? knife = Utilities.GetEntityFromIndex<CEntityInstance>(weaponEntityIndex);
if (knife != null && knife.IsValid && knife.Handle != -1 && knife.Index > 0)
{
knife.Remove();
}
}
catch (Exception) { }
});
break;
value = [];
weaponsWithAmmo.Add(weaponByDefindex, value);
}
value.Add((clip1, reservedAmmo));
if (gun.VData == null) return;
weapon.Value?.AddEntityIOEvent("Kill", weapon.Value, null, "", 0.1f);
}
if (weaponData.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE)
{
weapon.Value?.AddEntityIOEvent("Kill", weapon.Value, null, "", 0.1f);
}
}
}
}
internal void RefreshSkins(CCSPlayerController? player)
{
if (!Utility.IsPlayerValid(player) || !player!.PawnIsAlive) return;
AddTimer(0.18f, () => NativeAPI.IssueClientCommand((int)player.Index - 1, "slot3"));
AddTimer(0.25f, () => NativeAPI.IssueClientCommand((int)player.Index - 1, "slot2"));
AddTimer(0.38f, () => NativeAPI.IssueClientCommand((int)player.Index - 1, "slot1"));
}
internal void RefreshWeapons(CCSPlayerController? player)
{
if (player == null || !player.IsValid || player.PlayerPawn.Value == null || !player.PawnIsAlive) return;
if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null) return;
var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons;
if (weapons != null && weapons.Count > 0)
{
CCSPlayer_ItemServices service = new(player.PlayerPawn.Value.ItemServices.Handle);
foreach (var weapon in weapons)
catch (Exception ex)
{
if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid)
Logger.LogWarning(ex.Message);
}
}
AddTimer(0.23f, () =>
{
if (weapon.Index <= 0 || !weapon.Value.DesignerName.Contains("weapon_")) continue;
//if (weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 42 || weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 59)
try
if (!_gBCommandsAllowed) return;
if (!PlayerHasKnife(player))
GiveKnifeToPlayer(player);
foreach (var entry in weaponsWithAmmo)
{
if (weapon.Value.DesignerName.Contains("knife") || weapon.Value.DesignerName.Contains("bayonet"))
foreach (var ammo in entry.Value)
{
weapon.Value.Remove();
GiveKnifeToPlayer(player);
}
else
{
if (!weaponDefindex.ContainsKey(weapon.Value.AttributeManager.Item.ItemDefinitionIndex)) continue;
int clip1, reservedAmmo;
clip1 = weapon.Value.Clip1;
reservedAmmo = weapon.Value.ReserveAmmo[0];
weapon.Value.Remove();
string weaponByDefindex = weaponDefindex[weapon.Value.AttributeManager.Item.ItemDefinitionIndex];
CBasePlayerWeapon newWeapon = new(player.GiveNamedItem(weaponByDefindex));
var newWeapon = new CBasePlayerWeapon(player.GiveNamedItem(entry.Key));
Server.NextFrame(() =>
{
if (newWeapon == null) return;
try
{
newWeapon.Clip1 = clip1;
newWeapon.ReserveAmmo[0] = reservedAmmo;
}
catch (Exception)
{ }
});
{
try
{
newWeapon.Clip1 = ammo.Item1;
newWeapon.ReserveAmmo[0] = ammo.Item2;
IncrementWearForWeaponWithStickers(player, newWeapon);
}
catch (Exception ex)
{
Logger.LogWarning("Error setting weapon properties: " + ex.Message);
}
});
}
}
catch (Exception ex)
{
Console.WriteLine("[WeaponPaints] Refreshing weapons exception");
Console.WriteLine(ex.Message);
}
}
}
if (Config.Additional.SkinVisibilityFix)
RefreshSkins(player);
}
}, TimerFlags.STOP_ON_MAPCHANGE);
}
internal void RemovePlayerKnife(CCSPlayerController? player, bool force = false)
private void GivePlayerGloves(CCSPlayerController player)
{
if (player == null || !player.IsValid || player.PlayerPawn.Value == null || !player.PawnIsAlive) return;
if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null) return;
if (!Utility.IsPlayerValid(player) || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE) return;
var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons;
if (weapons != null && weapons.Count > 0)
CCSPlayerPawn? pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid)
return;
var model = pawn.CBodyComponent?.SceneNode?.GetSkeletonInstance()?.ModelState.ModelName ?? string.Empty;
if (!string.IsNullOrEmpty(model))
{
CCSPlayer_ItemServices service = new CCSPlayer_ItemServices(player.PlayerPawn.Value.ItemServices.Handle);
foreach (var weapon in weapons)
{
if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid)
{
//if (weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 42 || weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 59)
if (weapon.Value.DesignerName.Contains("knife") || weapon.Value.DesignerName.Contains("bayonet"))
{
if (!force)
{
if ((int)weapon.Index <= 0) return;
int weaponEntityIndex = (int)weapon.Index;
NativeAPI.IssueClientCommand((int)player.Index - 1, "slot3");
AddTimer(0.35f, () => service.DropActivePlayerWeapon(weapon.Value));
AddTimer(1.0f, () =>
{
CEntityInstance? knife = Utilities.GetEntityFromIndex<CEntityInstance>(weaponEntityIndex);
if (knife != null && knife.IsValid)
{
knife.Remove();
}
});
}
else
{
weapon.Value.Remove();
}
break;
}
}
}
pawn.SetModel("characters/models/tm_jumpsuit/tm_jumpsuit_varianta.vmdl");
pawn.SetModel(model);
}
Instance.AddTimer(0.08f, () =>
{
CEconItemView item = pawn.EconGloves;
try
{
if (!player.IsValid)
return;
if (!player.PawnIsAlive)
return;
if (!GPlayersGlove.TryGetValue(player.Slot, out var gloveInfo) || gloveInfo == 0) return;
WeaponInfo weaponInfo = GPlayerWeaponsInfo[player.Slot][gloveInfo];
item.ItemDefinitionIndex = gloveInfo;
item.ItemIDLow = 16384 & 0xFFFFFFFF;
item.ItemIDHigh = 16384;
CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weaponInfo.Paint);
CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture seed", weaponInfo.Seed);
CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture wear", weaponInfo.Wear);
item.Initialized = true;
SetBodygroup(pawn.Handle, "default_gloves", 1);
}
catch (Exception) { }
}, TimerFlags.STOP_ON_MAPCHANGE);
}
private static int GetRandomPaint(int defindex)
{
if (SkinsList.Count == 0)
return 0;
Random rnd = new Random();
if (WeaponPaints.skinsList != null)
{
// Filter weapons by the provided defindex
var filteredWeapons = skinsList.FindAll(w => w["weapon_defindex"]?.ToString() == defindex.ToString());
// Filter weapons by the provided defindex
var filteredWeapons = SkinsList.Where(w => w["weapon_defindex"]?.ToString() == defindex.ToString()).ToList();
if (filteredWeapons.Count > 0)
{
var randomWeapon = filteredWeapons[rnd.Next(filteredWeapons.Count)];
if (int.TryParse(randomWeapon["paint"]?.ToString(), out int paintValue))
{
return paintValue;
}
else
{
return 0;
}
}
}
return 0;
if (filteredWeapons.Count == 0)
return 0;
var randomWeapon = filteredWeapons[rnd.Next(filteredWeapons.Count)];
return int.TryParse(randomWeapon["paint"]?.ToString(), out var paintValue) ? paintValue : 0;
}
private static CSkeletonInstance GetSkeletonInstance(CGameSceneNode node)
private static void SubclassChange(CBasePlayerWeapon weapon, ushort itemD)
{
Func<nint, nint> GetSkeletonInstance = VirtualFunction.Create<nint, nint>(node.Handle, 8);
return new CSkeletonInstance(GetSkeletonInstance(node.Handle));
var subclassChangeFunc = VirtualFunction.Create<nint, string, int>(
GameData.GetSignature("ChangeSubclass")
);
subclassChangeFunc(weapon.Handle, itemD.ToString());
}
private static void UpdateWeaponMeshGroupMask(CBaseEntity weapon, bool isLegacy = false)
{
if (weapon.CBodyComponent?.SceneNode == null) return;
var skeleton = weapon.CBodyComponent.SceneNode.GetSkeletonInstance();
var value = (ulong)(isLegacy ? 2 : 1);
if (skeleton.ModelState.MeshGroupMask != value)
{
skeleton.ModelState.MeshGroupMask = value;
}
}
private static void UpdatePlayerWeaponMeshGroupMask(CCSPlayerController player, CBasePlayerWeapon weapon, bool isLegacy)
{
UpdateWeaponMeshGroupMask(weapon, isLegacy);
var viewModel = GetPlayerViewModel(player);
if (viewModel == null || viewModel.Weapon.Value == null ||
viewModel.Weapon.Value.Index != weapon.Index) return;
UpdateWeaponMeshGroupMask(viewModel, isLegacy);
Utilities.SetStateChanged(viewModel, "CBaseEntity", "m_CBodyComponent");
}
private static void GivePlayerAgent(CCSPlayerController player)
{
if (!GPlayersAgent.TryGetValue(player.Slot, out var value)) return;
var model = player.TeamNum == 3 ? value.CT : value.T;
if (string.IsNullOrEmpty(model)) return;
if (player.PlayerPawn.Value == null)
return;
try
{
Server.NextFrame(() =>
{
player.PlayerPawn.Value.SetModel(
$"characters/models/{model}.vmdl"
);
});
}
catch (Exception)
{
}
}
private static void GivePlayerMusicKit(CCSPlayerController player)
{
if (!GPlayersMusic.TryGetValue(player.Slot, out var value)) return;
if (player.InventoryServices == null) return;
player.InventoryServices.MusicID = value;
Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices");
player.MusicKitID = value;
Utilities.SetStateChanged(player, "CCSPlayerController", "m_iMusicKitID");
}
private void GiveOnItemPickup(CCSPlayerController player)
{
var pawn = player.PlayerPawn.Value;
if (pawn == null) return;
var myWeapons = pawn.WeaponServices?.MyWeapons;
if (myWeapons == null) return;
foreach (var handle in myWeapons)
{
var weapon = handle.Value;
if (weapon != null && weapon.DesignerName.Contains("knife"))
{
GivePlayerWeaponSkin(player, weapon);
}
}
}
private void UpdatePlayerEconItemId(CEconItemView econItemView)
{
var itemId = _nextItemId++;
econItemView.ItemID = itemId;
econItemView.ItemIDLow = (uint)itemId & 0xFFFFFFFF;
econItemView.ItemIDHigh = (uint)itemId >> 32;
}
private static CCSPlayerController? GetPlayerFromItemServices(CCSPlayer_ItemServices itemServices)
{
var pawn = itemServices.Pawn.Value;
if (!pawn.IsValid || !pawn.Controller.IsValid || pawn.Controller.Value == null) return null;
var player = new CCSPlayerController(pawn.Controller.Value.Handle);
return !Utility.IsPlayerValid(player) ? null : player;
}
private static unsafe CBaseViewModel? GetPlayerViewModel(CCSPlayerController player)
{
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.ViewModelServices == null) return null;
CCSPlayer_ViewModelServices viewModelServices = new(player.PlayerPawn.Value.ViewModelServices!.Handle);
var ptr = viewModelServices.Handle + Schema.GetSchemaOffset("CCSPlayer_ViewModelServices", "m_hViewModel");
var references = MemoryMarshal.CreateSpan(ref ptr, 3);
var viewModel = (CHandle<CBaseViewModel>)Activator.CreateInstance(typeof(CHandle<CBaseViewModel>), references[0])!;
return viewModel.Value == null ? null : viewModel.Value;
}
public static unsafe T[] GetFixedArray<T>(nint pointer, string @class, string member, int length) where T : CHandle<CBaseViewModel>
{
var ptr = pointer + Schema.GetSchemaOffset(@class, member);
var references = MemoryMarshal.CreateSpan(ref ptr, length);
var values = new T[length];
for (var i = 0; i < length; i++)
{
values[i] = (T)Activator.CreateInstance(typeof(T), references[i])!;
}
return values;
}
private float ViewAsFloat(uint value)
{
return BitConverter.Int32BitsToSingle((int)value);
}
}
}

View File

@@ -3,7 +3,30 @@
public class WeaponInfo
{
public int Paint { get; set; }
public int Seed { get; set; }
public int Seed { get; set; } = 0;
public float Wear { get; set; } = 0f;
public string Nametag { get; set; } = "";
public KeyChainInfo? KeyChain { get; set; }
public List<StickerInfo> Stickers { get; set; } = new List<StickerInfo>();
}
public class StickerInfo
{
public uint Id { get; set; }
public uint Schema { get; set; }
public float OffsetX { get; set; }
public float OffsetY { get; set; }
public float Wear { get; set; }
public float Scale { get; set; }
public float Rotation { get; set; }
}
public class KeyChainInfo
{
public uint Id { get; set; }
public float OffsetX { get; set; }
public float OffsetY { get; set; }
public float OffsetZ { get; set; }
public uint Seed { get; set; }
}
}

View File

@@ -1,242 +1,130 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Cvars;
using Newtonsoft.Json.Linq;
using Microsoft.Extensions.Logging;
using MySqlConnector;
namespace WeaponPaints;
[MinimumApiVersion(90)]
[MinimumApiVersion(276)]
public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig>
{
internal static readonly Dictionary<string, string> weaponList = new()
{
{"weapon_deagle", "Desert Eagle"},
{"weapon_elite", "Dual Berettas"},
{"weapon_fiveseven", "Five-SeveN"},
{"weapon_glock", "Glock-18"},
{"weapon_ak47", "AK-47"},
{"weapon_aug", "AUG"},
{"weapon_awp", "AWP"},
{"weapon_famas", "FAMAS"},
{"weapon_g3sg1", "G3SG1"},
{"weapon_galilar", "Galil AR"},
{"weapon_m249", "M249"},
{"weapon_m4a1", "M4A1"},
{"weapon_mac10", "MAC-10"},
{"weapon_p90", "P90"},
{"weapon_mp5sd", "MP5-SD"},
{"weapon_ump45", "UMP-45"},
{"weapon_xm1014", "XM1014"},
{"weapon_bizon", "PP-Bizon"},
{"weapon_mag7", "MAG-7"},
{"weapon_negev", "Negev"},
{"weapon_sawedoff", "Sawed-Off"},
{"weapon_tec9", "Tec-9"},
{"weapon_hkp2000", "P2000"},
{"weapon_mp7", "MP7"},
{"weapon_mp9", "MP9"},
{"weapon_nova", "Nova"},
{"weapon_p250", "P250"},
{"weapon_scar20", "SCAR-20"},
{"weapon_sg556", "SG 553"},
{"weapon_ssg08", "SSG 08"},
{"weapon_m4a1_silencer", "M4A1-S"},
{"weapon_usp_silencer", "USP-S"},
{"weapon_cz75a", "CZ75-Auto"},
{"weapon_revolver", "R8 Revolver"},
{ "weapon_knife", "Default Knife" },
{ "weapon_knife_m9_bayonet", "M9 Bayonet" },
{ "weapon_knife_karambit", "Karambit" },
{ "weapon_bayonet", "Bayonet" },
{ "weapon_knife_survival_bowie", "Bowie Knife" },
{ "weapon_knife_butterfly", "Butterfly Knife" },
{ "weapon_knife_falchion", "Falchion Knife" },
{ "weapon_knife_flip", "Flip Knife" },
{ "weapon_knife_gut", "Gut Knife" },
{ "weapon_knife_tactical", "Huntsman Knife" },
{ "weapon_knife_push", "Shadow Daggers" },
{ "weapon_knife_gypsy_jackknife", "Navaja Knife" },
{ "weapon_knife_stiletto", "Stiletto Knife" },
{ "weapon_knife_widowmaker", "Talon Knife" },
{ "weapon_knife_ursus", "Ursus Knife" },
{ "weapon_knife_css", "Classic Knife" },
{ "weapon_knife_cord", "Paracord Knife" },
{ "weapon_knife_canis", "Survival Knife" },
{ "weapon_knife_outdoor", "Nomad Knife" },
{ "weapon_knife_skeleton", "Skeleton Knife" }
};
internal static WeaponPaintsConfig _config = new WeaponPaintsConfig();
internal static Dictionary<int, int> g_knifePickupCount = new Dictionary<int, int>();
internal static Dictionary<int, string> g_playersKnife = new();
internal static Dictionary<int, Dictionary<int, WeaponInfo>> gPlayerWeaponsInfo = new Dictionary<int, Dictionary<int, WeaponInfo>>();
internal static List<JObject> skinsList = new List<JObject>();
internal static WeaponSynchronization? weaponSync;
//internal static List<int> g_changedKnife = new();
internal bool g_bCommandsAllowed = true;
internal Uri GlobalShareApi = new Uri("https://weaponpaints.fun/api.php");
internal int GlobalShareServerId = 0;
private DateTime[] commandCooldown = new DateTime[Server.MaxPlayers];
private string DatabaseConnectionString = string.Empty;
private CounterStrikeSharp.API.Modules.Timers.Timer? g_hTimerCheckSkinsData = null;
public static Dictionary<int, string> weaponDefindex { get; } = new Dictionary<int, string>
{
{ 1, "weapon_deagle" },
{ 2, "weapon_elite" },
{ 3, "weapon_fiveseven" },
{ 4, "weapon_glock" },
{ 7, "weapon_ak47" },
{ 8, "weapon_aug" },
{ 9, "weapon_awp" },
{ 10, "weapon_famas" },
{ 11, "weapon_g3sg1" },
{ 13, "weapon_galilar" },
{ 14, "weapon_m249" },
{ 16, "weapon_m4a1" },
{ 17, "weapon_mac10" },
{ 19, "weapon_p90" },
{ 23, "weapon_mp5sd" },
{ 24, "weapon_ump45" },
{ 25, "weapon_xm1014" },
{ 26, "weapon_bizon" },
{ 27, "weapon_mag7" },
{ 28, "weapon_negev" },
{ 29, "weapon_sawedoff" },
{ 30, "weapon_tec9" },
{ 32, "weapon_hkp2000" },
{ 33, "weapon_mp7" },
{ 34, "weapon_mp9" },
{ 35, "weapon_nova" },
{ 36, "weapon_p250" },
{ 38, "weapon_scar20" },
{ 39, "weapon_sg556" },
{ 40, "weapon_ssg08" },
{ 60, "weapon_m4a1_silencer" },
{ 61, "weapon_usp_silencer" },
{ 63, "weapon_cz75a" },
{ 64, "weapon_revolver" },
{ 500, "weapon_bayonet" },
{ 503, "weapon_knife_css" },
{ 505, "weapon_knife_flip" },
{ 506, "weapon_knife_gut" },
{ 507, "weapon_knife_karambit" },
{ 508, "weapon_knife_m9_bayonet" },
{ 509, "weapon_knife_tactical" },
{ 512, "weapon_knife_falchion" },
{ 514, "weapon_knife_survival_bowie" },
{ 515, "weapon_knife_butterfly" },
{ 516, "weapon_knife_push" },
{ 517, "weapon_knife_cord" },
{ 518, "weapon_knife_canis" },
{ 519, "weapon_knife_ursus" },
{ 520, "weapon_knife_gypsy_jackknife" },
{ 521, "weapon_knife_outdoor" },
{ 522, "weapon_knife_stiletto" },
{ 523, "weapon_knife_widowmaker" },
{ 525, "weapon_knife_skeleton" }
};
internal static WeaponPaints Instance { get; private set; } = new();
public WeaponPaintsConfig Config { get; set; } = new();
public override string ModuleAuthor => "Nereziel & daffyy";
public override string ModuleDescription => "Skin and knife selector, standalone and web-based";
private static WeaponPaintsConfig _config { get; set; } = new();
public override string ModuleAuthor => "Nereziel & daffyy";
public override string ModuleDescription => "Skin, gloves, agents and knife selector, standalone and web-based";
public override string ModuleName => "WeaponPaints";
public override string ModuleVersion => "1.3c";
public static WeaponPaintsConfig GetWeaponPaintsConfig()
{
return _config;
}
public override string ModuleVersion => "2.6a";
public override void Load(bool hotReload)
{
if (!Config.GlobalShare)
{
DatabaseConnectionString = Utility.BuildDatabaseConnectionString();
Utility.TestDatabaseConnection();
}
weaponSync = new WeaponSynchronization(DatabaseConnectionString, Config, GlobalShareApi, GlobalShareServerId);
Instance = this;
if (hotReload)
{
OnMapStart(string.Empty);
Task.Run(async () =>
{
for (int i = 1; i <= Server.MaxPlayers; i++)
{
if (Config.Additional.SkinEnabled && weaponSync != null)
await weaponSync.GetWeaponPaintsFromDatabase(i);
if (Config.Additional.KnifeEnabled && weaponSync != null)
await weaponSync.GetKnifeFromDatabase(i);
}
});
foreach (var player in Enumerable
.OfType<CCSPlayerController>(Utilities.GetPlayers().TakeWhile(player => WeaponSync != null))
.Where(player => player.IsValid &&
!string.IsNullOrEmpty(player.IpAddress) && player is
{ IsBot: false, Connected: PlayerConnectedState.PlayerConnected }))
{
GPlayerWeaponsInfo.TryRemove(player.Slot, out _);
GPlayersKnife.TryRemove(player.Slot, out _);
GPlayersGlove.TryRemove(player.Slot, out _);
GPlayersAgent.TryRemove(player.Slot, out _);
var playerInfo = new PlayerInfo
{
UserId = player.UserId,
Slot = player.Slot,
Index = (int)player.Index,
SteamId = player?.SteamID.ToString(),
Name = player?.PlayerName,
IpAddress = player?.IpAddress?.Split(":")[0]
};
_ = Task.Run(async () =>
{
if (WeaponSync != null) await WeaponSync.GetPlayerData(playerInfo);
});
}
}
Utility.LoadSkinsFromFile(ModuleDirectory + $"/data/skins_{_config.SkinsLanguage}.json", Logger);
Utility.LoadGlovesFromFile(ModuleDirectory + $"/data/gloves_{_config.SkinsLanguage}.json", Logger);
Utility.LoadAgentsFromFile(ModuleDirectory + $"/data/agents_{_config.SkinsLanguage}.json", Logger);
Utility.LoadMusicFromFile(ModuleDirectory + $"/data/music_{_config.SkinsLanguage}.json", Logger);
if (Config.Additional.KnifeEnabled)
SetupKnifeMenu();
if (Config.Additional.SkinEnabled)
SetupSkinsMenu();
if (Config.Additional.GloveEnabled)
SetupGlovesMenu();
if (Config.Additional.AgentEnabled)
SetupAgentsMenu();
if (Config.Additional.MusicEnabled)
SetupMusicMenu();
RegisterListeners();
RegisterCommands();
Utility.LoadSkinsFromFile(ModuleDirectory + "/skins.json");
}
public void OnConfigParsed(WeaponPaintsConfig config)
{
if (!config.GlobalShare)
{
if (config.DatabaseHost.Length < 1 || config.DatabaseName.Length < 1 || config.DatabaseUser.Length < 1)
{
throw new Exception("[WeaponPaints] You need to setup Database credentials in config!");
}
}
Config = config;
_config = config;
if (config.DatabaseHost.Length < 1 || config.DatabaseName.Length < 1 || config.DatabaseUser.Length < 1)
{
Logger.LogError("You need to setup Database credentials in \"configs/plugins/WeaponPaints/WeaponPaints.json\"!");
Unload(false);
return;
}
if (!File.Exists(Path.GetDirectoryName(Path.GetDirectoryName(ModuleDirectory)) + "/gamedata/weaponpaints.json"))
{
Logger.LogError("You need to upload \"weaponpaints.json\" to \"gamedata directory\"!");
Unload(false);
return;
}
var builder = new MySqlConnectionStringBuilder
{
Server = config.DatabaseHost,
UserID = config.DatabaseUser,
Password = config.DatabasePassword,
Database = config.DatabaseName,
Port = (uint)config.DatabasePort,
Pooling = true,
MaximumPoolSize = 640,
};
Database = new Database(builder.ConnectionString);
_ = Utility.CheckDatabaseTables();
_localizer = Localizer;
Utility.Config = config;
Utility.ShowAd(ModuleVersion);
Task.Run(async () => await Utility.CheckVersion(ModuleVersion, Logger));
}
public override void Unload(bool hotReload)
public override void OnAllPluginsLoaded(bool hotReload)
{
base.Unload(hotReload);
}
private void GlobalShareConnect()
{
if (!Config.GlobalShare) return;
var values = new Dictionary<string, string>
{
{ "server_address", $"{ConVar.Find("ip")!.StringValue}:{ConVar.Find("hostport")!.GetPrimitiveValue<int>().ToString()}" },
{ "server_hostname", ConVar.Find("hostname")!.StringValue }
};
using (var httpClient = new HttpClient())
try
{
httpClient.BaseAddress = GlobalShareApi;
var formContent = new FormUrlEncodedContent(values);
Task<HttpResponseMessage> responseTask = httpClient.PostAsync("", formContent);
responseTask.Wait();
HttpResponseMessage response = responseTask.Result;
if (response.IsSuccessStatusCode)
{
Task<string> responseBodyTask = response.Content.ReadAsStringAsync();
responseBodyTask.Wait();
string responseBody = responseBodyTask.Result;
GlobalShareServerId = Int32.Parse(responseBody);
}
else
{
throw new Exception("[WeaponPaints] Unable to retrieve serverid from GlobalShare!");
}
MenuApi = MenuCapability.Get();
}
catch (Exception)
{
MenuApi = null;
Logger.LogError("Error while loading required plugins");
throw;
}
Console.WriteLine("[WeaponPaints] GlobalShare ONLINE");
}
}

View File

@@ -1,16 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CounterStrikeSharp.API" Version="*" />
<PackageReference Include="Dapper" Version="2.1.24" />
<PackageReference Include="MySqlConnector" Version="2.3.1" />
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.281" />
<PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="MySqlConnector" Version="2.4.0-beta.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<None Update="lang\**\*.*" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<None Update="gamedata\*.*" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<Reference Include="MenuManagerApi">
<HintPath>3rd_party\MenuManagerApi.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=C_003A_005CUsers_005Cxdaff_005CDocuments_005CGitHub_005Ccs2_002DWeaponPaints_005C3rd_005Fparty_005CMenuManagerApi_002Edll/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -1,265 +1,353 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using Dapper;
using Dapper;
using MySqlConnector;
using Newtonsoft.Json.Linq;
using System.Collections.Concurrent;
namespace WeaponPaints
{
internal class WeaponSynchronization
{
private readonly WeaponPaintsConfig _config;
private readonly string _databaseConnectionString;
private readonly Uri _globalShareApi;
private readonly int _globalShareServerId;
private readonly Database _database;
internal WeaponSynchronization(string databaseConnectionString, WeaponPaintsConfig config, Uri globalShareApi, int globalShareServerId)
internal WeaponSynchronization(Database database, WeaponPaintsConfig config)
{
_databaseConnectionString = databaseConnectionString;
_database = database;
_config = config;
_globalShareApi = globalShareApi;
_globalShareServerId = globalShareServerId;
}
internal async Task GetKnifeFromDatabase(int playerIndex)
internal async Task GetPlayerData(PlayerInfo? player)
{
if (!_config.Additional.KnifeEnabled) return;
try
{
CCSPlayerController player = Utilities.GetPlayerFromIndex(playerIndex);
if (!Utility.IsPlayerValid(player)) return;
if (player.AuthorizedSteamID == null) return;
string steamId = player.AuthorizedSteamID.SteamId64.ToString();
await using var connection = await _database.GetConnectionAsync();
if (_config.GlobalShare)
{
var values = new Dictionary<string, string>
{
{ "server_id", _globalShareServerId.ToString() },
{ "steamid", steamId },
{ "knife", "1" }
};
UriBuilder builder = new UriBuilder(_globalShareApi);
builder.Query = string.Join("&", values.Select(p => $"{Uri.EscapeDataString(p.Key)}={Uri.EscapeDataString(p.Value)}"));
if (_config.Additional.KnifeEnabled)
GetKnifeFromDatabase(player, connection);
if (_config.Additional.GloveEnabled)
GetGloveFromDatabase(player, connection);
if (_config.Additional.AgentEnabled)
GetAgentFromDatabase(player, connection);
if (_config.Additional.MusicEnabled)
GetMusicFromDatabase(player, connection);
if (_config.Additional.SkinEnabled)
GetWeaponPaintsFromDatabase(player, connection);
}
catch (Exception ex)
{
// Log the exception or handle it appropriately
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = _globalShareApi;
var formContent = new FormUrlEncodedContent(values);
HttpResponseMessage response = await httpClient.GetAsync(builder.Uri);
if (response.IsSuccessStatusCode)
{
string result = await response.Content.ReadAsStringAsync();
if (!string.IsNullOrEmpty(result))
{
WeaponPaints.g_playersKnife[playerIndex] = result;
}
else
{
return;
}
}
else
{
return;
}
}
private void GetKnifeFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId))
return;
}
using (var connection = new MySqlConnection(_databaseConnectionString))
const string query = "SELECT `knife` FROM `wp_player_knife` WHERE `steamid` = @steamid";
var playerKnife = connection.QueryFirstOrDefault<string>(query, new { steamid = player.SteamId });
if (!string.IsNullOrEmpty(playerKnife))
{
await connection.OpenAsync();
string query = "SELECT `knife` FROM `wp_player_knife` WHERE `steamid` = @steamid";
string? PlayerKnife = await connection.QueryFirstOrDefaultAsync<string>(query, new { steamid = steamId });
if (PlayerKnife != null)
WeaponPaints.GPlayersKnife[player.Slot] = playerKnife;
}
}
catch (Exception ex)
{
Utility.Log($"An error occurred in GetKnifeFromDatabase: {ex.Message}");
}
}
private void GetGloveFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId))
return;
const string query = "SELECT `weapon_defindex` FROM `wp_player_gloves` WHERE `steamid` = @steamid";
var gloveData = connection.QueryFirstOrDefault<ushort?>(query, new { steamid = player.SteamId });
if (gloveData != null)
{
WeaponPaints.GPlayersGlove[player.Slot] = gloveData.Value;
}
}
catch (Exception ex)
{
Utility.Log($"An error occurred in GetGloveFromDatabase: {ex.Message}");
}
}
private void GetAgentFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId))
return;
const string query = "SELECT `agent_ct`, `agent_t` FROM `wp_player_agents` WHERE `steamid` = @steamid";
var agentData = connection.QueryFirstOrDefault<(string, string)>(query, new { steamid = player.SteamId });
if (agentData == default) return;
var agentCT = agentData.Item1;
var agentT = agentData.Item2;
if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT))
{
WeaponPaints.GPlayersAgent[player.Slot] = (
agentCT,
agentT
);
}
}
catch (Exception ex)
{
Utility.Log($"An error occurred in GetAgentFromDatabase: {ex.Message}");
}
}
private void GetWeaponPaintsFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.SkinEnabled || player == null || string.IsNullOrEmpty(player.SteamId))
return;
var weaponInfos = new ConcurrentDictionary<int, WeaponInfo>();
const string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid";
var playerSkins = connection.Query<dynamic>(query, new { steamid = player.SteamId });
foreach (var row in playerSkins)
{
int weaponDefIndex = row?.weapon_defindex ?? 0;
int weaponPaintId = row?.weapon_paint_id ?? 0;
float weaponWear = row?.weapon_wear ?? 0f;
int weaponSeed = row?.weapon_seed ?? 0;
string weaponNameTag = row?.weapon_nametag ?? "";
string[]? keyChainParts = row?.weapon_keychain?.ToString().Split(';');
KeyChainInfo keyChainInfo = new KeyChainInfo();
if (keyChainParts!.Length == 5 &&
uint.TryParse(keyChainParts[0], out uint keyChainId) &&
float.TryParse(keyChainParts[1], out float keyChainOffsetX) &&
float.TryParse(keyChainParts[2], out float keyChainOffsetY) &&
float.TryParse(keyChainParts[3], out float keyChainOffsetZ) &&
uint.TryParse(keyChainParts[4], out uint keyChainSeed))
{
WeaponPaints.g_playersKnife[playerIndex] = PlayerKnife;
// Successfully parsed the values
keyChainInfo.Id = keyChainId;
keyChainInfo.OffsetX = keyChainOffsetX;
keyChainInfo.OffsetY = keyChainOffsetY;
keyChainInfo.OffsetZ = keyChainOffsetZ;
keyChainInfo.Seed = keyChainSeed;
}
else
{
return;
// Failed to parse the values, default to 0
keyChainInfo.Id = 0;
keyChainInfo.OffsetX = 0f;
keyChainInfo.OffsetY = 0f;
keyChainInfo.OffsetZ = 0f;
keyChainInfo.Seed = 0;
}
await connection.CloseAsync();
// Create the WeaponInfo object
WeaponInfo weaponInfo = new WeaponInfo
{
Paint = weaponPaintId,
Seed = weaponSeed,
Wear = weaponWear,
Nametag = weaponNameTag,
KeyChain = keyChainInfo
};
// Retrieve and parse sticker data (up to 5 slots)
for (int i = 0; i <= 4; i++)
{
// Access the sticker data dynamically using reflection
string stickerColumn = $"weapon_sticker_{i}";
var stickerData = ((IDictionary<string, object>)row!)[stickerColumn]; // Safely cast row to a dictionary
if (string.IsNullOrEmpty(stickerData.ToString())) continue;
var parts = stickerData.ToString()!.Split(';');
//"id;schema;x;y;wear;scale;rotation"
if (parts.Length != 7 ||
!uint.TryParse(parts[0], out uint stickerId) ||
!uint.TryParse(parts[1], out uint stickerSchema) ||
!float.TryParse(parts[2], out float stickerOffsetX) ||
!float.TryParse(parts[3], out float stickerOffsetY) ||
!float.TryParse(parts[4], out float stickerWear) ||
!float.TryParse(parts[5], out float stickerScale) ||
!float.TryParse(parts[6], out float stickerRotation)) continue;
StickerInfo stickerInfo = new StickerInfo
{
Id = stickerId,
Schema = stickerSchema,
OffsetX = stickerOffsetX,
OffsetY = stickerOffsetY,
Wear = stickerWear,
Scale = stickerScale,
Rotation = stickerRotation
};
weaponInfo.Stickers.Add(stickerInfo);
}
weaponInfos[weaponDefIndex] = weaponInfo;
}
WeaponPaints.GPlayerWeaponsInfo[player.Slot] = weaponInfos;
}
catch (Exception e)
catch (Exception ex)
{
Utility.Log(e.Message);
return;
Utility.Log($"An error occurred in GetWeaponPaintsFromDatabase: {ex.Message}");
}
}
internal async Task GetWeaponPaintsFromDatabase(int playerIndex)
private void GetMusicFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
if (!_config.Additional.SkinEnabled) return;
CCSPlayerController player = Utilities.GetPlayerFromIndex(playerIndex);
if (!Utility.IsPlayerValid(player)) return;
if (player.AuthorizedSteamID == null) return;
string steamId = player.AuthorizedSteamID.SteamId64.ToString();
if (!WeaponPaints.gPlayerWeaponsInfo.TryGetValue(playerIndex, out _))
{
WeaponPaints.gPlayerWeaponsInfo[playerIndex] = new Dictionary<int, WeaponInfo>();
}
try
{
if (_config.GlobalShare)
if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player?.SteamId))
return;
const string query = "SELECT `music_id` FROM `wp_player_music` WHERE `steamid` = @steamid";
var musicData = connection.QueryFirstOrDefault<ushort?>(query, new { steamid = player.SteamId });
if (musicData != null)
{
var values = new Dictionary<string, string>
{
{ "server_id", _globalShareServerId.ToString() },
{ "steamid", steamId },
{ "skins", "1" }
};
UriBuilder builder = new UriBuilder(_globalShareApi);
builder.Query = string.Join("&", values.Select(p => $"{Uri.EscapeDataString(p.Key)}={Uri.EscapeDataString(p.Value)}"));
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = _globalShareApi;
var formContent = new FormUrlEncodedContent(values);
HttpResponseMessage response = await httpClient.GetAsync(builder.Uri);
if (response.IsSuccessStatusCode)
{
string responseBody = await response.Content.ReadAsStringAsync();
JArray jsonArray = JArray.Parse(responseBody);
if (jsonArray != null && jsonArray.Count > 0)
{
foreach (var weapon in jsonArray)
{
int? weaponDefIndex = weapon["weapon_defindex"]?.Value<int>();
int? weaponPaintId = weapon["weapon_paint_id"]?.Value<int>();
float? weaponWear = weapon["weapon_wear"]?.Value<float>();
int? weaponSeed = weapon["weapon_seed"]?.Value<int>();
if (weaponDefIndex != null && weaponPaintId != null && weaponWear != null && weaponSeed != null)
{
WeaponInfo weaponInfo = new WeaponInfo
{
Paint = weaponPaintId.Value,
Seed = weaponSeed.Value,
Wear = weaponWear.Value
};
WeaponPaints.gPlayerWeaponsInfo[playerIndex][weaponDefIndex.Value] = weaponInfo;
}
}
}
return;
}
else
{
return;
}
}
WeaponPaints.GPlayersMusic[player.Slot] = musicData.Value;
}
}
catch (Exception ex)
{
Utility.Log($"An error occurred in GetMusicFromDatabase: {ex.Message}");
}
}
using (var connection = new MySqlConnection(_databaseConnectionString))
internal async Task SyncKnifeToDatabase(PlayerInfo player, string knife)
{
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId) || string.IsNullOrEmpty(knife)) return;
const string query = "INSERT INTO `wp_player_knife` (`steamid`, `knife`) VALUES(@steamid, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife";
try
{
await using var connection = await _database.GetConnectionAsync();
await connection.ExecuteAsync(query, new { steamid = player.SteamId, newKnife = knife });
}
catch (Exception e)
{
Utility.Log($"Error syncing knife to database: {e.Message}");
}
}
internal async Task SyncGloveToDatabase(PlayerInfo player, int defindex)
{
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player.SteamId)) return;
try
{
await using var connection = await _database.GetConnectionAsync();
const string query = "INSERT INTO `wp_player_gloves` (`steamid`, `weapon_defindex`) VALUES(@steamid, @weapon_defindex) ON DUPLICATE KEY UPDATE `weapon_defindex` = @weapon_defindex";
await connection.ExecuteAsync(query, new { steamid = player.SteamId, weapon_defindex = defindex });
}
catch (Exception e)
{
Utility.Log($"Error syncing glove to database: {e.Message}");
}
}
internal async Task SyncAgentToDatabase(PlayerInfo player)
{
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player.SteamId)) return;
const string query = """
INSERT INTO `wp_player_agents` (`steamid`, `agent_ct`, `agent_t`)
VALUES(@steamid, @agent_ct, @agent_t)
ON DUPLICATE KEY UPDATE
`agent_ct` = @agent_ct,
`agent_t` = @agent_t
""";
try
{
await using var connection = await _database.GetConnectionAsync();
await connection.ExecuteAsync(query, new { steamid = player.SteamId, agent_ct = WeaponPaints.GPlayersAgent[player.Slot].CT, agent_t = WeaponPaints.GPlayersAgent[player.Slot].T });
}
catch (Exception e)
{
Utility.Log($"Error syncing agents to database: {e.Message}");
}
}
internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player)
{
if (string.IsNullOrEmpty(player.SteamId) || !WeaponPaints.GPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo))
return;
try
{
await using var connection = await _database.GetConnectionAsync();
foreach (var (weaponDefIndex, weaponInfo) in weaponsInfo)
{
await connection.OpenAsync();
var paintId = weaponInfo.Paint;
var wear = weaponInfo.Wear;
var seed = weaponInfo.Seed;
string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid";
IEnumerable<dynamic> PlayerSkins = await connection.QueryAsync<dynamic>(query, new { steamid = steamId });
const string queryCheckExistence = "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex";
if (PlayerSkins != null && PlayerSkins.AsList().Count > 0)
var existingRecordCount = await connection.ExecuteScalarAsync<int>(queryCheckExistence, new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex });
string query;
object parameters;
if (existingRecordCount > 0)
{
PlayerSkins.ToList().ForEach(row =>
{
int weaponDefIndex = row.weapon_defindex ?? default(int);
int weaponPaintId = row.weapon_paint_id ?? default(int);
float weaponWear = row.weapon_wear ?? default(float);
int weaponSeed = row.weapon_seed ?? default(int);
WeaponInfo weaponInfo = new WeaponInfo
{
Paint = weaponPaintId,
Seed = weaponSeed,
Wear = weaponWear
};
WeaponPaints.gPlayerWeaponsInfo[playerIndex][weaponDefIndex] = weaponInfo;
});
query = "UPDATE `wp_player_skins` SET `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex";
parameters = new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex, paintId, wear, seed };
}
else
{
return;
query = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) " +
"VALUES (@steamid, @weaponDefIndex, @paintId, @wear, @seed)";
parameters = new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex, paintId, wear, seed };
}
await connection.CloseAsync();
await connection.ExecuteAsync(query, parameters);
}
}
catch (Exception e)
{
Utility.Log(e.Message);
return;
Utility.Log($"Error syncing weapon paints to database: {e.Message}");
}
}
internal async Task SyncKnifeToDatabase(int playerIndex, string knife)
internal async Task SyncMusicToDatabase(PlayerInfo player, ushort music)
{
if (!_config.Additional.KnifeEnabled) return;
if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player.SteamId)) return;
try
{
CCSPlayerController player = Utilities.GetPlayerFromIndex(playerIndex);
if (player == null || !player.IsValid) return;
if (player.AuthorizedSteamID == null) return;
string steamId = player.AuthorizedSteamID.SteamId64.ToString();
using var connection = new MySqlConnection(_databaseConnectionString);
await connection.OpenAsync();
string query = "INSERT INTO `wp_player_knife` (`steamid`, `knife`) VALUES(@steamid, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife";
await connection.ExecuteAsync(query, new { steamid = steamId, newKnife = knife });
await connection.CloseAsync();
await using var connection = await _database.GetConnectionAsync();
const string query = "INSERT INTO `wp_player_music` (`steamid`, `music_id`) VALUES(@steamid, @newMusic) ON DUPLICATE KEY UPDATE `music_id` = @newMusic";
await connection.ExecuteAsync(query, new { steamid = player.SteamId, newMusic = music });
}
catch (Exception e)
{
Utility.Log(e.Message);
return;
Utility.Log($"Error syncing music kit to database: {e.Message}");
}
}
internal async Task SyncWeaponPaintsToDatabase(CCSPlayerController? player)
{
if (player == null || !Utility.IsPlayerValid(player)) return;
int playerIndex = (int)player.Index;
if (player.AuthorizedSteamID == null) return;
string steamId = player.AuthorizedSteamID.SteamId64.ToString();
using var connection = new MySqlConnection(_databaseConnectionString);
await connection.OpenAsync();
if (!WeaponPaints.gPlayerWeaponsInfo.ContainsKey(playerIndex))
return;
foreach (var weaponInfoPair in WeaponPaints.gPlayerWeaponsInfo[playerIndex])
{
int weaponDefIndex = weaponInfoPair.Key;
WeaponInfo weaponInfo = weaponInfoPair.Value;
int paintId = weaponInfo.Paint;
float wear = weaponInfo.Wear;
int seed = weaponInfo.Seed;
string updateSql = "UPDATE `wp_player_skins` SET `weapon_paint_id` = @paintId, " +
"`weapon_wear` = @wear, `weapon_seed` = @seed WHERE `steamid` = @steamid " +
"AND `weapon_defindex` = @weaponDefIndex";
var updateParams = new { paintId, wear, seed, steamid = steamId, weaponDefIndex };
int rowsAffected = await connection.ExecuteAsync(updateSql, updateParams);
if (rowsAffected == 0)
{
string insertSql = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, " +
"`weapon_paint_id`, `weapon_wear`, `weapon_seed`) " +
"VALUES (@steamid, @weaponDefIndex, @paintId, @wear, @seed)";
await connection.ExecuteAsync(insertSql, updateParams);
}
}
await connection.CloseAsync();
}
}
}

View File

@@ -0,0 +1,23 @@
{
"ChangeSubclass": {
"signatures": {
"library": "server",
"windows": "48 89 6C 24 ? 56 48 83 EC ? 48 8B EA 48 8B F1 E8 ? ? ? ? 84 C0 0F 84",
"linux": "55 48 89 E5 41 57 41 56 41 55 49 89 F5 41 54 49 89 FC 53 48 81 EC A8 00 00 00"
}
},
"CAttributeList_SetOrAddAttributeValueByName": {
"signatures": {
"library": "server",
"windows": "40 53 41 56 41 57 48 81 EC 90 00 00 00 0F 29 74 24 70",
"linux": "55 48 89 E5 41 57 41 56 49 89 FE 41 55 41 54 49 89 F4 53 48 83 EC 78"
}
},
"CBaseModelEntity_SetBodygroup": {
"signatures": {
"library": "server",
"windows": "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 41 8B F8 48 8B F2 48 8B D9 E8 ? ? ? ?",
"linux": "55 48 89 E5 41 56 49 89 F6 41 55 41 89 D5 41 54 49 89 FC 48 83 EC 08"
}
}
}

25
lang/en.json Normal file
View File

@@ -0,0 +1,25 @@
{
"wp_prefix": "{lightblue}[WeaponPaints] {default}",
"wp_info_website": "Visit {lime}{0}{default} where you can change skins",
"wp_info_refresh": "Type {lime}!wp{default} to synchronize chosen skins",
"wp_info_knife": "Type {lime}!knife{default} to open knife menu",
"wp_info_glove": "Type {lime}!gloves{default} to open gloves menu",
"wp_info_agent": "Type {lime}!agents{default} to open agents menu",
"wp_info_music": "Type {lime}!music{default} to open music menu",
"wp_command_cooldown": "{lightred}You can't refresh weapon paints right now",
"wp_command_refresh_done": "{lime}Refreshing weapon paints",
"wp_knife_menu_select": "You have chosen {lime}{0}{default} as your knife",
"wp_knife_menu_kill": "",
"wp_knife_menu_title": "Knife Menu",
"wp_glove_menu_select": "You have chosen {lime}{0}{default} as your glove",
"wp_glove_menu_title": "Gloves Menu",
"wp_agent_menu_select": "You have chosen {lime}{0}{default} as your agent",
"wp_agent_menu_title": "Agents Menu",
"wp_music_menu_title": "Music Menu",
"wp_music_menu_select": "You have chosen {lime}{0}{default} as your music kit",
"wp_skin_menu_weapon_title": "Weapon Menu",
"wp_skin_menu_skin_title": "Select skin for {lime}{0}{default}",
"wp_skin_menu_select": "You have chosen {lime}{0}{default} as your skin",
"None": "None"
}

25
lang/lv.json Normal file
View File

@@ -0,0 +1,25 @@
{
"wp_prefix": "{lightblue}[WeaponPaints] {default}",
"wp_info_website": "Apmeklē {lime}{0}{default}, kur varat mainīt ādas",
"wp_info_refresh": "Ievadiet {lime}!wp{default}, lai sinhronizētu izvēlētās ādas",
"wp_info_knife": "Ievadiet {lime}!knife{default}, lai atvērtu nazis izvēlni",
"wp_info_glove": "Ievadiet {lime}!gloves{default}, lai atvērtu cimdi izvēlni",
"wp_info_agent": "Ievadiet {lime}!agents{default}, lai atvērtu aģentu izvēlni",
"wp_info_music": "Ievadiet {lime}!music{default}, lai atvērtu mūzikas izvēlni",
"wp_command_cooldown": "{lightred}Šobrīd nevarat atsvaidzināt ieroča krāsas",
"wp_command_refresh_done": "{lime}Atsvaidzinot ieroča krāsas",
"wp_knife_menu_select": "Jūs esat izvēlējies {lime}{0}{default} kā savu nazi",
"wp_knife_menu_kill": "",
"wp_knife_menu_title": "Nazi Izvēlne",
"wp_glove_menu_select": "Jūs esat izvēlējies {lime}{0}{default} kā savu cimdu",
"wp_glove_menu_title": "Cimdu Izvēlne",
"wp_agent_menu_select": "Jūs esat izvēlējies {lime}{0}{default} kā savu aģentu",
"wp_agent_menu_title": "Aģentu Izvēlne",
"wp_music_menu_title": "Mūzikas Izvēlne",
"wp_music_menu_select": "Jūs esat izvēlējies {lime}{0}{default} kā savu mūzikas komplektu",
"wp_skin_menu_weapon_title": "Ieroču Izvēlne",
"wp_skin_menu_skin_title": "Izvēlieties ādu priekš {lime}{0}{default}",
"wp_skin_menu_select": "Jūs esat izvēlējies {lime}{0}{default} kā savu ādu",
"None": "Nav"
}

25
lang/pl.json Normal file
View File

@@ -0,0 +1,25 @@
{
"wp_prefix": "{lightblue}[WeaponPaints] {default}",
"wp_info_website": "Odwiedź {lime}{0}{default}, gdzie możesz zmieniać skórki",
"wp_info_refresh": "Wpisz {lime}!wp{default}, aby zsynchronizować wybrane skórki",
"wp_info_knife": "Wpisz {lime}!knife{default}, aby otworzyć menu noży",
"wp_info_glove": "Wpisz {lime}!gloves{default}, aby otworzyć menu rękawic",
"wp_info_agent": "Wpisz {lime}!agents{default}, aby otworzyć menu agentów",
"wp_info_music": "Wpisz {lime}!music{default}, aby otworzyć menu muzyczne",
"wp_command_cooldown": "{lightred}Nie możesz teraz odświeżyć kolorów broni",
"wp_command_refresh_done": "{lime}Odświeżanie kolorów broni",
"wp_knife_menu_select": "Wybrałeś {lime}{0}{default} jako swój nóż",
"wp_knife_menu_kill": "",
"wp_knife_menu_title": "Menu Noży",
"wp_glove_menu_select": "Wybrałeś {lime}{0}{default} jako swoją rękawiczkę",
"wp_glove_menu_title": "Menu Rękawiczek",
"wp_agent_menu_select": "Wybrałeś {lime}{0}{default} jako swojego agenta",
"wp_agent_menu_title": "Menu Agentów",
"wp_music_menu_title": "Menu Muzyczne",
"wp_music_menu_select": "Wybrałeś {lime}{0}{default} jako swój zestaw muzyczny",
"wp_skin_menu_weapon_title": "Menu Broni",
"wp_skin_menu_skin_title": "Wybierz skórkę dla {lime}{0}{default}",
"wp_skin_menu_select": "Wybrałeś {lime}{0}{default} jako swoją skórkę",
"None": "Brak"
}

25
lang/pt-BR.json Normal file
View File

@@ -0,0 +1,25 @@
{
"wp_prefix": "{lightblue}[WeaponPaints] {default}",
"wp_info_website": "Visite {lime}{0}{default}, onde você pode alterar as skins",
"wp_info_refresh": "Digite {lime}!wp{default} para sincronizar as skins escolhidas",
"wp_info_knife": "Digite {lime}!knife{default} para abrir o menu de facas",
"wp_info_glove": "Digite {lime}!gloves{default} para abrir o menu de luvas",
"wp_info_agent": "Digite {lime}!agents{default} para abrir o menu de agentes",
"wp_info_music": "Digite {lime}!music{default} para abrir o menu de música",
"wp_command_cooldown": "{lightred}Você não pode atualizar as skins de armas agora",
"wp_command_refresh_done": "{lime}Atualizando as skins de armas",
"wp_knife_menu_select": "Você escolheu {lime}{0}{default} como sua faca",
"wp_knife_menu_kill": "",
"wp_knife_menu_title": "Menu de Facas",
"wp_glove_menu_select": "Você escolheu {lime}{0}{default} como sua luva",
"wp_glove_menu_title": "Menu de Luvas",
"wp_agent_menu_select": "Você escolheu {lime}{0}{default} como seu agente",
"wp_agent_menu_title": "Menu de Agentes",
"wp_music_menu_title": "Menu de Música",
"wp_music_menu_select": "Você escolheu {lime}{0}{default} como seu kit de música",
"wp_skin_menu_weapon_title": "Menu de Armas",
"wp_skin_menu_skin_title": "Selecione a skin para {lime}{0}{default}",
"wp_skin_menu_select": "Você escolheu {lime}{0}{default} como sua skin",
"None": "Nenhum"
}

25
lang/pt-PT.json Normal file
View File

@@ -0,0 +1,25 @@
{
"wp_prefix": "{lightblue}[WeaponPaints] {default}",
"wp_info_website": "Visite {lime}{0}{default}, onde pode alterar as skins",
"wp_info_refresh": "Digite {lime}!wp{default} para sincronizar as skins escolhidas",
"wp_info_knife": "Digite {lime}!knife{default} para abrir o menu de facas",
"wp_info_glove": "Digite {lime}!gloves{default} para abrir o menu de luvas",
"wp_info_agent": "Digite {lime}!agents{default} para abrir o menu de agentes",
"wp_info_music": "Digite {lime}!music{default} para abrir o menu de música",
"wp_command_cooldown": "{lightred}Não pode atualizar as skins de armas de momento",
"wp_command_refresh_done": "{lime}Atualizando as skins de armas",
"wp_knife_menu_select": "Escolheu {lime}{0}{default} como a sua faca",
"wp_knife_menu_kill": "",
"wp_knife_menu_title": "Menu de Facas",
"wp_glove_menu_select": "Escolheu {lime}{0}{default} como a sua luva",
"wp_glove_menu_title": "Menu de Luvas",
"wp_agent_menu_select": "Escolheu {lime}{0}{default} como o seu agente",
"wp_agent_menu_title": "Menu de Agentes",
"wp_music_menu_title": "Menu de Música",
"wp_music_menu_select": "Escolheu {lime}{0}{default} como o seu kit de música",
"wp_skin_menu_weapon_title": "Menu de Armas",
"wp_skin_menu_skin_title": "Selecione a skin para {lime}{0}{default}",
"wp_skin_menu_select": "Escolheu {lime}{0}{default} como a sua skin",
"None": "Nenhum"
}

25
lang/ru.json Normal file
View File

@@ -0,0 +1,25 @@
{
"wp_prefix": "{lightblue}[WeaponPaints] {default}",
"wp_info_website": "Посетите {lime}{0}{default}, где вы можете изменить скины",
"wp_info_refresh": "Введите {lime}!wp{default}, чтобы синхронизировать выбранные скины",
"wp_info_knife": "Введите {lime}!knife{default}, чтобы открыть меню ножей",
"wp_info_glove": "Введите {lime}!gloves{default}, чтобы открыть меню перчаток",
"wp_info_agent": "Введите {lime}!agents{default}, чтобы открыть меню агентов",
"wp_info_music": "Введите {lime}!music{default}, чтобы открыть меню музыки",
"wp_command_cooldown": "{lightred}Вы не можете обновить раскраску оружия сейчас",
"wp_command_refresh_done": "{lime}Обновление раскраски оружия",
"wp_knife_menu_select": "Вы выбрали {lime}{0}{default} в качестве вашего ножа",
"wp_knife_menu_kill": "",
"wp_knife_menu_title": "Меню Ножей",
"wp_glove_menu_select": "Вы выбрали {lime}{0}{default} в качестве ваших перчаток",
"wp_glove_menu_title": "Меню Перчаток",
"wp_agent_menu_select": "Вы выбрали {lime}{0}{default} в качестве вашего агента",
"wp_agent_menu_title": "Меню Агентов",
"wp_music_menu_title": "Меню Музыки",
"wp_music_menu_select": "Вы выбрали {lime}{0}{default} в качестве вашего музыкального набора",
"wp_skin_menu_weapon_title": "Меню Оружия",
"wp_skin_menu_skin_title": "Выберите скин для {lime}{0}{default}",
"wp_skin_menu_select": "Вы выбрали {lime}{0}{default} в качестве вашего скина",
"None": "Нет"
}

25
lang/tr.json Normal file
View File

@@ -0,0 +1,25 @@
{
"wp_prefix": "{lightblue}[WeaponPaints] {default}",
"wp_info_website": "Ziyaret edin {lime}{0}{default}, nerede derileri değiştirebilirsiniz",
"wp_info_refresh": "Senkronize etmek için {lime}!wp{default} yazın seçilen deriler",
"wp_info_knife": "Bıçak menüsünü açmak için {lime}!knife{default} yazın",
"wp_info_glove": "Handskar menüsünü açmak için {lime}!gloves{default} yazın",
"wp_info_agent": "Ajan menüsünü açmak için {lime}!agents{default} yazın",
"wp_info_music": "Müzik menüsünü açmak için {lime}!music{default} yazın",
"wp_command_cooldown": "{lightred}Şu anda silah boyalarını yenileyemezsiniz",
"wp_command_refresh_done": "{lime}Silah boyaları yenileniyor",
"wp_knife_menu_select": "{lime}{0}{default} olarak bıçağınızı seçtiniz",
"wp_knife_menu_kill": "",
"wp_knife_menu_title": "Bıçak Menüsü",
"wp_glove_menu_select": "{lime}{0}{default} olarak eldiveninizi seçtiniz",
"wp_glove_menu_title": "Eldiven Menüsü",
"wp_agent_menu_select": "{lime}{0}{default} olarak ajanınızı seçtiniz",
"wp_agent_menu_title": "Ajanlar Menüsü",
"wp_music_menu_title": "Müzik Menüsü",
"wp_music_menu_select": "{lime}{0}{default} olarak müzik setinizi seçtiniz",
"wp_skin_menu_weapon_title": "Silah Menüsü",
"wp_skin_menu_skin_title": "{lime}{0}{default} için cilt seçin",
"wp_skin_menu_select": "{lime}{0}{default} olarak cildinizi seçtiniz",
"None": "Hiçbiri"
}

25
lang/ua.json Normal file
View File

@@ -0,0 +1,25 @@
{
"wp_prefix": "{lightblue}[WeaponPaints] {default}",
"wp_info_website": "Відвідайте {lime}{0}{default}, де ви можете змінити шкури",
"wp_info_refresh": "Введіть {lime}!wp{default}, щоб синхронізувати обрані шкури",
"wp_info_knife": "Введіть {lime}!knife{default}, щоб відкрити меню ножів",
"wp_info_glove": "Введіть {lime}!gloves{default}, щоб відкрити меню рукавичок",
"wp_info_agent": "Введіть {lime}!agents{default}, щоб відкрити меню агентів",
"wp_info_music": "Введіть {lime}!music{default}, щоб відкрити меню музики",
"wp_command_cooldown": "{lightred}Ви не можете оновити фарби зброї зараз",
"wp_command_refresh_done": "{lime}Оновлення фарби зброї",
"wp_knife_menu_select": "Ви обрали {lime}{0}{default} як свій ніж",
"wp_knife_menu_kill": "",
"wp_knife_menu_title": "Меню Ножів",
"wp_glove_menu_select": "Ви обрали {lime}{0}{default} як свої рукавички",
"wp_glove_menu_title": "Меню Рукавичок",
"wp_agent_menu_select": "Ви обрали {lime}{0}{default} як свого агента",
"wp_agent_menu_title": "Меню Агентів",
"wp_music_menu_title": "Меню Музики",
"wp_music_menu_select": "Ви обрали {lime}{0}{default} як свій набір музики",
"wp_skin_menu_weapon_title": "Меню Зброї",
"wp_skin_menu_skin_title": "Виберіть шкіру для {lime}{0}{default}",
"wp_skin_menu_select": "Ви обрали {lime}{0}{default} як свою шкіру",
"None": "Немає"
}

25
lang/zh-cn.json Normal file
View File

@@ -0,0 +1,25 @@
{
"wp_prefix": "{lightblue}[WeaponPaints] {default}",
"wp_info_website": "访问 {lime}{0}{default},您可以更改皮肤",
"wp_info_refresh": "输入 {lime}!wp{default} 同步选择的皮肤",
"wp_info_knife": "输入 {lime}!knife{default} 打开刀具菜单",
"wp_info_glove": "输入 {lime}!gloves{default} 打开手套菜单",
"wp_info_agent": "输入 {lime}!agents{default} 打开代理菜单",
"wp_info_music": "输入 {lime}!music{default} 打开音乐菜单",
"wp_command_cooldown": "{lightred}您现在无法刷新武器涂装",
"wp_command_refresh_done": "{lime}正在刷新武器涂装",
"wp_knife_menu_select": "您选择了 {lime}{0}{default} 作为您的刀具",
"wp_knife_menu_kill": "",
"wp_knife_menu_title": "刀具菜单",
"wp_glove_menu_select": "您选择了 {lime}{0}{default} 作为您的手套",
"wp_glove_menu_title": "手套菜单",
"wp_agent_menu_select": "您选择了 {lime}{0}{default} 作为您的代理",
"wp_agent_menu_title": "代理菜单",
"wp_music_menu_title": "音乐菜单",
"wp_music_menu_select": "您选择了 {lime}{0}{default} 作为您的音乐包",
"wp_skin_menu_weapon_title": "武器菜单",
"wp_skin_menu_skin_title": "选择 {lime}{0}{default} 的皮肤",
"wp_skin_menu_select": "您选择了 {lime}{0}{default} 作为您的皮肤",
"None": "无"
}

View File

@@ -5,6 +5,8 @@ define('DB_NAME', '');
define('DB_USER', '');
define('DB_PASS', '');
define('WEB_STYLE_DARK', true);
define('STEAM_API_KEY', '');
define('STEAM_DOMAIN_NAME', '');
define('STEAM_LOGOUT_PAGE', '');

View File

@@ -4,7 +4,14 @@ class DataBase {
private $PDO;
public function __construct() {
$this->PDO = new PDO("mysql:host=".DB_HOST."; port=".DB_PORT."; dbname=".DB_NAME, DB_USER, DB_PASS, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
try {
$this->PDO = new PDO("mysql:host=".DB_HOST."; port=".DB_PORT."; dbname=".DB_NAME, DB_USER, DB_PASS, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
}
catch(PDOException $ex)
{
echo "<div style='display: flex; flex-direction: column;align-items: center;justify-content: center;text-align: center;'><h2>Problem with database!</h2>";
die("<pre style='padding: 10px;text-wrap: balance; border: 2px solid #ed6bd3;background: #252525; color: #ed6bd3; width: 50%;'>" . $ex . "</pre>");
}
}
public function select($query, $bindings = []) {
$STH = $this->PDO->prepare($query);

View File

@@ -62,7 +62,8 @@ class UtilsClass
521,
522,
523,
525
525,
526
])
)
continue;
@@ -88,7 +89,11 @@ class UtilsClass
$selected = [];
foreach ($temp as $weapon) {
$selected[$weapon['weapon_defindex']] = $weapon['weapon_paint_id'];
$selected[$weapon['weapon_defindex']] = [
'weapon_paint_id' => $weapon['weapon_paint_id'],
'weapon_seed' => $weapon['weapon_seed'],
'weapon_wear' => $weapon['weapon_wear'],
];
}
return $selected;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -0,0 +1 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More