Giter Club home page Giter Club logo

counterstrikesharp's Introduction

CounterStrikeSharp

CounterStrikeSharp is a server side modding framework for Counter-Strike 2. This project implements a .NET 8 scripting layer on top of a Metamod Source Plugin, allowing developers to create plugins that interact with the game server in a modern language (C#) to facilitate the creation of maintainable and testable code.

Come and join our Discord

History

This project is an ongoing migration of a previous project (titled VSP.NET) whereby a scripting layer was added to a Valve Server Plugin for CSGO.

Due to the architectural changes of CS2, the plugin is being rebuilt on the ground up, to support Linux 64-bit, something which was previously impossible.

Install

Download the latest build from here. (Download the with runtime version if this is your first time installing).

Detailed installation instructions can be found in the docs.

What works?

These features are the core of the platform and work pretty well/have a low risk of causing issues.

  • Console Commands, Server Commands (e.g. css_mycommand)
  • Chat Commands with ! and / prefixes (e.g. !mycommand)
  • Fake Console Variables (commands which mimic ConVar behaviour as these have not been fully reverse engineered)
  • Game Event Handlers & Firing of Events (e.g. player_death)
    • Basic event value get/set (string, bool, int32, float)
    • Complex event values get/set (ehandle, pawn, player controller)
  • Game Tick Based Timers (e.g. repeating map timers)
    • Timer Flags (REPEAT, STOP_ON_MAPCHANGE)
  • Listeners (e.g. client connected, disconnected, map start etc.)
    • Client Listeners (e.g. connect, disconnect, put in server)
    • OnMapStart
    • OnTick
  • Server Information (current map, game time)
  • Schema System Access (access player values like current weapon, money, location etc.)

Links

Examples

You can view the example Warcraft plugin migrated from the previous VSP.NET project to give you an idea of the kind of power this scripting runtime is capable of. This plugin shows how you can hook events, create commands, use third party libraries (SQLite) and do basic entity manipulation.

Basic Example with Game Event & Console Commands

using CounterStrikeSharp.API.Core;

namespace HelloWorldPlugin;

public class HelloWorldPlugin : BasePlugin
{
    public override string ModuleName => "Hello World Plugin";

    public override string ModuleVersion => "0.0.1";

    public override string ModuleAuthor => "roflmuffin";

    public override string ModuleDescription => "Simple hello world plugin";

    public override void Load(bool hotReload)
    {
        Logger.LogInformation("Plugin loaded successfully!");
    }

    [GameEventHandler]
    public HookResult OnPlayerConnect(EventPlayerConnect @event, GameEventInfo info)
    {
        // Userid will give you a reference to a CCSPlayerController class
        Logger.LogInformation("Player {Name} has connected!", @event.Userid.PlayerName);

        return HookResult.Continue;
    }

    [ConsoleCommand("css_issue_warning", "Issue warning to player")]
    public void OnCommand(CCSPlayerController? player, CommandInfo command)
    {
        Logger.LogWarning("Player shouldn't be doing that");
    }
}

Credits

A lot of code has been borrowed from SourceMod as well as Source.Python, two pioneering source engine plugin frameworks which this project lends a lot of its credit to. I've also used the scripting context & native system that is implemented in FiveM for GTA5. Also shoutout to the CS2Fixes project for providing good reverse-engineering information so shortly after CS2 release.

How to Build

Building requires CMake.

Clone the repository

git clone https://github.com/roflmuffin/counterstrikesharp

Init and update submodules

git submodule update --init --recursive

Make build folder

mkdir build
cd build

Generate CMake Build Files

cmake ..

Build

cmake --build . --config Debug

License

CounterStrikeSharp is licensed under the GNU General Public License version 3. A special exemption is outlined regarding published plugins, which you can find in the LICENSE file.

counterstrikesharp's People

Contributors

abnerfs avatar apfelwurm avatar b3none avatar busheezy avatar charlesbarone avatar chte avatar dependabot[bot] avatar dliix66 avatar hackmastr avatar ianlucas avatar ikiwky avatar ipsvn avatar johnoclockdk avatar killstr3ak avatar laper32 avatar miguno avatar muinez avatar nukoooo avatar partiusfabaa avatar pedrotski avatar poggicek avatar roflmuffin avatar snorux avatar srtnlgn avatar stefanx111 avatar switz avatar ther00st3r avatar widovv avatar yarukon avatar zonical avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

counterstrikesharp's Issues

Multiple ConsoleCommandAttributes are not cleaned up properly on Unload

When you have multiple console command attributes, only one of the commands is automatically de-registered on unload, so hot-reload fails as it tries to add an existing command (since the old one still exists).

Repro code:

[ConsoleCommand("css_killmeplease", "Kills the player")]
[ConsoleCommand("css_killme", "Kills the player")]
public void OnKillme(CCSPlayerController? player, CommandInfo command)
{
    if (player == null) return;
    if (!player.PlayerPawn.IsValid) return;

    player.PlayerPawn.Value.CommitSuicide(true, true);
}

[BUG] HotReload command stacking

Description

Whenever you drag and drop the new files onto your server from the same project, the server reloads the plugin, right? Well yes, but actually the earlier data stay in the server memory. That means when you run a command, first get gets executed once, then twice and so on as many times as you upload a new build without restart or so.

Reproduce

  1. Create a simple command
  2. Upload it to the server
  3. Execute it (it will print once)
  4. Upload the files again (estimated modification on plugin or so)
  5. When you execute the command it is executed twice
  6. ...

EDIT

In addition, because probably it is connected to this bug, when you upload the new files or run css_plugins reload xy, it says the following:

css_plugins reload PluginName
Could not reload plugin "PluginName")

