mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-06 08:03:12 -08:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9071d51ecd | ||
|
|
0a32962f4a | ||
|
|
271705b377 | ||
|
|
cdcddbb5f3 | ||
|
|
91f51d0c5c | ||
|
|
e97f804294 | ||
|
|
4f805b18e2 | ||
|
|
e1f9b5635e | ||
|
|
59bff4f500 | ||
|
|
a2581d8e91 | ||
|
|
e7d190a6f7 | ||
|
|
5513d5710a | ||
|
|
e5c223699c | ||
|
|
fa37c222d9 | ||
|
|
3b633fafc7 | ||
|
|
765c56a38a | ||
|
|
204850fb55 | ||
|
|
bac31b9190 | ||
|
|
289f95a6b7 | ||
|
|
7b45a884d4 | ||
|
|
6ea6d0a22d | ||
|
|
12523455c0 | ||
|
|
db63fdc00c | ||
|
|
57747f2e1c | ||
|
|
66b5f77a2d | ||
|
|
8dbcb6d531 | ||
|
|
2f0d34b271 | ||
|
|
2a59544fbc | ||
|
|
f80f2ae949 | ||
|
|
f68a0abc61 | ||
|
|
a07dd9d7d4 | ||
|
|
d527038fba | ||
|
|
ca85922270 | ||
|
|
b837479f98 | ||
|
|
1e42f72655 | ||
|
|
1ad1828e30 | ||
|
|
563a5d7b3a | ||
|
|
983b673b4c | ||
|
|
74fd0e0832 | ||
|
|
44e3f2240c | ||
|
|
8af219e7a8 | ||
|
|
bff04e7795 | ||
|
|
d495ac6230 | ||
|
|
f78abf0c81 | ||
|
|
bcacc42d0e | ||
|
|
8235d5e728 | ||
|
|
56739356d5 | ||
|
|
aaba87551d | ||
|
|
a3466dd5d1 | ||
|
|
c8604760f2 | ||
|
|
d50a945317 |
10
.github/workflows/cmake-single-platform.yml
vendored
10
.github/workflows/cmake-single-platform.yml
vendored
@@ -196,6 +196,7 @@ jobs:
|
||||
(cd build/windows && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip *)
|
||||
|
||||
- name: Release
|
||||
id: release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: v${{ needs.build_managed.outputs.buildnumber }}
|
||||
@@ -208,4 +209,11 @@ jobs:
|
||||
- name: Publish NuGet package
|
||||
run: |
|
||||
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.build_managed.outputs.buildnumber }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.build_managed.outputs.buildnumber }}.snupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.build_managed.outputs.buildnumber }}.snupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
|
||||
- name: Send Notification to Discord
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
uses: Ilshidur/action-discord@0.3.2
|
||||
with:
|
||||
args: "A new release of CS# has been tagged (v${{ needs.build_managed.outputs.buildnumber }}) at ${{ steps.release.outputs.url }}"
|
||||
@@ -22,6 +22,22 @@ saul/demofile-net, https://github.com/saul/demofile-net/blob/main/LICENSE:
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
neverlosecc/source2gen, https://github.com/neverlosecc/source2gen
|
||||
source2gen - Source2 games SDK generator
|
||||
Copyright 2023 neverlosecc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Source2ZE/CS2Fixes:
|
||||
alliedmodders/sourcemod:
|
||||
Source-Python-Dev-Team/Source.Python:
|
||||
|
||||
@@ -18,6 +18,7 @@ SET(SOURCE_FILES
|
||||
src/mm_plugin.h
|
||||
libraries/hl2sdk-cs2/tier1/convar.cpp
|
||||
libraries/hl2sdk-cs2/tier1/generichash.cpp
|
||||
libraries/hl2sdk-cs2/entity2/entityidentity.cpp
|
||||
libraries/hl2sdk-cs2/entity2/entitysystem.cpp
|
||||
libraries/dotnet/hostfxr.h
|
||||
libraries/dotnet/coreclr_delegates.h
|
||||
@@ -75,6 +76,7 @@ SET(SOURCE_FILES
|
||||
src/scripting/natives/natives_memory.cpp
|
||||
src/scripting/natives/natives_schema.cpp
|
||||
src/scripting/natives/natives_entities.cpp
|
||||
src/scripting/natives/natives_voice.cpp
|
||||
src/core/managers/entity_manager.cpp
|
||||
src/core/managers/entity_manager.h
|
||||
src/core/managers/chat_manager.cpp
|
||||
@@ -83,6 +85,8 @@ SET(SOURCE_FILES
|
||||
src/core/managers/server_manager.h
|
||||
src/scripting/natives/natives_server.cpp
|
||||
libraries/nlohmann/json.hpp
|
||||
src/core/managers/voice_manager.cpp
|
||||
src/core/managers/voice_manager.h
|
||||
src/scripting/natives/natives_dynamichooks.cpp
|
||||
)
|
||||
|
||||
|
||||
1
CODEOWNERS
Normal file
1
CODEOWNERS
Normal file
@@ -0,0 +1 @@
|
||||
* @roflmuffin
|
||||
@@ -14,7 +14,7 @@ Due to the architectural changes of CS2, the plugin is being rebuilt on the grou
|
||||
|
||||
Download the latest build from [here](https://github.com/roflmuffin/CounterStrikeSharp/releases). (Download the with runtime version if this is your first time installing).
|
||||
|
||||
Detailed installation instructions can be found in the [docs](https://docs.cssharp.dev/guides/getting-started/).
|
||||
Detailed installation instructions can be found in the [docs](https://docs.cssharp.dev/docs/guides/getting-started.html).
|
||||
|
||||
## What works?
|
||||
|
||||
@@ -43,7 +43,7 @@ These features are the core of the platform and work pretty well/have a low risk
|
||||
- [Read the docs](https://docs.cssharp.dev/): Getting started guide, hello world plugin example
|
||||
- [Issue tracker](https://github.com/roflmuffin/CounterStrikeSharp/issues): Raise any issues here
|
||||
- [Builds](https://github.com/roflmuffin/CounterStrikeSharp/actions): Download latest unstable dev snapshot
|
||||
- [Install Docs](https://docs.cssharp.dev/guides/getting-started/): Installation instructions
|
||||
- [Install Docs](https://docs.cssharp.dev/docs/guides/getting-started.html): Installation instructions
|
||||
- [Example Plugin](managed/TestPlugin/TestPlugin.cs): Test plugin with basic functionality
|
||||
|
||||
## Examples
|
||||
@@ -91,8 +91,8 @@ public class HelloWorldPlugin : BasePlugin
|
||||
|
||||
## Credits
|
||||
|
||||
A lot of code has been borrowed from SourceMod as well as Source.Python, two pioneering source engine plugin frameworks which this project lends a lot of its credit to.
|
||||
I've also used the scripting context & native system that is implemented in FiveM for GTA5. Also shoutout to the [CS2Fixes](https://github.com/Source2ZE/CS2Fixes) project for providing good reverse-engineering information so shortly after CS2 release.
|
||||
A lot of code has been borrowed from [SourceMod](https://github.com/alliedmodders/sourcemod) as well as [Source.Python](https://github.com/Source-Python-Dev-Team/Source.Python), two pioneering source engine plugin frameworks which this project lends a lot of its credit to.
|
||||
I've also used the scripting context & native system that is implemented in [FiveM](https://github.com/citizenfx/fivem) for GTA5. Also shoutout to the [CS2Fixes](https://github.com/Source2ZE/CS2Fixes) project for providing good reverse-engineering information so shortly after CS2 release.
|
||||
|
||||
## How to Build
|
||||
|
||||
@@ -128,3 +128,4 @@ Build
|
||||
```bash
|
||||
cmake --build . --config Debug
|
||||
```
|
||||
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
"PublicChatTrigger": [ "!" ],
|
||||
"SilentChatTrigger": [ "/" ],
|
||||
"FollowCS2ServerGuidelines": true,
|
||||
"PluginHotReloadEnabled": true
|
||||
"PluginHotReloadEnabled": true,
|
||||
"ServerLanguage": "en"
|
||||
}
|
||||
@@ -28,8 +28,8 @@
|
||||
},
|
||||
"CCSPlayerController_Respawn": {
|
||||
"offsets": {
|
||||
"windows": 241,
|
||||
"linux": 243
|
||||
"windows": 242,
|
||||
"linux": 244
|
||||
}
|
||||
},
|
||||
"CCSPlayerPawn_Respawn": {
|
||||
@@ -74,6 +74,13 @@
|
||||
"linux": "\\x55\\x48\\x89\\xF2\\x48\\x89\\xE5\\x41\\x54\\x49\\x89\\xFC\\x48\\x8D\\x2A\\x2A\\x48\\x83\\x2A\\x2A\\x2A\\x8D\\x05\\x2A\\x2A\\x2A\\x00\\x48\\x8B\\x30\\x48\\x8B\\x06\\xFF\\x2A\\x2A\\x48\\x8B\\x45\\x2A\\x48\\x8D\\x2A\\x2A\\x4C\\x89\\x2A\\x48\\x89\\x45\\x2A\\x2A\\x68\\xFC"
|
||||
}
|
||||
},
|
||||
"CCSPlayer_WeaponServices_CanUse": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "\\x48\\x89\\x5C\\x24\\x10\\x48\\x89\\x6C\\x24\\x18\\x56\\x57\\x41\\x56\\x48\\x83\\xEC\\x30\\x80\\xB9\\xA8\\x00\\x00\\x00\\x00",
|
||||
"linux": "\\x48\\x85\\xF6\\x0F\\x84\\x2A\\x2A\\x2A\\x2A\\x55\\x31\\xC9\\x48\\x89\\xE5\\x41\\x55\\x49\\x89\\xFD"
|
||||
}
|
||||
},
|
||||
"CCSPlayer_ItemServices_DropActivePlayerWeapon": {
|
||||
"offsets": {
|
||||
"windows": 18,
|
||||
@@ -82,7 +89,7 @@
|
||||
},
|
||||
"CCSPlayer_ItemServices_RemoveWeapons": {
|
||||
"offsets": {
|
||||
"windows": 21,
|
||||
"windows": 19,
|
||||
"linux": 20
|
||||
}
|
||||
},
|
||||
@@ -113,6 +120,13 @@
|
||||
"linux": "\\x48\\x85\\xFF\\x74\\x4B\\x55\\x48\\x89\\xE5\\x41\\x56"
|
||||
}
|
||||
},
|
||||
"CEntityInstance_AcceptInput": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "\\x48\\x89\\x5C\\x24\\x10\\x48\\x89\\x74\\x24\\x18\\x57\\x48\\x83\\xEC\\x40\\x49\\x8B\\xF0",
|
||||
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x49\\x89\\xFF\\x41\\x56\\x48\\x8D\\x7D\\xC0"
|
||||
}
|
||||
},
|
||||
"LegacyGameEventListener": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
@@ -122,14 +136,21 @@
|
||||
},
|
||||
"CBasePlayerPawn_CommitSuicide": {
|
||||
"offsets": {
|
||||
"windows": 356,
|
||||
"linux": 356
|
||||
"windows": 357,
|
||||
"linux": 357
|
||||
}
|
||||
},
|
||||
"CBasePlayerPawn_RemovePlayerItem": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"linux": "\\x55\\x48\\x89\\x2A\\x41\\x2A\\x49\\x89\\x2A\\x41\\x2A\\x49\\x89\\x2A\\xE8\\x2A\\x2A\\x2A\\x2A\\x49\\x39",
|
||||
"windows": "\\x48\\x85\\xD2\\x0F\\x84\\x2A\\x2A\\x2A\\x2A\\x48\\x89\\x5C\\x24\\x08\\x57\\x48\\x83\\xEC\\x30\\x48\\x8B\\xDA"
|
||||
}
|
||||
},
|
||||
"CBaseEntity_Teleport": {
|
||||
"offsets": {
|
||||
"windows": 148,
|
||||
"linux": 147
|
||||
"windows": 149,
|
||||
"linux": 148
|
||||
}
|
||||
},
|
||||
"CBaseEntity_TakeDamageOld": {
|
||||
@@ -153,6 +174,20 @@
|
||||
"linux": "\\x55\\xBA\\xFF\\xFF\\xFF\\xFF\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x49"
|
||||
}
|
||||
},
|
||||
"StateChanged": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "\\x40\\x55\\x53\\x56\\x41\\x55\\x41\\x57\\x48\\x8D\\x6C\\x24\\xB0",
|
||||
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x41\\x54\\x53\\x89\\xD3"
|
||||
}
|
||||
},
|
||||
"NetworkStateChanged": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "\\x4C\\x8B\\xC9\\x48\\x8B\\x09\\x48\\x85\\xC9\\x74\\x2A\\x48\\x8B\\x41\\x10",
|
||||
"linux": "\\x4C\\x8B\\x07\\x4D\\x85\\xC0\\x74\\x2A\\x49\\x8B\\x40\\x10"
|
||||
}
|
||||
},
|
||||
"GameEntitySystem": {
|
||||
"offsets": {
|
||||
"windows": 88,
|
||||
|
||||
@@ -5,31 +5,52 @@ description: How to get started installing & using CounterStrikeSharp.
|
||||
|
||||
# Getting Started
|
||||
|
||||
How to get started installing & using CounterStrikeSharp.
|
||||
In this guide you will learn how to install CounterStrikeSharp onto your vanilla Counter-Strike 2 server. `CounterStrikeSharp` uses `Metamod:Source` as its main way of communicating with the game server, so both frameworks will need to be installed.
|
||||
|
||||
If you're more of a visual person, here is a <a href="https://www.youtube.com/watch?v=FlsKzStHJuY" target="_blank">Youtube video</a> that covers everything.
|
||||
|
||||
## Prerequisites
|
||||
- <a href="https://www.sourcemm.net/downloads.php/?branch=master" target="_blank">Metamod: Source 2.X Dev Build</a>
|
||||
- <a href="https://github.com/roflmuffin/CounterStrikeSharp/releases" target="_blank">CounterStrikeSharp With Runtime</a>
|
||||
|
||||
## Installing Metamod
|
||||
|
||||
`CounterStrikeSharp` uses `Metamod:Source` as its main way of communicating with the game server. To install it, you can follow the detailed instructions found <a href="https://cs2.poggu.me/metamod/installation/" target="_blank">here</a>.
|
||||
1. Extract Metamod and copy the `/addons/` directory to `/game/csgo/`.
|
||||
2. Inside `/game/csgo/`, locate `gameinfo.gi`.
|
||||
3. Create a new line underneath `Game_LowViolence csgo_lv` and add `Game csgo/addons/metamod`.
|
||||
4. Restart your game server.
|
||||
|
||||
Your `gameinfo.gi` should look like <a href="../../images/gameinfogi-example.png" target="_blank">this</a>. Type `meta list` in your server console to see if Metamod is loaded.
|
||||
|
||||
## Installing CounterStrikeSharp
|
||||
|
||||
Download the latest release of CounterStrikeSharp from <a href="https://github.com/roflmuffin/CounterStrikeSharp/actions/workflows/cmake-single-platform.yml" target="_blank">GitHub actions build pages</a> (just choose the latest development snapshot). **You may need to be logged into GitHub to gain access to the downloads**.
|
||||
1. Extract CounterStrikeSharp and copy the `/addons/` directory to `/game/csgo/`.
|
||||
2. Restart your game server.
|
||||
|
||||
Running the command `meta list` in the console should show 1 plugin loaded 🎉
|
||||
|
||||
```shell
|
||||
meta list
|
||||
Listing 1 plugin:
|
||||
[01] CounterStrikeSharp (0.1.0) by Roflmuffin
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> If this is your first time installing, you will need to download the `with-runtime` version. This includes a copy of the .NET runtime, which is required to run the plugin.
|
||||
> Depending on the os you might also either need to install `libicu` / `icu-libs` / `libicu-dev` using your package manager for .NET to run or setting `DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true` in your servers environment variables. You can find more infos about that <a href="https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md#enabling-the-invariant-mode" target="_blank">here</a>
|
||||
>
|
||||
> Subsequent upgrades will not require the runtime, unless a version bump of the .NET runtime is required (i.e. from 7.0.x to 8.0.x). We will inform you when this occurs.
|
||||
> For Windows servers, you must have <a href="https://aka.ms/vs/17/release/vc_redist.x64.exe" target="_blank">Visual Studio Redistributables</a> installed otherwise CounterStrikeSharp will not work.
|
||||
|
||||
> [!CAUTION]
|
||||
> For Windows users, you must ensure that you have installed **Visual Studio Redistributables**.
|
||||
> If not, you can download it here: <a href="https://aka.ms/vs/17/release/vc_redist.x64.exe" target="_blank">Download</a>
|
||||
> > This link will download VC Redistributable directly.
|
||||
>
|
||||
> You must install it before starting the server, otherwise CSS will not work!
|
||||
## Upgrading CounterStrikeSharp
|
||||
|
||||
To upgrade CounterStrikeSharp you simply need to download the latest release and copy it to your server, the same as the original installation.
|
||||
|
||||
Extract the `addons` folder to the `/csgo/` directory of the dedicated server. The contents of your addons folder should contain both the `counterstrikesharp` folder and the `metamod` folder as seen below.
|
||||
CounterStrikeSharp is designed in a way where your configuration files will not be overwritten if you do this. As CounterStrikeSharp is already installed, you may download the non `with-runtime` build, but you will need to ensure your .NET runtime is up-to-date yourself.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- If this is your first time installing, you **MUST** download the `with-runtime` version. This includes a copy of the .NET runtime, which is required to run the plugin.
|
||||
- Depending on your OS you might also either need to install `libicu` / `icu-libs` / `libicu-dev` using your package manager for .NET to run.
|
||||
- If you get `Unknown Command` when typing `meta list` into your console, double-check the folders are copied over correctly and that your `gameinfo.gi` file is correctly modified.
|
||||
|
||||
Your folder structure should look like this:
|
||||
|
||||
```shell
|
||||
<server_path>/game/csgo/addons > tree -L 2
|
||||
@@ -49,15 +70,3 @@ addons
|
||||
├── metamod.vdf
|
||||
└── metamod_x64.vdf
|
||||
```
|
||||
|
||||
## Start the Server
|
||||
|
||||
Launch your CS2 dedicated server as normal. If everything is working correctly, you should see a message in the console that says `CSSharp: CounterStrikeSharp.API Loaded Successfully.`.
|
||||
|
||||
Running the command `meta list` in the console should show 1 plugin loaded 🎉
|
||||
|
||||
```shell
|
||||
meta list
|
||||
Listing 1 plugin:
|
||||
[01] CounterStrikeSharp (0.1.0) by Roflmuffin
|
||||
```
|
||||
@@ -32,3 +32,7 @@ receive a ban.
|
||||
## PluginHotReloadEnabled
|
||||
|
||||
When enabled, plugins are automatically reloaded when their .dll file is updated.
|
||||
|
||||
## ServerLanguage
|
||||
|
||||
Configures the default language to use for server commands & messages. The format for the culture name based on RFC 4646 is `languagecode2-country`/`regioncode2`, where `languagecode2` is the two-letter language code and `country/regioncode2` is the two-letter subculture code. Examples include `ja-JP` for Japanese (Japan) and `en-US` for English (United States). Defaults to "en".
|
||||
5
docfx/examples/WithTranslations.md
Normal file
5
docfx/examples/WithTranslations.md
Normal file
@@ -0,0 +1,5 @@
|
||||
[!INCLUDE [WithTranslations](../../examples/WithTranslations/README.md)]
|
||||
|
||||
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WithTranslations" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
|
||||
|
||||
[!code-csharp[](../../examples/WithTranslations/WithTranslationsPlugin.cs)]
|
||||
5
docfx/examples/WithVoiceOverrides.md
Normal file
5
docfx/examples/WithVoiceOverrides.md
Normal file
@@ -0,0 +1,5 @@
|
||||
[!INCLUDE [WithVoiceOverrides](../../examples/WithVoiceOverrides/README.md)]
|
||||
|
||||
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WithVoiceOverrides" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
|
||||
|
||||
[!code-csharp[](../../examples/WithVoiceOverrides/WithVoiceOverridesPlugin.cs)]
|
||||
@@ -13,5 +13,9 @@ items:
|
||||
href: WithGameEventHandlers.md
|
||||
- name: Database (Dapper)
|
||||
href: WithDatabase.md
|
||||
- name: Translations
|
||||
href: WithTranslations.md
|
||||
- name: Voice Overrides
|
||||
href: WithVoiceOverrides.md
|
||||
- name: Warcraft Plugin
|
||||
href: WarcraftPlugin.md
|
||||
|
||||
BIN
docfx/images/gameinfogi-example.png
Normal file
BIN
docfx/images/gameinfogi-example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 275 KiB |
@@ -14,6 +14,7 @@ description: Write Counter-Strike 2 server plugins in C#.
|
||||
<span>CounterStrikeSharp is a simpler way to write CS2 server plugins.</span>
|
||||
<div>
|
||||
<a href="docs/guides/getting-started.md" class="btn btn-primary btn-lg fw-bold my-5">Get Started <i class="bi bi-arrow-right"></a>
|
||||
<a href="https://github.com/roflmuffin/CounterStrikeSharp/releases/latest" class="btn btn-secondary btn-lg fw-bold my-5">Download <i class="bi bi-download"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
8
examples/WithTranslations/README.md
Normal file
8
examples/WithTranslations/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# With Translations
|
||||
This example shows how to use an `IStringLocalizer` and language `json` files to provide localization for your plugins.
|
||||
|
||||
## How to use
|
||||
1. Add the `IStringLocalizer` to your services with dependency injection, or use the `Localizer` provided on the plugin instance.
|
||||
2. Add a `lang` folder to your plugin, and add a `json` file for each language you want to support. The name of the file should be a locale code, like `en.json` or `fr.json` etc.
|
||||
3. Ensure that the `lang` folder is shipped with your plugin, see the example `.csproj` file for an example to auto-copy to the output folder.
|
||||
4. Use the `IStringLocalizer` to localize your strings.
|
||||
15
examples/WithTranslations/WithTranslations.csproj
Normal file
15
examples/WithTranslations/WithTranslations.csproj
Normal file
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="lang\**\*.*" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
52
examples/WithTranslations/WithTranslationsPlugin.cs
Normal file
52
examples/WithTranslations/WithTranslationsPlugin.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Globalization;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace WithTranslations;
|
||||
|
||||
[MinimumApiVersion(80)]
|
||||
public class WithTranslationsPlugin : BasePlugin
|
||||
{
|
||||
public override string ModuleName => "Example: With Translations";
|
||||
public override string ModuleVersion => "1.0.0";
|
||||
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
|
||||
public override string ModuleDescription => "A simple plugin that provides translations";
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
// A global `Localizer` is provided on the plugin instance.
|
||||
// You can also use dependency injection to inject `IStringLocalizer` in your own services.
|
||||
Logger.LogInformation("This message is in the server language: {Message}", Localizer["test.translation"]);
|
||||
|
||||
// IStringLocalizer can accept standard string format arguments.
|
||||
// "This number has 2 decimal places {0:n2}" -> "This number has 2 decimal places 123.55"
|
||||
Logger.LogInformation(Localizer["test.format", 123.551]);
|
||||
|
||||
// This message has colour codes
|
||||
Server.PrintToChatAll(Localizer["test.colors"]);
|
||||
|
||||
// This message has colour codes and formatted values
|
||||
Server.PrintToChatAll(Localizer["test.colors.withformat", 123.551]);
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_replylanguage", "Test Translations")]
|
||||
public void OnCommandReplyLanguage(CCSPlayerController? player, CommandInfo command)
|
||||
{
|
||||
// Commands are executed in a players provided culture (or fallback to server culture).
|
||||
// Players can configure their language using the `!lang` or `css_lang` command.
|
||||
Logger.LogInformation("Current Culture is {Culture}", CultureInfo.CurrentCulture);
|
||||
command.ReplyToCommand(Localizer["test.translation"]);
|
||||
|
||||
if (player != null)
|
||||
{
|
||||
// You can also get the players language using the `GetLanguage` extension method.
|
||||
// This will always return a culture, defaulting to the server culture if the user has not configured it.
|
||||
var language = player.GetLanguage();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
examples/WithTranslations/lang/en-GB.json
Normal file
3
examples/WithTranslations/lang/en-GB.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"test.translation": "This is the english (GB) translation"
|
||||
}
|
||||
6
examples/WithTranslations/lang/en.json
Normal file
6
examples/WithTranslations/lang/en.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"test.translation": "This is the english translation",
|
||||
"test.format": "This number has 2 decimal places {0:n2}",
|
||||
"test.colors": "{orange}This{default} text has {green}green{default} text",
|
||||
"test.colors.withformat": "{orange}{0:n2}{default}"
|
||||
}
|
||||
3
examples/WithTranslations/lang/fr.json
Normal file
3
examples/WithTranslations/lang/fr.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"test.translation": "This is the french translation"
|
||||
}
|
||||
2
examples/WithVoiceOverrides/README.md
Normal file
2
examples/WithVoiceOverrides/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# With Voice Overrides
|
||||
Provides examples how to manipulate player voice flags & listening overrides to prevent certain players from hearing others.
|
||||
12
examples/WithVoiceOverrides/WithVoiceOverrides.csproj
Normal file
12
examples/WithVoiceOverrides/WithVoiceOverrides.csproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
79
examples/WithVoiceOverrides/WithVoiceOverridesPlugin.cs
Normal file
79
examples/WithVoiceOverrides/WithVoiceOverridesPlugin.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace WithVoiceOverrides;
|
||||
|
||||
[MinimumApiVersion(80)]
|
||||
public class WithVoiceOverridesPlugin : BasePlugin
|
||||
{
|
||||
public override string ModuleName => "Example: With Voice Overrides";
|
||||
public override string ModuleVersion => "1.0.0";
|
||||
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
|
||||
public override string ModuleDescription => "A plugin that manipulates voice flags";
|
||||
|
||||
[ConsoleCommand("css_hearall")]
|
||||
public void OnHearAllCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (caller is null) return;
|
||||
|
||||
if (caller.VoiceFlags.HasFlag(VoiceFlags.ListenAll))
|
||||
{
|
||||
caller.VoiceFlags = VoiceFlags.Normal;
|
||||
command.ReplyToCommand("Voice set back to default");
|
||||
}
|
||||
else
|
||||
{
|
||||
caller.VoiceFlags = VoiceFlags.ListenAll;
|
||||
command.ReplyToCommand("Can hear both teams");
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_muteself")]
|
||||
public void OnMuteSelfCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (caller is null) return;
|
||||
|
||||
if (caller.VoiceFlags.HasFlag(VoiceFlags.Muted))
|
||||
{
|
||||
caller.VoiceFlags = VoiceFlags.Normal;
|
||||
command.ReplyToCommand("Unmuted yourself");
|
||||
}
|
||||
else
|
||||
{
|
||||
caller.VoiceFlags = VoiceFlags.Muted;
|
||||
command.ReplyToCommand("Muted yourself");
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_muteothers")]
|
||||
[CommandHelper(minArgs: 1, usage: "[target]")]
|
||||
public void OnMuteOthersCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (caller is null) return;
|
||||
|
||||
var targetResult = command.GetArgTargetResult(1);
|
||||
|
||||
foreach (var player in targetResult.Players)
|
||||
{
|
||||
if (player == caller) continue;
|
||||
|
||||
|
||||
var existingOverride = caller.GetListenOverride(player);
|
||||
if (existingOverride == ListenOverride.Mute)
|
||||
{
|
||||
caller.SetListenOverride(player, ListenOverride.Default);
|
||||
command.ReplyToCommand($"Now hearing {player.PlayerName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
caller.SetListenOverride(player, ListenOverride.Mute);
|
||||
command.ReplyToCommand($"Muted {player.PlayerName}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Submodule libraries/hl2sdk-cs2 updated: 9363452257...2f9dd2e61a
@@ -14,8 +14,11 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING
|
||||
# TODO: Use C++20 instead.
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
Set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
Set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
if (LINUX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
endif()
|
||||
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||
|
||||
set(SOURCESDK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libraries/hl2sdk-cs2)
|
||||
@@ -51,8 +54,4 @@ include_directories(
|
||||
libraries
|
||||
)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/metamod/configure_metamod.cmake)
|
||||
|
||||
if (LINUX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
endif()
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/metamod/configure_metamod.cmake)
|
||||
110
managed/CounterStrikeSharp.API.Tests/AdminTests.cs
Normal file
110
managed/CounterStrikeSharp.API.Tests/AdminTests.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
|
||||
namespace CounterStrikeSharp.API.Tests;
|
||||
|
||||
[Collection("Logging collection")]
|
||||
public class AdminTests
|
||||
{
|
||||
public AdminTests()
|
||||
{
|
||||
AdminManager.LoadAdminData(TestUtils.GetTestPath("admins.json"));
|
||||
AdminManager.LoadAdminGroups(TestUtils.GetTestPath("admin_groups.json"));
|
||||
AdminManager.LoadCommandOverrides(TestUtils.GetTestPath("admin_overrides.json"));
|
||||
AdminManager.MergeGroupPermsIntoAdmins();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldReturnValidAdminData()
|
||||
{
|
||||
var adminData = AdminManager.GetPlayerAdminData((SteamID)76561197960265731);
|
||||
Assert.NotNull(adminData);
|
||||
Assert.Equal("#css/admin", adminData.Groups.Single());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldUseGroupImmunity()
|
||||
{
|
||||
var adminData = AdminManager.GetPlayerAdminData((SteamID)76561197960265731);
|
||||
Assert.NotNull(adminData);
|
||||
Assert.Equal(125u, AdminManager.GetPlayerImmunity((SteamID)76561197960265731)); // Group immunity is 125, Admin immunity is 100
|
||||
AdminManager.SetPlayerImmunity((SteamID)76561197960265731, 150u);
|
||||
Assert.Equal(150u, AdminManager.GetPlayerImmunity((SteamID)76561197960265731)); // Group immunity is 125, Admin immunity is 100
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldReturnNullAdminData()
|
||||
{
|
||||
var adminData = AdminManager.GetPlayerAdminData((SteamID)76561197960265732);
|
||||
Assert.Null(adminData);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldReturnValidCommandOverrides()
|
||||
{
|
||||
var adminData = AdminManager.GetPlayerAdminData((SteamID)76561197960265731);
|
||||
Assert.NotNull(adminData);
|
||||
Assert.True(adminData.CommandOverrides["fake_command"]);
|
||||
Assert.False(adminData.CommandOverrides["css"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldHandleWildcardDomainFlags()
|
||||
{
|
||||
// User has @mycustomplugin/* so should have the admin subflag despite it not being in their group.
|
||||
Assert.True(AdminManager.PlayerHasPermissions((SteamID)76561197960265731, "@mycustomplugin/admin"));
|
||||
|
||||
// User has @mycustomplugin/* so should have the admin subflag despite it not existing anywhere else.
|
||||
Assert.True(AdminManager.PlayerHasPermissions((SteamID)76561197960265731, "@mycustomplugin/fake"));
|
||||
|
||||
// User has @css/root so should have the slay subflag despite it not being in their group.
|
||||
Assert.True(AdminManager.PlayerHasPermissions((SteamID)76561197960265731, "@css/slay"));
|
||||
|
||||
// Flag provided explicitly in the admins.json file
|
||||
Assert.True(AdminManager.PlayerHasPermissions((SteamID)76561197960265731, "@css/custom-flag-2"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldAddFlagsAtRuntime()
|
||||
{
|
||||
// Existing player
|
||||
Assert.False(AdminManager.PlayerHasPermissions((SteamID)76561197960265731, "@runtime/flag1"));
|
||||
AdminManager.AddPlayerPermissions((SteamID)76561197960265731, "@runtime/flag1");
|
||||
Assert.True(AdminManager.PlayerHasPermissions((SteamID)76561197960265731, "@runtime/flag1"));
|
||||
|
||||
// Non-existent player
|
||||
Assert.False(AdminManager.PlayerHasPermissions((SteamID)76561197960265730, "@runtime/flag1"));
|
||||
AdminManager.AddPlayerPermissions((SteamID)76561197960265730, "@runtime/flag1");
|
||||
Assert.True(AdminManager.PlayerHasPermissions((SteamID)76561197960265730, "@runtime/flag1"));
|
||||
|
||||
AdminManager.ClearPlayerPermissions((SteamID)76561197960265730);
|
||||
Assert.False(AdminManager.PlayerHasPermissions((SteamID)76561197960265730, "@runtime/flag1"));
|
||||
Assert.Empty(AdminManager.GetPlayerAdminData((SteamID)76561197960265730)!.GetAllFlags());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldAddPlayerToGroup()
|
||||
{
|
||||
AdminManager.AddPlayerToGroup(new SteamID("STEAM_0:1:3"), "#css/root");
|
||||
var adminData = AdminManager.GetPlayerAdminData(new SteamID("STEAM_0:1:3"));
|
||||
Assert.NotNull(adminData);
|
||||
Assert.Equal("#css/root", adminData.Groups.Single());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldAddPlayerPermissionOverridesAtRuntime()
|
||||
{
|
||||
Assert.False(AdminManager.PlayerHasCommandOverride((SteamID)76561197960265731, "runtime_command"));
|
||||
AdminManager.SetPlayerCommandOverride((SteamID)76561197960265731, "runtime_command", true);
|
||||
Assert.True(AdminManager.PlayerHasCommandOverride((SteamID)76561197960265731, "runtime_command"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldAddCommandPermissionOverridesAtRuntime()
|
||||
{
|
||||
Assert.False(AdminManager.CommandIsOverriden("runtime_command"));
|
||||
AdminManager.AddPermissionOverride("runtime_command", "@runtime/override");
|
||||
Assert.True(AdminManager.CommandIsOverriden("runtime_command"));
|
||||
Assert.Equal("@runtime/override", AdminManager.GetPermissionOverrides("runtime_command").Single());
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2"/>
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="xunit" Version="2.4.2"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
@@ -20,9 +21,25 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Resources\**\*.*" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="lang\en.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="lang\en-GB.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="lang\fr.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using CounterStrikeSharp.API.Core.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CounterStrikeSharp.API.Tests.Fixtures;
|
||||
|
||||
public class CoreLoggingFixture : IDisposable
|
||||
{
|
||||
public CoreLoggingFixture()
|
||||
{
|
||||
var serviceProvider = new ServiceCollection()
|
||||
.AddLogging(builder =>
|
||||
{
|
||||
builder.ClearProviders();
|
||||
builder.AddCoreLogging(TestUtils.GetTestPath(""));
|
||||
})
|
||||
.BuildServiceProvider();
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
// TODO release managed resources here
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace CounterStrikeSharp.API.Tests.Fixtures;
|
||||
|
||||
[CollectionDefinition("Logging collection")]
|
||||
public class LoggingCollection : ICollectionFixture<CoreLoggingFixture>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"#css/admin": {
|
||||
"flags": [
|
||||
"@css/reservation",
|
||||
"@css/generic",
|
||||
"@css/kick",
|
||||
"@css/ban",
|
||||
"@css/unban",
|
||||
"@css/vip",
|
||||
"@css/changemap",
|
||||
"@css/cvar",
|
||||
"@css/config",
|
||||
"@css/chat",
|
||||
"@css/vote",
|
||||
"@css/password",
|
||||
"@css/rcon",
|
||||
"@css/cheats",
|
||||
"@css/root"
|
||||
],
|
||||
"immunity": 125
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"example_command": {
|
||||
"flags": [
|
||||
"@css/custom-permission"
|
||||
],
|
||||
"check_type": "all",
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
23
managed/CounterStrikeSharp.API.Tests/Resources/admins.json
Normal file
23
managed/CounterStrikeSharp.API.Tests/Resources/admins.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Erikj": {
|
||||
"identity": "76561197960265731",
|
||||
"immunity": 100,
|
||||
"flags": [
|
||||
"@css/custom-flag-1",
|
||||
"@css/custom-flag-2",
|
||||
"@mycustomplugin/*"
|
||||
],
|
||||
"groups": [
|
||||
"#css/admin"
|
||||
],
|
||||
"command_overrides": {
|
||||
"css_plugins": true,
|
||||
"css": false,
|
||||
"fake_command": true
|
||||
}
|
||||
},
|
||||
"Another erikj": {
|
||||
"identity": "STEAM_0:1:1",
|
||||
"flags": ["@mycustomplugin/admin"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"test.translation": "This is the english (GB) translation"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"test.translation": "This is the english translation",
|
||||
"test.format": "This number has 2 decimal places {0:n2}",
|
||||
"test.colors": "{orange}This{default} text has {green}green{default} text",
|
||||
"test.colors.withformat": "{orange}{0:n2}{default}"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"test.translation": "This is the french translation"
|
||||
}
|
||||
14
managed/CounterStrikeSharp.API.Tests/TestUtils.cs
Normal file
14
managed/CounterStrikeSharp.API.Tests/TestUtils.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace CounterStrikeSharp.API.Tests;
|
||||
|
||||
public static class TestUtils
|
||||
{
|
||||
public static string GetTestPath(string relativePath)
|
||||
{
|
||||
var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().Location);
|
||||
var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
|
||||
var dirPath = Path.GetDirectoryName(codeBasePath);
|
||||
return Path.Combine(dirPath, "Resources", relativePath);
|
||||
}
|
||||
}
|
||||
92
managed/CounterStrikeSharp.API.Tests/TranslationTests.cs
Normal file
92
managed/CounterStrikeSharp.API.Tests/TranslationTests.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System.Globalization;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Plugin;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Moq;
|
||||
|
||||
namespace CounterStrikeSharp.API.Tests;
|
||||
|
||||
public class TranslationTests
|
||||
{
|
||||
private readonly JsonStringLocalizerFactory _factory;
|
||||
private readonly IStringLocalizer _localizer;
|
||||
|
||||
public TranslationTests()
|
||||
{
|
||||
var pluginContextMock = new Mock<IPluginContext>();
|
||||
pluginContextMock.SetupGet(x => x.FilePath).Returns(TestUtils.GetTestPath("test_plugin.dll"));
|
||||
_factory = new JsonStringLocalizerFactory(pluginContextMock.Object);
|
||||
_localizer = _factory.Create(this.GetType());
|
||||
|
||||
// This is generally derived from the core config, but for the sake of these tests we default to `en`.
|
||||
var serverCulture = CultureInfo.GetCultureInfo("en");
|
||||
CultureInfo.DefaultThreadCurrentUICulture = serverCulture;
|
||||
CultureInfo.DefaultThreadCurrentCulture = serverCulture;
|
||||
CultureInfo.CurrentUICulture = serverCulture;
|
||||
CultureInfo.CurrentCulture = serverCulture;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TranslatesLanguagesCorrectly()
|
||||
{
|
||||
using (new WithTemporaryCulture(CultureInfo.GetCultureInfo("en")))
|
||||
{
|
||||
Assert.Equal("This is the english translation", _localizer["test.translation"]);
|
||||
}
|
||||
|
||||
using (new WithTemporaryCulture(CultureInfo.InvariantCulture))
|
||||
{
|
||||
Assert.Equal("This is the english translation", _localizer["test.translation"]);
|
||||
}
|
||||
|
||||
using (new WithTemporaryCulture(CultureInfo.GetCultureInfo("en-US")))
|
||||
{
|
||||
Assert.Equal("This is the english translation", _localizer["test.translation"]);
|
||||
}
|
||||
|
||||
using (new WithTemporaryCulture(CultureInfo.GetCultureInfo("en-GB")))
|
||||
{
|
||||
Assert.Equal("This is the english (GB) translation", _localizer["test.translation"]);
|
||||
}
|
||||
|
||||
using (new WithTemporaryCulture(CultureInfo.GetCultureInfo("fr")))
|
||||
{
|
||||
Assert.Equal("This is the french translation", _localizer["test.translation"]);
|
||||
}
|
||||
|
||||
using (new WithTemporaryCulture(CultureInfo.GetCultureInfo("fr-FR")))
|
||||
{
|
||||
Assert.Equal("This is the french translation", _localizer["test.translation"]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldFallbackToServerLanguage()
|
||||
{
|
||||
using (new WithTemporaryCulture(CultureInfo.GetCultureInfo("de")))
|
||||
{
|
||||
Assert.Equal("This is the english translation", _localizer["test.translation"]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldReturnKeyIfNotFound()
|
||||
{
|
||||
Assert.Equal("test.notfound", _localizer["test.notfound"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldHandleFormatStrings()
|
||||
{
|
||||
Assert.Equal("This number has 2 decimal places 0.25", _localizer["test.format", 0.251]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HandlesColorFormatting()
|
||||
{
|
||||
// Sets invisible pre-color if there is a color code in the string.
|
||||
Assert.Equal(" \x10This\x01 text has \x04green\x01 text", _localizer["test.colors"]);
|
||||
Assert.Equal($" {'\x10'}1.25\x01", _localizer["test.colors.withformat", 1.25]);
|
||||
}
|
||||
}
|
||||
BIN
managed/CounterStrikeSharp.API/ApiCompat/v151.dll
Normal file
BIN
managed/CounterStrikeSharp.API/ApiCompat/v151.dll
Normal file
Binary file not shown.
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -7,6 +8,7 @@ using CounterStrikeSharp.API.Core.Hosting;
|
||||
using CounterStrikeSharp.API.Core.Logging;
|
||||
using CounterStrikeSharp.API.Core.Plugin;
|
||||
using CounterStrikeSharp.API.Core.Plugin.Host;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -38,6 +40,7 @@ public static class Bootstrap
|
||||
services.AddSingleton<IScriptHostConfiguration, ScriptHostConfiguration>();
|
||||
services.AddScoped<Application>();
|
||||
services.AddSingleton<IPluginManager, PluginManager>();
|
||||
services.AddSingleton<IPlayerLanguageManager, PlayerLanguageManager>();
|
||||
services.AddScoped<IPluginContextQueryHandler, PluginContextQueryHandler>();
|
||||
|
||||
services.Scan(i => i.FromCallingAssembly()
|
||||
|
||||
@@ -312,6 +312,16 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetMaxClients(){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x5DF2E20D);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (int)ScriptContext.GlobalScriptContext.GetResult(typeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
public static void IssueServerCommand(string command){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
@@ -1064,6 +1074,18 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsSchemaFieldNetworked(string classname, string propname){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(classname);
|
||||
ScriptContext.GlobalScriptContext.Push(propname);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0xFE413B0C);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (bool)ScriptContext.GlobalScriptContext.GetResult(typeof(bool));
|
||||
}
|
||||
}
|
||||
|
||||
public static T GetSchemaValueByName<T>(IntPtr instance, int returntype, string classname, string propname){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
@@ -1311,5 +1333,51 @@ namespace CounterStrikeSharp.API.Core
|
||||
return (bool)ScriptContext.GlobalScriptContext.GetResult(typeof(bool));
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetClientListening(IntPtr receiver, IntPtr sender, uint listen){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(receiver);
|
||||
ScriptContext.GlobalScriptContext.Push(sender);
|
||||
ScriptContext.GlobalScriptContext.Push(listen);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0xD38BEE77);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public static ListenOverride GetClientListening(IntPtr receiver, IntPtr sender){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(receiver);
|
||||
ScriptContext.GlobalScriptContext.Push(sender);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0xE95644E3);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (ListenOverride)ScriptContext.GlobalScriptContext.GetResult(typeof(ListenOverride));
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetClientVoiceFlags(IntPtr client, uint flags){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(client);
|
||||
ScriptContext.GlobalScriptContext.Push(flags);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x48EB2FC8);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public static uint GetClientVoiceFlags(IntPtr client){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(client);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x9685205C);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (uint)ScriptContext.GlobalScriptContext.GetResult(typeof(uint));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,16 @@
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using CounterStrikeSharp.API.Core.Hosting;
|
||||
using CounterStrikeSharp.API.Core.Plugin;
|
||||
using CounterStrikeSharp.API.Core.Plugin.Host;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Menu;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -40,10 +43,11 @@ namespace CounterStrikeSharp.API.Core
|
||||
private readonly CoreConfig _coreConfig;
|
||||
private readonly IPluginManager _pluginManager;
|
||||
private readonly IPluginContextQueryHandler _pluginContextQueryHandler;
|
||||
private readonly IPlayerLanguageManager _playerLanguageManager;
|
||||
|
||||
public Application(ILoggerFactory loggerFactory, IScriptHostConfiguration scriptHostConfiguration,
|
||||
GameDataProvider gameDataProvider, CoreConfig coreConfig, IPluginManager pluginManager,
|
||||
IPluginContextQueryHandler pluginContextQueryHandler)
|
||||
IPluginContextQueryHandler pluginContextQueryHandler, IPlayerLanguageManager playerLanguageManager)
|
||||
{
|
||||
Logger = loggerFactory.CreateLogger("Core");
|
||||
_scriptHostConfiguration = scriptHostConfiguration;
|
||||
@@ -51,6 +55,7 @@ namespace CounterStrikeSharp.API.Core
|
||||
_coreConfig = coreConfig;
|
||||
_pluginManager = pluginManager;
|
||||
_pluginContextQueryHandler = pluginContextQueryHandler;
|
||||
_playerLanguageManager = playerLanguageManager;
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
@@ -61,29 +66,31 @@ namespace CounterStrikeSharp.API.Core
|
||||
_coreConfig.Load();
|
||||
_gameDataProvider.Load();
|
||||
|
||||
var adminGroupsPath = Path.Combine(_scriptHostConfiguration.RootPath, "configs", "admin_groups.json");
|
||||
Logger.LogInformation("Loading Admin Groups from {Path}", adminGroupsPath);
|
||||
AdminManager.LoadAdminGroups(adminGroupsPath);
|
||||
|
||||
var adminPath = Path.Combine(_scriptHostConfiguration.RootPath, "configs", "admins.json");
|
||||
Logger.LogInformation("Loading Admins from {Path}", adminPath);
|
||||
AdminManager.LoadAdminData(adminPath);
|
||||
|
||||
var adminGroupsPath = Path.Combine(_scriptHostConfiguration.RootPath, "configs", "admin_groups.json");
|
||||
Logger.LogInformation("Loading Admin Groups from {Path}", adminGroupsPath);
|
||||
AdminManager.LoadAdminGroups(adminGroupsPath);
|
||||
|
||||
var overridePath = Path.Combine(_scriptHostConfiguration.RootPath, "configs", "admin_overrides.json");
|
||||
Logger.LogInformation("Loading Admin Command Overrides from {Path}", overridePath);
|
||||
AdminManager.LoadCommandOverrides(overridePath);
|
||||
|
||||
AdminManager.MergeGroupPermsIntoAdmins();
|
||||
AdminManager.AddCommands();
|
||||
|
||||
_pluginManager.Load();
|
||||
|
||||
for (var i = 1; i <= 9; i++)
|
||||
{
|
||||
CommandUtils.AddStandaloneCommand("css_" + i, "Command Key Handler", (player, info) =>
|
||||
CommandUtils.AddStandaloneCommand($"css_{i}", "Command Key Handler", (player, info) =>
|
||||
{
|
||||
if (player == null) return;
|
||||
var key = Convert.ToInt32(info.GetArg(0).Split("_")[1]);
|
||||
ChatMenus.OnKeyPress(player, key);
|
||||
|
||||
MenuManager.OnKeyPress(player, key);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -98,7 +105,7 @@ namespace CounterStrikeSharp.API.Core
|
||||
|
||||
info.ReplyToCommand(
|
||||
" CounterStrikeSharp was created and is maintained by Michael \"roflmuffin\" Wilson.\n" +
|
||||
" Counter-Strike Sharp uses code borrowed from SourceMod, Source.Python, FiveM, Saul Rennison and CS2Fixes.\n" +
|
||||
" Counter-Strike Sharp uses code borrowed from SourceMod, Source.Python, FiveM, Saul Rennison, source2gen and CS2Fixes.\n" +
|
||||
" See ACKNOWLEDGEMENTS.md for more information.\n" +
|
||||
" Current API Version: " + currentVersion, true);
|
||||
return;
|
||||
@@ -145,14 +152,14 @@ namespace CounterStrikeSharp.API.Core
|
||||
case "start":
|
||||
case "load":
|
||||
{
|
||||
if (info.ArgCount < 2)
|
||||
if (info.ArgCount < 3)
|
||||
{
|
||||
info.ReplyToCommand(
|
||||
"Valid usage: css_plugins start/load [relative plugin path || absolute plugin path] (e.g \"TestPlugin\", \"plugins/TestPlugin/TestPlugin.dll\")\n",
|
||||
true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// If our arugment doesn't end in ".dll" - try and construct a path similar to PluginName/PluginName.dll.
|
||||
// We'll assume we have a full path if we have ".dll".
|
||||
var path = info.GetArg(2);
|
||||
@@ -172,23 +179,25 @@ namespace CounterStrikeSharp.API.Core
|
||||
try
|
||||
{
|
||||
_pluginManager.LoadPlugin(path);
|
||||
} catch (Exception e)
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
info.ReplyToCommand($"Could not load plugin \"{path}\")", true);
|
||||
Logger.LogError(e, "Could not load plugin \"{Path}\"", path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
plugin.Load(false);
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "stop":
|
||||
case "unload":
|
||||
{
|
||||
if (info.ArgCount < 2)
|
||||
if (info.ArgCount < 3)
|
||||
{
|
||||
info.ReplyToCommand(
|
||||
"Valid usage: css_plugins stop/unload [plugin name || #plugin id] (e.g \"TestPlugin\", \"1\")\n",
|
||||
@@ -211,7 +220,7 @@ namespace CounterStrikeSharp.API.Core
|
||||
case "restart":
|
||||
case "reload":
|
||||
{
|
||||
if (info.ArgCount < 2)
|
||||
if (info.ArgCount < 3)
|
||||
{
|
||||
info.ReplyToCommand(
|
||||
"Valid usage: css_plugins restart/reload [plugin name || #plugin id] (e.g \"TestPlugin\", \"#1\")\n",
|
||||
@@ -244,11 +253,44 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
[CommandHelper(usage: "[language code, e.g. \"de\", \"pl\", \"en\"]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
private void OnLangCommand(CCSPlayerController? player, CommandInfo command)
|
||||
{
|
||||
if (player == null) return;
|
||||
|
||||
SteamID steamId = (SteamID)player.SteamID;
|
||||
|
||||
if (command.ArgCount == 1)
|
||||
{
|
||||
var language = _playerLanguageManager.GetLanguage(steamId);
|
||||
command.ReplyToCommand(string.Format("Current language is \"{0}\" ({1})", language.Name, language.NativeName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (command.ArgCount != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var language = command.GetArg(1);
|
||||
var cultureInfo = CultureInfo.GetCultures(CultureTypes.AllCultures).Single(x => x.Name == language);
|
||||
_playerLanguageManager.SetLanguage(steamId, cultureInfo);
|
||||
command.ReplyToCommand($"Language set to {cultureInfo.NativeName}");
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
command.ReplyToCommand("Language not found.");
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterPluginCommands()
|
||||
{
|
||||
CommandUtils.AddStandaloneCommand("css", "Counter-Strike Sharp options.", OnCSSCommand);
|
||||
CommandUtils.AddStandaloneCommand("css_plugins", "Counter-Strike Sharp plugin options.",
|
||||
OnCSSPluginCommand);
|
||||
CommandUtils.AddStandaloneCommand("css_lang", "Set Counter-Strike Sharp language.", OnLangCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace CounterStrikeSharp.API.Core.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class SchemaMemberAttribute : Attribute
|
||||
{
|
||||
public string ClassName { get; }
|
||||
public string MemberName { get; }
|
||||
|
||||
public SchemaMemberAttribute(string className, string memberName)
|
||||
{
|
||||
ClassName = className;
|
||||
MemberName = memberName;
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,14 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Events;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.Config;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core
|
||||
@@ -58,6 +60,8 @@ namespace CounterStrikeSharp.API.Core
|
||||
public string ModuleDirectory => Path.GetDirectoryName(ModulePath);
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public IStringLocalizer Localizer { get; set; }
|
||||
|
||||
public virtual void Load(bool hotReload)
|
||||
{
|
||||
}
|
||||
@@ -170,39 +174,53 @@ namespace CounterStrikeSharp.API.Core
|
||||
{
|
||||
var caller = (i != -1) ? new CCSPlayerController(NativeAPI.GetEntityFromIndex(i + 1)) : null;
|
||||
var command = new CommandInfo(ptr, caller);
|
||||
|
||||
using var temporaryCulture = new WithTemporaryCulture(caller.GetLanguage());
|
||||
|
||||
var methodInfo = handler?.GetMethodInfo();
|
||||
|
||||
if (!AdminManager.CommandIsOverriden(name))
|
||||
// We do not need to do permission checks on commands executed from the server console.
|
||||
// The server will always be allowed to execute commands (unless marked as client only like above)
|
||||
if (caller != null)
|
||||
{
|
||||
// Do not execute command if we do not have the correct permissions.
|
||||
var permissions = methodInfo?.GetCustomAttributes<BaseRequiresPermissions>();
|
||||
if (permissions != null)
|
||||
var adminData = AdminManager.GetPlayerAdminData(caller!.AuthorizedSteamID);
|
||||
var permissionsToCheck = new List<BaseRequiresPermissions>();
|
||||
|
||||
|
||||
// If our command is overriden, we dynamically create a new permissions attribute
|
||||
// based on the data that is stored in admin_overrides.json.
|
||||
if (AdminManager.CommandIsOverriden(name))
|
||||
{
|
||||
foreach (var attr in permissions)
|
||||
var data = AdminManager.GetCommandOverrideData(name);
|
||||
if (data != null)
|
||||
{
|
||||
attr.Command = name;
|
||||
if (!attr.CanExecuteCommand(caller))
|
||||
{
|
||||
command.ReplyToCommand("[CSS] You do not have the correct permissions to execute this command.");
|
||||
return;
|
||||
}
|
||||
var attrType = (data.CheckType == "all") ? typeof(RequiresPermissions) : typeof(RequiresPermissionsOr);
|
||||
var attr = (BaseRequiresPermissions)Activator.CreateInstance(attrType, args: AdminManager.GetPermissionOverrides(name));
|
||||
|
||||
if (attr != null) permissionsToCheck.Add(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If this command has it's permissions overriden, we will do an AND check for all permissions.
|
||||
else
|
||||
{
|
||||
// I don't know if this is the most sane implementation of this, can be edited in code review.
|
||||
var data = AdminManager.GetCommandOverrideData(name);
|
||||
if (data != null)
|
||||
// The permissions for this command are not being overriden here, so we
|
||||
// grab the permissions to check straight from the attribute.
|
||||
else
|
||||
{
|
||||
var permissions = methodInfo?.GetCustomAttributes<BaseRequiresPermissions>();
|
||||
if (permissions != null) permissionsToCheck.AddRange(permissions);
|
||||
}
|
||||
|
||||
foreach (var attr in permissionsToCheck)
|
||||
{
|
||||
var attrType = (data.CheckType == "all") ? typeof(RequiresPermissions) : typeof(RequiresPermissionsOr);
|
||||
var attr = (BaseRequiresPermissions)Activator.CreateInstance(attrType, args: AdminManager.GetPermissionOverrides(name));
|
||||
attr.Command = name;
|
||||
if (!attr.CanExecuteCommand(caller))
|
||||
{
|
||||
command.ReplyToCommand("[CSS] You do not have the correct permissions to execute this command.");
|
||||
var responseStr = (attr.GetType() == typeof(RequiresPermissions)) ?
|
||||
"You are missing the correct permissions" : "You do not have one of the correct permissions";
|
||||
|
||||
var flags = attr.Permissions.Except(adminData?.GetAllFlags() ?? new HashSet<string>());
|
||||
flags = flags.Except(adminData?.Groups ?? new HashSet<string>());
|
||||
command.ReplyToCommand($"[CSS] {responseStr} ({string.Join(", ", flags)}) to execute this command.");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -210,15 +228,17 @@ namespace CounterStrikeSharp.API.Core
|
||||
|
||||
// Do not execute if we shouldn't be calling this command.
|
||||
var helperAttribute = methodInfo?.GetCustomAttribute<CommandHelperAttribute>();
|
||||
if (helperAttribute != null)
|
||||
if (helperAttribute != null)
|
||||
{
|
||||
switch (helperAttribute.WhoCanExcecute)
|
||||
{
|
||||
case CommandUsage.CLIENT_AND_SERVER: break; // Allow command through.
|
||||
case CommandUsage.CLIENT_ONLY:
|
||||
if (caller == null || !caller.IsValid) { command.ReplyToCommand("[CSS] This command can only be executed by clients."); return; } break;
|
||||
if (caller == null || !caller.IsValid) { command.ReplyToCommand("[CSS] This command can only be executed by clients."); return; }
|
||||
break;
|
||||
case CommandUsage.SERVER_ONLY:
|
||||
if (caller != null && caller.IsValid) { command.ReplyToCommand("[CSS] This command can only be executed by the server."); return; } break;
|
||||
if (caller != null && caller.IsValid) { command.ReplyToCommand("[CSS] This command can only be executed by the server."); return; }
|
||||
break;
|
||||
default: throw new ArgumentException("Unrecognised CommandUsage value passed in CommandHelperAttribute.");
|
||||
}
|
||||
|
||||
@@ -226,7 +246,12 @@ namespace CounterStrikeSharp.API.Core
|
||||
// but we'll just ignore that for this check.
|
||||
if (helperAttribute.MinArgs != 0 && command.ArgCount - 1 < helperAttribute.MinArgs)
|
||||
{
|
||||
command.ReplyToCommand($"[CSS] Expected usage: \"!{command.ArgByIndex(0)} {helperAttribute.Usage}\".");
|
||||
// Remove the "css_" from the beginning of the command name if it's present.
|
||||
// Most of the time, users will be calling commands from chat.
|
||||
var commandCalled = command.ArgByIndex(0);
|
||||
var properCommandName = (commandCalled.StartsWith("css_")) ? commandCalled.Replace("css_", "") : commandCalled;
|
||||
|
||||
command.ReplyToCommand($"[CSS] Expected usage: \"!{properCommandName} {helperAttribute.Usage}\".");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -23,6 +23,8 @@ using CounterStrikeSharp.API.Modules.Utils;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using CounterStrikeSharp.API.Core.Hosting;
|
||||
using CounterStrikeSharp.API.Core.Logging;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
@@ -46,6 +48,9 @@ namespace CounterStrikeSharp.API.Core
|
||||
|
||||
[JsonPropertyName("PluginHotReloadEnabled")]
|
||||
public bool PluginHotReloadEnabled { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("ServerLanguage")]
|
||||
public string ServerLanguage { get; set; } = "en";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -88,6 +93,8 @@ namespace CounterStrikeSharp.API.Core
|
||||
/// When enabled, plugins are automatically reloaded when their .dll file is updated.
|
||||
/// </summary>
|
||||
public static bool PluginHotReloadEnabled => _coreConfig.PluginHotReloadEnabled;
|
||||
|
||||
public static string ServerLanguage => _coreConfig.ServerLanguage;
|
||||
}
|
||||
|
||||
public partial class CoreConfig : IStartupService
|
||||
@@ -138,6 +145,29 @@ namespace CounterStrikeSharp.API.Core
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to load core configuration, fallback values will be used");
|
||||
}
|
||||
|
||||
var serverCulture = CultureInfo.GetCultures(CultureTypes.AllCultures)
|
||||
.FirstOrDefault(x => x.Name == ServerLanguage);
|
||||
if (serverCulture == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogWarning("Server Language \"{ServerLanguage}\" is not supported, falling back to \"en\"",
|
||||
ServerLanguage);
|
||||
_coreConfig.ServerLanguage = "en";
|
||||
serverCulture = new CultureInfo("en");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.LogWarning("Server is running in invariant mode, translations will not be available.");
|
||||
serverCulture = CultureInfo.InvariantCulture;
|
||||
}
|
||||
}
|
||||
|
||||
CultureInfo.DefaultThreadCurrentUICulture = serverCulture;
|
||||
CultureInfo.DefaultThreadCurrentCulture = serverCulture;
|
||||
CultureInfo.CurrentUICulture = serverCulture;
|
||||
CultureInfo.CurrentCulture = serverCulture;
|
||||
|
||||
_logger.LogInformation("Successfully loaded core configuration");
|
||||
}
|
||||
|
||||
@@ -34,34 +34,58 @@ public class Offsets
|
||||
|
||||
public sealed class GameDataProvider : IStartupService
|
||||
{
|
||||
private readonly string _gameDataFilePath;
|
||||
private readonly string _gameDataDirectoryPath;
|
||||
public Dictionary<string,LoadedGameData> Methods;
|
||||
private readonly ILogger<GameDataProvider> _logger;
|
||||
|
||||
public GameDataProvider(IScriptHostConfiguration scriptHostConfiguration, ILogger<GameDataProvider> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_gameDataFilePath = Path.Join(scriptHostConfiguration.GameDataPath, "gamedata.json");
|
||||
_gameDataDirectoryPath = scriptHostConfiguration.GameDataPath;
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
try
|
||||
{
|
||||
Methods = JsonSerializer.Deserialize<Dictionary<string, LoadedGameData>>(File.ReadAllText(_gameDataFilePath))!;
|
||||
Methods = new Dictionary<string, LoadedGameData>();
|
||||
|
||||
foreach (string filePath in Directory.EnumerateFiles(_gameDataDirectoryPath, "*.json"))
|
||||
{
|
||||
string jsonContent = File.ReadAllText(filePath);
|
||||
Dictionary<string, LoadedGameData> loadedMethods = JsonSerializer.Deserialize<Dictionary<string, LoadedGameData>>(jsonContent)!;
|
||||
|
||||
foreach (KeyValuePair<string, LoadedGameData> loadedMethod in loadedMethods)
|
||||
{
|
||||
if (Methods.ContainsKey(loadedMethod.Key))
|
||||
{
|
||||
_logger.LogWarning("GameData Method \"{Key}\" loaded a duplicate entry from {filePath}.", loadedMethod.Key, filePath);
|
||||
}
|
||||
|
||||
Methods[loadedMethod.Key] = loadedMethod.Value;
|
||||
}
|
||||
|
||||
if (loadedMethods != null)
|
||||
{
|
||||
_logger.LogInformation("Successfully loaded {Count} game data entries from {Path}", loadedMethods.Count, filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Unable to load game data entries from {Path}, game data file is empty", filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to load game data");
|
||||
}
|
||||
|
||||
_logger.LogInformation("Successfully loaded {Count} game data entries from {Path}", Methods.Count, _gameDataFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
public static class GameData
|
||||
{
|
||||
internal static GameDataProvider GameDataProvider { get; set; } = null!;
|
||||
|
||||
public static string GetSignature(string key)
|
||||
{
|
||||
Application.Instance.Logger.LogDebug("Getting signature: {Key}", key);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core
|
||||
@@ -54,6 +55,8 @@ namespace CounterStrikeSharp.API.Core
|
||||
string ModulePath { get; internal set; }
|
||||
|
||||
ILogger Logger { get; set; }
|
||||
|
||||
IStringLocalizer Localizer { get; set; }
|
||||
|
||||
void RegisterAllAttributes(object instance);
|
||||
|
||||
|
||||
@@ -93,6 +93,13 @@ namespace CounterStrikeSharp.API.Core
|
||||
[ListenerName("OnClientDisconnectPost")]
|
||||
public delegate void OnClientDisconnectPost(int playerSlot);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a client transmits voice data
|
||||
/// </summary>
|
||||
/// <param name="playerSlot">The player slot of the client.</param>
|
||||
[ListenerName("OnClientVoice")]
|
||||
public delegate void OnClientVoice(int playerSlot);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a client has been authorized by Steam.
|
||||
/// </summary>
|
||||
|
||||
@@ -14,4 +14,13 @@ public partial class CBasePlayerPawn
|
||||
{
|
||||
VirtualFunction.CreateVoid<IntPtr, bool, bool>(Handle, GameData.GetOffset("CBasePlayerPawn_CommitSuicide"))(Handle, explode, force);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove Player Item
|
||||
/// </summary>
|
||||
/// <param name="weapon"></param>
|
||||
public void RemovePlayerItem(CBasePlayerWeapon weapon)
|
||||
{
|
||||
VirtualFunctions.RemovePlayerItemVirtual(Handle, weapon.Handle);
|
||||
}
|
||||
}
|
||||
@@ -10,17 +10,13 @@ namespace CounterStrikeSharp.API.Core;
|
||||
|
||||
public partial class CCSPlayerController
|
||||
{
|
||||
public int? UserId
|
||||
{
|
||||
get
|
||||
{
|
||||
return NativeAPI.GetUseridFromIndex((int)this.Index);
|
||||
}
|
||||
}
|
||||
public int? UserId => NativeAPI.GetUseridFromIndex((int)Index);
|
||||
public CsTeam Team => (CsTeam)TeamNum;
|
||||
|
||||
public IntPtr GiveNamedItem(string item)
|
||||
{
|
||||
if (!PlayerPawn.IsValid) return 0;
|
||||
if (PlayerPawn.Value == null) return 0;
|
||||
if (!PlayerPawn.Value.IsValid) return 0;
|
||||
if (PlayerPawn.Value.ItemServices == null) return 0;
|
||||
|
||||
@@ -35,7 +31,7 @@ public partial class CCSPlayerController
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return this.GiveNamedItem(itemString);
|
||||
return GiveNamedItem(itemString);
|
||||
}
|
||||
|
||||
public void PrintToConsole(string message)
|
||||
@@ -45,12 +41,12 @@ public partial class CCSPlayerController
|
||||
|
||||
public void PrintToChat(string message)
|
||||
{
|
||||
VirtualFunctions.ClientPrint(this.Handle, HudDestination.Chat, message, 0, 0, 0, 0);
|
||||
VirtualFunctions.ClientPrint(Handle, HudDestination.Chat, message, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public void PrintToCenter(string message)
|
||||
{
|
||||
VirtualFunctions.ClientPrint(this.Handle, HudDestination.Center, message, 0, 0, 0, 0);
|
||||
VirtualFunctions.ClientPrint(Handle, HudDestination.Center, message, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public void PrintToCenterHtml(string message) => PrintToCenterHtml(message, 5);
|
||||
@@ -72,14 +68,16 @@ public partial class CCSPlayerController
|
||||
public void DropActiveWeapon()
|
||||
{
|
||||
if (!PlayerPawn.IsValid) return;
|
||||
if (PlayerPawn.Value == null) return;
|
||||
if (!PlayerPawn.Value.IsValid) return;
|
||||
if (PlayerPawn.Value.ItemServices == null) return;
|
||||
if (PlayerPawn.Value.WeaponServices == null) return;
|
||||
if (!PlayerPawn.Value.WeaponServices.ActiveWeapon.IsValid) return;
|
||||
|
||||
CCSPlayer_ItemServices itemServices = new CCSPlayer_ItemServices(PlayerPawn.Value.ItemServices.Handle);
|
||||
CCSPlayer_WeaponServices weponServices = new CCSPlayer_WeaponServices(PlayerPawn.Value.WeaponServices.Handle);
|
||||
itemServices.DropActivePlayerWeapon(weponServices.ActiveWeapon.Value);
|
||||
CCSPlayer_WeaponServices weaponServices = new CCSPlayer_WeaponServices(PlayerPawn.Value.WeaponServices.Handle);
|
||||
|
||||
itemServices.DropActivePlayerWeapon(weaponServices.ActiveWeapon.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -88,6 +86,7 @@ public partial class CCSPlayerController
|
||||
public void RemoveWeapons()
|
||||
{
|
||||
if (!PlayerPawn.IsValid) return;
|
||||
if (PlayerPawn.Value == null) return;
|
||||
if (!PlayerPawn.Value.IsValid) return;
|
||||
if (PlayerPawn.Value.ItemServices == null) return;
|
||||
|
||||
@@ -103,6 +102,7 @@ public partial class CCSPlayerController
|
||||
public void CommitSuicide(bool explode, bool force)
|
||||
{
|
||||
if (!PlayerPawn.IsValid) return;
|
||||
if (PlayerPawn.Value == null) return;
|
||||
if (!PlayerPawn.Value.IsValid) return;
|
||||
|
||||
PlayerPawn.Value.CommitSuicide(explode, force);
|
||||
@@ -114,6 +114,7 @@ public partial class CCSPlayerController
|
||||
public void Respawn()
|
||||
{
|
||||
if (!PlayerPawn.IsValid) return;
|
||||
if (PlayerPawn.Value == null) return;
|
||||
if (!PlayerPawn.Value.IsValid) return;
|
||||
|
||||
VirtualFunctions.CCSPlayerPawn_Respawn(PlayerPawn.Value.Handle);
|
||||
@@ -128,7 +129,7 @@ public partial class CCSPlayerController
|
||||
/// <param name="team">The team to switch to</param>
|
||||
public void SwitchTeam(CsTeam team)
|
||||
{
|
||||
VirtualFunctions.SwitchTeam(this.Handle, (byte)team);
|
||||
VirtualFunctions.SwitchTeam(Handle, (byte)team);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -151,7 +152,7 @@ public partial class CCSPlayerController
|
||||
/// <returns>ConVar string value</returns>
|
||||
public string GetConVarValue(string conVar)
|
||||
{
|
||||
return NativeAPI.GetClientConvarValue(this.Slot, conVar);
|
||||
return NativeAPI.GetClientConvarValue(Slot, conVar);
|
||||
}
|
||||
|
||||
public string GetConVarValue(ConVar? conVar)
|
||||
@@ -177,7 +178,7 @@ public partial class CCSPlayerController
|
||||
throw new InvalidOperationException("'SetFakeClientConVar' can only be called for fake clients (bots)");
|
||||
}
|
||||
|
||||
NativeAPI.SetFakeClientConvarValue(this.Slot, conVar, value);
|
||||
NativeAPI.SetFakeClientConvarValue(Slot, conVar, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -202,6 +203,21 @@ public partial class CCSPlayerController
|
||||
|
||||
public void ExecuteClientCommand(string command) => NativeAPI.IssueClientCommand(Slot, command);
|
||||
|
||||
/// <summary>
|
||||
/// Overrides who a player can hear in voice chat.
|
||||
/// </summary>
|
||||
/// <param name="sender">Player talking in the voice chat</param>
|
||||
/// <param name="override">Whether the talker should be heard</param>
|
||||
public void SetListenOverride(CCSPlayerController sender, ListenOverride @override)
|
||||
{
|
||||
NativeAPI.SetClientListening(Handle, sender.Handle, (Byte)@override);
|
||||
}
|
||||
|
||||
public ListenOverride GetListenOverride(CCSPlayerController sender)
|
||||
{
|
||||
return NativeAPI.GetClientListening(Handle, sender.Handle);
|
||||
}
|
||||
|
||||
public int Slot => (int)Index - 1;
|
||||
|
||||
/// <summary>
|
||||
@@ -211,8 +227,8 @@ public partial class CCSPlayerController
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.IsValid) return null;
|
||||
var authorizedSteamId = NativeAPI.GetPlayerAuthorizedSteamid(this.Slot);
|
||||
if (!IsValid) return null;
|
||||
var authorizedSteamId = NativeAPI.GetPlayerAuthorizedSteamid(Slot);
|
||||
if ((long)authorizedSteamId == -1) return null;
|
||||
|
||||
return (SteamID)authorizedSteamId;
|
||||
@@ -227,11 +243,20 @@ public partial class CCSPlayerController
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.IsValid) return null;
|
||||
var ipAddress = NativeAPI.GetPlayerIpAddress(this.Slot);
|
||||
if (!IsValid) return null;
|
||||
var ipAddress = NativeAPI.GetPlayerIpAddress(Slot);
|
||||
if (string.IsNullOrWhiteSpace(ipAddress)) return null;
|
||||
|
||||
return ipAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines how the player interacts with voice chat.
|
||||
/// </summary>
|
||||
public VoiceFlags VoiceFlags
|
||||
{
|
||||
get => (VoiceFlags)NativeAPI.GetClientVoiceFlags(Handle);
|
||||
set => NativeAPI.SetClientVoiceFlags(Handle, (Byte)value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,24 @@ public partial class CEntityInstance : IEquatable<CEntityInstance>
|
||||
{
|
||||
return !Equals(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls a named input method on an entity.
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// entity.AcceptInput("Break");
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
/// <param name="inputName">Input action name</param>
|
||||
/// <param name="activator">Entity which initiated the action, <see langword="null"/> for no entity</param>
|
||||
/// <param name="caller">Entity that is sending the event, <see langword="null"/> for no entity</param>
|
||||
/// <param name="value">String variant value to send with the event</param>
|
||||
/// <param name="outputId">Unknown, defaults to 0</param>
|
||||
public void AcceptInput(string inputName, CEntityInstance? activator = null, CEntityInstance? caller = null, string value = "", int outputId = 0)
|
||||
{
|
||||
VirtualFunctions.AcceptInput(Handle, inputName, activator?.Handle ?? IntPtr.Zero, caller?.Handle ?? IntPtr.Zero, value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class CEntityIdentity
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@ public interface IPluginContext
|
||||
IPlugin Plugin { get; }
|
||||
int PluginId { get; }
|
||||
|
||||
string FilePath { get; }
|
||||
void Load(bool hotReload);
|
||||
void Unload(bool hotReload);
|
||||
}
|
||||
@@ -20,8 +20,11 @@ using System.Threading.Tasks;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Core.Hosting;
|
||||
using CounterStrikeSharp.API.Core.Logging;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using McMaster.NETCore.Plugins;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Serilog;
|
||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
@@ -43,6 +46,8 @@ namespace CounterStrikeSharp.API.Core.Plugin
|
||||
private readonly string _path;
|
||||
private readonly FileSystemWatcher _fileWatcher;
|
||||
private readonly IServiceProvider _applicationServiceProvider;
|
||||
|
||||
public string FilePath => _path;
|
||||
|
||||
// TOOD: ServiceCollection
|
||||
private ILogger _logger = CoreLogging.Factory.CreateLogger<PluginContext>();
|
||||
@@ -163,8 +168,12 @@ namespace CounterStrikeSharp.API.Core.Plugin
|
||||
method?.Invoke(pluginServiceCollection, new object[] { serviceCollection });
|
||||
}
|
||||
}
|
||||
|
||||
serviceCollection.AddSingleton<IPluginContext>(this);
|
||||
serviceCollection.TryAddSingleton<IStringLocalizerFactory, JsonStringLocalizerFactory>();
|
||||
serviceCollection.TryAddTransient(typeof(IStringLocalizer<>), typeof(StringLocalizer<>));
|
||||
serviceCollection.TryAddTransient(typeof(IStringLocalizer), typeof(StringLocalizer));
|
||||
|
||||
serviceCollection.AddSingleton(this);
|
||||
ServiceProvider = serviceCollection.BuildServiceProvider();
|
||||
|
||||
var minimumApiVersion = pluginType.GetCustomAttribute<MinimumApiVersion>()?.Version;
|
||||
@@ -185,6 +194,7 @@ namespace CounterStrikeSharp.API.Core.Plugin
|
||||
|
||||
Plugin.ModulePath = _path;
|
||||
Plugin.RegisterAllAttributes(Plugin);
|
||||
Plugin.Localizer = ServiceProvider.GetRequiredService<IStringLocalizer>();
|
||||
Plugin.Logger = ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(pluginType);
|
||||
|
||||
Plugin.InitializeConfig(Plugin, pluginType);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Globalization;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Translations;
|
||||
|
||||
public interface IPlayerLanguageManager
|
||||
{
|
||||
void SetLanguage(SteamID steamId, CultureInfo cultureInfo);
|
||||
CultureInfo GetLanguage(SteamID steamId);
|
||||
CultureInfo GetDefaultLanguage();
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Translations
|
||||
{
|
||||
public class JsonResourceManager
|
||||
{
|
||||
private static readonly JsonDocumentOptions _jsonDocumentOptions = new()
|
||||
{
|
||||
CommentHandling = JsonCommentHandling.Skip,
|
||||
AllowTrailingCommas = true,
|
||||
};
|
||||
|
||||
private ConcurrentDictionary<string, ConcurrentDictionary<string, string>> _resourcesCache = new();
|
||||
|
||||
public JsonResourceManager(string resourcesPath)
|
||||
{
|
||||
ResourcesPath = resourcesPath;
|
||||
}
|
||||
|
||||
public string ResourcesPath { get; }
|
||||
|
||||
public virtual ConcurrentDictionary<string, string> GetResourceSet(string cultureName)
|
||||
{
|
||||
TryLoadResourceSet(cultureName);
|
||||
_resourcesCache.TryGetValue(cultureName, out ConcurrentDictionary<string, string> resources);
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
public virtual ConcurrentDictionary<string, string> GetResourceSet(CultureInfo culture, bool tryParents)
|
||||
{
|
||||
TryLoadResourceSet(culture);
|
||||
|
||||
if (tryParents)
|
||||
{
|
||||
var allResources = new ConcurrentDictionary<string, string>();
|
||||
do
|
||||
{
|
||||
TryLoadResourceSet(culture);
|
||||
if (_resourcesCache.TryGetValue(culture.Name, out ConcurrentDictionary<string, string> resources))
|
||||
{
|
||||
foreach (var entry in resources)
|
||||
{
|
||||
allResources.TryAdd(entry.Key, entry.Value);
|
||||
}
|
||||
}
|
||||
|
||||
culture = culture.Parent;
|
||||
} while (culture != CultureInfo.InvariantCulture);
|
||||
|
||||
return allResources;
|
||||
}
|
||||
else
|
||||
{
|
||||
_resourcesCache.TryGetValue(culture.Name, out ConcurrentDictionary<string, string> resources);
|
||||
|
||||
return resources;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetFallbackString(string name)
|
||||
{
|
||||
GetResourceSet("en");
|
||||
|
||||
if (_resourcesCache.ContainsKey("en"))
|
||||
{
|
||||
if (_resourcesCache["en"].TryGetValue(name, out string value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual string GetString(string name)
|
||||
{
|
||||
var culture = CultureInfo.CurrentUICulture;
|
||||
GetResourceSet(culture, tryParents: true);
|
||||
|
||||
if (_resourcesCache.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (_resourcesCache.ContainsKey(culture.Name))
|
||||
{
|
||||
if (_resourcesCache[culture.Name].TryGetValue(name, out string value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
culture = culture.Parent;
|
||||
} while (culture != culture.Parent);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual string? GetString(string name, CultureInfo culture)
|
||||
{
|
||||
var values = GetResourceSet(culture, tryParents: true);
|
||||
|
||||
if (values.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return values.TryGetValue(name, out string value)
|
||||
? value
|
||||
: null;
|
||||
}
|
||||
|
||||
private void TryLoadResourceSet(string cultureName)
|
||||
{
|
||||
if (!_resourcesCache.ContainsKey(cultureName))
|
||||
{
|
||||
var file = Path.Combine(ResourcesPath, $"{cultureName}.json");
|
||||
|
||||
var resources = LoadJsonResources(file);
|
||||
|
||||
_resourcesCache.TryAdd(cultureName,
|
||||
new ConcurrentDictionary<string, string>(resources.ToDictionary(r => r.Key, r => r.Value)));
|
||||
}
|
||||
}
|
||||
|
||||
private void TryLoadResourceSet(CultureInfo culture)
|
||||
{
|
||||
TryLoadResourceSet(culture.Name);
|
||||
}
|
||||
|
||||
private static IDictionary<string, string> LoadJsonResources(string filePath)
|
||||
{
|
||||
var resources = new Dictionary<string, string>();
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
using var reader = new StreamReader(filePath);
|
||||
|
||||
using var document = JsonDocument.Parse(reader.BaseStream, _jsonDocumentOptions);
|
||||
|
||||
resources = document.RootElement.EnumerateObject().ToDictionary(e => e.Name, e => e.Value.ToString());
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Resources;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Translations;
|
||||
|
||||
public class JsonStringLocalizer : IStringLocalizer
|
||||
{
|
||||
private readonly JsonResourceManager _resourceManager;
|
||||
private readonly JsonStringProvider _resourceStringProvider;
|
||||
|
||||
public JsonStringLocalizer(string langPath)
|
||||
{
|
||||
_resourceManager = new JsonResourceManager(langPath);
|
||||
_resourceStringProvider = new(_resourceManager);
|
||||
}
|
||||
|
||||
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
|
||||
{
|
||||
return GetAllStrings(includeParentCultures, CultureInfo.CurrentUICulture);
|
||||
}
|
||||
|
||||
public LocalizedString this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
}
|
||||
|
||||
var value = GetStringSafely(name);
|
||||
|
||||
return new LocalizedString(name, value ?? name, resourceNotFound: value == null);
|
||||
}
|
||||
}
|
||||
|
||||
public LocalizedString this[string name, params object[] arguments]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
}
|
||||
|
||||
var format = GetStringSafely(name);
|
||||
var value = string.Format(format ?? name, arguments);
|
||||
|
||||
return new LocalizedString(name, value, resourceNotFound: format == null);
|
||||
}
|
||||
}
|
||||
|
||||
protected string? GetStringSafely(string name, CultureInfo? culture = null)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
}
|
||||
|
||||
culture = culture ?? CultureInfo.CurrentUICulture;
|
||||
|
||||
var result = _resourceManager.GetString(name, culture);
|
||||
|
||||
// Fallback to en if running in invariant mode.
|
||||
if (result == null && culture.Equals(CultureInfo.InvariantCulture))
|
||||
{
|
||||
result = _resourceManager.GetFallbackString(name);
|
||||
}
|
||||
|
||||
// Fallback to the default culture (en-US) if the resource is not found for the current culture.
|
||||
if (result == null && !culture.Equals(CultureInfo.DefaultThreadCurrentUICulture))
|
||||
{
|
||||
result = _resourceManager.GetString(name, CultureInfo.DefaultThreadCurrentUICulture!);
|
||||
}
|
||||
|
||||
return result?.ReplaceColorTags();
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures, CultureInfo culture)
|
||||
{
|
||||
if (culture == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(culture));
|
||||
}
|
||||
|
||||
var resourceNames = includeParentCultures
|
||||
? GetResourceNamesFromCultureHierarchy(culture)
|
||||
: _resourceStringProvider.GetAllResourceStrings(culture, true);
|
||||
|
||||
foreach (var name in resourceNames)
|
||||
{
|
||||
var value = GetStringSafely(name, culture);
|
||||
yield return new LocalizedString(name, value ?? name, resourceNotFound: value == null);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetResourceNamesFromCultureHierarchy(CultureInfo startingCulture)
|
||||
{
|
||||
var currentCulture = startingCulture;
|
||||
var resourceNames = new HashSet<string>();
|
||||
|
||||
while (currentCulture != currentCulture.Parent)
|
||||
{
|
||||
var cultureResourceNames = _resourceStringProvider.GetAllResourceStrings(currentCulture, false);
|
||||
|
||||
if (cultureResourceNames != null)
|
||||
{
|
||||
foreach (var resourceName in cultureResourceNames)
|
||||
{
|
||||
resourceNames.Add(resourceName);
|
||||
}
|
||||
}
|
||||
|
||||
currentCulture = currentCulture.Parent;
|
||||
}
|
||||
|
||||
return resourceNames;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using CounterStrikeSharp.API.Core.Hosting;
|
||||
using CounterStrikeSharp.API.Core.Plugin;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Translations;
|
||||
|
||||
public class JsonStringLocalizerFactory : IStringLocalizerFactory
|
||||
{
|
||||
private readonly IPluginContext _pluginContext;
|
||||
|
||||
public JsonStringLocalizerFactory(IPluginContext pluginContext)
|
||||
{
|
||||
_pluginContext = pluginContext;
|
||||
}
|
||||
|
||||
public IStringLocalizer Create(Type resourceSource)
|
||||
{
|
||||
return new JsonStringLocalizer(Path.Join(Path.GetDirectoryName(_pluginContext.FilePath), "lang"));
|
||||
}
|
||||
|
||||
public IStringLocalizer Create(string baseName, string location)
|
||||
{
|
||||
return new JsonStringLocalizer(Path.Join(Path.GetDirectoryName(_pluginContext.FilePath), "lang"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Resources;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Translations;
|
||||
|
||||
public class JsonStringProvider
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, IList<string>> _resourceNamesCache = new();
|
||||
private readonly JsonResourceManager _jsonResourceManager;
|
||||
|
||||
public JsonStringProvider(JsonResourceManager jsonResourceManager)
|
||||
{
|
||||
_jsonResourceManager = jsonResourceManager;
|
||||
}
|
||||
|
||||
private string GetResourceCacheKey(CultureInfo culture)
|
||||
{
|
||||
return $"Culture={culture.Name}";
|
||||
}
|
||||
|
||||
public IList<string> GetAllResourceStrings(CultureInfo culture, bool throwOnMissing)
|
||||
{
|
||||
var cacheKey = GetResourceCacheKey(culture);
|
||||
|
||||
return _resourceNamesCache.GetOrAdd(cacheKey, _ =>
|
||||
{
|
||||
var resourceSet = _jsonResourceManager.GetResourceSet(culture, tryParents: false);
|
||||
if (resourceSet == null)
|
||||
{
|
||||
if (throwOnMissing)
|
||||
{
|
||||
throw new MissingManifestResourceException($"The manifest resource for the culture '{culture.Name}' is missing.");
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var names = new List<string>();
|
||||
foreach (var entry in resourceSet)
|
||||
{
|
||||
names.Add(entry.Key);
|
||||
}
|
||||
|
||||
return names;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System.Globalization;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Translations;
|
||||
|
||||
public static class PlayerLanguageExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the players configured language, as set using the "css_lang" command.
|
||||
/// </summary>
|
||||
public static CultureInfo GetLanguage(this CCSPlayerController? player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return PlayerLanguageManager.Instance.GetDefaultLanguage();
|
||||
|
||||
return PlayerLanguageManager.Instance.GetLanguage((SteamID)player.SteamID);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Globalization;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Translations;
|
||||
|
||||
public class PlayerLanguageManager : IPlayerLanguageManager
|
||||
{
|
||||
private readonly ConcurrentDictionary<SteamID, CultureInfo> _playerLanguages = new();
|
||||
|
||||
public static IPlayerLanguageManager Instance { get; private set; } = null!;
|
||||
|
||||
public PlayerLanguageManager()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public void SetLanguage(SteamID steamId, CultureInfo cultureInfo)
|
||||
{
|
||||
_playerLanguages[steamId] = cultureInfo;
|
||||
}
|
||||
|
||||
public CultureInfo GetLanguage(SteamID steamId)
|
||||
{
|
||||
return _playerLanguages.TryGetValue(steamId, out var cultureInfo) ? cultureInfo : GetDefaultLanguage();
|
||||
}
|
||||
|
||||
public CultureInfo GetDefaultLanguage()
|
||||
{
|
||||
return CultureInfo.DefaultThreadCurrentUICulture!;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Reflection;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Translations;
|
||||
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string ReplaceColorTags(this string message)
|
||||
{
|
||||
var modifiedValue = message;
|
||||
foreach (var field in typeof(ChatColors).GetFields())
|
||||
{
|
||||
string pattern = $"{{{field.Name}}}";
|
||||
if (modifiedValue.Contains(pattern, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
modifiedValue = modifiedValue.Replace(pattern, field.GetValue(null)?.ToString() ?? string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
return modifiedValue.Equals(message) ? message : $" {modifiedValue}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Translations;
|
||||
|
||||
internal class StringLocalizer : IStringLocalizer
|
||||
{
|
||||
private IStringLocalizer _localizer;
|
||||
|
||||
public StringLocalizer(IStringLocalizerFactory factory)
|
||||
{
|
||||
var type = typeof(StringLocalizer);
|
||||
var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
|
||||
_localizer = factory.Create(string.Empty, assemblyName.FullName);
|
||||
}
|
||||
|
||||
public LocalizedString this[string name] => _localizer[name];
|
||||
|
||||
public LocalizedString this[string name, params object[] arguments] => _localizer[name, arguments];
|
||||
|
||||
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures) => _localizer.GetAllStrings(includeParentCultures);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Translations;
|
||||
|
||||
public sealed class WithTemporaryCulture : IDisposable
|
||||
{
|
||||
private readonly CultureInfo _originalCulture;
|
||||
|
||||
public WithTemporaryCulture(CultureInfo culture)
|
||||
{
|
||||
_originalCulture = CultureInfo.CurrentCulture;
|
||||
SetCulture(culture);
|
||||
}
|
||||
|
||||
private void SetCulture(CultureInfo cultureInfo)
|
||||
{
|
||||
CultureInfo.CurrentCulture = cultureInfo;
|
||||
CultureInfo.CurrentUICulture = cultureInfo;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
SetCulture(_originalCulture);
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,8 @@
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<EnablePackageValidation>true</EnablePackageValidation>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
<NoWarn>$(NoWarn);CS1591;CP0003</NoWarn>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<Authors>Roflmuffin</Authors>
|
||||
<Description>Official server side runtime assembly for CounterStrikeSharp</Description>
|
||||
<PackageProjectUrl>http://docs.cssharp.dev/</PackageProjectUrl>
|
||||
@@ -16,6 +15,10 @@
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApiCompatValidateAssemblies>true</ApiCompatValidateAssemblies>
|
||||
<ApiCompatContractAssembly>.\ApiCompat\v151.dll</ApiCompatContractAssembly>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Modules\Commands\CommandInfo" />
|
||||
<None Remove="Modules\Disabled\**" />
|
||||
@@ -23,8 +26,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="Microsoft.DotNet.ApiCompat.Task" Version="7.0.404" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
|
||||
<PackageReference Include="Scrutor" Version="4.2.2" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Admin
|
||||
{
|
||||
@@ -64,18 +66,18 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
// Loop over each of the admins. If one of our admins is in a group,
|
||||
// add the flags from the group to their admin definition and change
|
||||
// the admin's immunity if it's higher.
|
||||
foreach (var adminData in Admins.Values)
|
||||
foreach (var (admin, data) in Admins)
|
||||
{
|
||||
var groups = adminData.Groups;
|
||||
var groups = data.Groups;
|
||||
foreach (var group in groups)
|
||||
{
|
||||
// roflmuffin is probably smart enough to condense this function down ;)
|
||||
if (Groups.TryGetValue(group, out var groupData))
|
||||
{
|
||||
adminData.Flags.UnionWith(groupData.Flags);
|
||||
if (groupData.Immunity > adminData.Immunity)
|
||||
AddPlayerPermissions(admin, groupData.Flags.ToArray());
|
||||
if (groupData.Immunity > data.Immunity)
|
||||
{
|
||||
adminData.Immunity = groupData.Immunity;
|
||||
data.Immunity = groupData.Immunity;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,9 +95,21 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
// This is here for cases where the server console is attempting to call commands.
|
||||
// The server console should have access to all commands, regardless of groups.
|
||||
if (player == null) return true;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return false; }
|
||||
var playerData = GetPlayerAdminData((SteamID)player.AuthorizedSteamID);
|
||||
return playerData?.Groups.IsSupersetOf(groups) ?? false;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) { return false; }
|
||||
|
||||
var playerData = GetPlayerAdminData(player.AuthorizedSteamID);
|
||||
if (playerData == null) return false;
|
||||
|
||||
var playerGroups = groups.ToHashSet();
|
||||
foreach (var domain in playerData.Flags)
|
||||
{
|
||||
if (playerData.DomainHasRootFlag(domain.Key))
|
||||
{
|
||||
playerGroups.ExceptWith(groups.Where(group => group.Contains(domain.Key + '/')));
|
||||
}
|
||||
}
|
||||
|
||||
return playerData.Groups.IsSupersetOf(playerGroups);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -104,31 +118,44 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// <param name="steamId">SteamID of the player.</param>
|
||||
/// <param name="groups">Groups to check for.</param>
|
||||
/// <returns>True if a player is part of all of the groups provided, false if not.</returns>
|
||||
public static bool PlayerInGroup(SteamID steamId, params string[] groups)
|
||||
public static bool PlayerInGroup(SteamID? steamId, params string[] groups)
|
||||
{
|
||||
if (steamId == null) return false;
|
||||
var playerData = GetPlayerAdminData(steamId);
|
||||
return playerData?.Groups.IsSupersetOf(groups) ?? false;
|
||||
if (playerData == null) return false;
|
||||
|
||||
var playerGroups = groups.ToHashSet<string>();
|
||||
foreach (var domain in playerData.Flags)
|
||||
{
|
||||
if (playerData.DomainHasRootFlag(domain.Key))
|
||||
{
|
||||
playerGroups.ExceptWith(groups.Where(group => group.Contains(domain.Key + '/')));
|
||||
}
|
||||
}
|
||||
|
||||
return playerData.Groups.IsSupersetOf(playerGroups);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a player to a group.
|
||||
/// </summary>
|
||||
/// <param name="player">Player controller.</param>
|
||||
/// <param name="groups">Groups to add the player to.</param>
|
||||
public static void AddPlayerToGroup(CCSPlayerController? player, params string[] groups)
|
||||
/// <summary>
|
||||
/// Adds a player to a group. This does NOT modify the immunity of the player (see SetPlayerImmunity).
|
||||
/// </summary>
|
||||
/// <param name="player">Player controller.</param>
|
||||
/// <param name="groups">Groups to add the player to.</param>
|
||||
public static void AddPlayerToGroup(CCSPlayerController? player, params string[] groups)
|
||||
{
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return; }
|
||||
AddPlayerToGroup((SteamID)player.AuthorizedSteamID, groups);
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) { return; }
|
||||
AddPlayerToGroup(player.AuthorizedSteamID, groups);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a player to a group.
|
||||
/// Adds a player to a group. This does NOT modify the immunity of the player (see SetPlayerImmunity).
|
||||
/// </summary>
|
||||
/// <param name="steamId">SteamID of the player.</param>
|
||||
/// <param name="groups">Groups to add the player to.</param>
|
||||
public static void AddPlayerToGroup(SteamID steamId, params string[] groups)
|
||||
public static void AddPlayerToGroup(SteamID? steamId, params string[] groups)
|
||||
{
|
||||
if (steamId == null) return;
|
||||
var data = GetPlayerAdminData(steamId);
|
||||
if (data == null)
|
||||
{
|
||||
@@ -144,7 +171,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
{
|
||||
if (Groups.TryGetValue(group, out var groupDef))
|
||||
{
|
||||
data.Flags.UnionWith(groupDef.Flags);
|
||||
AddPlayerPermissions(steamId, groupDef.Flags.ToArray());
|
||||
groupDef.CommandOverrides.ToList().ForEach(x => data.CommandOverrides[x.Key] = x.Value);
|
||||
}
|
||||
}
|
||||
@@ -160,8 +187,8 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
public static void RemovePlayerFromGroup(CCSPlayerController? player, bool removeInheritedFlags = true, params string[] groups)
|
||||
{
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return; }
|
||||
RemovePlayerFromGroup((SteamID)player.AuthorizedSteamID, true, groups);
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) { return; }
|
||||
RemovePlayerFromGroup(player.AuthorizedSteamID, true, groups);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -170,8 +197,9 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// <param name="steamId">SteamID of the player.</param>
|
||||
/// <param name="removeInheritedFlags">If true, all of the flags that the player inherited from being in the group will be removed.</param>
|
||||
/// <param name="groups"></param>
|
||||
public static void RemovePlayerFromGroup(SteamID steamId, bool removeInheritedFlags = true, params string[] groups)
|
||||
public static void RemovePlayerFromGroup(SteamID? steamId, bool removeInheritedFlags = true, params string[] groups)
|
||||
{
|
||||
if (steamId == null) return;
|
||||
var data = GetPlayerAdminData(steamId);
|
||||
if (data == null) return;
|
||||
|
||||
@@ -183,7 +211,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
{
|
||||
if (Groups.TryGetValue(group, out var groupDef))
|
||||
{
|
||||
data.Flags.ExceptWith(groupDef.Flags);
|
||||
RemovePlayerPermissions(steamId, groupDef.Flags.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using CounterStrikeSharp.API.Core.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Admin
|
||||
{
|
||||
|
||||
public static partial class AdminManager
|
||||
{
|
||||
static AdminManager()
|
||||
public static void AddCommands()
|
||||
{
|
||||
CommandUtils.AddStandaloneCommand("css_admins_reload", "Reloads the admin file.", ReloadAdminsCommand);
|
||||
CommandUtils.AddStandaloneCommand("css_admins_list", "List admins and their flags.", ListAdminsCommand);
|
||||
@@ -37,6 +33,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
Admins.Clear();
|
||||
var rootDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.Parent;
|
||||
LoadAdminData(Path.Combine(rootDir.FullName, "configs", "admins.json"));
|
||||
MergeGroupPermsIntoAdmins();
|
||||
}
|
||||
|
||||
[RequiresPermissions(permissions:"@css/generic")]
|
||||
@@ -45,7 +42,11 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
{
|
||||
foreach (var (steamId, data) in Admins)
|
||||
{
|
||||
command.ReplyToCommand($"{steamId.SteamId64}, {steamId.SteamId2} - {string.Join(", ", data.Flags)}");
|
||||
command.ReplyToCommand($"{steamId.SteamId64}, {steamId.SteamId2} - FLAGS: ");
|
||||
foreach (var domain in data.Flags.Keys)
|
||||
{
|
||||
command.ReplyToCommand($" Domain {domain}: {string.Join(", ", data.Flags[domain])}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +57,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
Groups.Clear();
|
||||
var rootDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.Parent;
|
||||
LoadAdminGroups(Path.Combine(rootDir.FullName, "configs", "admin_groups.json"));
|
||||
MergeGroupPermsIntoAdmins();
|
||||
}
|
||||
|
||||
[RequiresPermissions(permissions: "@css/generic")]
|
||||
|
||||
@@ -3,24 +3,110 @@ using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using System.Reflection;
|
||||
using System.Numerics;
|
||||
using System.Linq;
|
||||
using CounterStrikeSharp.API.Core.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Numerics;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using System.Diagnostics.Eventing.Reader;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Admin
|
||||
{
|
||||
public partial class AdminData
|
||||
{
|
||||
[JsonPropertyName("identity")] public required string Identity { get; init; }
|
||||
[JsonPropertyName("flags")] public HashSet<string> Flags { get; init; } = new();
|
||||
// Flags loaded from file. Do not use this for actual comparisons.
|
||||
[JsonPropertyName("flags")] public HashSet<string> _flags { get; init; } = new();
|
||||
|
||||
[JsonPropertyName("immunity")] public uint Immunity { get; set; } = 0;
|
||||
[JsonPropertyName("command_overrides")] public Dictionary<string, bool> CommandOverrides { get; init; } = new();
|
||||
|
||||
// Key is the domain of the flag "e.g "css, os, kzsurf"). This should NOT include the @ character.
|
||||
// Value is a hashmap of the flags inside of the domain (e.g "@css/generic")
|
||||
public Dictionary<string, HashSet<string>> Flags { get; init; } = new();
|
||||
|
||||
public void InitalizeFlags()
|
||||
{
|
||||
AddFlags(_flags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if a domain has a root flag inside of it.
|
||||
/// </summary>
|
||||
/// <param name="domain">Domain to check for.</param>
|
||||
/// <returns>True if "@{domain}/root" or "@{domain}/*" is present, false if not.</returns>
|
||||
public bool DomainHasRootFlag(string domain)
|
||||
{
|
||||
if (!Flags.ContainsKey(domain)) return false;
|
||||
if (Flags[domain].Contains("@" + domain + "/root")) return true;
|
||||
else if (Flags[domain].Contains("@" + domain + "/*")) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all domains for flags.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string[] GetFlagDomains()
|
||||
{
|
||||
return Flags.Keys.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a HashSet of all flags.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public HashSet<string> GetAllFlags()
|
||||
{
|
||||
var flags = new HashSet<string>();
|
||||
foreach (var domainFlags in Flags.Values)
|
||||
{
|
||||
flags.UnionWith(domainFlags);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
public void AddFlags(HashSet<string> flags)
|
||||
{
|
||||
var domains = flags.Where(
|
||||
flag => flag.StartsWith(PermissionCharacters.UserPermissionChar))
|
||||
.Distinct()
|
||||
.Select(domain => domain.Split('/').First()[1..]);
|
||||
|
||||
foreach (var domain in domains)
|
||||
{
|
||||
if (!Flags.ContainsKey(domain))
|
||||
{
|
||||
Flags[domain] = new HashSet<string>();
|
||||
}
|
||||
Flags[domain].UnionWith(flags.Where(flag => flag.StartsWith(PermissionCharacters.UserPermissionChar + domain + '/')).ToHashSet());
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveFlags(HashSet<string> flags)
|
||||
{
|
||||
var domains = flags.Where(
|
||||
flag => flag.StartsWith(PermissionCharacters.UserPermissionChar))
|
||||
.Distinct()
|
||||
.Select(domain => domain.Split('/').First()[1..]);
|
||||
|
||||
foreach (var domain in domains)
|
||||
{
|
||||
if (!Flags.ContainsKey(domain)) continue;
|
||||
var domainFlags = flags.Where(flag => flag.StartsWith(PermissionCharacters.UserPermissionChar + domain + '/')).ToHashSet();
|
||||
Flags[domain].ExceptWith(flags);
|
||||
if (Flags[domain].Count() == 0) Flags.Remove(domain);
|
||||
}
|
||||
}
|
||||
|
||||
public bool DomainHasFlags(string domain, string[] flags, bool ignoreRoot = false)
|
||||
{
|
||||
if (!Flags.ContainsKey(domain)) return false;
|
||||
if (DomainHasRootFlag(domain) && !ignoreRoot) return true;
|
||||
return Flags[domain].IsSupersetOf(flags);
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class AdminManager
|
||||
@@ -39,16 +125,28 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
_logger.LogWarning("Admin data file not found. Skipping admin data load.");
|
||||
return;
|
||||
}
|
||||
|
||||
var adminsFromFile = JsonSerializer.Deserialize<Dictionary<string, AdminData>>(File.ReadAllText(adminDataPath), new JsonSerializerOptions() { ReadCommentHandling = JsonCommentHandling.Skip });
|
||||
var settings = new JsonSerializerOptions() { ReadCommentHandling = JsonCommentHandling.Skip };
|
||||
var adminsFromFile = JsonSerializer.Deserialize<Dictionary<string, AdminData>>(File.ReadAllText(adminDataPath), settings);
|
||||
if (adminsFromFile == null) { throw new FileNotFoundException(); }
|
||||
|
||||
foreach (var adminDef in adminsFromFile.Values)
|
||||
{
|
||||
adminDef.InitalizeFlags();
|
||||
Console.WriteLine($"Domains: {adminDef.Flags.Count}");
|
||||
|
||||
if (SteamID.TryParse(adminDef.Identity, out var steamId))
|
||||
{
|
||||
if (Admins.ContainsKey(steamId!))
|
||||
{
|
||||
Admins[steamId!].Flags.UnionWith(adminDef.Flags);
|
||||
// Merge domains together if we already have pre-existing values.
|
||||
foreach (var (domain, flags) in adminDef.Flags)
|
||||
{
|
||||
if (Admins[steamId!].Flags.ContainsKey(domain))
|
||||
{
|
||||
Admins[steamId!].Flags[domain].UnionWith(flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (adminDef.Immunity > Admins[steamId!].Immunity)
|
||||
{
|
||||
Admins[steamId!].Immunity = adminDef.Immunity;
|
||||
@@ -69,22 +167,45 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Grabs the admin data for a player that was loaded from "configs/admins.json".
|
||||
/// </summary>
|
||||
/// <param name="steamId">SteamID object of the player.</param>
|
||||
/// <returns>AdminData class if data found, null if not.</returns>
|
||||
public static AdminData? GetPlayerAdminData(SteamID steamId)
|
||||
/// <summary>
|
||||
/// Grabs the admin data for a player that was loaded from "configs/admins.json" and "configs/admins_groups.json".
|
||||
/// </summary>
|
||||
/// <param name="player">Player controller</param>
|
||||
/// <returns>AdminData class if data found, null if not.</returns>
|
||||
public static AdminData? GetPlayerAdminData(CCSPlayerController? player)
|
||||
{
|
||||
if (player == null) return null;
|
||||
return GetPlayerAdminData(player.AuthorizedSteamID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Grabs the admin data for a player that was loaded from "configs/admins.json" and "configs/admins_groups.json".
|
||||
/// </summary>
|
||||
/// <param name="steamId">SteamID object of the player.</param>
|
||||
/// <returns>AdminData class if data found, null if not.</returns>
|
||||
public static AdminData? GetPlayerAdminData(SteamID? steamId)
|
||||
{
|
||||
if (steamId == null) return null;
|
||||
return Admins.GetValueOrDefault(steamId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a players admin data. This is not saved to "configs/admins.json"
|
||||
/// </summary>
|
||||
/// <param name="steamId">Steam ID remove admin data from.</param>
|
||||
public static void RemovePlayerAdminData(SteamID steamId)
|
||||
/// <summary>
|
||||
/// Removes a players admin data. This is not saved to "configs/admins.json"
|
||||
/// </summary>
|
||||
/// <param name="player">Player controller</param>
|
||||
public static void RemovePlayerAdminData(CCSPlayerController? player)
|
||||
{
|
||||
if (player == null) return;
|
||||
RemovePlayerAdminData(player.AuthorizedSteamID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a players admin data. This is not saved to "configs/admins.json"
|
||||
/// </summary>
|
||||
/// <param name="steamId">Steam ID remove admin data from.</param>
|
||||
public static void RemovePlayerAdminData(SteamID? steamId)
|
||||
{
|
||||
if (steamId == null) return;
|
||||
Admins.Remove(steamId);
|
||||
}
|
||||
|
||||
@@ -101,9 +222,8 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
// This is here for cases where the server console is attempting to call commands.
|
||||
// The server console should have access to all commands, regardless of permissions.
|
||||
if (player == null) return true;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return false; }
|
||||
var playerData = GetPlayerAdminData(player.AuthorizedSteamID);
|
||||
return playerData?.Flags.IsSupersetOf(flags) ?? false;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) { return false; }
|
||||
return PlayerHasPermissions(player.AuthorizedSteamID, flags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -112,10 +232,36 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// <param name="steamId">Steam ID object.</param>
|
||||
/// <param name="flags">Flags to look for in the players permission flags.</param>
|
||||
/// <returns>True if flags are present, false if not.</returns>
|
||||
public static bool PlayerHasPermissions(SteamID steamId, params string[] flags)
|
||||
public static bool PlayerHasPermissions(SteamID? steamId, params string[] flags)
|
||||
{
|
||||
if (steamId == null) return false;
|
||||
var playerData = GetPlayerAdminData(steamId);
|
||||
return playerData?.Flags.IsSupersetOf(flags) ?? false;
|
||||
if (playerData == null) return false;
|
||||
|
||||
// Check to see that all of the domains in the flags that we're checking are
|
||||
// present in our player data.
|
||||
var localDomains = flags.Where(
|
||||
flag => flag.StartsWith(PermissionCharacters.UserPermissionChar))
|
||||
.Distinct()
|
||||
.Select(domain => domain.Split('/').First()[1..])
|
||||
.ToHashSet();
|
||||
var playerFlagDomains = playerData.GetFlagDomains().ToHashSet();
|
||||
if (!playerFlagDomains.IsSupersetOf(localDomains)) return false;
|
||||
|
||||
// Loop through all of the domains and see if we have the required flags
|
||||
// for every domain.
|
||||
bool returnValue = true;
|
||||
foreach (var domain in playerData.Flags)
|
||||
{
|
||||
if (!playerData.DomainHasFlags(domain.Key,
|
||||
flags
|
||||
.Where(flag => flag.StartsWith(PermissionCharacters.UserPermissionChar + domain.Key + '/'))
|
||||
.ToArray()))
|
||||
{
|
||||
returnValue = false; break;
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -135,8 +281,8 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
// This is here for cases where the server console is attempting to call commands.
|
||||
// The server console should have access to all commands, regardless of permissions.
|
||||
if (player == null) return true;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return false; }
|
||||
var playerData = GetPlayerAdminData((SteamID)player.AuthorizedSteamID);
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) { return false; }
|
||||
var playerData = GetPlayerAdminData(player.AuthorizedSteamID);
|
||||
return playerData?.CommandOverrides.ContainsKey(command) ?? false;
|
||||
}
|
||||
|
||||
@@ -147,8 +293,9 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// <param name="steamId">Steam ID object.</param>
|
||||
/// <param name="command">Name of the command to check for.</param>
|
||||
/// <returns>True if override exists, false if not.</returns>
|
||||
public static bool PlayerHasCommandOverride(SteamID steamId, string command)
|
||||
public static bool PlayerHasCommandOverride(SteamID? steamId, string command)
|
||||
{
|
||||
if (steamId == null) return false;
|
||||
var playerData = GetPlayerAdminData(steamId);
|
||||
return playerData?.CommandOverrides.ContainsKey(command) ?? false;
|
||||
}
|
||||
@@ -164,8 +311,8 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
// This is here for cases where the server console is attempting to call commands.
|
||||
// The server console should have access to all commands, regardless of permissions.
|
||||
if (player == null) return true;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return false; }
|
||||
var playerData = GetPlayerAdminData((SteamID)player.AuthorizedSteamID);
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) { return false; }
|
||||
var playerData = GetPlayerAdminData(player.AuthorizedSteamID);
|
||||
return playerData?.CommandOverrides.GetValueOrDefault(command) ?? false;
|
||||
}
|
||||
|
||||
@@ -175,8 +322,9 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// <param name="steamId">Steam ID object.</param>
|
||||
/// <param name="command">Name of the command to check for.</param>
|
||||
/// <returns>True if override is active, false if not.</returns>
|
||||
public static bool GetPlayerCommandOverrideState(SteamID steamId, string command)
|
||||
public static bool GetPlayerCommandOverrideState(SteamID? steamId, string command)
|
||||
{
|
||||
if (steamId == null) return false;
|
||||
var playerData = GetPlayerAdminData(steamId);
|
||||
return playerData?.CommandOverrides.GetValueOrDefault(command) ?? false;
|
||||
}
|
||||
@@ -192,8 +340,8 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
// This is here for cases where the server console is attempting to call commands.
|
||||
// The server console should have access to all commands, regardless of permissions.
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return; }
|
||||
SetPlayerCommandOverride((SteamID)player.AuthorizedSteamID, command, state);
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) { return; }
|
||||
SetPlayerCommandOverride(player.AuthorizedSteamID, command, state);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -202,8 +350,9 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// <param name="steamId">SteamID to add a flag to.</param>
|
||||
/// <param name="command">Name of the command to check for.</param>
|
||||
/// <param name="state">New state of the command override.</param>
|
||||
public static void SetPlayerCommandOverride(SteamID steamId, string command, bool state)
|
||||
public static void SetPlayerCommandOverride(SteamID? steamId, string command, bool state)
|
||||
{
|
||||
if (steamId == null) return;
|
||||
var data = GetPlayerAdminData(steamId);
|
||||
if (data == null)
|
||||
{
|
||||
@@ -234,8 +383,8 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
public static void AddPlayerPermissions(CCSPlayerController? player, params string[] flags)
|
||||
{
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) return;
|
||||
AddPlayerPermissions((SteamID)player.AuthorizedSteamID, flags);
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) return;
|
||||
AddPlayerPermissions(player.AuthorizedSteamID, flags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -244,27 +393,23 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// </summary>
|
||||
/// <param name="steamId">SteamID to add a flag to.</param>
|
||||
/// <param name="flags">Flags to add for the player.</param>
|
||||
public static void AddPlayerPermissions(SteamID steamId, params string[] flags)
|
||||
public static void AddPlayerPermissions(SteamID? steamId, params string[] flags)
|
||||
{
|
||||
if (steamId == null) return;
|
||||
var data = GetPlayerAdminData(steamId);
|
||||
if (data == null)
|
||||
{
|
||||
data = new AdminData()
|
||||
{
|
||||
Identity = steamId.SteamId64.ToString(),
|
||||
Flags = new(flags),
|
||||
Flags = new(),
|
||||
Groups = new()
|
||||
};
|
||||
|
||||
Admins[steamId] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var flag in flags)
|
||||
{
|
||||
data.Flags.Add(flag);
|
||||
}
|
||||
Admins[steamId] = data;
|
||||
|
||||
Admins[steamId].AddFlags(flags.ToHashSet<string>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -276,9 +421,9 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
public static void RemovePlayerPermissions(CCSPlayerController? player, params string[] flags)
|
||||
{
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) return;
|
||||
|
||||
RemovePlayerPermissions((SteamID)player.AuthorizedSteamID, flags);
|
||||
RemovePlayerPermissions(player.AuthorizedSteamID, flags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -287,13 +432,12 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// </summary>
|
||||
/// <param name="steamId">Steam ID to remove flags from.</param>
|
||||
/// <param name="flags">Flags to remove from the player.</param>
|
||||
public static void RemovePlayerPermissions(SteamID steamId, params string[] flags)
|
||||
public static void RemovePlayerPermissions(SteamID? steamId, params string[] flags)
|
||||
{
|
||||
if (steamId == null) return;
|
||||
var data = GetPlayerAdminData(steamId);
|
||||
if (data == null) return;
|
||||
|
||||
data.Flags.ExceptWith(flags);
|
||||
Admins[steamId] = data;
|
||||
Admins[steamId].RemoveFlags(flags.ToHashSet<string>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -304,9 +448,9 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
public static void ClearPlayerPermissions(CCSPlayerController? player)
|
||||
{
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) return;
|
||||
|
||||
ClearPlayerPermissions((SteamID)player.AuthorizedSteamID);
|
||||
ClearPlayerPermissions(player.AuthorizedSteamID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -314,8 +458,9 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// "configs/admins.json".
|
||||
/// </summary>
|
||||
/// <param name="steamId">Steam ID to remove flags from.</param>
|
||||
public static void ClearPlayerPermissions(SteamID steamId)
|
||||
public static void ClearPlayerPermissions(SteamID? steamId)
|
||||
{
|
||||
if (steamId == null) return;
|
||||
var data = GetPlayerAdminData(steamId);
|
||||
if (data == null) return;
|
||||
|
||||
@@ -333,9 +478,9 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
public static void SetPlayerImmunity(CCSPlayerController? player, uint value)
|
||||
{
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) return;
|
||||
|
||||
SetPlayerImmunity((SteamID)player.AuthorizedSteamID, value);
|
||||
SetPlayerImmunity(player.AuthorizedSteamID, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -343,8 +488,9 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// </summary>
|
||||
/// <param name="steamId">Steam ID of the player.</param>
|
||||
/// <param name="value">New immunity value.</param>
|
||||
public static void SetPlayerImmunity(SteamID steamId, uint value)
|
||||
public static void SetPlayerImmunity(SteamID? steamId, uint value)
|
||||
{
|
||||
if (steamId == null) return;
|
||||
var data = GetPlayerAdminData(steamId);
|
||||
if (data == null) return;
|
||||
|
||||
@@ -352,13 +498,44 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
Admins[steamId] = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if a player can target another player based on their immunity value.
|
||||
/// </summary>
|
||||
/// <param name="caller">Caller of the command.</param>
|
||||
/// <param name="target">Target of the command.</param>
|
||||
/// <returns></returns>
|
||||
public static bool CanPlayerTarget(CCSPlayerController? caller, CCSPlayerController? target)
|
||||
/// <summary>
|
||||
/// Returns the immunity value for a player.
|
||||
/// </summary>
|
||||
/// <param name="player">Player controller.</param>
|
||||
/// <returns> If an immunity value is present in "configs/admins_groups.json"
|
||||
/// and in "configs/admins.json", the returned value will be the greater of the two.
|
||||
/// If the value is overriden with SetPlayerImmunity, that value is returned instead.</returns>
|
||||
public static uint GetPlayerImmunity(CCSPlayerController? player)
|
||||
{
|
||||
if (player == null) return 0;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot || player.IsHLTV) return 0;
|
||||
|
||||
return GetPlayerImmunity(player.AuthorizedSteamID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the immunity value for a player.
|
||||
/// </summary>
|
||||
/// <param name="steamId">Steam ID of the player.</param>
|
||||
/// <returns> If an immunity value is present in "configs/admins_groups.json"
|
||||
/// and in "configs/admins.json", the returned value will be the greater of the two.
|
||||
/// If the value is overriden with SetPlayerImmunity, that value is returned instead.</returns>
|
||||
public static uint GetPlayerImmunity(SteamID? steamId)
|
||||
{
|
||||
if (steamId == null) return 0;
|
||||
var data = GetPlayerAdminData(steamId);
|
||||
if (data == null) return 0;
|
||||
|
||||
return data.Immunity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if a player can target another player based on their immunity value.
|
||||
/// </summary>
|
||||
/// <param name="caller">Caller of the command.</param>
|
||||
/// <param name="target">Target of the command.</param>
|
||||
/// <returns></returns>
|
||||
public static bool CanPlayerTarget(CCSPlayerController? caller, CCSPlayerController? target)
|
||||
{
|
||||
// The server console should be able to target everyone.
|
||||
if (caller == null) return true;
|
||||
@@ -366,10 +543,10 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
if (target == null) return false;
|
||||
if (!target.IsValid || target.Connected != PlayerConnectedState.PlayerConnected) return false;
|
||||
|
||||
var callerData = GetPlayerAdminData((SteamID)caller.AuthorizedSteamID);
|
||||
var callerData = GetPlayerAdminData(caller.AuthorizedSteamID);
|
||||
if (callerData == null) return false;
|
||||
|
||||
var targetData = GetPlayerAdminData((SteamID)target.AuthorizedSteamID);
|
||||
var targetData = GetPlayerAdminData(target.AuthorizedSteamID);
|
||||
if (targetData == null) return true;
|
||||
|
||||
return callerData.Immunity >= targetData.Immunity;
|
||||
@@ -381,12 +558,15 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// <param name="caller">Caller of the command.</param>
|
||||
/// <param name="target">Target of the command.</param>
|
||||
/// <returns></returns>
|
||||
public static bool CanPlayerTarget(SteamID caller, SteamID target)
|
||||
public static bool CanPlayerTarget(SteamID? caller, SteamID? target)
|
||||
{
|
||||
if (caller == null) return false;
|
||||
if (target == null) return false;
|
||||
|
||||
var callerData = GetPlayerAdminData(caller);
|
||||
if (callerData == null) return false;
|
||||
|
||||
var targetData = GetPlayerAdminData(caller);
|
||||
var targetData = GetPlayerAdminData(target);
|
||||
if (targetData == null) return true;
|
||||
|
||||
return callerData.Immunity >= targetData.Immunity;
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
/// <summary>
|
||||
/// The permissions for the command.
|
||||
/// </summary>
|
||||
public string[] Permissions { get; }
|
||||
public HashSet<string> Permissions { get; }
|
||||
/// <summary>
|
||||
/// The name of the command that is attached to this attribute.
|
||||
/// </summary>
|
||||
@@ -23,7 +23,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
|
||||
public BaseRequiresPermissions(params string[] permissions)
|
||||
{
|
||||
Permissions = permissions;
|
||||
Permissions = permissions.ToHashSet();
|
||||
Command = "";
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,14 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
var groupPermissions = Permissions.Where(perm => perm.StartsWith(PermissionCharacters.GroupPermissionChar));
|
||||
var userPermissions = Permissions.Where(perm => perm.StartsWith(PermissionCharacters.UserPermissionChar));
|
||||
|
||||
if (!AdminManager.PlayerInGroup(caller, groupPermissions.ToArray())) return false;
|
||||
if (!AdminManager.PlayerHasPermissions(caller, userPermissions.ToArray())) return false;
|
||||
if (!AdminManager.PlayerHasPermissions(caller, userPermissions.ToArray()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!AdminManager.PlayerInGroup(caller, groupPermissions.ToArray()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -20,12 +20,28 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
}
|
||||
if (!base.CanExecuteCommand(caller)) return false;
|
||||
|
||||
var groupPermissions = Permissions.Where(perm => perm.StartsWith(PermissionCharacters.GroupPermissionChar));
|
||||
var userPermissions = Permissions.Where(perm => perm.StartsWith(PermissionCharacters.UserPermissionChar));
|
||||
|
||||
var adminData = AdminManager.GetPlayerAdminData(caller.AuthorizedSteamID);
|
||||
if (adminData == null) return false;
|
||||
return (groupPermissions.Intersect(adminData.Groups).Count() + userPermissions.Intersect(adminData.Flags).Count()) > 0;
|
||||
|
||||
// Check to see if the caller has a root flag for any of the domains in our permissions.
|
||||
// If they do, remove all of the user flags and groups that belong to the domain
|
||||
// from our permission check.
|
||||
var domains = Permissions.Where(
|
||||
flag => flag.StartsWith(PermissionCharacters.GroupPermissionChar))
|
||||
.Distinct()
|
||||
.Select(domain => domain.Split('/').First()[1..]);
|
||||
|
||||
foreach (var domain in domains)
|
||||
{
|
||||
if (adminData.DomainHasRootFlag(domain))
|
||||
{
|
||||
Permissions.RemoveWhere(flag => flag.Contains(domain + '/'));
|
||||
}
|
||||
}
|
||||
|
||||
var groupPermissions = Permissions.Where(perm => perm.StartsWith(PermissionCharacters.GroupPermissionChar));
|
||||
var userPermissions = Permissions.Where(perm => perm.StartsWith(PermissionCharacters.UserPermissionChar));
|
||||
return (groupPermissions.Intersect(adminData.Groups).Count() + userPermissions.Intersect(adminData.GetAllFlags()).Count()) > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace CounterStrikeSharp.API.Modules.Commands
|
||||
|
||||
public IntPtr Handle { get; }
|
||||
|
||||
internal CommandInfo(IntPtr pointer, CCSPlayerController player)
|
||||
internal CommandInfo(IntPtr pointer, CCSPlayerController? player)
|
||||
{
|
||||
Handle = pointer;
|
||||
CallingPlayer = player;
|
||||
|
||||
@@ -90,11 +90,11 @@ public class Target
|
||||
case TargetType.TeamSpec:
|
||||
return player.TeamNum == (byte)CsTeam.Spectator;
|
||||
case TargetType.GroupAll:
|
||||
return true;
|
||||
return !player.IsHLTV;
|
||||
case TargetType.GroupBots:
|
||||
return player.IsBot;
|
||||
case TargetType.GroupHumans:
|
||||
return !player.IsBot;
|
||||
return !player.IsBot && !player.IsHLTV;
|
||||
case TargetType.GroupAlive:
|
||||
return player.PlayerPawn is { IsValid: true, Value.LifeState: (byte)LifeState_t.LIFE_ALIVE };
|
||||
case TargetType.GroupDead:
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Listeners;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Cvars
|
||||
{
|
||||
public class ConVar
|
||||
{
|
||||
public delegate void ConVarChangedCallback(ConVar convar, string oldValue, string newValue);
|
||||
|
||||
public IntPtr Handle { get; private set; }
|
||||
|
||||
internal ConVar(IntPtr handle)
|
||||
{
|
||||
Handle = handle;
|
||||
}
|
||||
|
||||
public ConVar(string name, string value, string description, ConVarFlags flags, bool hasMinValue, float minValue, bool hasMaxValue, float maxValue) :
|
||||
this(NativeAPI.CreateConvar(name, value, description, (int)flags, hasMinValue, minValue, hasMaxValue, maxValue))
|
||||
{
|
||||
}
|
||||
|
||||
public ConVar(string name, string value, string description = null, ConVarFlags flags = ConVarFlags.None, float? minValue = null, float? maxValue = null) :
|
||||
this(name, value, description, flags, minValue.HasValue, minValue?? 0, maxValue.HasValue, maxValue?? 0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string Name => NativeAPI.ConvarGetName(Handle);
|
||||
|
||||
public string StringValue
|
||||
{
|
||||
get { return NativeAPI.ConvarGetStringValue(Handle); }
|
||||
set { NativeAPI.ConvarSetStringValue(Handle, value); }
|
||||
}
|
||||
|
||||
public float FloatValue
|
||||
{
|
||||
get { return Convert.ToSingle(NativeAPI.ConvarGetStringValue(Handle)); }
|
||||
set { NativeAPI.ConvarSetStringValue(Handle, value.ToString("n2")); }
|
||||
}
|
||||
|
||||
public int IntValue
|
||||
{
|
||||
get { return Convert.ToInt32(NativeAPI.ConvarGetStringValue(Handle)); }
|
||||
set { NativeAPI.ConvarSetStringValue(Handle, value.ToString()); }
|
||||
}
|
||||
|
||||
public bool BoolValue
|
||||
{
|
||||
get { return NativeAPI.ConvarGetStringValue(Handle) == "1"; }
|
||||
set { NativeAPI.ConvarSetStringValue(Handle, value ? "1" : "0"); }
|
||||
}
|
||||
|
||||
public ConVarFlags Flags
|
||||
{
|
||||
get { return (ConVarFlags) NativeAPI.ConvarGetFlags(Handle); }
|
||||
set { NativeAPI.ConvarSetFlags(Handle, (int)value); }
|
||||
}
|
||||
|
||||
public bool Public
|
||||
{
|
||||
get { return Flags.HasFlag(ConVarFlags.Notify); }
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
Flags |= ConVarFlags.Notify;
|
||||
}
|
||||
else
|
||||
{
|
||||
Flags &= ~ConVarFlags.Notify;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ConVar Find(string name)
|
||||
{
|
||||
var ptr = NativeAPI.FindConvar(name);
|
||||
if (ptr == IntPtr.Zero) return null;
|
||||
|
||||
return new ConVar(ptr);
|
||||
}
|
||||
|
||||
public void Unregister()
|
||||
{
|
||||
NativeAPI.ConvarUnregister(Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Engine.Trace
|
||||
{
|
||||
public enum ContentMasks
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Engine.Trace
|
||||
{
|
||||
public enum RayType
|
||||
{
|
||||
EndPoint,
|
||||
Infinite
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Listeners;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Engine.Trace
|
||||
{
|
||||
public class SimpleTraceFilter : NativeObject
|
||||
{
|
||||
public SimpleTraceFilter(IntPtr cPtr) : base(cPtr)
|
||||
{
|
||||
}
|
||||
|
||||
public SimpleTraceFilter(int indexToIgnore) : base(NativeAPI.NewSimpleTraceFilter(indexToIgnore))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class TraceFilterProxy : NativeObject
|
||||
{
|
||||
private ITraceFilter _filter;
|
||||
private FunctionReference.CallbackDelegate getTypeCallback;
|
||||
private FunctionReference.CallbackDelegate shouldHitCallback;
|
||||
|
||||
public TraceFilterProxy(IntPtr cPtr) : base(cPtr)
|
||||
{
|
||||
}
|
||||
|
||||
public TraceFilterProxy(ITraceFilter filter) : base(NativeAPI.NewTraceFilterProxy())
|
||||
{
|
||||
_filter = filter;
|
||||
|
||||
/*
|
||||
getTypeCallback = Utilities.SafeExecute(intPtr =>
|
||||
{
|
||||
var marshal = new CMarshalObject();
|
||||
marshal.PushInt((int) _filter.GetTraceType());
|
||||
return marshal.GetPointer();
|
||||
});
|
||||
*/
|
||||
|
||||
/*shouldHitCallback = Utilities.SafeExecute(ptr =>
|
||||
{
|
||||
var marshal = new CMarshalObject(ptr, true);
|
||||
var entity = marshal.GetValue<BaseEntity>();
|
||||
var contentMask = marshal.GetInt();
|
||||
|
||||
var isValidEntity = _filter.ShouldHitEntity(entity, contentMask);
|
||||
|
||||
var response = new CMarshalObject();
|
||||
response.PushInt(isValidEntity ? 1 : 0);
|
||||
|
||||
return response.GetPointer();
|
||||
});*/
|
||||
|
||||
unsafe
|
||||
{
|
||||
getTypeCallback = (fxScriptContext* context) =>
|
||||
{
|
||||
var scriptContext = new ScriptContext(context);
|
||||
|
||||
scriptContext.Push(_filter.GetTraceType());
|
||||
};
|
||||
|
||||
shouldHitCallback = (fxScriptContext* context) =>
|
||||
{
|
||||
var scriptContext = new ScriptContext(context);
|
||||
|
||||
var entity = new BaseEntity(scriptContext.GetArgument<int>(0));
|
||||
var contentMask = scriptContext.GetArgument<int>(1);
|
||||
|
||||
var isValidEntity = _filter.ShouldHitEntity(entity, contentMask);
|
||||
|
||||
Console.WriteLine($"Returning {isValidEntity} to `ShouldHitEntity`");
|
||||
|
||||
scriptContext.SetResult(isValidEntity, context);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
NativeAPI.TraceFilterProxySetTraceTypeCallback(Handle, Marshal.GetFunctionPointerForDelegate(getTypeCallback));
|
||||
NativeAPI.TraceFilterProxySetShouldHitEntityCallback(Handle, Marshal.GetFunctionPointerForDelegate(shouldHitCallback));
|
||||
/*NativeAPI.TraceFilterProxySetTraceTypeCallback(Handle, getTypeCallback);
|
||||
NativePINVOKE.TraceFilterProxy_SetGetTraceTypeCallback(ptr, getTypeCallback.ToHandle());
|
||||
NativePINVOKE.TraceFilterProxy_SetShouldHitEntityCallback(ptr, shouldHitCallback.ToHandle());*/
|
||||
}
|
||||
}
|
||||
|
||||
public enum TraceType
|
||||
{
|
||||
Everything = 0,
|
||||
WorldOnly, // NOTE: This does *not* test static props!!!
|
||||
EntitiesOnly, // NOTE: This version will *not* test static props
|
||||
EverythingFilterProps, // NOTE: This version will pass the IHandleEntity for props through the filter, unlike all other filters
|
||||
};
|
||||
|
||||
public class CustomTraceFilter : TraceFilter
|
||||
{
|
||||
private Func<BaseEntity, bool> _filter;
|
||||
|
||||
public CustomTraceFilter(Func<BaseEntity, bool> filter)
|
||||
{
|
||||
_filter = filter;
|
||||
}
|
||||
public override bool ShouldHitEntity(BaseEntity entity, int contentMask)
|
||||
{
|
||||
return _filter.Invoke(entity);
|
||||
}
|
||||
|
||||
public override TraceType GetTraceType()
|
||||
{
|
||||
return TraceType.Everything;
|
||||
}
|
||||
}
|
||||
|
||||
public class ExclusionTraceFilter : TraceFilter
|
||||
{
|
||||
private int _indexToExclude;
|
||||
|
||||
public ExclusionTraceFilter(int indexToExclude)
|
||||
{
|
||||
this._indexToExclude = indexToExclude;
|
||||
}
|
||||
public override bool ShouldHitEntity(BaseEntity entity, int contentMask)
|
||||
{
|
||||
if (entity.Index == _indexToExclude) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override TraceType GetTraceType()
|
||||
{
|
||||
return TraceType.Everything;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class TraceFilter : ITraceFilter
|
||||
{
|
||||
public abstract bool ShouldHitEntity(BaseEntity entity, int contentMask);
|
||||
public abstract TraceType GetTraceType();
|
||||
}
|
||||
|
||||
public interface ITraceFilter
|
||||
{
|
||||
bool ShouldHitEntity(BaseEntity entity, int contentMask);
|
||||
TraceType GetTraceType();
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Engine.Trace
|
||||
{
|
||||
public class TraceEngine
|
||||
{
|
||||
public static IntPtr CreateRay(RayType rayType, Vector vec1, Vector vec2)
|
||||
{
|
||||
return NativeAPI.CreateRay1((int) rayType, vec1.Handle, vec2.Handle);
|
||||
}
|
||||
|
||||
public static IntPtr CreateRay(Vector vec1, Vector vec2, Vector vec3, Vector vec4)
|
||||
{
|
||||
return NativeAPI.CreateRay2(vec1.Handle, vec2.Handle, vec3.Handle, vec4.Handle);
|
||||
}
|
||||
|
||||
public static TraceResult TraceRay(IntPtr ray, uint mask, ITraceFilter filter)
|
||||
{
|
||||
var tr = new TraceResult();
|
||||
var proxy = new TraceFilterProxy(filter);
|
||||
NativeAPI.TraceRay(ray, tr.Handle, proxy.Handle, mask);
|
||||
return tr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Engine.Trace
|
||||
{
|
||||
public class TraceResult : NativeObject
|
||||
{
|
||||
public TraceResult(IntPtr cPtr) : base(cPtr)
|
||||
{
|
||||
}
|
||||
|
||||
public TraceResult() : base(NativeAPI.NewTraceResult())
|
||||
{
|
||||
}
|
||||
|
||||
public bool DidHit()
|
||||
{
|
||||
// return NativeAPI.TraceDidHit(Handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
public BaseEntity Entity
|
||||
{
|
||||
get
|
||||
{
|
||||
var entity = new BaseEntity(NativeAPI.TraceResultEntity(Handle));
|
||||
if (entity?.IsNetworked == true)
|
||||
{
|
||||
return entity;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*public TraceSurface Surface => NativePINVOKE.CGameTrace_surface_get(ptr).ToObject<TraceSurface>();
|
||||
public int Hitbox => NativePINVOKE.CGameTrace_hitbox_get(ptr);
|
||||
public int Hitgroup => NativePINVOKE.CGameTrace_hitgroup_get(ptr);
|
||||
public float FractionLeftSolid => NativePINVOKE.CGameTrace_fractionleftsolid_get(ptr);
|
||||
public int PhysicsBone => NativePINVOKE.CGameTrace_physicsbone_get(ptr);*/
|
||||
|
||||
/*public Vector StartPosition => NativePINVOKE.CBaseTrace_startpos_get(ptr).ToObject<Vector>();
|
||||
public Vector EndPosition => NativePINVOKE.CBaseTrace_endpos_get(ptr).ToObject<Vector>();*/
|
||||
}
|
||||
}
|
||||
@@ -1,449 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities
|
||||
{
|
||||
public class BaseEntity : NativeObject
|
||||
{
|
||||
public BaseEntity(int index) : base(NativeAPI.BaseentityFromIndex(index))
|
||||
{
|
||||
_index = index;
|
||||
}
|
||||
|
||||
public BaseEntity(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
_index = NativeAPI.IndexFromBaseentity(pointer);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}", Index);
|
||||
}
|
||||
|
||||
#region Props
|
||||
public int GetProp(PropType type, string name) => NativeAPI.EntityGetPropInt(Index, (int) type, name);
|
||||
|
||||
public T GetProp<T>(PropType type, string name) => (T) (NativeAPI.EntityGetPropInt(Index, (int) type, name) as object);
|
||||
|
||||
public void SetProp(PropType type, string name, int value) => NativeAPI.EntitySetPropInt(Index, (int)type, name, value);
|
||||
|
||||
public void SetProp<T>(PropType type, string name, T value) => NativeAPI.EntitySetPropInt(Index, (int)type, name, (int)(object)value);
|
||||
|
||||
public bool GetPropBool(PropType type, string name) => GetProp(type, name) == 1;
|
||||
|
||||
public void SetPropBool(PropType type, string name, bool value) => SetProp(type, name, value ? 1 : 0);
|
||||
|
||||
public float GetPropFloat(PropType type, string name) => NativeAPI.EntityGetPropFloat(Index, (int) type, name);
|
||||
|
||||
public void SetPropFloat(PropType type, string name, float value) => NativeAPI.EntitySetPropFloat(Index, (int)type, name, value);
|
||||
|
||||
public Vector GetPropVector(PropType type, string name) => new(NativeAPI.EntityGetPropVector(Index, (int) type, name));
|
||||
|
||||
public void SetPropVector(PropType type, string name, Vector vector) => NativeAPI.EntitySetPropVector(Index, (int) type, name, vector.Handle);
|
||||
|
||||
public string GetPropString(PropType type, string name) => NativeAPI.EntityGetPropString(Index, (int)type, name);
|
||||
|
||||
public void SetPropString(PropType type, string name, string value) => NativeAPI.EntitySetPropString(Index, (int)type, name, value);
|
||||
|
||||
public BaseEntity GetPropEnt(PropType type, string name)
|
||||
{
|
||||
var returnVal = NativeAPI.EntityGetPropEnt(Index, (int) type, name);
|
||||
if (returnVal < 0) return null;
|
||||
return BaseEntity.FromIndex(returnVal);
|
||||
}
|
||||
|
||||
public BaseEntity GetPropEntByOffset(int offset)
|
||||
{
|
||||
var returnVal = NativeAPI.EntityGetPropEntByOffset(Index, offset);
|
||||
if (returnVal < 0) return null;
|
||||
return BaseEntity.FromIndex(returnVal);
|
||||
}
|
||||
|
||||
public void SetPropEnt(PropType type, string name, int index) => NativeAPI.EntitySetPropEnt(Index, (int) type, name, index);
|
||||
|
||||
#endregion
|
||||
|
||||
#region KeyValues
|
||||
public string GetKeyValue(string name) => NativeAPI.EntityGetKeyvalue(Index, name);
|
||||
|
||||
public Vector GetKeyValueVector(string name)
|
||||
{
|
||||
var values = GetKeyValue(name).Split(new []{" "}, StringSplitOptions.None).Select(float.Parse).ToArray();
|
||||
return new Vector(values[0], values[1], values[2]);
|
||||
}
|
||||
|
||||
public float GetKeyValueFloat(string name)
|
||||
{
|
||||
return Convert.ToSingle(GetKeyValue(name));
|
||||
}
|
||||
|
||||
public void SetKeyValue(string name, string value) => NativeAPI.EntitySetKeyvalue(Index, name, value);
|
||||
|
||||
public void SetKeyValueFloat(string name, float value) => SetKeyValue(name, value.ToString());
|
||||
|
||||
public void SetKeyValueVector(string name, Vector vec)
|
||||
{
|
||||
string strValue = $"{vec.X} {vec.Y} {vec.Z}";
|
||||
NativeAPI.EntitySetKeyvalue(Index, name, strValue);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool IsPlayer => NativeAPI.EntityIsPlayer(Index);
|
||||
public bool IsWeapon => NativeAPI.EntityIsWeapon(Index);
|
||||
|
||||
public bool IsNetworked => NativeAPI.EntityIsNetworked(Index);
|
||||
public bool IsValid => NativeAPI.EntityIsValid(Index);
|
||||
|
||||
/*public bool IsPlayer => NativePINVOKE.CBaseEntityWrapper_IsPlayer(ptr);
|
||||
public bool IsWeapon => NativePINVOKE.CBaseEntityWrapper_IsWeapon(ptr);
|
||||
public bool IsMoving => NativePINVOKE.CBaseEntityWrapper_IsMoving(ptr);*/
|
||||
|
||||
|
||||
public Vector Origin
|
||||
{
|
||||
get => GetKeyValueVector("origin");
|
||||
set => SetKeyValueVector("origin", value);
|
||||
}
|
||||
|
||||
|
||||
public Vector Maxs
|
||||
{
|
||||
get => GetPropVector(PropType.Send, "m_Collision.m_vecMaxs");
|
||||
set => SetPropVector(PropType.Send, "m_Collision.m_vecMaxs", value);
|
||||
}
|
||||
|
||||
public Vector Mins
|
||||
{
|
||||
get => GetPropVector(PropType.Send, "m_Collision.m_vecMins");
|
||||
set => SetPropVector(PropType.Send, "m_Collision.m_vecMins", value);
|
||||
}
|
||||
|
||||
public int EntityFlags
|
||||
{
|
||||
get => GetProp(PropType.Data, "m_iEFlags");
|
||||
set => SetProp(PropType.Data, "m_iEFlags", value);
|
||||
}
|
||||
|
||||
public SolidType SolidType
|
||||
{
|
||||
get => (SolidType)GetProp(PropType.Send, "m_Collision.m_nSolidType");
|
||||
set => SetProp(PropType.Send, "m_Collision.m_nSolidType", (int)value);
|
||||
}
|
||||
|
||||
public SolidFlags SolidFlags
|
||||
{
|
||||
get => GetProp<SolidFlags>(PropType.Send, "m_Collision.m_usSolidFlags");
|
||||
set => SetProp(PropType.Send, "m_Collision.m_usSolidFlags", value);
|
||||
}
|
||||
|
||||
public CollisionGroup CollisionGroup
|
||||
{
|
||||
get => GetProp<CollisionGroup>(PropType.Send, "m_CollisionGroup");
|
||||
set => SetProp(PropType.Send, "m_CollisionGroup", value);
|
||||
}
|
||||
|
||||
// TODO: ENTITY RENDER COLOR
|
||||
public Color Color
|
||||
{
|
||||
get
|
||||
{
|
||||
int offset = NativeAPI.FindDatamapInfo(Index, "m_clrRender");
|
||||
|
||||
int r = NativeAPI.EntityGetProp(Index, offset + 0, 8);
|
||||
int g = NativeAPI.EntityGetProp(Index, offset + 1, 8);
|
||||
int b = NativeAPI.EntityGetProp(Index, offset + 2, 8);
|
||||
int a = NativeAPI.EntityGetProp(Index, offset + 3, 8);
|
||||
return Color.FromArgb(a, r, g, b);
|
||||
}
|
||||
set
|
||||
{
|
||||
int offset = NativeAPI.FindDatamapInfo(Index, "m_clrRender");
|
||||
|
||||
NativeAPI.EntitySetProp(Index, offset + 0, 8, value.R);
|
||||
NativeAPI.EntitySetProp(Index, offset + 1, 8, value.G);
|
||||
NativeAPI.EntitySetProp(Index, offset + 2, 8, value.B);
|
||||
NativeAPI.EntitySetProp(Index, offset + 3, 8, value.A);
|
||||
}
|
||||
}
|
||||
|
||||
public float Elasticity
|
||||
{
|
||||
get => GetPropFloat(PropType.Send, "m_flElasticity");
|
||||
set => SetPropFloat(PropType.Send, "m_flElasticity", value);
|
||||
}
|
||||
|
||||
public BaseEntity GroundEntity
|
||||
{
|
||||
get => GetPropEnt(PropType.Data, "m_hGroundEntity");
|
||||
set => SetPropEnt(PropType.Data, "m_hGroundEntity", value.Index);
|
||||
}
|
||||
|
||||
public Team Team
|
||||
{
|
||||
get => GetProp<Team>(PropType.Send, "m_iTeamNum");
|
||||
set => SetProp(PropType.Send, "m_iTeamNum", value);
|
||||
}
|
||||
|
||||
public RenderFx RenderFx
|
||||
{
|
||||
get => (RenderFx)GetProp(PropType.Send, "m_nRenderFX");
|
||||
set => SetProp(PropType.Send, "m_nRenderFX", (int)value);
|
||||
}
|
||||
|
||||
public RenderMode RenderMode
|
||||
{
|
||||
get => (RenderMode)GetProp(PropType.Send, "m_nRenderMode");
|
||||
set => SetProp(PropType.Send, "m_nRenderMode", (int)value);
|
||||
}
|
||||
|
||||
public MoveType MoveType
|
||||
{
|
||||
get => (MoveType)GetProp(PropType.Send, "movetype");
|
||||
set => SetProp(PropType.Send, "movetype", (int)value);
|
||||
}
|
||||
|
||||
public new IntPtr Handle => NativeAPI.BaseentityFromIndex(Index);
|
||||
|
||||
public int ParentHandle
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetProp(PropType.Data, "m_pParent");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
set => SetProp(PropType.Data, "m_pParent", value);
|
||||
}
|
||||
|
||||
public Vector Angles
|
||||
{
|
||||
get => GetKeyValueVector("angles");
|
||||
set => SetKeyValueVector("angles", value);
|
||||
}
|
||||
|
||||
public string TargetName
|
||||
{
|
||||
get => GetKeyValue("targetname");
|
||||
set => SetKeyValue("targetname", value);
|
||||
}
|
||||
|
||||
// TODO: Entity Owner Handle
|
||||
|
||||
public Vector AngVelocity
|
||||
{
|
||||
get => GetPropVector(PropType.Data, "m_vecAngVelocity");
|
||||
set => SetPropVector(PropType.Data, "m_vecAngVelocity", value);
|
||||
}
|
||||
|
||||
public Vector BaseVelocity
|
||||
{
|
||||
get => GetPropVector(PropType.Data, "m_vecBaseVelocity");
|
||||
set => SetPropVector(PropType.Data, "m_vecBaseVelocity", value);
|
||||
}
|
||||
|
||||
public string DamageFilter
|
||||
{
|
||||
get => GetKeyValue("damagefilter");
|
||||
set => SetKeyValue("damagefilter", value);
|
||||
}
|
||||
|
||||
public int Effects
|
||||
{
|
||||
get => GetProp(PropType.Data, "m_fEffects");
|
||||
set => SetProp(PropType.Data, "m_fEffects", value);
|
||||
}
|
||||
|
||||
public float Friction
|
||||
{
|
||||
get => GetPropFloat(PropType.Data, "m_flFriction");
|
||||
set => SetPropFloat(PropType.Data, "m_flFriction", value);
|
||||
}
|
||||
|
||||
public string GlobalName
|
||||
{
|
||||
get => GetKeyValue("globalname");
|
||||
set => SetKeyValue("globalname", value);
|
||||
}
|
||||
|
||||
public float Gravity
|
||||
{
|
||||
get => GetPropFloat(PropType.Data, "m_flGravity");
|
||||
set => SetPropFloat(PropType.Data, "m_flGravity", value);
|
||||
}
|
||||
|
||||
public int HammerId
|
||||
{
|
||||
get => GetProp(PropType.Data, "m_iHammerID");
|
||||
set => SetProp(PropType.Data, "m_iHammerID", value);
|
||||
}
|
||||
public int Health
|
||||
{
|
||||
get => GetProp(PropType.Data, "m_iHealth");
|
||||
set => SetProp(PropType.Data, "m_iHealth", value);
|
||||
}
|
||||
|
||||
public float LocalTime
|
||||
{
|
||||
get => GetPropFloat(PropType.Data, "m_flLocalTime");
|
||||
set => SetPropFloat(PropType.Data, "m_flLocalTime", value);
|
||||
}
|
||||
|
||||
public int MaxHealth
|
||||
{
|
||||
get => GetProp(PropType.Data, "m_iMaxHealth");
|
||||
set => SetProp(PropType.Data, "m_iMaxHealth", value);
|
||||
}
|
||||
|
||||
public string ParentName
|
||||
{
|
||||
get => GetKeyValue("parentname");
|
||||
set => SetKeyValue("parentname", value);
|
||||
}
|
||||
|
||||
public float ShadowCastDistance
|
||||
{
|
||||
get => GetPropFloat(PropType.Send, "m_flShadowCastDistance");
|
||||
set => SetPropFloat(PropType.Send, "m_flShadowCastDistance", value);
|
||||
}
|
||||
public int SpawnFlags
|
||||
{
|
||||
get => GetProp(PropType.Data, "m_spawnflags");
|
||||
set => SetProp(PropType.Data, "m_spawnflags", value);
|
||||
}
|
||||
|
||||
public float Speed
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetPropFloat(PropType.Data, "m_flLaggedMovementValue");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return GetKeyValueFloat("speed");
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
try
|
||||
{
|
||||
SetPropFloat(PropType.Data, "m_flLaggedMovementValue", value);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
SetKeyValueFloat("speed", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Target
|
||||
{
|
||||
get => GetKeyValue("target");
|
||||
set => SetKeyValue("target", value);
|
||||
}
|
||||
|
||||
public Vector Velocity
|
||||
{
|
||||
get => GetPropVector(PropType.Data, "m_vecVelocity");
|
||||
set => SetPropVector(PropType.Data, "m_vecVelocity", value);
|
||||
}
|
||||
|
||||
public int WaterLevel
|
||||
{
|
||||
get => GetProp(PropType.Data, "m_nWaterLevel");
|
||||
set => SetProp(PropType.Data, "m_nWaterLevel", value);
|
||||
}
|
||||
|
||||
public Vector Rotation
|
||||
{
|
||||
get => GetPropVector(PropType.Data, "m_angRotation");
|
||||
set => SetPropVector(PropType.Data, "m_angRotation", value);
|
||||
}
|
||||
|
||||
private int? _index;
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
return _index.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public string ClassName => NativeAPI.EntityGetClassname(Index);
|
||||
|
||||
public Vector AbsVelocity
|
||||
{
|
||||
get => GetPropVector(PropType.Data, "m_vecAbsVelocity");
|
||||
set => SetPropVector(PropType.Data, "m_vecAbsVelocity", value);
|
||||
}
|
||||
|
||||
public Vector AbsOrigin
|
||||
{
|
||||
get => GetPropVector(PropType.Data, "m_vecAbsOrigin");
|
||||
set => SetPropVector(PropType.Data, "m_vecAbsOrigin", value);
|
||||
}
|
||||
|
||||
public void Spawn() => NativeAPI.EntitySpawn(Index);
|
||||
|
||||
public void AcceptInput(string name) => NativeAPI.AcceptInput(Index, name);
|
||||
|
||||
public static BaseEntity Create(string className)
|
||||
{
|
||||
var index = NativeAPI.EntityCreateByClassname(className);
|
||||
if (index < 0) return null;
|
||||
return new BaseEntity(index);
|
||||
}
|
||||
|
||||
public static BaseEntity FromIndex(int index)
|
||||
{
|
||||
if (index < 0) return null;
|
||||
var entity = new BaseEntity(index);
|
||||
if (!entity.IsValid) return null;
|
||||
return entity;
|
||||
}
|
||||
|
||||
public static BaseEntity FindByClassname(int startIndex, string className)
|
||||
{
|
||||
var index = NativeAPI.EntityFindByClassname(startIndex, className);
|
||||
if (index < 0) return null;
|
||||
return new BaseEntity(index);
|
||||
}
|
||||
|
||||
public static BaseEntity FindByNetClass(int startIndex, string className)
|
||||
{
|
||||
var index = NativeAPI.EntityFindByNetclass(startIndex, className);
|
||||
if (index < 0) return null;
|
||||
return new BaseEntity(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
public enum DamageType
|
||||
{
|
||||
DMG_GENERIC = 0, // generic damage was done
|
||||
DMG_CRUSH = (1 << 0), // crushed by falling or moving object.
|
||||
// = NOTE: It's assumed crush damage is occurring as a result of physics collision, so no extra physics force is generated by crush damage.
|
||||
DMG_BULLET = (1 << 1), // shot
|
||||
DMG_SLASH = (1 << 2), // cut, clawed, stabbed
|
||||
DMG_BURN = (1 << 3), // heat burned
|
||||
DMG_VEHICLE = (1 << 4), // hit by a vehicle
|
||||
DMG_FALL = (1 << 5), // fell too far
|
||||
DMG_BLAST = (1 << 6), // explosive blast damage
|
||||
DMG_CLUB = (1 << 7), // crowbar, punch, headbutt
|
||||
DMG_SHOCK = (1 << 8), // electric shock
|
||||
DMG_SONIC = (1 << 9), // sound pulse shockwave
|
||||
DMG_ENERGYBEAM = (1 << 10), // laser or other high energy beam
|
||||
DMG_PREVENT_PHYSICS_FORCE = (1 << 11), // Prevent a physics force
|
||||
DMG_NEVERGIB = (1 << 12), // with this bit OR'd in, no damage type will be able to gib victims upon death
|
||||
DMG_ALWAYSGIB = (1 << 13), // with this bit OR'd in, any damage type can be made to gib victims upon death.
|
||||
DMG_DROWN = (1 << 14), // Drowning
|
||||
|
||||
DMG_PARALYZE = (1 << 15), // slows affected creature down
|
||||
DMG_NERVEGAS = (1 << 16), // nerve toxins, very bad
|
||||
DMG_POISON = (1 << 17), // blood poisoning - heals over time like drowning damage
|
||||
DMG_RADIATION = (1 << 18), // radiation exposure
|
||||
DMG_DROWNRECOVER = (1 << 19), // drowning recovery
|
||||
DMG_ACID = (1 << 20), // toxic chemicals or acid burns
|
||||
DMG_SLOWBURN = (1 << 21), // in an oven
|
||||
|
||||
DMG_REMOVENORAGDOLL = (1 << 22), // with this bit OR'd in, no ragdoll will be created, and the target will be quietly removed.
|
||||
// = use this to kill an entity that you've already got a server-side ragdoll for
|
||||
|
||||
DMG_PHYSGUN = (1 << 23), // Hit by manipulator. Usually doesn't do any damage.
|
||||
DMG_PLASMA = (1 << 24), // Shot by Cremator
|
||||
DMG_AIRBOAT = (1 << 25), // Hit by the airboat's gun
|
||||
|
||||
DMG_DISSOLVE = (1 << 26), // Dissolving!
|
||||
DMG_BLAST_SURFACE = (1 << 27), // A blast on the surface of water that cannot harm things underwater
|
||||
DMG_DIRECT = (1 << 28),
|
||||
DMG_BUCKSHOT = (1 << 29), // not quite a bullet. Little, rounder, different.
|
||||
DMG_HEADSHOT = (1 << 30)
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
[Flags]
|
||||
public enum EntityFlags
|
||||
{
|
||||
Onground = (1 << 0), // At rest / on the ground
|
||||
Ducking = (1 << 1), // Player flag -- Player is fully crouched
|
||||
Waterjump = (1 << 3), // player jumping out of water
|
||||
Ontrain = (1 << 4), // Player is _controlling_ a train, so movement commands should be ignored on client during prediction.
|
||||
Inrain = (1 << 5), // Indicates the entity is standing in rain
|
||||
Frozen = (1 << 6), // Player is frozen for 3rd person camera
|
||||
Atcontrols = (1 << 7), // Player can't move, but keeps key inputs for controlling another entity
|
||||
Client = (1 << 8), // Is a player
|
||||
Fakeclient = (1 << 9), // Fake client, simulated server side; don't send network messages to them
|
||||
Inwater = (1 << 10), // In water
|
||||
Fly = (1 << 11), // Changes the SV_Movestep() behavior to not need to be on ground
|
||||
Swim = (1 << 12), // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water)
|
||||
Conveyor = (1 << 13),
|
||||
Npc = (1 << 14),
|
||||
Godmode = (1 << 15),
|
||||
Notarget = (1 << 16),
|
||||
Aimtarget = (1 << 17), // set if the crosshair needs to aim onto the entity
|
||||
Partialground = (1 << 18), // not all corners are valid
|
||||
Staticprop = (1 << 19), // Eetsa static prop!
|
||||
Graphed = (1 << 20), // worldgraph has this ent listed as something that blocks a connection
|
||||
Grenade = (1 << 21),
|
||||
Stepmovement = (1 << 22), // Changes the SV_Movestep() behavior to not do any processing
|
||||
Donttouch = (1 << 23), // Doesn't generate touch functions, generates Untouch() for anything it was touching when this flag was set
|
||||
Basevelocity = (1 << 24), // Base velocity has been applied this frame (used to convert base velocity into momentum)
|
||||
Worldbrush = (1 << 25), // Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something)
|
||||
Object = (1 << 26), // Terrible name. This is an object that NPCs should see. Missiles, for example.
|
||||
Killme = (1 << 27), // This entity is marked for death -- will be freed by game DLL
|
||||
Onfire = (1 << 28), // You know...
|
||||
Dissolving = (1 << 29), // We're dissolving!
|
||||
Transragdoll = (1 << 30), // In the process of turning into a client side ragdoll.
|
||||
UnblockableByPlayer = (1 << 31) // pusher that can't be blocked by the player
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
public enum HitGroup
|
||||
{
|
||||
HITGROUP_GENERIC = 0,
|
||||
HITGROUP_HEAD = 1,
|
||||
HITGROUP_CHEST = 2,
|
||||
HITGROUP_STOMACH = 3,
|
||||
HITGROUP_LEFTARM = 4,
|
||||
HITGROUP_RIGHTARM = 5,
|
||||
HITGROUP_LEFTLEG = 6,
|
||||
HITGROUP_RIGHTLEG = 7,
|
||||
HITGROUP_GEAR = 10,
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
public enum LifeState
|
||||
{
|
||||
LIFE_ALIVE = 0, // alive
|
||||
LIFE_DYING, // playing death animation or still falling off of a ledge waiting to hit ground
|
||||
LIFE_DEAD, // dead. lying still.
|
||||
LIFE_RESPAWNABLE,
|
||||
LIFE_DISCARDBODY,
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
public enum MoveType
|
||||
{
|
||||
MOVETYPE_NONE = 0, // never moves
|
||||
MOVETYPE_ISOMETRIC, // For players -- in TF2 commander view, etc.
|
||||
MOVETYPE_WALK, // Player only - moving on the ground
|
||||
MOVETYPE_STEP, // gravity, special edge handling -- monsters use this
|
||||
MOVETYPE_FLY, // No gravity, but still collides with stuff
|
||||
MOVETYPE_FLYGRAVITY, // flies through the air + is affected by gravity
|
||||
MOVETYPE_VPHYSICS, // uses VPHYSICS for simulation
|
||||
MOVETYPE_PUSH, // no clip to world, push and crush
|
||||
MOVETYPE_NOCLIP, // No gravity, no collisions, still do velocity/avelocity
|
||||
MOVETYPE_LADDER, // Used by players only when going onto a ladder
|
||||
MOVETYPE_OBSERVER, // Observer movement, depends on player's observer mode
|
||||
MOVETYPE_CUSTOM, // Allows the entity to describe its own physics
|
||||
|
||||
// should always be defined as the last item in the list
|
||||
MOVETYPE_LAST = MOVETYPE_CUSTOM,
|
||||
|
||||
MOVETYPE_MAX_BITS = 4
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
public enum ObserverMode
|
||||
{
|
||||
OBS_MODE_NONE = 0, // not in spectator mode
|
||||
OBS_MODE_DEATHCAM, // special mode for death cam animation
|
||||
OBS_MODE_FREEZECAM, // zooms to a target, and freeze-frames on them
|
||||
OBS_MODE_FIXED, // view from a fixed camera position
|
||||
OBS_MODE_IN_EYE, // follow a player in first person view
|
||||
OBS_MODE_CHASE, // follow a player in third person view
|
||||
OBS_MODE_ROAMING, // free roaming
|
||||
|
||||
NUM_OBSERVER_MODES,
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Property types for entity
|
||||
/// </summary>
|
||||
public enum PropType
|
||||
{
|
||||
/// <summary>
|
||||
/// Property is networked
|
||||
/// </summary>
|
||||
Send,
|
||||
/// <summary>
|
||||
/// Property is a save data field
|
||||
/// </summary>
|
||||
Data
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
public enum RenderFx
|
||||
{
|
||||
RENDERFX_NONE = 0,
|
||||
RENDERFX_PULSE_SLOW,
|
||||
RENDERFX_PULSE_FAST,
|
||||
RENDERFX_PULSE_SLOW_WIDE,
|
||||
RENDERFX_PULSE_FAST_WIDE,
|
||||
RENDERFX_FADE_SLOW,
|
||||
RENDERFX_FADE_FAST,
|
||||
RENDERFX_SOLID_SLOW,
|
||||
RENDERFX_SOLID_FAST,
|
||||
RENDERFX_STROBE_SLOW,
|
||||
RENDERFX_STROBE_FAST,
|
||||
RENDERFX_STROBE_FASTER,
|
||||
RENDERFX_FLICKER_SLOW,
|
||||
RENDERFX_FLICKER_FAST,
|
||||
RENDERFX_NO_DISSIPATION,
|
||||
RENDERFX_DISTORT, /**< Distort/scale/translate flicker */
|
||||
RENDERFX_HOLOGRAM, /**< kRenderFxDistort + distance fade */
|
||||
RENDERFX_EXPLODE, /**< Scale up really big! */
|
||||
RENDERFX_GLOWSHELL, /**< Glowing Shell */
|
||||
RENDERFX_CLAMP_MIN_SCALE, /**< Keep this sprite from getting very small (SPRITES only!) */
|
||||
RENDERFX_ENV_RAIN, /**< for environmental rendermode, make rain */
|
||||
RENDERFX_ENV_SNOW, /**< " " " , make snow */
|
||||
RENDERFX_SPOTLIGHT, /**< TEST CODE for experimental spotlight */
|
||||
RENDERFX_RAGDOLL, /**< HACKHACK: TEST CODE for signalling death of a ragdoll character */
|
||||
RENDERFX_PULSE_FAST_WIDER,
|
||||
RENDERFX_MAX
|
||||
};
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
public enum RenderMode
|
||||
{
|
||||
RENDER_NORMAL, /**< src */
|
||||
RENDER_TRANSCOLOR, /**< c*a+dest*(1-a) */
|
||||
RENDER_TRANSTEXTURE, /**< src*a+dest*(1-a) */
|
||||
RENDER_GLOW, /**< src*a+dest -- No Z buffer checks -- Fixed size in screen space */
|
||||
RENDER_TRANSALPHA, /**< src*srca+dest*(1-srca) */
|
||||
RENDER_TRANSADD, /**< src*a+dest */
|
||||
RENDER_ENVIRONMENTAL, /**< not drawn, used for environmental effects */
|
||||
RENDER_TRANSADDFRAMEBLEND, /**< use a fractional frame value to blend between animation frames */
|
||||
RENDER_TRANSALPHAADD, /**< src + dest*(1-a) */
|
||||
RENDER_WORLDGLOW, /**< Same as kRenderGlow but not fixed size in screen space */
|
||||
RENDER_NONE /**< Don't render. */
|
||||
};
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
[Flags]
|
||||
public enum SolidFlags
|
||||
{
|
||||
FSOLID_CUSTOMRAYTEST = 0x0001, // Ignore solid type + always call into the entity for ray tests
|
||||
FSOLID_CUSTOMBOXTEST = 0x0002, // Ignore solid type + always call into the entity for swept box tests
|
||||
FSOLID_NOT_SOLID = 0x0004, // Are we currently not solid?
|
||||
FSOLID_TRIGGER = 0x0008, // This is something may be collideable but fires touch functions
|
||||
// even when it's not collideable (when the FSOLID_NOT_SOLID flag is set)
|
||||
FSOLID_NOT_STANDABLE = 0x0010, // You can't stand on this
|
||||
FSOLID_VOLUME_CONTENTS = 0x0020, // Contains volumetric contents (like water)
|
||||
FSOLID_FORCE_WORLD_ALIGNED = 0x0040, // Forces the collision rep to be world-aligned even if it's SOLID_BSP or SOLID_VPHYSICS
|
||||
FSOLID_USE_TRIGGER_BOUNDS = 0x0080, // Uses a special trigger bounds separate from the normal OBB
|
||||
FSOLID_ROOT_PARENT_ALIGNED = 0x0100, // Collisions are defined in root parent's local coordinate space
|
||||
FSOLID_TRIGGER_TOUCH_DEBRIS = 0x0200, // This trigger will touch debris objects
|
||||
FSOLID_TRIGGER_TOUCH_PLAYER = 0x0400, // This trigger will touch only players
|
||||
FSOLID_NOT_MOVEABLE = 0x0800, // Assume this object will not move
|
||||
|
||||
FSOLID_MAX_BITS = 12
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
public enum SolidType
|
||||
{
|
||||
SOLID_NONE = 0, // no solid model
|
||||
SOLID_BSP = 1, // a BSP tree
|
||||
SOLID_BBOX = 2, // an AABB
|
||||
SOLID_OBB = 3, // an OBB (not implemented yet)
|
||||
SOLID_OBB_YAW = 4, // an OBB, constrained so that it can only yaw
|
||||
SOLID_CUSTOM = 5, // Always call into the entity for tests
|
||||
SOLID_VPHYSICS = 6, // solid vphysics object, get vcollide from the model and collide with that
|
||||
SOLID_LAST,
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
public enum Team
|
||||
{
|
||||
TEAM_ANY = -1,
|
||||
TEAM_INVALID = 1,
|
||||
TEAM_UNASSIGNED = 0,
|
||||
TEAM_SPECTATOR = 1,
|
||||
TEAM_TERRORIST = 2,
|
||||
TEAM_CT = 3,
|
||||
TEAM_MAXCOUNT = 4,
|
||||
}
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Players
|
||||
{
|
||||
public class Player : BaseEntity
|
||||
{
|
||||
public Player(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
public new static Player FromIndex(int index)
|
||||
{
|
||||
var playerBaseEntity = BaseEntity.FromIndex(index);
|
||||
if (playerBaseEntity != null && !NativeAPI.ClientIsInGame(index)) return null;
|
||||
if (playerBaseEntity == null) return null;
|
||||
return new Player(playerBaseEntity.Handle);
|
||||
}
|
||||
|
||||
private PlayerInfo _playerInfo;
|
||||
|
||||
public PlayerInfo PlayerInfo => _playerInfo ??= new PlayerInfo(NativeAPI.PlayerinfoFromIndex(Index));
|
||||
public bool IsAlive => LifeState == (int)Entities.Constants.LifeState.LIFE_ALIVE;
|
||||
|
||||
public ObserverMode ObserverMode
|
||||
{
|
||||
get => (ObserverMode)GetProp(PropType.Send, "m_iObserverMode");
|
||||
set => SetProp(PropType.Send, "m_iObserverMode", (int)value);
|
||||
}
|
||||
|
||||
public PlayerButtons Buttons => (PlayerButtons)GetProp(PropType.Data, "m_nButtons");
|
||||
public IEnumerable<PlayerButtons> SelectedButtons => Buttons.FlagsToList();
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => PlayerInfo.Name;
|
||||
}
|
||||
|
||||
public Player ObserverTarget
|
||||
{
|
||||
get
|
||||
{
|
||||
var targetIndex= GetPropEnt(PropType.Send, "m_hObserverTarget")?.Index;
|
||||
return targetIndex != null ? Player.FromIndex(targetIndex.Value) : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsScoped
|
||||
{
|
||||
get => GetPropBool(PropType.Send, "m_bIsScoped");
|
||||
set => SetPropBool(PropType.Send, "m_bIsScoped", value);
|
||||
}
|
||||
|
||||
public EntityFlags Flags
|
||||
{
|
||||
get => (EntityFlags)GetProp(PropType.Data, "m_fFlags");
|
||||
set => SetProp(PropType.Data, "m_fFlags", (int)value);
|
||||
}
|
||||
|
||||
public int LifeState
|
||||
{
|
||||
get => GetProp(PropType.Send, "m_lifeState");
|
||||
set => SetProp(PropType.Send, "m_lifeState", value);
|
||||
}
|
||||
|
||||
public Vector ViewOffset
|
||||
{
|
||||
get => GetPropVector(PropType.Data, "m_vecViewOffset");
|
||||
set => SetPropVector(PropType.Data, "m_vecViewOffset", value);
|
||||
}
|
||||
|
||||
public Vector EyeLocation => Origin + ViewOffset;
|
||||
|
||||
public Angle EyeAngle
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
var x = GetPropFloat(PropType.Send, "m_angEyeAngles[0]");
|
||||
var y = GetPropFloat(PropType.Send, "m_angEyeAngles[1]");
|
||||
return new Angle(x, y, 0);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Server.PrintToConsole($"Error when retrieving eye angles: {e.Message}, {e.StackTrace}");
|
||||
return new Angle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Vector ViewVector
|
||||
{
|
||||
get
|
||||
{
|
||||
double yaw = (Math.PI / 180) * EyeAngle.Y;
|
||||
double pitch = (Math.PI / 180) * EyeAngle.X;
|
||||
|
||||
var sy = Math.Sin(yaw);
|
||||
var cy = Math.Cos(yaw);
|
||||
|
||||
var sp = Math.Sin(pitch);
|
||||
var cp = Math.Cos(pitch);
|
||||
|
||||
return new Vector((float)(cp * cy), (float)(cp * sy), (float)-sp);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFakeClient => NativeAPI.IsFakeClient(Index);
|
||||
|
||||
public BaseEntity ActiveWeapon
|
||||
{
|
||||
get => GetPropEnt(PropType.Data, "m_hActiveWeapon");
|
||||
set => SetPropEnt(PropType.Data, "m_hActiveWeapon", value.Index);
|
||||
}
|
||||
|
||||
public static Player FromUserId(int userid)
|
||||
{
|
||||
var index = NativeAPI.IndexFromUserid(userid);
|
||||
if (index <= 0) return null;
|
||||
return FromIndex(index);
|
||||
}
|
||||
|
||||
public void PrintToChat(string message) => NativeAPI.PrintToChat(Index, message);
|
||||
public void PrintToHint(string message) => NativeAPI.PrintToHint(Index, message);
|
||||
public void PrintToCenter(string message) => NativeAPI.PrintToCenter(Index, message);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Players
|
||||
{
|
||||
public class PlayerInfo : NativeObject
|
||||
{
|
||||
internal PlayerInfo(IntPtr cHandle) : base(cHandle)
|
||||
{
|
||||
}
|
||||
|
||||
public string Name => NativeAPI.PlayerinfoGetName(Handle);
|
||||
|
||||
public int UserId => NativeAPI.PlayerinfoGetUserid(Handle);
|
||||
public string SteamId => NativeAPI.PlayerinfoGetSteamid(Handle);
|
||||
|
||||
public Team Team
|
||||
{
|
||||
get => (Team)NativeAPI.PlayerinfoGetTeam(Handle);
|
||||
set => NativeAPI.PlayerinfoSetTeam(Handle, (int) value);
|
||||
}
|
||||
|
||||
public int Kills => NativeAPI.PlayerinfoGetKills(Handle);
|
||||
public int Deaths => NativeAPI.PlayerinfoGetKills(Handle);
|
||||
|
||||
public bool IsConnected => NativeAPI.PlayerinfoIsConnected(Handle);
|
||||
|
||||
public int Armor => NativeAPI.PlayerinfoGetArmor(Handle);
|
||||
public bool IsHLTV => NativeAPI.PlayerinfoIsHltv(Handle);
|
||||
public bool IsPlayer => NativeAPI.PlayerinfoIsPlayer(Handle);
|
||||
public bool IsFakeClient => NativeAPI.PlayerinfoIsFakeclient(Handle);
|
||||
public bool IsDead => NativeAPI.PlayerinfoIsDead(Handle);
|
||||
public bool IsInAVehicle => NativeAPI.PlayerinfoIsInVehicle(Handle);
|
||||
public bool IsObserver => NativeAPI.PlayerinfoIsObserver(Handle);
|
||||
/*public Angle Origin => NativePINVOKE.IPlayerInfo_GetAbsOrigin(Handle).ToObject<Angle>();
|
||||
public Angle Angles => NativePINVOKE.IPlayerInfo_GetAbsAngles(Handle).ToObject<Angle>();
|
||||
public Angle MinSize => NativePINVOKE.IPlayerInfo_GetPlayerMins(Handle).ToObject<Angle>();
|
||||
public Angle MaxSize => NativePINVOKE.IPlayerInfo_GetPlayerMaxs(Handle).ToObject<Angle>();*/
|
||||
public string WeaponName => NativeAPI.PlayerinfoGetWeaponName(Handle);
|
||||
public string ModelName => NativeAPI.PlayerinfoGetModelName(Handle);
|
||||
public int Health => NativeAPI.PlayerinfoGetHealth(Handle);
|
||||
public int MaxHealth => NativeAPI.PlayerinfoGetMaxHealth(Handle);
|
||||
//public CBotCmd LastUserCommand => NativePINVOKE.IPlayerInfo_GetLastUserCommand(Handle);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Sound.Constants
|
||||
{
|
||||
public static class SoundAttenuation
|
||||
{
|
||||
public const float ATTN_NONE = 0.0f;
|
||||
public const float ATTN_NORM = 0.8f;
|
||||
public const float ATTN_IDLE = 2.0f;
|
||||
public const float ATTN_STATIC = 1.25f;
|
||||
public const float ATTN_RICOCHET = 1.5f;
|
||||
public const float ATTN_GUNFIRE = 0.27f;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Sound.Constants
|
||||
{
|
||||
public enum SoundChannel
|
||||
{
|
||||
CHAN_REPLACE = -1,
|
||||
CHAN_AUTO = 0,
|
||||
CHAN_WEAPON = 1,
|
||||
CHAN_VOICE = 2,
|
||||
CHAN_ITEM = 3,
|
||||
CHAN_BODY = 4,
|
||||
CHAN_STREAM = 5, // allocate stream channel from the static or dynamic area
|
||||
CHAN_STATIC = 6, // allocate channel from the static area
|
||||
CHAN_VOICE_BASE = 7, // allocate channel for network voice data
|
||||
CHAN_USER_BASE = 135
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Sound.Constants
|
||||
{
|
||||
[Flags]
|
||||
public enum SoundFlags
|
||||
{
|
||||
SND_NOFLAGS = 0, // to keep the compiler happy
|
||||
SND_CHANGE_VOL = (1<<0), // change sound vol
|
||||
SND_CHANGE_PITCH = (1<<1), // change sound pitch
|
||||
SND_STOP = (1<<2), // stop the sound
|
||||
SND_SPAWNING = (1<<3), // we're spawning, used in some cases for ambients
|
||||
// not sent over net, only a param between dll and server.
|
||||
SND_DELAY = (1<<4), // sound has an initial delay
|
||||
SND_STOP_LOOPING = (1<<5), // stop all looping sounds on the entity.
|
||||
SND_SPEAKER = (1<<6), // being played again by a microphone through a speaker
|
||||
|
||||
SND_SHOULDPAUSE = (1<<7), // this sound should be paused if the game is paused
|
||||
SND_IGNORE_PHONEMES = (1<<8),
|
||||
SND_IGNORE_NAME = (1<<9), // used to change all sounds emitted by an entity, regardless of scriptname
|
||||
SND_IS_SCRIPTHANDLE = (1<<10), // server has passed the actual SoundEntry instead of wave filename
|
||||
|
||||
SND_UPDATE_DELAY_FOR_CHOREO = (1<<11), // True if we have to update snd_delay_for_choreo with the IO latency.
|
||||
SND_GENERATE_GUID = (1<<12),
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Sound.Constants
|
||||
{
|
||||
public enum SoundLevel
|
||||
{
|
||||
SNDLVL_NONE = 0,
|
||||
|
||||
SNDLVL_20dB = 20, // rustling leaves
|
||||
SNDLVL_25dB = 25, // whispering
|
||||
SNDLVL_30dB = 30, // library
|
||||
SNDLVL_35dB = 35,
|
||||
SNDLVL_40dB = 40,
|
||||
SNDLVL_45dB = 45, // refrigerator
|
||||
|
||||
SNDLVL_50dB = 50, // 3.9 // average home
|
||||
SNDLVL_55dB = 55, // 3.0
|
||||
|
||||
SNDLVL_IDLE = 60, // 2.0
|
||||
SNDLVL_60dB = 60, // 2.0 // normal conversation, clothes dryer
|
||||
|
||||
SNDLVL_65dB = 65, // 1.5 // washing machine, dishwasher
|
||||
SNDLVL_STATIC = 66, // 1.25
|
||||
|
||||
SNDLVL_70dB = 70, // 1.0 // car, vacuum cleaner, mixer, electric sewing machine
|
||||
|
||||
SNDLVL_NORM = 75,
|
||||
SNDLVL_75dB = 75, // 0.8 // busy traffic
|
||||
|
||||
SNDLVL_80dB = 80, // 0.7 // mini-bike, alarm clock, noisy restaurant, office tabulator, outboard motor, passing snowmobile
|
||||
SNDLVL_TALKING = 80, // 0.7
|
||||
SNDLVL_85dB = 85, // 0.6 // average factory, electric shaver
|
||||
SNDLVL_90dB = 90, // 0.5 // screaming child, passing motorcycle, convertible ride on frw
|
||||
SNDLVL_95dB = 95,
|
||||
SNDLVL_100dB = 100, // 0.4 // subway train, diesel truck, woodworking shop, pneumatic drill, boiler shop, jackhammer
|
||||
SNDLVL_105dB = 105, // helicopter, power mower
|
||||
SNDLVL_110dB = 110, // snowmobile drvrs seat, inboard motorboat, sandblasting
|
||||
SNDLVL_120dB = 120, // auto horn, propeller aircraft
|
||||
SNDLVL_130dB = 130, // air raid siren
|
||||
|
||||
SNDLVL_GUNFIRE = 140, // 0.27 // THRESHOLD OF PAIN, gunshot, jet engine
|
||||
SNDLVL_140dB = 140, // 0.2
|
||||
|
||||
SNDLVL_150dB = 150, // 0.2
|
||||
|
||||
SNDLVL_180dB = 180, // rocket launching
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Sound.Constants
|
||||
{
|
||||
public static class SoundPitch
|
||||
{
|
||||
public const int PITCH_NORM = 100;
|
||||
public const int PITCH_LOW = 95;
|
||||
public const int PITCH_HIGH = 120;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Sound.Constants
|
||||
{
|
||||
public static class SoundSource
|
||||
{
|
||||
public const int SOUND_FROM_PLAYER = -2;
|
||||
public const int SOUND_FROM_LOCAL_PLAYER = -1;
|
||||
public const int SOUND_FROM_WORLD = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Players;
|
||||
using CounterStrikeSharp.API.Modules.Sound.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Sound
|
||||
{
|
||||
public static class Sound
|
||||
{
|
||||
public static bool PrecacheSound(string sound) => NativeAPI.PrecacheSound(sound, true);
|
||||
|
||||
public static bool IsSoundPrecached(string sound) => NativeAPI.IsSoundPrecached(sound);
|
||||
|
||||
public static float GetSoundDuration(string sound) => NativeAPI.GetSoundDuration(sound);
|
||||
|
||||
public static void EmitSound(int client,
|
||||
string sound,
|
||||
int entity = SoundSource.SOUND_FROM_PLAYER,
|
||||
SoundChannel channel = SoundChannel.CHAN_AUTO,
|
||||
SoundLevel level = SoundLevel.SNDLVL_NORM,
|
||||
float attenuation = SoundAttenuation.ATTN_NORM,
|
||||
SoundFlags flags = SoundFlags.SND_NOFLAGS,
|
||||
float volume = 1.0f,
|
||||
int pitch = SoundPitch.PITCH_NORM,
|
||||
Vector origin = null,
|
||||
Vector direction = null)
|
||||
{
|
||||
NativeAPI.EmitSound(client, entity, (int) channel, sound, volume, attenuation, (int) flags,
|
||||
pitch, origin?.Handle ?? IntPtr.Zero, direction?.Handle ?? IntPtr.Zero);
|
||||
}
|
||||
|
||||
public static void EmitSoundToAll(string sound,
|
||||
int entity = SoundSource.SOUND_FROM_PLAYER,
|
||||
SoundChannel channel = SoundChannel.CHAN_AUTO,
|
||||
SoundLevel level = SoundLevel.SNDLVL_NORM,
|
||||
float attenuation = SoundAttenuation.ATTN_NORM,
|
||||
SoundFlags flags = SoundFlags.SND_NOFLAGS,
|
||||
float volume = 1.0f,
|
||||
int pitch = SoundPitch.PITCH_NORM,
|
||||
Vector origin = null,
|
||||
Vector direction = null)
|
||||
{
|
||||
for (int i = 1; i < 65; i++)
|
||||
{
|
||||
var client = Player.FromIndex(i);
|
||||
if (client?.IsValid == true)
|
||||
{
|
||||
Sound.EmitSound(i, sound, entity, channel, level, attenuation, flags, volume, pitch, origin,
|
||||
direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user