AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   General (https://forums.alliedmods.net/forumdisplay.php?f=58)
-   -   SourceGo: Golang to SourcePawn Transpiler (v1.4 beta) (https://forums.alliedmods.net/showthread.php?t=328269)

nergal 11-02-2020 17:18

SourceGo: Golang to SourcePawn Transpiler (v1.4 beta)
 
I'm happy to announce that, with the help of many SM devs, I've created an experimental Golang to SourcePawn source to source compiler aka a transpiler.

What does it do? It takes (a subset of) Golang code and converts it to an equivalent SourcePawn version, here's a quick example:

Code:

/// SourceGo
package main

const (
        a, b = "A", MAXPLAYERS
        c = a
        d string = "D"
        e = "e1"
        f = 1.00
)

var (
        myself = Plugin{
                name: "SrcGo Plugin",
                author: "Nergal",
                description: "Plugin made into SP from SrcGo.",
                version: "1.0a",
                url: "https://github.com/assyrianic/Go2SourcePawn",
        }
       
        str_array = [...]string{
                "kek",
                "foo",
                "bar",
                "bazz",
        }
)

type (
        Point struct{ x, y float }
        QAngle Vec3
        Name [64]char
        Color = [4]int
       
        PlayerInfo struct {
                Origin Vec3
                Angle QAngle
                Weaps [3]Entity
        }
       
        Kektus    func(i, x Vec3, b string, blocks *Name, KC *int)  Handle
        EventFunc func(event Event, name string, dontBroadcast bool) Action
)


func OnlyScoutsLeft(team int) bool {
        for i:=0; i<=MaxClients; i++ {
                if !IsValidClient(i) || !IsPlayerAlive(i) {
                        continue;
                } else if GetClientTeam(i) == team && TF2_GetPlayerClass(i) != TFClass_Scout {
                        return false
                }
        }
        return true
}


func IsClientInGame(client Entity) bool

func main() {
        for i := 1; i<=MaxClients; i++ {
                if IsClientInGame(i) {
                        OnClientPutInServer(i)
                }
        }
}

func OnClientPutInServer(client Entity) {
        /// do something with client.
}

Code:

/// Generated SourcePawn:
#include <sourcemod>

char a[] = "A";
int b = MAXPLAYERS;
char c[] = a;
char d[] = "D";
char e[] = "e1";
float f = 1.00;

public Plugin myself = {
        name = "SrcGo Plugin",
        author = "Nergal",
        description = "Plugin made into SP from SrcGo.",
        version = "1.0a",
        url = "https://github.com/assyrianic/Go2SourcePawn"
};
char str_array[4][] = {
        "kek",
        "foo",
        "bar",
        "bazz"
};

enum struct Point {
        float x;
        float y;
}
enum struct PlayerInfo {
        float Origin[3];
        float Angle[3];
        int Weaps[3];
}
typedef Kektus = function Handle (const float i[3], const float x[3], const char[] b, char blocks[64], int& KC);
typedef EventFunc = function Action (Event event, const char[] name, bool dontBroadcast);


public bool OnlyScoutsLeft(int team) {
        for (int i = 0; i <= MaxClients; i++) {
                if (!IsValidClient(i) || !IsPlayerAlive(i)) {
                        continue;
                }
                else if (GetClientTeam(i) == team && TF2_GetPlayerClass(i) != TFClass_Scout) {
                        return false;
                }

        }
        return true;
}

native bool IsClientInGame(int client);
public void OnPluginStart() {
        for (int i = 1; i <= MaxClients; i++) {
                if (IsClientInGame(i)) {
                        OnClientPutInServer(i);
                }

        }

}

public void OnClientPutInServer(int client) {
}


The transpiler itself is written in Golang and can easily be cross-compiled for Windows 32-bit, 64-bit and Linux/Mac 32-bit, 64-bit from the Go compiler directly.

The project is MIT licensed and is currently in open Alpha phase.

The purpose of this project is to help automate and abstract over many SourcePawn constructs in order to significantly improve plugin development time. Part of this is stronger typing & type abstraction and a simpler, more expressive syntax.

Project Repo.

An important thing to remember is that, with SourceGo, you're not making SourceMod plugins with Golang, you're using Golang's syntax that is then transformed into its SourcePawn equivalent code.

Domino_ 11-02-2020 18:01

Re: SourceGo: Experimental Golang to SourcePawn Transpiler
 
I look forward to seeing where this goes :)

Mayor Gamer 11-03-2020 13:32

Re: SourceGo: Experimental Golang to SourcePawn Transpiler
 
This looks pretty interesting. I've seen lots of interest with Rust nowadays, but GoLang is something I definitely would love to see having SourcePawn support.

Also looking forward to this! :bee:

nergal 11-03-2020 17:26

Re: SourceGo: Experimental Golang to SourcePawn Transpiler
 
In terms of what SourceGo is capable of, here's an example using a receiver, returning multiple values, and assigning multiple values.

Code:

type PlayerInfo struct {
        Origin Vec3
        Angle QAngle
        Weaps [3]Entity
}

func (pi PlayerInfo) GetOrigin(buffer *Vec3) (float, float, float) {
        *buffer = pi.Origin
        return pi.Origin[0], pi.Origin[1], pi.Origin[2]
}

var p PlayerInfo
var origin Vec3
x,y,z := p.GetOrigin(&origin)
origin[0], origin[1], origin[2] = x,y,z

this becomes:
Code:

enum struct PlayerInfo {
        float Origin[3];
        float Angle[3];
        int Weaps[3];
}

public float PlayerInfo_GetOrigin(const PlayerInfo pi, float buffer[3], float& PlayerInfo_GetOrigin_param1, float& PlayerInfo_GetOrigin_param2) {
        buffer = pi.Origin;
        PlayerInfo_GetOrigin_param1 = pi.Origin[1];
        PlayerInfo_GetOrigin_param2 = pi.Origin[2];
        return pi.Origin[0];
}

PlayerInfo p;
float origin[3];

float x;
float y;
float z;

x = PlayerInfo_GetOrigin(p, origin, y, z);
origin[0] = x;
origin[1] = y;
origin[2] = z;


nergal 11-04-2020 23:01

Re: SourceGo: Experimental Golang to SourcePawn Transpiler
 
Update v0.20a. Ranged for-loops are now supported.

Code:

var clients [MAXPLAYERS+1]Entity
for index, client := range clients {
    /// code;
}


nergal 11-05-2020 17:25

Re: SourceGo: Experimental Golang to SourcePawn Transpiler
 
another update, v0.22A, added two types of switch statements: normal and "true" switch statements.

Normal is of course what you'd expect:
Code:

/// Original:
switch x {
        case 1, 2:
        case 3:
        default:
}

/// Generated:
switch (x) {
        case 1, 2: {
        }
        case 3: {
        }
        default: {
        }
}

Golang has a feature where you can omit the controller expression, which basically makes it "true" in terms of value. Thus you have "true" switch statements which can act as a more compact form of an if-else-if series. This is also supported and appropriately generated!
Code:

/// Original:
switch {
        case x < 10, x+y < 10.0:
        case x * y <= 1024.0:
        default:
}

/// Generated:
if ((x < 10) || (x + y < 10.0)) {
}
else if ((x * y <= 1024.0)) {
}
else {
}


nergal 11-07-2020 18:16

Re: SourceGo: Experimental Golang to SourcePawn Transpiler
 
alright, with version v0.25a.
Here's a sample of a plugin that modifies the mantreads damage written in "SourceGolang" and the code it generated:

Code:

package main

import (
        "sdkhooks"
)

func main() {
        for i := 1; i<=MaxClients; i++ {
                if IsClientInGame(i) {
                        OnClientPutInServer(i)
                }
        }
}


func OnClientPutInServer(client Entity) {
        SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage)
}