[BUG] Chat is not responding to commands, but server console does

So basically, I've encountered a weird bug, which is appeared only on one server of the several, which I was checking on. First I was thinking about that possibly some leftover from meta plugins or so, which is incompatible with CSS, so I installed freshly the server, added Metamod dev2 and css latest (v53). When I installed a test plugin to check the problem again it does the following:

  • If you use the command (which is registered) in the chat, it just simply send "!test" to the chat as message.
  • If you use the command in server console, the command is executed properly.

I tried to check this on multiple dev servers from multiple hosts, but so far I see this bug only on one and first server so far.

Suggestion: ReplyToCommand should know a command's origin (chat, console) and respond to the correct location

Status quo
As of v50, one cannot tell whether a command was issued in the console (my_command) vs. in chat (!my_command). As a result, a plugin developer must decide a priori whether a reply to a command should always be printed EITHER to chat OR to console.

(Well, to be safe, one could always print to both chat and console, but this isn't ideal either.)

Suggestion

Make it possible to use ReplyToCommand so that:

  1. If the command was run in chat, ReplyToCommand automatically responds to chat.
  2. If the command was run in console, ReplyToCommand automatically responds to console.
  3. Ideally, there is a way to get the origin information to implement different logic depending on the origin. For example, if the origin is chat, then we want to use ChatColors to colorize the chat response. If the origin is the console, we may want to use ANSI colors or something similar to colorize the console response.

NativeAPI.FireEvent crash

Firing events created by the NativeAPI results in Segmentation fault (core dumped)

Repro code:

var eventptr = NativeAPI.CreateEvent("player_score", true);

NativeAPI.SetEventPlayerController(eventptr, "userid", player.Handle);
NativeAPI.SetEventInt(eventptr, "kills", 20);
NativeAPI.SetEventInt(eventptr, "deaths", 10);
NativeAPI.SetEventInt(eventptr, "score", 100);

NativeAPI.FireEvent(eventptr, false);

Compat: CS2Fixes compatibility issues

We need to handle compatibility with CS2Fixes, at least in a basic sense, that means:

  • Don't send "player_chat" event if CS2Fixes is found as they send this also.

Chat detour

First, thanks for a fantastic project! ๐Ÿ’ฏ

I noticed that the chat detour auto dispatches anything that stars with '/' and '!'. This creates a few problems for us since we have some other infrastructure that needs to know about chats that starts with '!'.

Also I found that it's not possible to implement a '!pause' command since pause is already a command (leads to seg fault).

I see a couple of solutions here that would fit nicely for us at least.

  1. Always do m_pHostSay
  2. Configuration to turn off chat commands

What do you think?

Strange behavior when setting the `mp_backup_round_file` convar

Hey, we experience strange behavior when setting the mp_backup_round_file convar.

We tried to set it like:

 string prefix = $"PugSharp_Match_{_Match.MatchInfo.Config.MatchId}";
            _Logger.LogInformation("Create round backup files: {prefix}", prefix);
            UpdateConvar("mp_backup_round_file", prefix);

After the update, the cvar content seems to not be the same, even if the prefix content stays exactly the same.

  799,1: mp_backup_round_file = `๏ฟฝ๏ฟฝ
  1125,21: mp_backup_round_file = `๏ฟฝ๏ฟฝ
  1127,1: mp_backup_round_file = `๏ฟฝ๏ฟฝ
  1129,1: mp_backup_round_file = `๏ฟฝ๏ฟฝ
  1131,1: mp_backup_round_file = `๏ฟฝ๏ฟฝ
  1133,1: mp_backup_round_file = `๏ฟฝ๏ฟฝ
  2049,1: mp_backup_round_file = ๏ฟฝX๏ฟฝM๏ฟฝ~
  2864,1: mp_backup_round_file = ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ-V
  7209,1: mp_backup_round_file = ๏ฟฝX9๏ฟฝ๏ฟฝ

The files are later named something like (not sure which filename belongs to which output above) :

'`'$'\372\256\b\365\177''_round00.txt'
'`'$'\372\256\b\365\177''_round01.txt'   
'`'$'\372\256\b\365\177''_round02.txt'   
'`'$'\372\256\b\365\177''_round03.txt'   
'`'$'\372\360\t\r\177''_round00.txt'     
'`'$'\372\360\t\r\177''_round01.txt'     
'`'$'\372\360\t\r\177''_round02.txt'     
'xJ'$'\212\232\364\177''_round00.txt'
'xJ'$'\212\232\364\177''_round01.txt'
'xJ'$'\212\232\364\177''_round02.txt'
''$'\320''Z'$'\325\n''W'$'\177''_round00.txt'
''$'\320''Z'$'\325\n''W'$'\177''_round01.txt'
''$'\320''Z'$'\325\n''W'$'\177''_round02.txt'
''$'\320''Z'$'\325\n''W'$'\177''_round03.txt'
''$'\320''Z'$'\325\n''W'$'\177''_round04.txt'
''$'\320\362\343\310''-V_round00.txt'
''$'\320\362\343\310''-V_round01.txt'
''$'\330''X9'$'\223\256\177''_round00.txt'
''$'\330''X9'$'\223\256\177''_round01.txt'
''$'\330''X9'$'\223\256\177''_round02.txt'
''$'\330''X9'$'\223\256\177''_round03.txt'
''$'\330''X9'$'\223\256\177''_round04.txt'
''$'\330''X9'$'\223\256\177''_round05.txt'
''$'\330''X'$'\373''M'$'\376''~_round00.txt'
''$'\330''X'$'\373''M'$'\376''~_round01.txt'
'ุทs'$'\025\006\177''_round00.txt'
'p'$'\226''Z'$'\222\275''U_round00.txt'
'p'$'\226''Z'$'\222\275''U_round01.txt'
'p'$'\226''Z'$'\222\275''U_round02.txt'
'p'$'\226''Z'$'\222\275''U_round03.txt'
'p'$'\226''Z'$'\222\275''U_round04.txt'
'p'$'\226''Z'$'\222\275''U_round05.txt'

We can use Server.ExecuteCommand($"mp_backup_round_file {prefix}"); as a workaround which sets mp_backup_round_file = PugSharp_Match_59 and creates PugSharp_Match_59_round01.txt just fine.

Sugestion: Upload a Nuget package

By creating a hello world plugin I had to download the CounterStrikeSharp.API.dll DLL and reference it in my project manually, I believe you could upload it to Nuget packages (add a step to do that in Github Actions pipeline) so we can leverage a package manager to avoid referencing the DLL manually.

Doesnt loading

Hi i install right but when i write to console css_plugins list its says that command doesnt exist when i write meta list i see that folder that mean to be a sharp its with no name and next writting

image

Bad type is being used in GameEvent?

I guess this has just remained like that and it throws the exception below when try to set the CCSPlayerController

image

Repro code:

EventPlayerScore eventPlayerScore = new EventPlayerScore(true);
eventPlayerScore.Userid = player; // exception
eventPlayerScore.Kills = 20;
eventPlayerScore.Deaths = 10;
eventPlayerScore.Score = 100;
eventPlayerScore.FireEvent(false);

crash

compiled without error but server crashes.

[19:43:13.904] CSSharp: Initializing
[19:43:13.904] CSSharp: Globals loaded.
cs2: /root/counterstrikesharp/src/scripting/dotnet_host.cpp:59: void* {anonymous}::load_library(const char_t*): Assertion `h != nullptr' failed.

[Command Listeners] Listening to certain sv_cheat commands

After experimenting a fair bit with command listeners earlier today, I think I might have stumbled upon a bug.
I was able to tap in to commands such as the jointeam, and meta commands and the likes.

I found that I was unable to track when the "kill" and "explode" commands were being used, and I suspect it is because it requires sv_cheats 1 to be enabled in order to use these two commands. But despite enabling sv_cheats, I could use the commands, but the command listener did not seem to register the use of them.
The code compiled just fine, and no errors were to be found in the console when the two commands were used.

This is what I had in my load function:

        AddCommandListener("kill", CommandListener_Kill);
        AddCommandListener("explode", CommandListener_Kill);

This is what I had outside of my load function, within the main / base class:

    private HookResult CommandListener_Kill(CCSPlayerController? player, CommandInfo info)
    {
        Console.WriteLine("Debug - Listener kill / explode");

        // If the the CCSPlayerController entity is invalid then execute this section
        if (!player.IsValid)
        {
            return HookResult.Continue;
        }

        // If the pawn associated with the CCSPlayerController is invalid then execute this section
        if (!player.PlayerPawn.IsValid)
        {
            return HookResult.Continue;
        }

        Server.PrintToChatAll("The kill / explode commands are blocked");

        return HookResult.Stop;
    }

AddCommand Server Crash

When the AddCommand is used with an existing command, the server crashes. The crash occurs during the server boot-up, even without invoking the command.

To reproduce:
Use "kill" as a command and attempt to run your server.
(The arguments should resemble the image below)
grafik

Artifact crashes the whole app

Hey,

I downloaded this artifact: https://github.com/roflmuffin/CounterStrikeSharp/actions/runs/6782595525 and I get these texts so it seems like it succesfully initializes:

[12:38:16.708] CSSharp: Initializing
[12:38:16.708] CSSharp: Globals loaded.
[12:38:16.721] CSSharp: .NET Runtime Initialised.
Loading GameData
Loaded game data with 8 methods.
Loading C# plugins...
All managed modules were loaded. 0 plugins loaded.
[12:38:16.866] CSSharp: CounterStrikeSharp.API Loaded Successfully.
[12:38:16.866] CSSharp: Hooks added.

However meta list command returns this where [01] and [04] are added when adding that counterstrikesharp runtime:

Listing 4 plugins:
  [01] CounterStrikeSharp (0.1.0) by Roflmuffin
  [02] Fake RCON (1.2.1) by Kriax
  [03] Base Admin (1.2) by Pisex
  [04] <FAILED>

Also when joining to server, the whole server crashes. All these issues disappear when removing addons/counterstrikesharp/* and metamod/counterstrikesharp.vdf files.

Any ideas what should I test?

GiveNamedItem BUG

GiveNamedItem on windows cant give weapon_knife_m9_bayonet or other knives?
CSS version 56

read me not clear for simple users

this mod is installed succesfully but i dont know where are the commands ? not single tutorial present on google already did a little search.

css_changemap ?
css_kick
css_ban
css_slay

how to check if im an admin , i set the id in admin.jason

[Command Issue] SwitchTeam And Unassigned

Hi, so we just stumbled upon this minor thing.

I assume it is an issue on the end of CounterStrikeSharp and not CS2 itself, so take it with a grain of salt.
But I just so happened to stumble upon a minor thing with the SwitchTeam command, as I was trying to issue it on a player, with the team index of NONE, and 0.

I had no errors with my compiler, and the plugin loads fine. But when the code is run, I receive the following output in my server console:
CCSPlayerPawnBase::SwitchTeam( 0 ) - invalid team index.

What I am trying to do is to move a player to the 'unassigned' team.
I know it was possible to do in CS:GO, so I am just going out on a limb assuming the same applies here, albeit I am uncertain of whether it is the case. Hopefully, this is on the CounterStrikeSharp end of things and is an easy fix, and not an actual limitation.

AdminManager improvements

This is just a collection of some ideas that people have been discussing in the Discord to improve the AdminManager API:

  • Add groups of permissions to simplify how many flags are required. This can probably be enforced by including a syntax for individual flags @ and groups of flags #
  • Remove all arbitrary flags from core e.g can_execute_css_commands
  • Add wildcard support for RequiresPermissions and PlayerHasPermissions e.g @css/*
  • Add OR support for RequiresPermissions, this can probably be done with a simple bool argument

Help

Where can i download directly the run time version?

PrintToCenterHtml results in Segmentation Fault

For some reason show_survival_respawn_status event crash server. Code below was tested on three different servers with latest CS2 and CounterStrikeSharp versions. Do you have any idea what happend?

Operation System: Ubuntu 22.04 / Ubuntu 22.10

Simple reproduction code

using CounterStrikeSharp.API.Core;

namespace TestPlugin;

public class TestPlugin : BasePlugin
{
    public override string ModuleName => "TestPlugin";

    public override string ModuleVersion => "0.0.0";

    public override void Load(bool hotReload)
    {
        base.Load(hotReload);

        AddCommand("test", "test", (player, info) => {
            if (player == null) {
                return;
            }

            player.PrintToCenterHtml("<font color=\"red\">TEST</font>");
        });
    }
}

Metamod list and css version

meta list
Listing 1 plugin:
  [01] CounterStrikeSharp (0.1.0) by Roflmuffin
css
  CounterStrikeSharp was created and is maintained by Michael "roflmuffin" Wilson.
  Counter-Strike Sharp uses code borrowed from SourceMod, Source.Python, FiveM, Saul Rennison and CS2Fixes.
  See ACKNOWLEDGEMENTS.md for more information.
  Current API Version: 30

Question: How to write a message to the client's dev console and/or the in-game chat?

Background: I created a custom command plugin_info, and clients (once connected to the server) can successfully run that command when they open the in-game console.

Question 1: How can I write a response message back to the client so it shows up in their CS2 developer console?

What I want is something like this:

# Client opens developer console

> plugin_info
Plugin version: 1.2.3.4

With Console.Writeln(), which is what the custom command currently uses, the output is (obviously) written to the server's log/console, but not back to the client. I have dug through the CounterStrikeSharp API but have not found what I was looking for.

Question 2: Are there equivalent methods for CS2's console commands say and say_team? Or is there a way to run CS2's built-in console commands via CounterStrikeSharp? Here, it's about sending messages from the server to the in-game chat.

Edit: I did find Server.PrintToChatAll() to print a message to all players in the in-game chat.

Attempting to read CCSPlayer_ViewModelServices.ViewModel throws System.Reflection.TargetInvocationException

I'm attempting to get the player's view model

server.hpp schema

class CCSPlayer_ViewModelServices : public CPlayer_ViewModelServices
{
public:
	// MNetworkEnable
	CHandle< CBaseViewModel > m_hViewModel[3]; // 0x40	
};

What i've attempted in c# plugin:

var ViewModelServices = new CCSPlayer_ViewModelServices(this.PlayerPawn.Value.ViewModelServices.Handle);
var viewModelArray = ViewModelServices.ViewModel; // line "68"

but receive the following error:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.ArgumentException: Cannot use type 'CounterStrikeSharp.API.Modules.Utils.CHandle`1[CounterStrikeSharp.API.Core.CBaseViewModel]'. Only value types without pointers or references are supported.
   at CounterStrikeSharp.API.Modules.Memory.Schema.GetFixedArray[T](IntPtr pointer, String className, String memberName, Int32 count) in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/CounterStrikeSharp.API/Modules/Memory/Schema.cs:line 69
   at CounterStrikeSharp.API.Core.CCSPlayer_ViewModelServices.get_ViewModel() in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/CounterStrikeSharp.API/Core/Objects.g.cs:line 7576
   at <my function name> in <my file name>.cs:line 68

i've tried various null checks and tried using Server.NextFrame to access the different properties but all leads to the same exception

Menu

Hello,
Can you add admin menu?
I know that cs2 doesnt have menu yet like csgo, but im thinking of that if i say !admin, than a menu appears in the chat (just like in the mini admin plugin), which show me that !1 slay !2 slap !3 kick etc....

System.InvalidCastException: Unable to cast object of type 'System.UInt64' to type 'System.Int64'

When extracting some data from events with the long data type, we get the following error:
System.InvalidCastException: Unable to cast object of type 'System.UInt64' to type 'System.Int64'.

(ulong),Convert., etc cant help

Using latest version build
Using latest version MM
Not using another MM plugins

Exception System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidCastException: Unable to cast object of type 'System.UInt64' to type 'System.Int64'. at CounterStrikeSharp.API.Modules.Events.GameEvent.Get[T](String name) in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/CounterStrikeSharp.API/Modules/Events/GameEvent.cs:line 58 at CounterStrikeSharp.API.Core.EventItemPickup.get_Defindex() in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/CounterStrikeSharp.API/Core/GameEvents.g.cs:line 3572 at Weapon_Restrict.Weapon_Restrict.OnEventItemPickupPost(EventItemPickup event, GameEventInfo info) in E:\SteamLibrary\steamapps\common\Counter-Strike Global Offensive\game\csgo\addons\counterstrikesharp\plugins\Weapon_Restrict\Weapon_Restrict.cs:line 63 at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr) --- End of inner exception stack trace --- at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Delegate.DynamicInvokeImpl(Object[] args) at CounterStrikeSharp.API.Core.FunctionReference.<>c__DisplayClass3_0.<.ctor>b__0(fxScriptContext* context) in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/CounterStrikeSharp.API/Core/FunctionReference.cs:line 70
private HookResult OnEventItemPickupPost(EventItemPickup @event, GameEventInfo info)
{
    Server.PrintToConsole($"{@event.Defindex}");      // reported line 63. Type long
    return HookResult.Continue;
}
private HookResult OnEventItemPickupPost(EventRoundMvp@event, GameEventInfo info)
{
    Server.PrintToConsole($"{@event.Musickitid}");      // reported line. Type long
    return HookResult.Continue;
}
private HookResult OnEventItemPickupPost(EventRoundMvp@event, GameEventInfo info)
{
    Server.PrintToConsole($"{@event.Musickitmvps}");      // reported line. Type long
    return HookResult.Continue;
}

