mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-08 00:46:34 -08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b45a884d4 | ||
|
|
6ea6d0a22d | ||
|
|
12523455c0 | ||
|
|
db63fdc00c | ||
|
|
57747f2e1c |
@@ -113,6 +113,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",
|
||||
@@ -160,6 +167,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,
|
||||
|
||||
@@ -1074,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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -69,6 +69,11 @@ public class Schema
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
public static bool IsSchemaFieldNetworked(string className, string propertyName)
|
||||
{
|
||||
return NativeAPI.IsSchemaFieldNetworked(className, propertyName);
|
||||
}
|
||||
|
||||
public static T GetSchemaValue<T>(IntPtr handle, string className, string propertyName)
|
||||
{
|
||||
|
||||
@@ -80,4 +80,15 @@ public static class VirtualFunctions
|
||||
public static MemoryFunctionVoid<IntPtr, IntPtr> RemovePlayerItemFunc =
|
||||
new(GameData.GetSignature("CBasePlayerPawn_RemovePlayerItem"));
|
||||
public static Action<IntPtr, IntPtr> RemovePlayerItemVirtual = RemovePlayerItemFunc.Invoke;
|
||||
|
||||
public static MemoryFunctionVoid<IntPtr, string, IntPtr, IntPtr, string, int> AcceptInputFunc = new(GameData.GetSignature("CEntityInstance_AcceptInput"));
|
||||
public static Action<IntPtr, string, IntPtr, IntPtr, string, int> AcceptInput = AcceptInputFunc.Invoke;
|
||||
|
||||
public static MemoryFunctionVoid<IntPtr, IntPtr, int, short, short> StateChangedFunc =
|
||||
new(GameData.GetSignature("StateChanged"));
|
||||
public static Action<IntPtr, IntPtr, int, short, short> StateChanged = StateChangedFunc.Invoke;
|
||||
|
||||
public static MemoryFunctionVoid<IntPtr, int, long> NetworkStateChangedFunc = new("NetworkStateChanged");
|
||||
public static Action<IntPtr, int, long> NetworkStateChanged = NetworkStateChangedFunc.Invoke;
|
||||
|
||||
}
|
||||
@@ -21,8 +21,10 @@ using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using CounterStrikeSharp.API.Core.Logging;
|
||||
using CounterStrikeSharp.API.Modules.Commands.Targeting;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CounterStrikeSharp.API
|
||||
{
|
||||
@@ -136,9 +138,9 @@ namespace CounterStrikeSharp.API
|
||||
{
|
||||
List<CCSPlayerController> players = new();
|
||||
|
||||
for (int i = 1; i <= Server.MaxPlayers; i++)
|
||||
for (int i = 0; i < Server.MaxPlayers; i++)
|
||||
{
|
||||
var controller = GetPlayerFromIndex(i);
|
||||
var controller = GetPlayerFromSlot(i);
|
||||
|
||||
if (!controller.IsValid || controller.UserId == -1)
|
||||
continue;
|
||||
@@ -196,5 +198,38 @@ namespace CounterStrikeSharp.API
|
||||
|
||||
return (T)Activator.CreateInstance(typeof(T), pointerTo)!;
|
||||
}
|
||||
|
||||
private static int FindSchemaChain(string className) => Schema.GetSchemaOffset(className, "__m_pChainEntity");
|
||||
|
||||
/// <summary>
|
||||
/// Marks a field as changed for network transmission.
|
||||
/// Not all schema fields are network enabled, so please check the schema before using this.
|
||||
/// </summary>
|
||||
/// <param name="entity">Entity to update</param>
|
||||
/// <param name="className" example="CBaseEntity">Schema field class name</param>
|
||||
/// <param name="fieldName" example="m_iHealth">Schema field name</param>
|
||||
/// <param name="extraOffset">Any additional offset to the schema field</param>
|
||||
public static void SetStateChanged(CBaseEntity entity, string className, string fieldName, int extraOffset = 0)
|
||||
{
|
||||
if (!Schema.IsSchemaFieldNetworked(className, fieldName))
|
||||
{
|
||||
Application.Instance.Logger.LogWarning("Field {ClassName}:{FieldName} is not networked, but SetStateChanged was called on it.", className, fieldName);
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = Schema.GetSchemaOffset(className, fieldName);
|
||||
int chainOffset = FindSchemaChain(className);
|
||||
|
||||
if (chainOffset != 0)
|
||||
{
|
||||
VirtualFunctions.NetworkStateChanged(entity.Handle + chainOffset, offset + extraOffset, 0xFFFFFFFF);
|
||||
return;
|
||||
}
|
||||
|
||||
VirtualFunctions.StateChanged(entity.NetworkTransmitComponent.Handle, entity.Handle, offset + extraOffset, -1, -1);
|
||||
|
||||
entity.LastNetworkChange = Server.CurrentTime;
|
||||
entity.IsSteadyState.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,11 +247,13 @@ namespace TestPlugin
|
||||
// Set player to random colour
|
||||
player.PlayerPawn.Value.Render = Color.FromArgb(Random.Shared.Next(0, 255),
|
||||
Random.Shared.Next(0, 255), Random.Shared.Next(0, 255));
|
||||
Utilities.SetStateChanged(player.PlayerPawn.Value, "CBaseModelEntity", "m_clrRender");
|
||||
|
||||
activeWeapon.ReserveAmmo[0] = 250;
|
||||
activeWeapon.Clip1 = 250;
|
||||
|
||||
pawn.Health += 5;
|
||||
Utilities.SetStateChanged(pawn, "CBaseEntity", "m_iHealth");
|
||||
|
||||
return HookResult.Continue;
|
||||
});
|
||||
@@ -501,6 +503,30 @@ namespace TestPlugin
|
||||
player.Respawn();
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_break", "Breaks the breakable entities")]
|
||||
public void OnBreakCommand(CCSPlayerController? player, CommandInfo command)
|
||||
{
|
||||
var entities = Utilities.FindAllEntitiesByDesignerName<CBreakable>("prop_dynamic")
|
||||
.Concat(Utilities.FindAllEntitiesByDesignerName<CBreakable>("func_breakable"));
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
entity.AcceptInput("Break");
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_fov", "Sets the player's FOV")]
|
||||
[CommandHelper(minArgs: 1, usage: "[fov]")]
|
||||
public void OnFovCommand(CCSPlayerController? player, CommandInfo command)
|
||||
{
|
||||
if (player == null) return;
|
||||
if (!player.PlayerPawn.IsValid) return;
|
||||
|
||||
if (!Int32.TryParse(command.GetArg(1), out var desiredFov)) return;
|
||||
|
||||
player.DesiredFOV = (uint)desiredFov;
|
||||
Utilities.SetStateChanged(player, "CBasePlayerController", "m_iDesiredFOV");
|
||||
}
|
||||
|
||||
[ConsoleCommand("cssharp_attribute", "This is a custom attribute event")]
|
||||
public void OnCommand(CCSPlayerController? player, CommandInfo command)
|
||||
{
|
||||
|
||||
@@ -115,7 +115,6 @@ SchemaKey schema::GetOffset(const char* className,
|
||||
SchemaKeyValueMap_t* tableMap = schemaTableMap[tableMapIndex];
|
||||
int16_t memberIndex = tableMap->Find(memberKey);
|
||||
if (!tableMap->IsValidIndex(memberIndex)) {
|
||||
Warning("schema::GetOffset(): '%s' was not found in '%s'!\n", memberName, className);
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,18 @@ int16 GetSchemaOffset(ScriptContext& script_context)
|
||||
return m_key.offset;
|
||||
}
|
||||
|
||||
bool IsSchemaFieldNetworked(ScriptContext& script_context)
|
||||
{
|
||||
auto className = script_context.GetArgument<const char*>(0);
|
||||
auto memberName = script_context.GetArgument<const char*>(1);
|
||||
auto classKey = hash_32_fnv1a_const(className);
|
||||
auto memberKey = hash_32_fnv1a_const(memberName);
|
||||
|
||||
const auto m_key = schema::GetOffset(className, classKey, memberName, memberKey);
|
||||
|
||||
return m_key.networked;
|
||||
}
|
||||
|
||||
int GetSchemaClassSize(ScriptContext& script_context)
|
||||
{
|
||||
auto className = script_context.GetArgument<const char*>(0);
|
||||
@@ -150,19 +162,6 @@ void SetSchemaValueByName(ScriptContext& script_context)
|
||||
auto memberKey = hash_32_fnv1a_const(memberName);
|
||||
|
||||
const auto m_key = schema::GetOffset(className, classKey, memberName, memberKey);
|
||||
const auto m_chain = schema::FindChainOffset(className);
|
||||
|
||||
|
||||
// todo network updates
|
||||
// if (m_chain != 0 && m_key.networked) {
|
||||
// addresses::NetworkStateChanged((uintptr_t)(instancePointer) + m_chain, m_key.offset,
|
||||
// 0xFFFFFFFF);
|
||||
// } else if (m_key.networked) { /* WIP: Works fine for most props, but inlined classes in
|
||||
// the
|
||||
// middle of a class will need to have their this pointer
|
||||
// corrected by the offset .*/
|
||||
// CALL_VIRTUAL(void, 1, instancePointer, m_key.offset, 0xFFFFFFFF, 0xFFFF);
|
||||
// }
|
||||
|
||||
switch (dataType) {
|
||||
case DATA_TYPE_BOOL:
|
||||
@@ -239,6 +238,7 @@ void SetSchemaValueByName(ScriptContext& script_context)
|
||||
|
||||
REGISTER_NATIVES(schema, {
|
||||
ScriptEngine::RegisterNativeHandler("GET_SCHEMA_OFFSET", GetSchemaOffset);
|
||||
ScriptEngine::RegisterNativeHandler("IS_SCHEMA_FIELD_NETWORKED", IsSchemaFieldNetworked);
|
||||
ScriptEngine::RegisterNativeHandler("GET_SCHEMA_VALUE_BY_NAME", GetSchemaValueByName);
|
||||
ScriptEngine::RegisterNativeHandler("SET_SCHEMA_VALUE_BY_NAME", SetSchemaValueByName);
|
||||
ScriptEngine::RegisterNativeHandler("GET_SCHEMA_CLASS_SIZE", GetSchemaClassSize);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
GET_SCHEMA_OFFSET: className:string, propName:string -> short
|
||||
IS_SCHEMA_FIELD_NETWORKED: className:string, propName:string -> bool
|
||||
GET_SCHEMA_VALUE_BY_NAME: instance:pointer, returnType:int, className:string, propName:string -> any
|
||||
SET_SCHEMA_VALUE_BY_NAME: instance:pointer, returnType:int, className:string, propName:string, value:any -> void
|
||||
GET_SCHEMA_CLASS_SIZE: className:string -> int
|
||||
Reference in New Issue
Block a user