func OnTakeDamage(victim Entity, attacker, inflictor, damagetype, weapon *Entity, damage *float, damageForce, damagePos *Vec3) Action {
        if IsValidEntity(*weapon) && GetEntProp(*weapon, Prop_Send, "m_iItemDefinitionIndex")==444 {
                *damage *= 5.0
                return Plugin_Changed
        }
        return Plugin_Continue
}

Code:

/**
 * file generated by the GoToSourcePawn Transpiler v0.25a
 * Copyright 2020 (C) Kevin Yonan aka Nergal, Assyrianic.
 * GoToSourcePawn Project is licensed under MIT.
 * link: 'https://github.com/assyrianic/Go2SourcePawn'
 */

#include <sourcemod>
#include <sdkhooks>


public void OnPluginStart() {
        for (int i = 1; i <= MaxClients; i++) {
                if (IsClientInGame(i)) {
                        OnClientPutInServer(i);
                }

        }

}

public void OnClientPutInServer(int client) {
        SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);
}

public Action OnTakeDamage(int victim, int& attacker, int& inflictor, int& damagetype, int& weapon, float& damage, float damageForce[3], float damagePos[3]) {
        if (IsValidEntity(weapon) && GetEntProp(weapon, Prop_Send, "m_iItemDefinitionIndex") == 444) {
                damage *= 5.0;
                return Plugin_Changed;
        }
        return Plugin_Continue;
}


nergal 11-16-2020 22:51

Re: SourceGo: Experimental Golang to SourcePawn Transpiler
 
After exactly a week of time gone, I have finally managed to abstract function pointers to where they appropriately break down to manual function calling API:


Code:

func main() {
        CB := OnClientPutInServer
        for i := 1; i<=MaxClients; i++ {
                CB(i)
        }
}

func OnClientPutInServer(client Entity) {}

Becomes:
Code:

public void OnPluginStart() {
        Function CB = OnClientPutInServer;
        for (int i = 1; i <= MaxClients; i++) {
                Call_StartFunction(null, CB);
                Call_PushCell(i);
                Call_Finish();
        }
}

public void OnClientPutInServer(int client) {}


nergal 02-11-2021 17:50

Re: SourceGo: Golang to SourcePawn Transpiler (v1.4 beta)
 
good news, SourceGo aka Go2SourcePawn, is now in open beta at version 1.4

It now has a complete SourceMod interface file for being able to use SM's natives in a Golang-way.
SourceGo also has a built-in function `__sp__` for inlining SourcePawn code that can't be replicated from SourceGo:
PHP Code:

var kv KeyValues
__sp__
(`kv = new KeyValues("config.cfg");`) 

becomes:
PHP Code:

KeyValues kv;
kv = new KeyValues("config.cfg"); 

Newest feature for 1.4 is using `make` to create dynamically sized, local arrays.
PHP Code:

my_str := make([]charsize

which would become:
PHP Code:

char[] my_str = new char[size]; 


wopox3 07-18-2021 15:43

Re: SourceGo: Golang to SourcePawn Transpiler (v1.4 beta)
 
This looks very interesting! Is it possible to write transpiler SourcePawn -> GoLang? Is it planned?


All times are GMT -4. The time now is 07:59.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.