-
-
Notifications
You must be signed in to change notification settings - Fork 147
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into virtual-hooks
- Loading branch information
Showing
18 changed files
with
499 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# With CheckTransmit | ||
This example shows how to work with the `CheckTransmit` listener. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
using CounterStrikeSharp.API; | ||
using CounterStrikeSharp.API.Core; | ||
using CounterStrikeSharp.API.Core.Attributes; | ||
|
||
namespace WithCheckTransmit; | ||
|
||
[MinimumApiVersion(276)] | ||
public class WithCheckTransmitPlugin : BasePlugin | ||
{ | ||
public override string ModuleName => "Example: With CheckTransmit"; | ||
public override string ModuleVersion => "1.0.0"; | ||
public override string ModuleAuthor => "CounterStrikeSharp & Contributors"; | ||
public override string ModuleDescription => "A simple plugin that uses the CheckTransmit listener!"; | ||
|
||
private Dictionary<int, bool> ShouldSeeDoors = new Dictionary<int, bool>(); | ||
|
||
public override void Load(bool hotReload) | ||
{ | ||
// This command is related to the following example. | ||
AddCommand("nodoors", "Toggle door transmit", (player, info) => | ||
{ | ||
if (player == null) | ||
return; | ||
|
||
if (ShouldSeeDoors.ContainsKey(player.Slot)) | ||
{ | ||
ShouldSeeDoors[player.Slot] = !ShouldSeeDoors[player.Slot]; | ||
} else | ||
{ | ||
ShouldSeeDoors.Add(player.Slot, false); | ||
} | ||
|
||
info.ReplyToCommand($"You should {(ShouldSeeDoors[player.Slot] ? "see" : "not see")} doors"); | ||
}); | ||
|
||
// In this example, we will hide every door for players that have enabled the option with the command 'nodoors' | ||
RegisterListener<Listeners.CheckTransmit>((CCheckTransmitInfoList infoList) => | ||
{ | ||
// Get the list of the currently available doors (prop_door_rotating) | ||
IEnumerable<CPropDoorRotating> doors = Utilities.FindAllEntitiesByDesignerName<CPropDoorRotating>("prop_door_rotating"); | ||
|
||
// Do nothing if there is none. | ||
if (!doors.Any()) | ||
return; | ||
|
||
// Go through every received info | ||
foreach ((CCheckTransmitInfo info, CCSPlayerController? player) in infoList) | ||
{ | ||
// If no player is found, we can continue | ||
if (player == null) | ||
continue; | ||
|
||
// Otherwise, lets do the work: | ||
|
||
// Check if we should clear or not: | ||
|
||
// If we have no data saved for this player, then we should not continue | ||
if (!ShouldSeeDoors.ContainsKey(player.Slot)) | ||
continue; | ||
|
||
// If this value is true, then this player should see doors | ||
if (ShouldSeeDoors[player.Slot]) | ||
continue; | ||
|
||
// Otherwise, lets remove the door entity indexes from the info list so they won't be transmitted | ||
foreach (CPropDoorRotating door in doors) | ||
{ | ||
info.TransmitEntities.Remove(door); | ||
} | ||
|
||
// NOTE: this is a barebone example, saving data and doing sanity checks is up to you. | ||
} | ||
}); | ||
|
||
// In this example, we will hide other players in the same team as the player. | ||
// NOTE: 'Hiding' players requires extra work to do, killing non-transmitted players results in crash. | ||
RegisterListener<Listeners.CheckTransmit>((CCheckTransmitInfoList infoList) => | ||
{ | ||
// Get the list of the current players, we only work with this value later on | ||
List<CCSPlayerController> players = Utilities.GetPlayers(); | ||
|
||
// Go through every received info | ||
foreach ((CCheckTransmitInfo info, CCSPlayerController? player) in infoList) | ||
{ | ||
// If no player is found, we can continue | ||
if (player == null) | ||
continue; | ||
|
||
// Otherwise, lets do the work: | ||
|
||
// as an example, lets hide everyone for this player who is in the same team. | ||
IEnumerable<CCSPlayerController> targetPlayers = players.Where(p => | ||
// is the player and its pawn valid | ||
p.IsValid && p.Pawn.IsValid && | ||
|
||
// we shouldn't hide ourselves | ||
p.Slot != player.Slot && | ||
|
||
// is the player is in the same team | ||
p.Team == player.Team && | ||
|
||
// is alive | ||
p.PlayerPawn.Value?.LifeState == (byte)LifeState_t.LIFE_ALIVE | ||
); | ||
|
||
foreach (CCSPlayerController targetPlayer in targetPlayers) | ||
{ | ||
// Calling 'Remove' will clear the entity index of the target player pawn from the transmission list | ||
// so it won't be transmitted for the 'player'. | ||
info.TransmitEntities.Remove(targetPlayer.Pawn); | ||
} | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
managed/CounterStrikeSharp.API/Core/Model/CCheckTransmitInfo.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* | ||
* 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.Collections; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace CounterStrikeSharp.API.Core | ||
{ | ||
[StructLayout(LayoutKind.Explicit)] | ||
public struct CCheckTransmitInfo | ||
{ | ||
/// <summary> | ||
/// Entity n is already marked for transmission | ||
/// </summary> | ||
[FieldOffset(0x0)] | ||
public CFixedBitVecBase TransmitEntities; | ||
|
||
/// <summary> | ||
/// Entity n is always send even if not in PVS (HLTV and Replay only) | ||
/// </summary> | ||
[FieldOffset(0x8)] | ||
public CFixedBitVecBase TransmitAlways; | ||
}; | ||
|
||
public sealed class CCheckTransmitInfoList : NativeObject, IReadOnlyList<(CCheckTransmitInfo info, CCSPlayerController? player)> | ||
{ | ||
private int CheckTransmitPlayerSlotOffset = GameData.GetOffset("CheckTransmitPlayerSlot"); | ||
|
||
private unsafe nint* Inner => (nint*)base.Handle; | ||
|
||
public unsafe int Count { get => (int)(*(this.Inner + 1)); } | ||
|
||
public unsafe CCheckTransmitInfoList(IntPtr pointer) : base(pointer) | ||
{ } | ||
|
||
/// <summary> | ||
/// Get transmit info for the given index. | ||
/// </summary> | ||
/// <param name="index">Index of the info you want to retrieve from the list, should be between 0 and '<see cref="Count"/>' - 1</param> | ||
/// <returns></returns> | ||
public (CCheckTransmitInfo info, CCSPlayerController? player) this[int index] | ||
{ | ||
get | ||
{ | ||
var (transmit, slot) = this.Get(index); | ||
CCSPlayerController? player = Utilities.GetPlayerFromSlot(slot); | ||
return (transmit, player); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Get transmit info for the given index. | ||
/// </summary> | ||
/// <param name="index">Index of the info you want to retrieve from the list, should be between 0 and '<see cref="Count"/>' - 1</param> | ||
/// <returns></returns> | ||
private unsafe (CCheckTransmitInfo, int) Get(int index) | ||
{ | ||
if (index < 0 || index >= this.Count) | ||
{ | ||
throw new ArgumentOutOfRangeException("index"); | ||
} | ||
|
||
// 'base.Handle' holds the pointer for our 'CCheckTransmitInfoList' wrapper class | ||
|
||
// Get the pointer to the array of 'CCheckTransmitInfo' | ||
nint* infoListPtr = *(nint**)this.Inner; // Dereference 'Inner' to get the pointer to the array | ||
|
||
// Access the specific 'CCheckTransmitInfo*' | ||
nint infoPtr = *(infoListPtr + index); | ||
|
||
// Retrieve the 'CCheckTransmitInfo' from the pointer | ||
CCheckTransmitInfo info = Marshal.PtrToStructure<CCheckTransmitInfo>(infoPtr); | ||
|
||
// Get player slot from the 'infoPtr' using the 'CheckTransmitPlayerSlotOffset' offset | ||
int playerSlot = *(int*)((byte*)infoPtr + CheckTransmitPlayerSlotOffset); | ||
|
||
return (info, playerSlot); | ||
} | ||
|
||
public IEnumerator<(CCheckTransmitInfo, CCSPlayerController?)> GetEnumerator() | ||
{ | ||
for (int i = 0; i < this.Count; i++) | ||
{ | ||
yield return this[i]; | ||
} | ||
} | ||
|
||
IEnumerator IEnumerable.GetEnumerator() | ||
{ | ||
return this.GetEnumerator(); | ||
} | ||
} | ||
} |
Oops, something went wrong.