199 lines
8.7 KiB
C#
199 lines
8.7 KiB
C#
using CounterStrikeSharp.API;
|
|
using CounterStrikeSharp.API.Core;
|
|
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
|
using CounterStrikeSharp.API.Modules.Commands;
|
|
using CounterStrikeSharp.API.Modules.Memory;
|
|
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
|
using CounterStrikeSharp.API.Modules.Utils;
|
|
using System.Runtime.InteropServices;
|
|
using System.Net.Http.Json;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace OPorning;
|
|
|
|
public class OPorning : BasePlugin
|
|
{
|
|
public override string ModuleName => "p0rning";
|
|
public override string ModuleVersion => "1.0.0";
|
|
|
|
private static readonly ulong WeaponId = 16384;
|
|
|
|
private static readonly HttpClient Client = new HttpClient();
|
|
|
|
public class LegacyClass
|
|
{
|
|
[JsonPropertyName("legacy")]
|
|
public bool Legacy { get; set; }
|
|
}
|
|
|
|
private static readonly MemoryFunctionVoid<nint, string, float> CAttributeListSetOrAddAttributeValueByName = new(GameData.GetSignature("CAttributeList_SetOrAddAttributeValueByName"));
|
|
|
|
private void Info(string message) => Console.WriteLine("\x1b[38;5;129m[AINDUSTRIES PRODUCTIONS] \x1b[38;5;82m[INFO] \x1b[38;5;255m{0}\x1b[0m", message);
|
|
private void Debug(string message) => Console.WriteLine("\x1b[38;5;129m[AINDUSTRIES PRODUCTIONS] \x1b[38;5;214m[DEBUG] \x1b[38;5;255m{0}\x1b[0m", message);
|
|
|
|
public override void Load(bool hotReload)
|
|
{
|
|
RegisterListener<Listeners.OnEntitySpawned>(OnEntityCreated);
|
|
RegisterListener<Listeners.OnEntityParentChanged>((entity, parent) =>
|
|
{
|
|
var designerName = entity.DesignerName;
|
|
|
|
if (!designerName.Contains("weapon_"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Debug("Parent changed for weapon");
|
|
|
|
var weapon = new CBasePlayerWeapon(entity.Handle);
|
|
if (weapon.AttributeManager.Item.ItemID != WeaponId)
|
|
{
|
|
Debug("Weapon is not a spawned weapon");
|
|
return;
|
|
}
|
|
|
|
DebugWeapon(weapon);
|
|
|
|
bool legacy = IsWeaponLegacy(weapon);
|
|
|
|
//TODO: Check if this is necessary
|
|
// Seems not necessary, will keep it for now.
|
|
|
|
//CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit);
|
|
//CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture seed", weapon.FallbackSeed);
|
|
//CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture prefab", weapon.FallbackPaintKit);
|
|
//CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture seed", weapon.FallbackSeed);
|
|
|
|
UpdateWeaponMeshGroupMask(weapon, legacy);
|
|
});
|
|
Info("Plugin Loaded");
|
|
}
|
|
|
|
[ConsoleCommand("css_give", "Give an item to yourself")]
|
|
[CommandHelper(minArgs: 1, usage: "[name] [paint] [seed]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
|
public void Give(CCSPlayerController? player, CommandInfo commandInfo)
|
|
{
|
|
string weaponName = commandInfo.GetArg(1);
|
|
string paint = commandInfo.GetArg(2);
|
|
int paintId = 0;
|
|
if (paint != "")
|
|
{
|
|
paintId = Int32.Parse(paint);
|
|
}
|
|
|
|
string pattern = commandInfo.GetArg(3);
|
|
int patternId = 1;
|
|
if (pattern != "")
|
|
{
|
|
patternId = Int32.Parse(pattern);
|
|
}
|
|
|
|
if (player == null) return;
|
|
|
|
var entity = player.GiveNamedItem(weaponName);
|
|
|
|
var weaponEntity = new CCSWeaponBase(entity);
|
|
var baseWeapon = new CBasePlayerWeapon(weaponEntity.Handle);
|
|
|
|
commandInfo.ReplyToCommand("Weapon given");
|
|
Server.NextFrame(() =>
|
|
{
|
|
GivePlayerWeaponSkin(player, baseWeapon, paintId, patternId);
|
|
Info("Weapon given and skin applied.");
|
|
});
|
|
}
|
|
|
|
private static void UpdateWeaponMeshGroupMask(CBaseEntity weapon, bool isLegacy = false)
|
|
{
|
|
if (weapon.CBodyComponent?.SceneNode == null) return;
|
|
var skeleton = weapon.CBodyComponent.SceneNode.GetSkeletonInstance();
|
|
var value = (ulong)(isLegacy ? 2 : 1);
|
|
|
|
if (skeleton.ModelState.MeshGroupMask != value)
|
|
{
|
|
skeleton.ModelState.MeshGroupMask = value;
|
|
}
|
|
}
|
|
|
|
private static void UpdatePlayerWeaponMeshGroupMask(CCSPlayerController player, CBasePlayerWeapon weapon, bool isLegacy)
|
|
{
|
|
UpdateWeaponMeshGroupMask(weapon, isLegacy);
|
|
|
|
var viewModel = GetPlayerViewModel(player);
|
|
if (viewModel == null || viewModel.Weapon.Value == null ||
|
|
viewModel.Weapon.Value.Index != weapon.Index) return;
|
|
|
|
UpdateWeaponMeshGroupMask(viewModel, isLegacy);
|
|
Utilities.SetStateChanged(viewModel, "CBaseEntity", "m_CBodyComponent");
|
|
}
|
|
|
|
private static CBaseViewModel? GetPlayerViewModel(CCSPlayerController player)
|
|
{
|
|
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.ViewModelServices == null) return null;
|
|
CCSPlayer_ViewModelServices viewModelServices = new(player.PlayerPawn.Value.ViewModelServices!.Handle);
|
|
var ptr = viewModelServices.Handle + Schema.GetSchemaOffset("CCSPlayer_ViewModelServices", "m_hViewModel");
|
|
var references = MemoryMarshal.CreateSpan(ref ptr, 3);
|
|
var viewModel = (CHandle<CBaseViewModel>)Activator.CreateInstance(typeof(CHandle<CBaseViewModel>), references[0])!;
|
|
return viewModel.Value == null ? null : viewModel.Value;
|
|
}
|
|
|
|
private void GivePlayerWeaponSkin(CCSPlayerController? player, CBasePlayerWeapon baseWeapon, int paint, int pattern)
|
|
{
|
|
var weapon = new CEconEntity(baseWeapon.Handle);
|
|
baseWeapon.AttributeManager.Item.AttributeList.Attributes.RemoveAll();
|
|
baseWeapon.AttributeManager.Item.NetworkedDynamicAttributes.Attributes.RemoveAll();
|
|
|
|
weapon.FallbackPaintKit = paint;
|
|
weapon.FallbackSeed = pattern;
|
|
weapon.FallbackWear = 0.01f;
|
|
weapon.AttributeManager.Item.AccountID = (uint)player.SteamID;
|
|
|
|
/*
|
|
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit);
|
|
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture seed", weapon.FallbackSeed);
|
|
|
|
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture prefab", weapon.FallbackPaintKit);
|
|
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture seed", weapon.FallbackSeed);
|
|
*/
|
|
|
|
weapon.AttributeManager.Item.ItemID = WeaponId;
|
|
weapon.AttributeManager.Item.ItemIDLow = (uint)WeaponId & 0xFFFFFFFF;
|
|
weapon.AttributeManager.Item.ItemIDHigh = (uint)WeaponId >> 32;
|
|
|
|
bool legacy = IsWeaponLegacy(baseWeapon);
|
|
|
|
UpdatePlayerWeaponMeshGroupMask(player, baseWeapon, legacy);
|
|
Info($"Gave weapon to {player.PlayerName}");
|
|
DebugWeapon(baseWeapon);
|
|
}
|
|
|
|
private void OnEntityCreated(CEntityInstance entity)
|
|
{
|
|
// TODO: Check if user has a loadout set, if so change the skins.
|
|
}
|
|
|
|
private void DebugWeapon(CBasePlayerWeapon weapon)
|
|
{
|
|
Debug("[WEAPON DEBUG]");
|
|
Console.WriteLine("[Entity ID]: {0}", weapon.AttributeManager.Item.ItemID);
|
|
Console.WriteLine("[Owner ID]: {0}", weapon.AttributeManager.Item.AccountID);
|
|
Console.WriteLine("[Owner ID Low]: {0}", weapon.AttributeManager.Item.ItemIDLow);
|
|
Console.WriteLine("[Owner ID High]: {0}", weapon.AttributeManager.Item.ItemIDHigh);
|
|
Console.WriteLine("[Paint]: {0}", weapon.FallbackPaintKit);
|
|
Console.WriteLine("[Pattern]: {0}", weapon.FallbackSeed);
|
|
Console.WriteLine("[DefIndex]: {0}", weapon.AttributeManager.Item.ItemDefinitionIndex);
|
|
}
|
|
|
|
private bool IsWeaponLegacy(CBasePlayerWeapon weapon)
|
|
{
|
|
var designerName = weapon.DesignerName;
|
|
var paint = weapon.FallbackPaintKit;
|
|
HttpResponseMessage response = Client.GetAsync($"http://127.0.0.1:8900/api/legacy/{designerName}/{paint}").GetAwaiter().GetResult();
|
|
LegacyClass? value = null;
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
value = response.Content.ReadFromJsonAsync<LegacyClass>().GetAwaiter().GetResult();
|
|
}
|
|
return value?.Legacy ?? false;
|
|
}
|
|
} |