VoidSharp - A GMod C# Abstraction Layer

VoidSharp - A Garry’s Mod C# Abstraction Layer

A few months ago I started working on an C# abstraction layer with @Menschlich.
It is a layer on top of GLua, allowing you to use proper OOP C# code which is then transpiled to Lua with CSharp.lua. It’s basically an environment enabling you to write addons in Garry’s Mod with C#. Some code is kinda inspired by S&box.

I managed to get it in a working state, so it’s useable. It is FAR from finished, most of the stuff is missing.
It IS NOT easy to setup, you WILL encounter a lot of issues. You can definitely make some stuff with it, it works (sometimes). Since S&box is around the corner, I have decided to stop working on it and open-source it. The code behind VoidSharp is not that great, but the working-side is okay. It’s just something I worked on before S&box was in a working state and before when I had time.

VoidSharp manages Hooks, Console Commands, Net Messages, UI, Database Connections (with an ORM), and wraps around some gmod libraries - Players, entities, vectors, etc…

The source code of VoidSharp and how to get it working is on GitHub:

And you can view example code using VoidSharp here:


Let’s start with an example: We want to make a UI in C#. We use the VoidSharp library which exposes a lot of Garry’s Mod functions. The code can look like this:

public class MainPanel : Frame
    public MainPanel()
        Title = "VoidSharp TEST";

        TextEntry textEntry = Add("DTextEntry").Cast<TextEntry>();
        textEntry.DockMargin(50, 50, 50, 10);
        textEntry.Height = 40;

        textEntry.UpdateOnType = true;
        textEntry.OnValueChange((self, str) =>
            Title = str;

        ColorMixer mixer = Add("DColorMixer").Cast<ColorMixer>();
        mixer.DockMargin(50, 10, 50, 10);
        mixer.Height = 150;

        Button button = Add("DButton").Cast<Button>();
        button.DockMargin(100, 20, 100, 40);
        button.Height = 40;
        button.Text = "Click me!!";

        button.DoClick(() =>
            button.Text = "You clicked me!";

This code is then transpiled by the CSharp.lua compiler into Lua code. The code is ugly, but still readable (but working in Garry’s Mod!)

-- Generated by CSharp.lua Compiler
local System = System
local VoidSharpDerma = VoidSharp.Derma
local VoidSharpNetworking = VoidSharp.Networking
local VoidSharpTestModels
System.import(function (out)
  VoidSharpTestModels = VoidSharpTest.Models
System.namespace("VoidSharpTest.UI", function (namespace)
  namespace.class("MainPanel", function (namespace)
    local SendDataToServer, __ctor__
    __ctor__ = function (this)
  this:setTitle("VoidSharp TEST")

  local textEntry = this:Add("DTextEntry"):Cast(VoidSharpDerma.TextEntry)
  textEntry:Dock(4 --[[DockType.Top]])
  textEntry:DockMargin(50, 50, 50, 10)


  textEntry:OnValueChange(function (self, str)

  local mixer = this:Add("DColorMixer"):Cast(VoidSharpDerma.ColorMixer)
  mixer:Dock(4 --[[DockType.Top]])
  mixer:DockMargin(50, 10, 50, 10)

  local button = this:Add("DButton"):Cast(VoidSharpDerma.Button)
  button:Dock(4 --[[DockType.Top]])
  button:DockMargin(100, 20, 100, 40)
  button:setText("Click me!!")

  button:DoClick(function ()
    button:setText("You clicked me!")
return {
  base = function (out)
    return {
  __ctor__ = __ctor__,
  __metadata__ = function (out)
    return {
      methods = {
        { ".ctor", 0x6, nil },
      class = { 0x6 }

This however just creates the custom panel for the UI. We need to show the UI somehow to the player. Let’s use a console command to do that:

public void OpenMenu(Player ply, string s, string[] args, string argStr)
     MainPanel panel = new MainPanel();
     panel.SetSize(400, 400);

After we type voidsharptest_ui in our client’s console, we can see the UI we made purely in C#!
Not that beautiful, but we can style that later.

But that’s not everything. We can use hooks, RPCs (net messages), save data into databases, etc…
Here are a few examples, you can view all at the example github link above.

This notifies all players that someone died

    public void OnPlayerDeath(dynamic gVictim, dynamic gInflictor, dynamic gAttacker)
        // The hook gets called with gmod entities, we need to convert them to VoidSharp entities so we have OOP advantages
        Player victim = (Player) new Entity(gVictim);

        foreach (var ply in Players.GetAll()) {
              ply.ChatPrint(victim.Nick + " died!");

Sending net messages:

Sending side:

var data = new InventoryItem
      CreatedAt = DateTime.Now,
      PlayerName = "SMG",
      SteamId64 = player.SteamId64
RPC.SendToClient<InventoryItem>(player, "ReceiveInventoryRPC", data);

Receiving side:

    public void ReceiveInventoryRPC(InventoryItem item)
        var player = Player.LocalPlayer();
        player.ChatPrint("Got some useful data!");

Every object you send is automatically serialized, so you don’t need to worry about that.

Saving data to databases:

Class we wanna save:

public class InventoryItem
    public int Id { get; set; }
    public string SteamId64 { get; set; }
    public string PlayerName { get; set; }
    public Color PlayerColor { get; set; }
    public DateTime CreatedAt { get; set; }

Actually inserting it to the database:

var item = new InventoryItem
     PlayerColor = networkData.Color,
     PlayerName = networkData.Name,
     CreatedAt = DateTime.Now,
     SteamId64 = player.SteamId64


Fetching data from the database:

InventoryItem selectedItem = await Database.Select<InventoryItem>()
    .Where("SteamId64", "=", "76561198152492642")

There’s much more, but I can’t be arsed to show more. Just look here GitHub - VoidTeam1/voidcsharp: A Garry's Mod C# abstraction layer.


Cool project no doubt, but its hard to see the benefits of it all.

That being said, its still a cool ass project.


I don’t know their project, but I’m quite sure this isn’t a little project :sweat_smile:

@m0uka @Menschlich Good job!

1 Like

Cool concept, I can’t see a good use case in production as I expect it’ll produce quite un-optimized code. As is the nature of transpiled languages without that being their primary goal.

1 Like

Regardless of performance this is really dope. Seeing that shorthand code for RPC and panel callbacks warms my heart. :relieved:

1 Like

This is really cool! Is there any way to hot reload?

1 Like

If you configure everything correctly, then yes:

First you have to put this comment in all files you want to auto-refresh to call the autorefresh function (if you have changed the function in the Lua loader, you need to change this too, in the case of VoidSharpTest it’s this:)


and then in Program.cs, you need to have a static void method called HandleAutoRefresh(), from there you can basically reload your code

1 Like