admin permissions

added myself as admin but it doesn't work, i get always.

[CSS] You do not have the correct permissions to execute this command.

Feedback re: high level API design

Kia ora,
I've been wanting to experiment with some high level helper functions for the C# API, similar in scope to Utilities.FindAllEntitiesByDesignerName<> function that I implemented. The thing I would like to have wider input on is the separation between higher level functions like these and functions for specific classes. I was planning on implementing a more cleaner get/set function for entity origins, but the main question is where to place it. Does it belong in the Utilities class? A separate class for entities? Or CBaseEntity? Where should we put the divide between more global functions and entity/object specific type things?

I think a good place to start would be to get some ideas for what the community wants to have implemented that could then be sorted into categories for implementation.

GetPlayers() sometimes return wrong list. (CS2 problem userid after mapchange)

Sometimes after map change one user id will be -256, which is valid one somehow.
In controller my userid is -256, in status is 65280, 65280 & FF = 0, real id.

for (int i = 0; i <= Server.MaxPlayers; i++)
{
    var controller = GetPlayerFromIndex(i);

    if (!controller.IsValid || controller.UserId < 0)
        continue;

    players.Add(controller);
}

Here, controller.UserId < 0 should not exists?

Admin Immunity

I was vote kicked on my own server and temporary banned even tho i am css admin!

