mirror of
https://github.com/Nereziel/cs2-WeaponPaints.git
synced 2026-03-12 17:16:29 +00:00
Compare commits
2 Commits
973a067c79
...
build-387
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30c0ae5665 | ||
|
|
953c3847b1 |
221
Patches/MemoryLinux.cs
Normal file
221
Patches/MemoryLinux.cs
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WeaponPaints;
|
||||||
|
|
||||||
|
public static class MemoryLinux
|
||||||
|
{
|
||||||
|
// Based on https://github.com/Source2ZE/CS2Fixes/blob/main/src/utils/plat_unix.cpp
|
||||||
|
static int ParseProt(string s)
|
||||||
|
{
|
||||||
|
int prot = 0;
|
||||||
|
|
||||||
|
foreach (var c in s)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '-':
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
prot |= NativeMethods.PROT_READ;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
prot |= NativeMethods.PROT_WRITE;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
prot |= NativeMethods.PROT_EXEC;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prot;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GetProt(IntPtr pAddr, uint nSize)
|
||||||
|
{
|
||||||
|
using (var f = File.OpenRead("/proc/self/maps"))
|
||||||
|
using (var reader = new StreamReader(f))
|
||||||
|
{
|
||||||
|
while (!reader.EndOfStream)
|
||||||
|
{
|
||||||
|
var line = reader.ReadLine();
|
||||||
|
if (line == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (parts.Length < 5)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var range = parts[0];
|
||||||
|
var prot = parts[1];
|
||||||
|
|
||||||
|
var startEnd = range.Split('-');
|
||||||
|
if (startEnd.Length != 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var start = Convert.ToUInt64(startEnd[0], 16);
|
||||||
|
var end = Convert.ToUInt64(startEnd[1], 16);
|
||||||
|
|
||||||
|
if (start < (ulong)pAddr && end > (ulong)pAddr + nSize)
|
||||||
|
{
|
||||||
|
return ParseProt(prot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PatchBytesAtAddress(IntPtr pPatchAddress, byte[] pPatch, int iPatchSize)
|
||||||
|
{
|
||||||
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return;
|
||||||
|
|
||||||
|
var oldProt = GetProt(pPatchAddress, (uint)iPatchSize);
|
||||||
|
|
||||||
|
var pageSize = (ulong)NativeMethods.sysconf(NativeMethods._SC_PAGESIZE);
|
||||||
|
var alignAddr = (IntPtr)((long)pPatchAddress & ~(long)(pageSize - 1));
|
||||||
|
|
||||||
|
var end = (IntPtr)((long)pPatchAddress + iPatchSize);
|
||||||
|
var alignSize = (ulong)((long)end - (long)alignAddr);
|
||||||
|
|
||||||
|
var result = NativeMethods.mprotect(alignAddr, alignSize, NativeMethods.PROT_READ | NativeMethods.PROT_WRITE);
|
||||||
|
|
||||||
|
Marshal.Copy(pPatch, 0, pPatchAddress, iPatchSize);
|
||||||
|
|
||||||
|
result = NativeMethods.mprotect(alignAddr, alignSize, oldProt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[]? ReadProcessMemory(int pid, long address, int size)
|
||||||
|
{
|
||||||
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return null;
|
||||||
|
|
||||||
|
byte[] buffer = new byte[size];
|
||||||
|
|
||||||
|
NativeMethods.Iovec local = new NativeMethods.Iovec
|
||||||
|
{
|
||||||
|
iov_base = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0),
|
||||||
|
iov_len = new IntPtr(size)
|
||||||
|
};
|
||||||
|
|
||||||
|
NativeMethods.Iovec remote = new NativeMethods.Iovec
|
||||||
|
{
|
||||||
|
iov_base = new IntPtr(address),
|
||||||
|
iov_len = new IntPtr(size)
|
||||||
|
};
|
||||||
|
|
||||||
|
long bytesRead = NativeMethods.process_vm_readv(pid, new NativeMethods.Iovec[] { local }, 1, new NativeMethods.Iovec[] { remote }, 1, 0);
|
||||||
|
if (bytesRead == -1)
|
||||||
|
{
|
||||||
|
throw new Exception($"process_vm_readv failed with error {Marshal.GetLastPInvokeError()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[]? ReadMemory(IntPtr address, int size)
|
||||||
|
{
|
||||||
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return null;
|
||||||
|
|
||||||
|
return ReadProcessMemory(Process.GetCurrentProcess().Id, (long)address, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value
|
||||||
|
#pragma warning disable CS8981 // The type name only contains lower-cased ascii characters. Such names may become reserved for the language.
|
||||||
|
static class NativeMethods
|
||||||
|
{
|
||||||
|
public const int O_RDONLY = 0;
|
||||||
|
public const int PROT_READ = 0x1;
|
||||||
|
public const int PROT_WRITE = 0x2;
|
||||||
|
public const int PROT_EXEC = 0x4;
|
||||||
|
public const int MAP_PRIVATE = 0x2;
|
||||||
|
public const int PT_LOAD = 1;
|
||||||
|
public const int PF_X = 0x1;
|
||||||
|
public const int _SC_PAGESIZE = 30;
|
||||||
|
public const int RTLD_DI_LINKMAP = 2;
|
||||||
|
|
||||||
|
[DllImport("libc")]
|
||||||
|
public static extern int dlinfo(IntPtr handle, int request, out link_map lmap);
|
||||||
|
|
||||||
|
[DllImport("libc")]
|
||||||
|
public static extern int dlclose(IntPtr handle);
|
||||||
|
|
||||||
|
[DllImport("libc")]
|
||||||
|
public static extern int open(string pathname, int flags);
|
||||||
|
|
||||||
|
[DllImport("libc")]
|
||||||
|
public static extern int fstat(int fd, out stat buf);
|
||||||
|
|
||||||
|
[DllImport("libc")]
|
||||||
|
public static extern IntPtr mmap(IntPtr addr, ulong length, int prot, int flags, int fd, ulong offset);
|
||||||
|
|
||||||
|
[DllImport("libc")]
|
||||||
|
public static extern int munmap(IntPtr addr, ulong length);
|
||||||
|
|
||||||
|
[DllImport("libc")]
|
||||||
|
public static extern int mprotect(IntPtr addr, ulong len, int prot);
|
||||||
|
|
||||||
|
[DllImport("libc")]
|
||||||
|
public static extern long sysconf(int name);
|
||||||
|
|
||||||
|
[DllImport("libc")]
|
||||||
|
public static extern long process_vm_readv(int pid, Iovec[] local_iov, ulong liovcnt, Iovec[] remote_iov, ulong riovcnt, ulong flags);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Iovec
|
||||||
|
{
|
||||||
|
public IntPtr iov_base;
|
||||||
|
public IntPtr iov_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct link_map
|
||||||
|
{
|
||||||
|
public IntPtr l_addr;
|
||||||
|
public IntPtr l_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct ElfW
|
||||||
|
{
|
||||||
|
public struct Ehdr
|
||||||
|
{
|
||||||
|
public byte e_shnum;
|
||||||
|
public uint e_shoff;
|
||||||
|
public ushort e_phnum;
|
||||||
|
public uint e_phoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Phdr
|
||||||
|
{
|
||||||
|
public int p_type;
|
||||||
|
public int p_flags;
|
||||||
|
|
||||||
|
public ulong p_vaddr;
|
||||||
|
public ulong p_filesz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Shdr
|
||||||
|
{
|
||||||
|
public uint sh_name;
|
||||||
|
public uint sh_offset;
|
||||||
|
public uint sh_size;
|
||||||
|
public ulong sh_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
|
||||||
|
public struct stat
|
||||||
|
{
|
||||||
|
public ulong st_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma warning restore CS8981 // The type name only contains lower-cased ascii characters. Such names may become reserved for the language.
|
||||||
|
#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value
|
||||||
|
}
|
||||||
34
Patches/MemoryWindows.cs
Normal file
34
Patches/MemoryWindows.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WeaponPaints;
|
||||||
|
|
||||||
|
public static class MemoryWindows
|
||||||
|
{
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out IntPtr lpNumberOfBytesWritten);
|
||||||
|
|
||||||
|
public static void PatchBytesAtAddress(IntPtr pPatchAddress, byte[] pPatch, int iPatchSize)
|
||||||
|
{
|
||||||
|
if(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return;
|
||||||
|
|
||||||
|
IntPtr bytesWritten;
|
||||||
|
WriteProcessMemory(Process.GetCurrentProcess().Handle, pPatchAddress, pPatch, (uint)iPatchSize, out bytesWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
private static extern IntPtr OpenProcess(int processAccess, bool bInheritHandle, int processId);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out int lpNumberOfBytesRead);
|
||||||
|
|
||||||
|
public static byte[]? ReadMemory(IntPtr address, int size)
|
||||||
|
{
|
||||||
|
if(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return null;
|
||||||
|
|
||||||
|
byte[] buffer = new byte[size];
|
||||||
|
int bytesRead;
|
||||||
|
ReadProcessMemory(Process.GetCurrentProcess().Handle, address, buffer, size, out bytesRead);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
104
Patches/Patch.cs
Normal file
104
Patches/Patch.cs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using CounterStrikeSharp.API.Core;
|
||||||
|
using CounterStrikeSharp.API.Modules.Memory;
|
||||||
|
|
||||||
|
namespace WeaponPaints;
|
||||||
|
|
||||||
|
// Thanks cssharp-fixes
|
||||||
|
public static class Patch
|
||||||
|
{
|
||||||
|
private static IntPtr GetAddress(string modulePath, string signature)
|
||||||
|
{
|
||||||
|
// Returns address if found, otherwise a C++ nullptr which is a IntPtr.Zero in C#
|
||||||
|
var address = NativeAPI.FindSignature(modulePath, signature);
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PerformPatch(string signature, string patch)
|
||||||
|
{
|
||||||
|
IntPtr address = GetAddress(Addresses.ServerPath, signature);
|
||||||
|
if(address == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteBytesToAddress(address, HexToByte(patch));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteBytesToAddress(IntPtr address, List<byte> bytes)
|
||||||
|
{
|
||||||
|
int patchSize = bytes.Count;
|
||||||
|
if(patchSize == 0) throw new ArgumentException("Patch bytes list cannot be empty.");
|
||||||
|
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
{
|
||||||
|
MemoryLinux.PatchBytesAtAddress(address, bytes.ToArray(), patchSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MemoryWindows.PatchBytesAtAddress(address, bytes.ToArray(), patchSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<byte> HexToByte(string src)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(src))
|
||||||
|
{
|
||||||
|
return new List<byte>();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte HexCharToByte(char c)
|
||||||
|
{
|
||||||
|
if (c is >= '0' and <= '9') return (byte)(c - '0');
|
||||||
|
if (c is >= 'A' and <= 'F') return (byte)(c - 'A' + 10);
|
||||||
|
if (c is >= 'a' and <= 'f') return (byte)(c - 'a' + 10);
|
||||||
|
return 0xFF; // Invalid hex character
|
||||||
|
}
|
||||||
|
|
||||||
|
List<byte> result = new List<byte>();
|
||||||
|
bool isCodeStyle = src[0] == '\\';
|
||||||
|
string pattern = isCodeStyle ? "\\x" : " ";
|
||||||
|
string wildcard = isCodeStyle ? "2A" : "?";
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while (pos < src.Length)
|
||||||
|
{
|
||||||
|
int found = src.IndexOf(pattern, pos);
|
||||||
|
if (found == -1)
|
||||||
|
{
|
||||||
|
found = src.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
string str = src.Substring(pos, found - pos);
|
||||||
|
pos = found + pattern.Length;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(str)) continue;
|
||||||
|
|
||||||
|
string byteStr = str;
|
||||||
|
|
||||||
|
if (byteStr.Substring(0, wildcard.Length) == wildcard)
|
||||||
|
{
|
||||||
|
result.Add(0xFF); // Representing wildcard as 0xFF
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byteStr.Length < 2)
|
||||||
|
{
|
||||||
|
return new List<byte>(); // Invalid byte length
|
||||||
|
}
|
||||||
|
|
||||||
|
byte high = HexCharToByte(byteStr[0]);
|
||||||
|
byte low = HexCharToByte(byteStr[1]);
|
||||||
|
|
||||||
|
if (high == 0xFF || low == 0xFF)
|
||||||
|
{
|
||||||
|
return new List<byte>(); // Invalid hex character
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Add((byte)((high << 4) | low));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
153
README.md
153
README.md
@@ -1,36 +1,20 @@
|
|||||||
```
|
# CS2 Weapon Paints
|
||||||
|
|
||||||
__ __ ___ _ _
|
## Description
|
||||||
/ / /\ \ \___ __ _ _ __ ___ _ __ / _ \__ _(_)_ __ | |_ ___
|
|
||||||
\ \/ \/ / _ \/ _` | '_ \ / _ \| '_ \ / /_)/ _` | | '_ \| __/ __|
|
|
||||||
\ /\ / __/ (_| | |_) | (_) | | | / ___/ (_| | | | | | |_\__ \
|
|
||||||
\/ \/ \___|\__,_| .__/ \___/|_| |_\/ \__,_|_|_| |_|\__|___/
|
|
||||||
|_|
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://github.com/Nereziel/cs2-WeaponPaints/releases">📖 Releases</a> •
|
|
||||||
<a href="https://discord.gg/d9CvaYPSFe">💬 Discord</a>
|
|
||||||
<br /><br />
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
## 📝 Description
|
|
||||||
Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin for **[CSSharp](https://docs.cssharp.dev/docs/guides/getting-started.html)**.
|
Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin for **[CSSharp](https://docs.cssharp.dev/docs/guides/getting-started.html)**.
|
||||||
|
|
||||||
|
## Created [Discord server](https://discord.gg/d9CvaYPSFe) where you can discuss about plugin.
|
||||||
|
|
||||||
### 💸 Consider to donate instead of buying from unknown sources.
|
### Consider to donate instead of buying from unknown sources.
|
||||||
[](https://ko-fi.com/E1E2G0P2O) or [](https://steamcommunity.com/tradeoffer/new/?partner=41515647&token=gW2W-nXE)
|
[](https://ko-fi.com/E1E2G0P2O) or [](https://steamcommunity.com/tradeoffer/new/?partner=41515647&token=gW2W-nXE)
|
||||||
|
|
||||||
## ✨ Features
|
## Features
|
||||||
- Changes only paint, seed and wear on weapons, knives, gloves and agents
|
- Changes only paint, seed and wear on weapons, knives, gloves and agents
|
||||||
- MySQL based
|
- MySQL based
|
||||||
- Data syncs on player connect
|
- Data syncs on player connect
|
||||||
- Added command **`!wp`** to refresh skins ***(with cooldown in seconds can be configured)***
|
- Added command **`!wp`** to refresh skins ***(with cooldown in seconds can be configured)***
|
||||||
- Added command **`!ws`** to show website
|
- Added command **`!ws`** to show website
|
||||||
- Added command **`!knife`** to show menu with knives
|
- Added command **`!knife`** to show menu with knives
|
||||||
- Added command **`!stattrak`** to enable stattrak on weapon
|
|
||||||
- Added command **`!gloves`** to show menu with gloves
|
- Added command **`!gloves`** to show menu with gloves
|
||||||
- Added command **`!agents`** to show menu with agents
|
- Added command **`!agents`** to show menu with agents
|
||||||
- Added command **`!pins`** to show menu with pins
|
- Added command **`!pins`** to show menu with pins
|
||||||
@@ -45,7 +29,7 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
|
|||||||
- [MenuManagerCS2](https://github.com/NickFox007/MenuManagerCS2)
|
- [MenuManagerCS2](https://github.com/NickFox007/MenuManagerCS2)
|
||||||
- MySQL database
|
- MySQL database
|
||||||
|
|
||||||
## 🗄️ CS2 Server
|
## CS2 Server
|
||||||
- Have working CounterStrikeSharp (**with RUNTIME!**)
|
- Have working CounterStrikeSharp (**with RUNTIME!**)
|
||||||
- Download from Release and copy plugin to plugins
|
- Download from Release and copy plugin to plugins
|
||||||
- Run server with plugin, **it will generate config if installed correctly!**
|
- Run server with plugin, **it will generate config if installed correctly!**
|
||||||
@@ -53,72 +37,49 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
|
|||||||
- In `addons/counterstrikesharp/configs/`**`core.json`** set **FollowCS2ServerGuidelines** to **`false`**
|
- In `addons/counterstrikesharp/configs/`**`core.json`** set **FollowCS2ServerGuidelines** to **`false`**
|
||||||
- Copy from plugins folder gamedata file **`weaponpaints.json`** to folder **`addons/counterstrikesharp/gamedata/`**
|
- Copy from plugins folder gamedata file **`weaponpaints.json`** to folder **`addons/counterstrikesharp/gamedata/`**
|
||||||
|
|
||||||
## 🛠️ Plugin Configuration
|
## Plugin Configuration
|
||||||
<details>
|
<details>
|
||||||
<summary>Click to expand</summary>
|
<summary>Click to expand</summary>
|
||||||
<code><pre>{
|
<code><pre>{
|
||||||
"ConfigVersion": 10, // Don't touch
|
"Version": 4, // Don't touch
|
||||||
"SkinsLanguage": "en", // Language
|
"DatabaseHost": "", // MySQL host
|
||||||
"DatabaseHost": "", // MySQL host
|
"DatabasePort": 3306, // MySQL port
|
||||||
"DatabasePort": 3306, // MySQL Port
|
"DatabaseUser": "", // MySQL username
|
||||||
"DatabaseUser": "", // MySQL Username
|
"DatabasePassword": "", // MySQL user password
|
||||||
"DatabasePassword": "", // MySQL User password
|
"DatabaseName": "", // MySQL database name
|
||||||
"DatabaseName": "", // MySQL Database name
|
"CmdRefreshCooldownSeconds": 60, // Cooldown time in refreshing skins (!wp command)
|
||||||
"CmdRefreshCooldownSeconds": 3, // Cooldown time in refreshing skins (!wp command)
|
"Prefix": "[WeaponPaints]", // Prefix every chat message
|
||||||
"Website": "example.com/skins", // Website used in WebsiteMessageCommand (!ws command)
|
"Website": "example.com/skins", // Website used in WebsiteMessageCommand (!ws command)
|
||||||
"Additional": {
|
"Messages": {
|
||||||
"KnifeEnabled": true, // If knives are enabled
|
"WebsiteMessageCommand": "Visit {WEBSITE} where you can change skins.", // Information about website where player can change skins (!ws command) Set to empty to disable
|
||||||
"GloveEnabled": true, // If gloves are enabled
|
"SynchronizeMessageCommand": "Type !wp to synchronize chosen skins.", // Information about skins refreshing (!ws command) Set to empty to disable
|
||||||
"MusicEnabled": true, // If music kits are enabled
|
"KnifeMessageCommand": "Type !knife to open knife menu.", // Information about knife menu (!ws command) Set to empty to disable
|
||||||
"AgentEnabled": true, // If agents are enabled
|
"CooldownRefreshCommand": "You can\u0027t refresh weapon paints right now.", // Cooldown information (!wp command) Set to empty to disable
|
||||||
"SkinEnabled": true, // If skins are enabled
|
"SuccessRefreshCommand": "Refreshing weapon paints.", // Information about refreshing skins (!wp command) Set to empty to disable
|
||||||
"PinsEnabled": true, // If pins are enabled
|
"ChosenKnifeMenu": "You have chosen {KNIFE} as your knife.", // Information about choosen knife (!knife command) Set to empty to disable
|
||||||
"CommandWpEnabled": true, // If command !wp is enabled
|
"ChosenSkinMenu": "You have chosen {SKIN} as your skin.", // Information about choosen skin (!skins command) Set to empty to disable
|
||||||
"CommandKillEnabled": true, // If command !kill is enabled
|
"ChosenKnifeMenuKill": "To correctly apply skin for knife, you need to type !kill.", // Information about suicide after knife selection (!knife command) Set to empty to disable
|
||||||
"CommandKnife": [ // Command for knives
|
"KnifeMenuTitle": "Knife Menu.", // Menu title (!knife menu)
|
||||||
"knife"
|
"WeaponMenuTitle": "Weapon Menu.", // Menu title (!skins menu)
|
||||||
],
|
"SkinMenuTitle": "Select skin for {WEAPON}" // Menu title (!skins menu, after weapon select)
|
||||||
"CommandMusic": [ // Command for music kits
|
},
|
||||||
"music"
|
"Additional": {
|
||||||
],
|
"KnifeEnabled": true, // Enable or disable knife feature
|
||||||
"CommandPin": [ // Command for pins
|
"SkinEnabled": true, // Enable or disable skin feature
|
||||||
"pin",
|
"CommandWpEnabled": true, // Enable or disable refreshing command
|
||||||
"pins",
|
"CommandKillEnabled": true, // Enable or disable kill command
|
||||||
"coin",
|
"CommandKnife": "knife", // Name of knife menu command, u can change to for e.g, knives
|
||||||
"coins"
|
"CommandSkin": "ws", // Name of skin information command, u can change to for e.g, skins
|
||||||
],
|
"CommandSkinSelection": "skins", // Name of skins menu command, u can change to for e.g, weapons
|
||||||
"CommandGlove": [ // Command for gloves
|
"CommandRefresh": "wp", // Name of skin refreshing command, u can change to for e.g, refreshskins
|
||||||
"gloves"
|
"CommandKill": "kill", // Name of kill command, u can change to for e.g, suicide
|
||||||
],
|
"GiveRandomKnife": false, // Give random knife to players if they didn't choose
|
||||||
"CommandAgent": [ // Command for agents
|
"GiveRandomSkins": false // Give random skins to players if they didn't choose
|
||||||
"agents"
|
},
|
||||||
],
|
|
||||||
"CommandStattrak": [ // Command for stattrak
|
|
||||||
"stattrak",
|
|
||||||
"st"
|
|
||||||
],
|
|
||||||
"CommandSkin": [ // Command for skins
|
|
||||||
"ws"
|
|
||||||
],
|
|
||||||
"CommandSkinSelection": [ // Command for skin selection
|
|
||||||
"skins"
|
|
||||||
],
|
|
||||||
"CommandRefresh": [ // Command for refreshing your skins
|
|
||||||
"wp"
|
|
||||||
],
|
|
||||||
"CommandKill": [ // Command for death
|
|
||||||
"kill"
|
|
||||||
],
|
|
||||||
"GiveRandomKnife": false, // If it should give you Random Knife
|
|
||||||
"GiveRandomSkin": false, // If it should give you Random Skin
|
|
||||||
"ShowSkinImage": true // When you select a skin if it should show skins image
|
|
||||||
},
|
|
||||||
"MenuType": "selectable" // Menu type commands. Can be: selectable, dynamic, center, chat, console
|
|
||||||
}
|
|
||||||
</pre></code>
|
</pre></code>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## 🖥️ Web install
|
## Web install
|
||||||
- Requires PHP >= 7.4 with curl and pdo_mysql ***(Tested on php ver **`8.2.3`** and nginx webserver)***
|
- Requires PHP >= 7.4 with curl and pdo_mysql ***(Tested on php ver **`8.2.3`** and nginx webserver)***
|
||||||
- **Before using website, make sure the plugin is correctly loaded in cs2 server!** Mysql tables are created by plugin not by website.
|
- **Before using website, make sure the plugin is correctly loaded in cs2 server!** Mysql tables are created by plugin not by website.
|
||||||
- Copy website to web server ***(Folder `img` not needed)***
|
- Copy website to web server ***(Folder `img` not needed)***
|
||||||
@@ -126,44 +87,22 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
|
|||||||
- Fill in database credentials and api key in `class/config.php`
|
- Fill in database credentials and api key in `class/config.php`
|
||||||
- Visit website and login via steam
|
- Visit website and login via steam
|
||||||
|
|
||||||
## 🧩 Web Features
|
## Web Features
|
||||||
> [!WARNING]
|
|
||||||
> We recommend you to use any third-party website for WeaponPaints. Website by us doesn't get updated!
|
|
||||||
- Basic website
|
- Basic website
|
||||||
- Steam login/logout
|
- Steam login/logout
|
||||||
- Change knife, paint, seed and wear
|
- Change knife, paint, seed and wear
|
||||||
|
|
||||||
## 🌐 Third-party websites
|
## Troubleshooting
|
||||||
- **[CSS-Bans](https://github.com/counterstrikesharp-panel/css-bans)**
|
|
||||||
- **[CS2-WeaponPaints-Website](https://github.com/LielXD/CS2-WeaponPaints-Website)**
|
|
||||||
- **[cs2-WeaponPaints-website](https://github.com/L1teD/cs2-WeaponPaints-website)** > This webiste is different from the one above!
|
|
||||||
- **[CS2-WeaponPaints-Web](https://github.com/rogeraabbccdd/CS2-WeaponPaints-Web)**
|
|
||||||
## 🤔 Troubleshooting
|
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
**Skins are not changing:**
|
**Skins are not changing:**
|
||||||
Set FollowCSGOGuidelines to false in cssharp’s core.jcon config
|
Set FollowCSGOGuidelines to false in cssharp’s core.jcon config
|
||||||
|
|
||||||
**Database error table does not exists:**
|
**Database error table does not exists:**
|
||||||
Plugin is not loaded or configured with mysql credentials. Tables are auto-created by plugin.
|
Plugin is not loaded or configured with mysql credentials. Tables are auto-created by plugin.
|
||||||
|
|
||||||
**An error occured in Get....FromDatabase:**
|
|
||||||
If you used WeaponPaints and you update to newer version you could get this error. You need to add this queries to Database:
|
|
||||||
```
|
|
||||||
ALTER TABLE wp_player_skins
|
|
||||||
ADD COLUMN weapon_nametag VARCHAR(128) DEFAULT NULL,
|
|
||||||
ADD COLUMN weapon_stattrak tinyint(1) NOT NULL,
|
|
||||||
ADD COLUMN weapon_stattrak_count int(10) NOT NULL,
|
|
||||||
ADD COLUMN weapon_sticker_0 VARCHAR(128) DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
|
|
||||||
ADD COLUMN weapon_sticker_1 VARCHAR(128) DEFAULT '0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
|
|
||||||
ADD COLUMN weapon_sticker_2 VARCHAR(128) DEFAULT '0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
|
|
||||||
ADD COLUMN weapon_sticker_3 VARCHAR(128) DEFAULT '0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
|
|
||||||
ADD COLUMN weapon_sticker_4 VARCHAR(128) DEFAULT '0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
|
|
||||||
ADD COLUMN weapon_keychain VARCHAR(128) DEFAULT '0;0;0;0;0' COMMENT 'id;x;y;z;seed';
|
|
||||||
```
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Use this plugin at your own risk! Using this may lead to GSLT ban or something else Valve come with. [Valve Server guidelines](https://blog.counter-strike.net/index.php/server_guidelines/)
|
### Use this plugin at your own risk! Using this may lead to GSLT ban or something else Valve come with. [Valve Server guidelines](https://blog.counter-strike.net/index.php/server_guidelines/)
|
||||||
|
|
||||||
## Website Preview
|
## Preview
|
||||||

|

|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
using CounterStrikeSharp.API;
|
using CounterStrikeSharp.API;
|
||||||
using CounterStrikeSharp.API.Core;
|
using CounterStrikeSharp.API.Core;
|
||||||
using CounterStrikeSharp.API.Core.Attributes;
|
using CounterStrikeSharp.API.Core.Attributes;
|
||||||
@@ -16,10 +17,16 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
|
|||||||
public override string ModuleAuthor => "Nereziel & daffyy";
|
public override string ModuleAuthor => "Nereziel & daffyy";
|
||||||
public override string ModuleDescription => "Skin, gloves, agents and knife selector, standalone and web-based";
|
public override string ModuleDescription => "Skin, gloves, agents and knife selector, standalone and web-based";
|
||||||
public override string ModuleName => "WeaponPaints";
|
public override string ModuleName => "WeaponPaints";
|
||||||
public override string ModuleVersion => "3.1c";
|
public override string ModuleVersion => "3.1d";
|
||||||
|
|
||||||
public override void Load(bool hotReload)
|
public override void Load(bool hotReload)
|
||||||
{
|
{
|
||||||
|
// Hardcoded hotfix needs to be changed later
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
Patch.PerformPatch("0F 85 ? ? ? ? 31 C0 B9 ? ? ? ? BA ? ? ? ? 66 0F EF C0 31 F6 31 FF 48 C7 45 ? ? ? ? ? 48 C7 45 ? ? ? ? ? 48 C7 45 ? ? ? ? ? 48 C7 45 ? ? ? ? ? 0F 29 45 ? 48 C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? 66 89 45 ? E8 ? ? ? ? 41 89 C5 85 C0 0F 8E", "90 90 90 90 90 90");
|
||||||
|
else
|
||||||
|
Patch.PerformPatch("74 ? 48 8D 0D ? ? ? ? FF 15 ? ? ? ? EB ? BA", "EB");
|
||||||
|
|
||||||
Instance = this;
|
Instance = this;
|
||||||
|
|
||||||
if (hotReload)
|
if (hotReload)
|
||||||
|
|||||||
30
lang/cs.json
30
lang/cs.json
@@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"wp_prefix": "{lightblue}[WeaponPaints] {default}",
|
|
||||||
"wp_info_website": "Navštiv {lime}{0}{default} kde si můžeš změnit skiny",
|
|
||||||
"wp_info_refresh": "Napiš {lime}!wp{default} pro synchronizaci vybraných skinů",
|
|
||||||
"wp_info_knife": "Napiš {lime}!knife{default} pro otevření menu nožů",
|
|
||||||
"wp_info_glove": "Napiš {lime}!gloves{default} pro otevření menu rukavic",
|
|
||||||
"wp_info_agent": "Napiš {lime}!agents{default} pro otevření menu agentů",
|
|
||||||
"wp_info_music": "Napiš {lime}!music{default} pro otevření menu MVP hudeb",
|
|
||||||
"wp_info_pin": "Napiš {lime}!pins{default} pro otevření menu odznaků",
|
|
||||||
"wp_command_cooldown": "{lightred}Skiny nelze nýni obnovit!",
|
|
||||||
"wp_command_refresh_done": "{lime}Obnovuji skiny",
|
|
||||||
"wp_knife_menu_select": "Vybral jsi si {lime}{0}{default} jako tvůj nůž",
|
|
||||||
"wp_knife_menu_kill": "",
|
|
||||||
"wp_knife_menu_title": "Menu nožů",
|
|
||||||
"wp_glove_menu_select": "Vybral jsi si {lime}{0}{default} jako tvoje rukavice",
|
|
||||||
"wp_glove_menu_title": "Menu rukavic",
|
|
||||||
"wp_agent_menu_select": "Vybral jsi si {lime}{0}{default} jako tvůj agent",
|
|
||||||
"wp_agent_menu_title": "Menu agentů",
|
|
||||||
"wp_music_menu_title": "Menu MVP hudeb",
|
|
||||||
"wp_music_menu_select": "Vybral jsi si {lime}{0}{default} jako tvojí MVP hudbu",
|
|
||||||
"wp_pins_menu_title": "Menu odznaků",
|
|
||||||
"wp_pins_menu_select": "Vybral jsi si {lime}{0}{default} jako tvůj odznak",
|
|
||||||
"wp_skin_menu_weapon_title": "Menu zbraní",
|
|
||||||
"wp_skin_menu_skin_title": "Vyběr skinů pro {lime}{0}{default}",
|
|
||||||
"wp_skin_menu_select": "Vybral jsi si {lime}{0}{default} jako tvůj skin",
|
|
||||||
|
|
||||||
"wp_stattrak_action": "Úspěšně jste změnil nastavení stattraku",
|
|
||||||
|
|
||||||
"None": "Žádné"
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user