C++ Module

I’m trying to make a C++ Module which should run a console command, but I’m kinda stuck where to start. Anybody there could help ?

Push -> global table
Push -> RunConCommand func
PushString -> command
Call stack
pop

[editline]asd[/editline]

I realize that may not have been enough info for a beginner. Try something like this

[cpp]
using namespace GarrysMod;

LUA->PushSpecial( Lua::SPECIAL_GLOB ); //push global table
LUA->GetField(-1, “RunConCommand”); //push reference to RunConCommand func
LUA->PushString(“disconnect”); //push function argument as string datatype
LUA->Call(1, 0); //call with 1 argument, expecting 0 return value
LUA->Pop();
[/cpp]

You could start here, here, here, or here. But first, you need to know c++, which you could also look here. Lets say you want to make a command that will print your text. Here is an example:


#define GMMODULE 
#include "Interface.h"
#include <stdio.h> //////
#include <iostream>/////////
#include <cstring>///////////// Extra files/functions
#include <string>///////////
#include <sstream>//////

using namespace std; // A namespace shortcut
using namespace GarrysMod::Lua; // Same with this

int printtext(lua_State* state)
{
	int iTop = LUA->Top(); // Get the number of arguments
	if (!LUA->IsType(1, Type::STRING)){ // If the type is not a string, return 0
		return 0;
	}
	if (iTop < 2){ // If there is only 1 argument, keep going, else, return 0
		stringstream txt; // Declare a stringstream
		const char* ttxt = LUA->GetString(1); // Get the first argument
		txt << "Your string is: " << ttxt << "
";
		LUA->PushSpecial(SPECIAL_GLOB); // Push the special table
			LUA->GetField(-1, "print"); // Grab the print function
				LUA->PushString(txt.str().c_str()); // Push it with str() and c_str()
			LUA->PCall(1, 0, 0); // Call it
		LUA->Pop(); // Pop the table off the stack
		return 1; // Return 1
	}
	else{
		return 0;
	}
}
GMOD_MODULE_OPEN(){ // When the Module Opens
	LUA->PushSpecial(GarrysMod::Lua::SPECIAL_GLOB); // Push Table
		LUA->PushCFunction(printtext); LUA->SetField(-2, "rprint"); // Push the function printtext and call it 'rprint'
	LUA->Pop(); // Pop the table off the stack
	
	return 0; 
}

GMOD_MODULE_CLOSE() // When it closes
{
	return 0;
}

So we need to call the dll which mine is called ‘bird’, So this would be my code to call it:



require("bird")

rprint(":D")

And, it works!

I’ll probably update this post overtime, Hope I helped!

EDIT:

Another example using the boost random library to generate 2 numbers of your choice:



#define GMMODULE 
#include "Interface.h"
#include <stdio.h> /////////////////////////////////////
#include <iostream>///////////////////////////////////////
#include <cstring>////////////////////////////////////////// 
#include <string>///////////////////////////////////////////// Extra files/functions
#include <sstream>////////////////////////////////////////
#include <boost/random/mersenne_twister.hpp>//////////
#include "boost\random.hpp"//////////////////////
using namespace std; // A namespace shortcut
using namespace GarrysMod::Lua; // Same with this

int printtext(lua_State* state)
{
	int iTop = LUA->Top();
	if (!LUA->IsType(1, Type::NUMBER)) // Make sure 1st argument is a number
	{
		return 0;
	}
	if (!LUA->IsType(2, Type::NUMBER)){ // Make sure 2st argument is a number
		return 0;
	}

	if (iTop < 3 && iTop > 1){ // If there is 2 arguments, continue
		double num1 = LUA->GetNumber(1); // Get arg1
		double num2 = LUA->GetNumber(2); // Get arg2
		if (num1 == num2){  // If they are the same, don't continue
			return 0;
		}
		boost::random::mt19937 gen; // Create number (2 to the 32nd power times negative 1)
		boost::random::uniform_int_distribution<> dist(num1, num2); // Distribution selector
		stringstream txt; // Declare a stringstream
		uint64_t ttxt = dist(gen); // Make it an unsigned integer
		txt << "Your random number between " << num1 << " and " << num2 << " is: " << ttxt << "
"; // Ex. Your random number between 4 and 10 is 8 /NEWLINE
		LUA->PushSpecial(SPECIAL_GLOB); // Push the special table
		LUA->GetField(-1, "print"); // Grab the print function
		LUA->PushString(txt.str().c_str()); // Push it with str() and c_str()
		LUA->PCall(1, 0, 0); // Call it
		LUA->Pop(); // Pop the table off the stack
		return 1; // Return 1
	}
	else{
		return 0; // Thing
	}
	return 0; // Fail-safe
}
GMOD_MODULE_OPEN(){ // When the Module Opens
	LUA->PushSpecial(GarrysMod::Lua::SPECIAL_GLOB); // Push Table
	LUA->PushCFunction(printtext); LUA->SetField(-2, "rand"); // Push the function printtext and call it 'rand'
	LUA->Pop(); // Pop the table off the stack
	return 0; // its k
}

GMOD_MODULE_CLOSE() // When it closes
{
	return 0; // its k
}


Lua File:



require("bird");
rand(1,90);


Here is the result:

While we’re on the topic:-

Is it possible to send binary modules to the client in the same way as you can with AddCSLuaFile?

I want to draw out to render targets from C++ code for part of my gamemode.

no

That’s a real shame. Not even via a client-installed add-on?

They must be in “garrysmod/lua/bin” (or the MOD game path through other hackery). You can’t make clients automatically download them for security reasons.

That would be huge security risk. Although if your really want clients to run C++ module, you can show warning which would ask clients to install the module manually.

It would be - that’s why I thought it might not work. Thanks for the suggestion.

I’ll probably release that part separately then and people can compile it themselves if they wish / want to audit my code for hax.