I set myself as admin in the admins.json file. most commands dont work or maybe i dont know how to use them? however i can use css_rcon so i been getting by with that.

Here are my flags
"flags": [
"can_execute_css_commands",
"@css/reservation",
"@css/generic",
"@css/kick",
"@css/ban",
"@css/unban",
"@css/vip",
"@css/slay",
"@css/changemap",
"@css/cvar",
"@css/config",
"@css/chat",
"@css/vote",
"@css/password",
"@css/rcon",
"@css/cheats",
"@css/root"
]

earlier today i joined my server. at the last round map changed and as soon as the new map started someone started a vote to kick me. I was kicked and could not rejoin the server. so i shut it down! any suggestions would be greatly appreciated.

Thanks

Crash on player connects.

I found my server randomly crash when player connecting.
I was watching the server console and found each crash happens after print someone connecting.

My css version: v56
Server OS: Windows 10,11

there was no PDB file so the mdmp file get no stacktrace.
And finally I built a release counterstrikesharp.dll with PDB file.
According to the mdmp file, the problem is in src\core\managers\player_manager.cpp(367).

image

full stack:

[Inline Frame] counterstrikesharp.dll!std::_Adjust_manually_vector_aligned(void * &) Line 160
	at C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.37.32822\include\xmemory(160)
