Compare commits
7 Commits
7063f3fd82
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b35c44506 | |||
| 19ff46ed06 | |||
| e923a772cc | |||
| d5cffea428 | |||
| 816d71ebfe | |||
| 6cd51f0a64 | |||
| 90ec00c5da |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
bin
|
bin
|
||||||
obj
|
obj
|
||||||
|
plugin.csproj
|
||||||
@@ -3,7 +3,7 @@ The official plugin of Porning's CS2 server
|
|||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
### Installing Metamod
|
### Installing Metamod
|
||||||
Download the latest version [here](https://www.metamodsource.net/downloads.php/?branch=master).
|
Download the latest version [here](https://www.metamodsource.net/downloads.php/?branch=master). \
|
||||||
Extract the files and copy the `/addons/` directory into `/game/csgo/`. \
|
Extract the files and copy the `/addons/` directory into `/game/csgo/`. \
|
||||||
Modify `/game/csgo/gameinfo.gi` as such by adding `Game csgo/addons/metamod`:
|
Modify `/game/csgo/gameinfo.gi` as such by adding `Game csgo/addons/metamod`:
|
||||||
```cs
|
```cs
|
||||||
|
|||||||
@@ -6,14 +6,15 @@ public class Porning : BasePlugin
|
|||||||
{
|
{
|
||||||
public override string ModuleName => "p0rning";
|
public override string ModuleName => "p0rning";
|
||||||
public override string ModuleVersion => "0.0.1";
|
public override string ModuleVersion => "0.0.1";
|
||||||
private static readonly ulong SpawnedWeaponId = 16384; // Randomly chosen
|
|
||||||
private readonly AdminCommands adminCommands;
|
private readonly AdminCommands adminCommands;
|
||||||
private readonly PlayerCommands playerCommands;
|
private readonly PlayerCommands playerCommands;
|
||||||
|
private SkinsManager skinsManager;
|
||||||
|
|
||||||
public Porning()
|
public Porning()
|
||||||
{
|
{
|
||||||
adminCommands = new AdminCommands(this);
|
adminCommands = new AdminCommands(this);
|
||||||
playerCommands = new PlayerCommands(this);
|
playerCommands = new PlayerCommands(this);
|
||||||
|
skinsManager = new SkinsManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Load(bool hotReload)
|
public override void Load(bool hotReload)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="CounterStrikeSharp.API">
|
<Reference Include="CounterStrikeSharp.API">
|
||||||
<HintPath>/games/cs2-server/game/csgo/addons/counterstrikesharp/api/CounterStrikeSharp.API.dll</HintPath>
|
<HintPath>/run/media/aindustries/porning/server/game/csgo/addons/counterstrikesharp/api/CounterStrikeSharp.API.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<MyOutputFiles Include="$(TargetDir)**\*.*" />
|
<MyOutputFiles Include="$(TargetDir)**\*.*" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Copy SourceFiles="@(MyOutputFiles)" DestinationFolder="/games/cs2-server/game/csgo/addons/counterstrikesharp/plugins/plugin/%(RecursiveDir)" />
|
<Copy SourceFiles="@(MyOutputFiles)" DestinationFolder="/run/media/aindustries/porning/server/game/csgo/addons/counterstrikesharp/plugins/plugin/%(RecursiveDir)" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
257
skins/skins.cs
Normal file
257
skins/skins.cs
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
using CounterStrikeSharp.API.Core;
|
||||||
|
using CounterStrikeSharp.API;
|
||||||
|
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||||
|
|
||||||
|
namespace Porning;
|
||||||
|
|
||||||
|
class SkinsManager
|
||||||
|
{
|
||||||
|
private readonly BasePlugin plugin;
|
||||||
|
private static readonly ulong SpawnedWeaponId = 16384; // Randomly chosen
|
||||||
|
private static readonly MemoryFunctionVoid<nint, string, float> CAttributeListSetOrAddAttributeValueByName = new(GameData.GetSignature("CAttributeList_SetOrAddAttributeValueByName"));
|
||||||
|
|
||||||
|
public SkinsManager(BasePlugin plugin)
|
||||||
|
{
|
||||||
|
this.plugin = plugin;
|
||||||
|
plugin.RegisterListener<Listeners.OnEntitySpawned>((entity) => { OnEntitySpawned(entity); });
|
||||||
|
plugin.RegisterListener<Listeners.OnEntityParentChanged>((entity, parent) => { OnEntityParentChanged(entity, parent); });
|
||||||
|
plugin.RegisterEventHandler<EventItemPickup>(OnItemEquip);
|
||||||
|
plugin.RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEntitySpawned(CEntityInstance entity)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEntityParentChanged(CEntityInstance entity, CEntityInstance parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info)
|
||||||
|
{
|
||||||
|
var player = @event.Userid;
|
||||||
|
|
||||||
|
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||||
|
|
||||||
|
// On attend la frame suivante pour s'assurer que le moteur du jeu a fini
|
||||||
|
// d'attribuer le corps (Pawn) et l'équipement par défaut au joueur.
|
||||||
|
Server.NextFrame(() =>
|
||||||
|
{
|
||||||
|
if (player.IsValid && player.PlayerPawn.IsValid && player.PawnIsAlive)
|
||||||
|
{
|
||||||
|
ApplySportGlovesPandorasBox(player);
|
||||||
|
ApplyAgentSirBloodyMiamiDarryl(player);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return HookResult.Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HookResult OnItemEquip(EventItemPickup @event, GameEventInfo info)
|
||||||
|
{
|
||||||
|
var player = @event.Userid;
|
||||||
|
|
||||||
|
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||||
|
|
||||||
|
Server.NextFrame(() =>
|
||||||
|
{
|
||||||
|
if (!player.IsValid || !player.PlayerPawn.IsValid) return;
|
||||||
|
|
||||||
|
var pawn = player.PlayerPawn.Value;
|
||||||
|
if (pawn == null) return;
|
||||||
|
|
||||||
|
var myWeapons = pawn.WeaponServices?.MyWeapons;
|
||||||
|
if (myWeapons == null) return;
|
||||||
|
|
||||||
|
// Reproduction de la méthode GiveOnItemPickup du dépôt GitHub
|
||||||
|
foreach (var handle in myWeapons)
|
||||||
|
{
|
||||||
|
var weapon = handle.Value;
|
||||||
|
|
||||||
|
if (weapon == null || !weapon.IsValid) continue;
|
||||||
|
|
||||||
|
if (weapon.DesignerName == "weapon_ak47")
|
||||||
|
{
|
||||||
|
ApplyAK47Skin1171(weapon, player);
|
||||||
|
}
|
||||||
|
else if (weapon.DesignerName == "weapon_deagle")
|
||||||
|
{
|
||||||
|
ApplyDeagleSkin(weapon, player);
|
||||||
|
}
|
||||||
|
else if (weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet"))
|
||||||
|
{
|
||||||
|
ApplyButterflyKnifeFade(weapon, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return HookResult.Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyAK47Skin1171(CBasePlayerWeapon weapon, CCSPlayerController player)
|
||||||
|
{
|
||||||
|
if (weapon.AttributeManager.Item.ItemDefinitionIndex != 7) return;
|
||||||
|
|
||||||
|
weapon.AttributeManager.Item.AttributeList.Attributes.RemoveAll();
|
||||||
|
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Attributes.RemoveAll();
|
||||||
|
|
||||||
|
weapon.AttributeManager.Item.ItemID = SpawnedWeaponId;
|
||||||
|
weapon.AttributeManager.Item.ItemIDLow = (uint)(SpawnedWeaponId & 0xFFFFFFFF);
|
||||||
|
weapon.AttributeManager.Item.ItemIDHigh = (uint)(SpawnedWeaponId >> 32);
|
||||||
|
|
||||||
|
weapon.AttributeManager.Item.AccountID = (uint)player.SteamID;
|
||||||
|
|
||||||
|
weapon.FallbackPaintKit = 1171;
|
||||||
|
weapon.FallbackSeed = 0;
|
||||||
|
weapon.FallbackWear = 0.01f;
|
||||||
|
|
||||||
|
var handle = weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle;
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(handle, "set item texture prefab", 1171);
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(handle, "set item texture seed", 0);
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(handle, "set item texture wear", 0.01f);
|
||||||
|
|
||||||
|
weapon.AcceptInput("SetBodygroup", value: "body,0");
|
||||||
|
|
||||||
|
Utilities.SetStateChanged(weapon, "CEconEntity", "m_nFallbackPaintKit");
|
||||||
|
Utilities.SetStateChanged(weapon, "CEconEntity", "m_nFallbackSeed");
|
||||||
|
Utilities.SetStateChanged(weapon, "CEconEntity", "m_flFallbackWear");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyDeagleSkin(CBasePlayerWeapon weapon, CCSPlayerController player)
|
||||||
|
{
|
||||||
|
if (weapon.AttributeManager.Item.ItemDefinitionIndex != 1) return;
|
||||||
|
|
||||||
|
weapon.AttributeManager.Item.AttributeList.Attributes.RemoveAll();
|
||||||
|
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Attributes.RemoveAll();
|
||||||
|
|
||||||
|
weapon.AttributeManager.Item.ItemID = SpawnedWeaponId;
|
||||||
|
weapon.AttributeManager.Item.ItemIDLow = (uint)(SpawnedWeaponId & 0xFFFFFFFF);
|
||||||
|
weapon.AttributeManager.Item.ItemIDHigh = (uint)(SpawnedWeaponId >> 32);
|
||||||
|
|
||||||
|
weapon.AttributeManager.Item.AccountID = (uint)player.SteamID;
|
||||||
|
|
||||||
|
weapon.FallbackPaintKit = 962;
|
||||||
|
weapon.FallbackSeed = 0;
|
||||||
|
weapon.FallbackWear = 0.01f;
|
||||||
|
|
||||||
|
var handle = weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle;
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(handle, "set item texture prefab", 962);
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(handle, "set item texture seed", 0);
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(handle, "set item texture wear", 0.01f);
|
||||||
|
|
||||||
|
weapon.AcceptInput("SetBodygroup", value: "body,1");
|
||||||
|
|
||||||
|
Utilities.SetStateChanged(weapon, "CEconEntity", "m_nFallbackPaintKit");
|
||||||
|
Utilities.SetStateChanged(weapon, "CEconEntity", "m_nFallbackSeed");
|
||||||
|
Utilities.SetStateChanged(weapon, "CEconEntity", "m_flFallbackWear");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyButterflyKnifeFade(CBasePlayerWeapon weapon, CCSPlayerController player)
|
||||||
|
{
|
||||||
|
// Vérifier si l'arme est un couteau (pour ne pas transformer un pistolet en couteau)
|
||||||
|
if (!weapon.DesignerName.Contains("knife") && !weapon.DesignerName.Contains("bayonet")) return;
|
||||||
|
|
||||||
|
ushort butterflyDefIndex = 515;
|
||||||
|
|
||||||
|
// Changement de la sous-classe pour charger le bon modèle d'animation et de mesh
|
||||||
|
if (weapon.AttributeManager.Item.ItemDefinitionIndex != butterflyDefIndex)
|
||||||
|
{
|
||||||
|
weapon.AcceptInput("ChangeSubclass", value: butterflyDefIndex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
weapon.AttributeManager.Item.ItemDefinitionIndex = butterflyDefIndex;
|
||||||
|
weapon.AttributeManager.Item.EntityQuality = 3; // Qualité "Étoile" / rare, obligatoire pour les couteaux
|
||||||
|
|
||||||
|
weapon.AttributeManager.Item.AttributeList.Attributes.RemoveAll();
|
||||||
|
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Attributes.RemoveAll();
|
||||||
|
|
||||||
|
weapon.AttributeManager.Item.ItemID = SpawnedWeaponId;
|
||||||
|
weapon.AttributeManager.Item.ItemIDLow = (uint)(SpawnedWeaponId & 0xFFFFFFFF);
|
||||||
|
weapon.AttributeManager.Item.ItemIDHigh = (uint)(SpawnedWeaponId >> 32);
|
||||||
|
|
||||||
|
weapon.AttributeManager.Item.AccountID = (uint)player.SteamID;
|
||||||
|
|
||||||
|
// Application du skin Fade (38)
|
||||||
|
weapon.FallbackPaintKit = 38;
|
||||||
|
weapon.FallbackSeed = 0; // Pattern 0, modifiable pour des variations de Fade
|
||||||
|
weapon.FallbackWear = 0.01f; // Factory New
|
||||||
|
|
||||||
|
var handle = weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle;
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(handle, "set item texture prefab", 38);
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(handle, "set item texture seed", 0);
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(handle, "set item texture wear", 0.01f);
|
||||||
|
|
||||||
|
weapon.AcceptInput("SetBodygroup", value: "body,0");
|
||||||
|
|
||||||
|
Utilities.SetStateChanged(weapon, "CEconEntity", "m_nFallbackPaintKit");
|
||||||
|
Utilities.SetStateChanged(weapon, "CEconEntity", "m_nFallbackSeed");
|
||||||
|
Utilities.SetStateChanged(weapon, "CEconEntity", "m_flFallbackWear");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplySportGlovesPandorasBox(CCSPlayerController player)
|
||||||
|
{
|
||||||
|
var pawn = player.PlayerPawn.Value;
|
||||||
|
if (pawn == null || !pawn.IsValid) return;
|
||||||
|
|
||||||
|
CEconItemView item = pawn.EconGloves;
|
||||||
|
|
||||||
|
item.NetworkedDynamicAttributes.Attributes.RemoveAll();
|
||||||
|
item.AttributeList.Attributes.RemoveAll();
|
||||||
|
|
||||||
|
// 5030 = Sport Gloves
|
||||||
|
item.ItemDefinitionIndex = 5030;
|
||||||
|
|
||||||
|
item.ItemID = SpawnedWeaponId;
|
||||||
|
item.ItemIDLow = (uint)(SpawnedWeaponId & 0xFFFFFFFF);
|
||||||
|
item.ItemIDHigh = (uint)(SpawnedWeaponId >> 32);
|
||||||
|
item.AccountID = (uint)player.SteamID;
|
||||||
|
|
||||||
|
// 10037 = Pandora's Box, 0.06f = Factory New (min float pour ce skin)
|
||||||
|
int paintKit = 10037;
|
||||||
|
float wear = 0.06f;
|
||||||
|
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture prefab", paintKit);
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture seed", 0);
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture wear", wear);
|
||||||
|
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(item.AttributeList.Handle, "set item texture prefab", paintKit);
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(item.AttributeList.Handle, "set item texture seed", 0);
|
||||||
|
CAttributeListSetOrAddAttributeValueByName.Invoke(item.AttributeList.Handle, "set item texture wear", wear);
|
||||||
|
|
||||||
|
item.Initialized = true;
|
||||||
|
|
||||||
|
// Rafraîchissement visuel pour éviter les superpositions de modèles
|
||||||
|
player.ExecuteClientCommand("lastinv");
|
||||||
|
|
||||||
|
Server.NextFrame(() =>
|
||||||
|
{
|
||||||
|
if (pawn.IsValid)
|
||||||
|
{
|
||||||
|
pawn.AcceptInput("SetBodygroup", value: "first_or_third_person,0");
|
||||||
|
plugin.AddTimer(0.2f, () =>
|
||||||
|
{
|
||||||
|
if (pawn.IsValid) pawn.AcceptInput("SetBodygroup", value: "first_or_third_person,1");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyAgentSirBloodyMiamiDarryl(CCSPlayerController player)
|
||||||
|
{
|
||||||
|
// L'agent est exclusif à l'équipe Terroriste (TeamNum 2)
|
||||||
|
if (player.TeamNum != 2) return;
|
||||||
|
|
||||||
|
Server.NextFrame(() =>
|
||||||
|
{
|
||||||
|
if (player.IsValid && player.PlayerPawn.IsValid && player.PawnIsAlive)
|
||||||
|
{
|
||||||
|
var pawn = player.PlayerPawn.Value;
|
||||||
|
if (pawn != null)
|
||||||
|
{
|
||||||
|
pawn.SetModel("agents/models/tm_professional/tm_professional_varf.vmdl");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user