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 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(OnEntityCreated); RegisterListener((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)Activator.CreateInstance(typeof(CHandle), 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().GetAwaiter().GetResult(); } return value?.Legacy ?? false; } }