[Inline Frame] counterstrikesharp.dll!std::_Deallocate(void * _Ptr, unsigned __int64 _Bytes) Line 262
	at C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.37.32822\include\xmemory(262)
[Inline Frame] counterstrikesharp.dll!std::allocator<char>::deallocate(char * const _Count, const unsigned __int64) Line 969
	at C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.37.32822\include\xmemory(969)
[Inline Frame] counterstrikesharp.dll!std::string::_Tidy_deallocate() Line 4838
	at C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.37.32822\include\xstring(4838)
counterstrikesharp.dll!std::string::operator=(std::string && _Right) Line 2981
	at C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.37.32822\include\xstring(2981)
[Inline Frame] counterstrikesharp.dll!counterstrikesharp::CPlayer::Initialize(const char *) Line 367
	at D:\a\CounterStrikeSharp\CounterStrikeSharp\src\core\managers\player_manager.cpp(367)
counterstrikesharp.dll!counterstrikesharp::PlayerManager::OnClientConnect(CPlayerSlot slot, const char * pszName, unsigned __int64 xuid, const char * pszNetworkID, bool unk1, CBufferString * pRejectReason) Line 126
	at D:\a\CounterStrikeSharp\CounterStrikeSharp\src\core\managers\player_manager.cpp(126)
counterstrikesharp.dll!__SourceHook_FHCls_IServerGameClientsClientConnect0::Func(CPlayerSlot p1, const char * p2, unsigned __int64 p3, const char * p4, bool p5, CBufferString * p6) Line 54
	at D:\a\CounterStrikeSharp\CounterStrikeSharp\src\core\managers\player_manager.cpp(54)
[Frames may be missing, no binary loaded for engine2.dll]
engine2.dll!00007ffd05fb6993()

there are 3 mdmp file. my server crashed 3 times in 2 hour. and they all get the same stack.
20:26, 21:07, 22:02
image
image
image

System.Reflection.TargetInvocationException thrown when accessing fields of `@event.Userid` in a GameEventHandler

The server throws an exception when trying to use the simple GampleEventHandler from the docs. The only change is that I used Console.Writeln() instead of the Log() method in the example. The exception is thrown when the @event is being read.

[GameEventHandler]
public HookResult OnPlayerConnect(EventPlayerConnect @event, GameEventInfo info) {
  // This works:
  Server.PrintToChatAll($"Player {@event.Name} has connected!");

  // But this will trigger an exception:
  Server.PrintToChatAll($"{@event.Userid.IsBot} will trigger an exception!");

  // @event.Userid will give you a reference to a CCSPlayerController class.
  // However, accessing any of its fields will throw an exception!
  HookResult.Continue;
}

Exception:

Creating NetChan for user 0 'm0NESY' @ 192.168.0.44:59053
Associating NetChan       m0NESY    192.168.0.44:59053[1] (192.168.0.44:59053) wit
CServerSideClientBase::Connect( name='m0NESY', userid=0, fake=0, chan->addr=192.16
Client 0 'm0NESY' signon state SIGNONSTATE_NONE -> SIGNONSTATE_CONNECTED
Server waking up from hibernation
L 11/05/2023 - 19:50:43: "m0NESY<0><[U:1:81210237]><>" connected, address "192.168
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at System.Runtime.InteropServices.Marshal.ReadByte(IntPtr ptr, Int32 ofs)
   at CounterStrikeSharp.API.Core.ScriptContext.GetResult(Type type, Byte* ptr) in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/CounterStrikeSharp.API/Core/Script
Context.cs:line 407
   at CounterStrikeSharp.API.Core.ScriptContext.GetResultHelper(fxScriptContext* context, Type type) in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/CounterStrike
Sharp.API/Core/ScriptContext.cs:line 391
   at CounterStrikeSharp.API.Core.ScriptContext.GetResultHelper(Type type) in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/CounterStrikeSharp.API/Core/ScriptConte
xt.cs:line 384
   at CounterStrikeSharp.API.Core.ScriptContext.GetResult(Type type) in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/CounterStrikeSharp.API/Core/ScriptContext.cs:
line 370
   at CounterStrikeSharp.API.Core.NativeAPI.GetSchemaValueByName[T](IntPtr instance, Int32 returntype, String classname, String propname) in /__w/CounterStrikeSharp/Cou
nterStrikeSharp/managed/CounterStrikeSharp.API/Core/API.cs:line 868
   at CounterStrikeSharp.API.Modules.Memory.Schema.GetSchemaValue[T](IntPtr handle, String className, String propertyName) in /__w/CounterStrikeSharp/CounterStrikeSharp
/managed/CounterStrikeSharp.API/Modules/Memory/Schema.cs:line 26
   at CounterStrikeSharp.API.Modules.Memory.Schema.GetString(IntPtr pointer, String className, String memberName) in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/
CounterStrikeSharp.API/Modules/Memory/Schema.cs:line 79
   at CounterStrikeSharp.API.Core.CBasePlayerController.get_PlayerName() in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/CounterStrikeSharp.API/Core/Objects.g.cs:
line 4308
   at MigunoPlugin.MigunoPlugin.OnPlayerConnect(EventPlayerConnect event, GameEventInfo info) in /Users/miguno/git/cs2miguno/MigunoPlugin/MigunoPlugin.cs:line 34
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
   --- End of inner exception stack trace ---
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at CounterStrikeSharp.API.Core.FunctionReference.<>c__DisplayClass3_0.<.ctor>b__0(fxScriptContext* context) in /__w/CounterStrikeSharp/CounterStrikeSharp/managed/Cou
nterStrikeSharp.API/Core/FunctionReference.cs:line 70

Environment:

  • Debian GNU/Linux 12 (bookworm) x86_64
  • Kernel: 6.1.0-13-amd64

Have you come across this error before?

PS: Thank you for the work on this project! :-)

Listeners.OnMapStart Does not seem to be working

tried setting up a listener

RegisterListener<Listeners.OnMapStart>((mapName) =>
        {
            Console.WriteLine($"MAP CHANGED {mapName}");
            SetupMatch();
        });

it seems to be not triggering when a map is changed.

using newest version 1.0.30

Sugestion: Semantic versioning

Hey first of all congratulations for the amazing work, it is really exciting to use a modern language like C# to build plugins ๐Ÿฅณ.
The releases are being generated using simple version numbers like from v12 -> v13, it would be interesting to follow the semantic versioning specification so it is easier to identify what is changing, for example if it goes from 12.0.0 to 12.0.1 I can tell that it has only bug fixes, but when it moves from 12.0.0 to 13.0.0 I might expect breaking changes, just a suggestion, I can see this is incentivized in the versioning of the plugins by looking at the examples.

The whole design of CounterStrikeSharp

Instead of shared data between app domains, I'd better call it: The whole design of CounterStrikeSharp.

You could find that shared data between app domains is the subset of the whole design of 'CounterStrikeSharp'.

Why we discuss it? Well, this project, CounterStrikeSharp, will be renamed to a better name in the future, and it will directly affect the future of the project, and the future of the whole ecosystem.

Any progress will be updated in this issue.

For now, yes, we are now using C# for scripting, but if I remember correctly, one of the aims is: any language what supports the format can be integrated easily and can also share data between different languages.

This requires us to make well-designed architecture. Generally, this MUST lead to a result: We are doing an engine, a tiny Operating System, in fact.

If we want to do it, Unreal, Unity, etc. must be important references, and also S&Box, which is the only game what using C# for scripting in Source 2.

Now, back to our question: How many layers should we have?

  1. Engine layer.
    It can also be called Unmanaged layer (aka, not managed by the next layer), which handles such things:
    • Interact with native engine.
    • Provides infrastructures, which may include:
      • Reverse-engineering tools
      • Centralized logging
      • Hacked functions
      • Game-specific information
    • Distributed folder layout
      It should also be easily expanded.
  2. Runtime layer.
    It handles such things:
    • Provide user space infrastructures, may include:
      • GC
      • User friendly API
      • Simplified error handling
      • Distributed folder layout
        It inherits the engine layer, and adds user space specific layers.
        It won't contradict the engine layer folder layout.
    • Wrapper of engine layer APIs
    • Application infrastructures.
      Based on the above, in general, we would select something VM-based, like Android of Java, Unity of C#, Unreal of Blueprint.
      Also, this layer should also be expanded easily.
      Our choice is C#.
  3. Application layer.
    Since previous layers have already provided all infrastructure what you need, you now can write your own application.
    These applications should be restricted in their own space, and MUST NOT let them pollute any other, even any parent layers.

So, we have discussed a lot, what should it look like?
For distributed folder layout:

. // addons/counterstrikesharp
|
|---bin                                                1)
|---config                                             2)
|---log                                                3)
|    |---L20231101.log
|    \---L20231102.log
|---gamedata                                           4)
|    |---counterstrikesharp.games.kv
|    \---cs2.games.kv
|---modules                                            5)
|    |---managed                                     5.a)
|    \---unmnaged                                    5.b)  
\---plugins                                            6)
     |---disabled                                      7)
     |---Warcraft                                      8)
     |    |---bin                                      9)
     |    |    |---Warcraft.API.dll
     |    |    \---Warcraft.Core.dll
     |    |---config                                  10)
     |    |---gamedata                                11)
     |    |    |---warcraft.games.kv
     |    |    |---whatever.games.kv
     |    \---Plugin.toml                             12)
     |---Admin
     |---VIP
     |---ZombiePlague                                 13)
     |    |---ZombiePlague.Core
     |    |---ZombiePlague.Weapons
     |    \---ZombiePlague.Classes
     \---Store

where:

  1. Core binaries, which contain engine layer output and runtime layer output, and all of these extensions, and modules.

    For example, for now, unmanaged output is counterstrikesharp.dll, the runtime is CounterStrikeSharp.API.dll

  2. Core configs. Other layers can only read, but can not write.
  3. All log messages should be written in one place.
  4. Core gamedata. Other layers can only read, but can not write.
  5. Provides additional modules for engine layer and runtime layer.
    a. Unmanaged, what engine layer uses
    b. Managed, what runtime layer uses.
  6. Plugins folder. All plugins are based on folders.
  7. If you don't want to modify the config, just simply drag the plugin in what you don't want.
  8. Plugin folder
  9. Plugin binaries
  10. Plugin config
  11. Plugin game data
  12. Plugin configuration, which declares the plugin information
  13. A folder which can contain multiple plugins, since we control the plugin node by looking for Plugin.toml

    Noting that a plugin can have no binaries, just only config or gamedata provided, or some plugins provides a new language, then this plugin's sub-plugins, definitely, is the ecosystem of the language.

For implementation, in my opinion, we should:

  • Separate API and implementation if possible.
  • Modularize the structure, from project to binary output.

Thus, what can we do?

We use the current version of css as an example.

The current version of css's layer is:

  • Plugins
  • Managed side
  • Unmanaged side

Currently, for the managed side, we have only CounterStrikeSharp.API.dll, which contains all implementations and interfaces.

Indeed, it is a single file, easy to develop, and easy to take. People will only take care of the API.

But what will happen if css updated? Well, it may crash, right? Then that's the problem.

So we need to separate the implementation and interface, I will call them:

  • CounterStrikeSharp.Core.dll
  • CounterStrikeSharp.API.dll

Then, no matter how implementation changed, it won't affect the interface. The Plugin will only invoke the API, and will not take care of how this interface is implemented.

Also, the CounterStrikeSharp.Core.dll also acts as a runtime of application and unmanaged side.

On the unmanaged side, as I stated previously, it interacts with the game engine, provide reversed-engineering stuffs, etc., and this is exactly what is doing.

OK, you may say: "This is too abstract, I want to see the sample code!", now here we go.
For Core, as I said, interacts with engine layer and interface layer, it is used to initialize the scripting runtime.

// Example core, part of the CounterStrikeSharp.Core.dll

class Bootstrap
{
    [Unmanaged]
    public static bool Initialize()
    {
        // These are all samples, what we need to initialize are all depends on
        // the implementation in the future.
        
        // Initialize sharesys
        // Initialize configsys
        // Initialize additional systems
        // Initialize pluginsys
        // Initialize modulesys
        // Load all modules inside the plugin
    }
    
    [Unmanaged]
    public static void Shutdown()
    {
        // unload all of them, reversed sequence.
    }
}

the CounterStrikeSharp.API.dll, provides the API exposed from .Core, and also wraps APIs from engine layers.

Some functional suggestions

Based on my previous experience using Pug, may I ask if it is possible to add features such as

1.Vote for maps before starting the competition (very important)
2.Administrators can set whether to disrupt the team (very important)
3.Add a prompt box below the warm-up time prompt
4.Add [Ready] to the player name prefix on the scoreboard
5.Whether to enable edge selection in blade games when adding players to cast screens (convenient for me to copy this function to add other votes)

This is an important option for the competition function in the first part
I have many ideas about improving the completeness of functions, based on my long-term experience

Also, can we achieve registration setting Commands like sm_setting are much more convenient for administrators to control on the console

Thanks a lot !

Add admin functionality

Since CSSharp is taking off rapidly, and large amounts of plugins are being created, I'd like to suggest a long-term solution here.
A lot of plugins have unique admins.cfg files. This will be confusing for the average user when adding multiple plugins.

I'd advise CSSharp to add a base admins.cfg file that works similar to how it did in SourceMod: https://wiki.alliedmods.net/Adding_Admins_(SourceMod)

This way, the average user (and plugin creator) will save a lot of time, both in terms of developing an admin system, but also to manage the plugins.

Windows Support

Investigate work required to support 64 bit Windows servers

  • CMake modifications
  • Windows .NET Runtime
  • CI matrix builds
  • Managed Code Windows Support (marshalling/DllImport)

Bug: Event handler for `EventPlayerSpawn` is called multiple times

(Reposting from a discussion by Dliix66 in Discord so it is tracked here.)

[When registering a handler for] EventPlayerSpawn when joining the server, it's called many times, but I can't really understand whether I did something wrong of if i need to handle differently some of these.

  1. Called on player connect (player.CSTeam = None)
  2. Called on team join (player.CSTeam = T|CT)
  3. Called right after (2) (player.CSTeam = T|CT)

But if I respawn, go spectator or change team, this will only ever be triggered once every respawn (which is what I want).

I understand the 1st one and I can handle this easily with TeamNum, but for the 2 calls on first spawn after server connect, I don't quite get it.

and from a subsequent Discord message

It seems that calling the method player.PrintToChat inside Server.NextFrame fixes the issue in EventPlayerSpawn callbacks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.