Remote Exec - An alternative to Streams
Remote Exec
- What is it?
It is a collection of plugin + server-script + client-script. - How to use it?
Put remoteexec04rel32/64 under 'plugins' directory, RemoteExec.nut, SendReply.nut, main.nut inside 'store/script' directory. - What are the function names used in client-side script?
There is only one function ProcessData( Stream, array ) in RemoteExec.nut and two functions SendReply(token, result) and WriteDataToStream(data, Stream) in SendReply.nut
- Did you reserve any global variable names?(client-side)
No,just the function names seen above.
Function Documentation
1. SetRemoteValue( key, value )
In server, if you do SetRemoteValue( "a", 10 ). It is equivalent to a<-10 ( rawset ) on client side. Here 'Remote' means Client.
2. GetRemoteValue( "a" )
If you have a global variable named 'a' in client-scripts, this function fetches its value.
3. GetRemoteValueEx( obj, key )
If you have an object obj (table, class, instance) on client side and has a field key in obj, then this function fetches its value.//Suppose a<-Vector( 1, 2, 3 ) in client-side.
//To get a.Z
GetRemoteValueEx( GetRemoteValue( "a" ), "Z" )
4. SetRemoteValueEx( obj, key, value )
Performs a rawset on object obj with key and value. I have coded it so that you can perform this on Player, Vehicle, etc classes too.//Suppose a<-Vector( 1, 2, 3 ) client side
//To set a.Z = 0
SetRemoteValueEx( GetRemoteValue( "a" ), "Z", 0 )
5. CallRemoteFunc( func, arg1, arg2, ... )
Calls the func=GetRemoteValue("funcname") with arguments arg1, arg2 , etc.
//Suppose i want to call function foo("hello", 1, 100.0 )
CallRemoteFunc(GetRemoteValue("foo"),"hello", 1, 100.0)
6. CallRemoteFuncEx( func, env, arg1, arg2, ... )
Now you can specify the 'this' object with the function is called.//This is very complicated and hence i am not providing an example here
RemoteExec ( ... )
RemoteExec( SetRemoteValue("a",100), FindPlayer(0), true, print)
The above six functions are to be used inside 'RemoteExec'. RemoteExec( userdata, player, (should_return), (callback_func) )
The last two parameters are used for getting the result back to server. They are optional. The callback_func must be a one-parameter function like print. I have managed to include a token with every RemoteExec and client sends the result with this token. Thus that function will be called when the token arrivesinvolvesChecking for error in callback_funcThe global variable REMEXEC_ERROR will be set to 1 if client throwed error. This variable is to be used inside the callback as follows:
RemoteExec( GetRemoteValue( myvariable ), player, true, function(res)
{
if(!REMEXEC_ERROR)do_something(res);
});
Metamethods
The userdata returned by functions 2, 3,5-6, supports Get and Call metamethods on them.
long code:
CallRemoteFuncEx(GetRemoteValueEx(GetRemoteValue("Console"), "Print"), GetRemoteValue("Console"), "Hello World" )
short code:
local Console=GetRemoteValue("Console");
RemoteExec( Console.Print("Helloworld"), player);
The metamethods add, sub, mul, div, modulo and unary minus are likewise defined. See the immediately following post after this for details.
DownloadDownload plugin ( store files included ) 51.3 KB below (updated Sep 29):
(https://i.imgur.com/EA45WpM.png) (https://www.mediafire.com/file/a23uw15i6vl5uzc/remexec_v1.1.1_a.7z/file)
Installation - Client Side store/script/main.nut looks like: (
partial code, full files included in archive)
dofile("RemoteExec.nut");
dofile("SendReply.nut");
enum StreamType
{
RemoteExecute=0x40ffffe1 //Used for executing
RemoteExecuteSpecial=0x40ffffe2 //Used for execution and return result using token
Reply=0x40ffffe3 //Used when sending result to server
CompileString=0x40ffffe4
RPrint=0x40ffffe5
}
function Server::ServerData(stream) {
//Warning: We are reading Int and not byte !!!!
local i=stream.ReadInt();
if(stream.Error)
{
return;
}
if(i==StreamType.CompileString)
{
local script = compilestring(stream.ReadString());
try{
local result=script();
}catch(e)
{
}
}else if(i==StreamType.RemoteExecute)
{
try
{
local res=ProcessData(stream);
}catch(e)
{
SendReply(-1, e, true);
}
}else if(i==StreamType.RemoteExecuteSpecial)
{
local token=stream.ReadInt();
try
{
local res=ProcessData(stream);
SendReply(token, res);
}catch(e)
{
SendReply(token, e, true);
}
}
}
Source-code of plugin (cpp): mediafire-link (https://www.mediafire.com/file/umwuejwf3b8fd4y/remexec-source-v1.1.1-a.7z/file) (updated Sep 29) or github (https://github.com/habi498/Remote-Exec)
The function is able to return values like integer, float, string, null, boolean and arrays. However, classes and tables cannot be returned. In such cases the return value will be typeof(result).
If error occurs while executing them on client side, the error is catched and returned as string, which will be printed on server console "remexec (remote): Error message" and if return callback was specifed, the error message string will be the parameter.
Stream InformationThe first bytes of the Streams (ServerData/ClientScriptData) uses the following:
Value | Type |
0x40ffffe1 - 0x40ffffe5 | Integer |
Default CallbackWhen parameter three is set to true, but no callback is given as fourth parameter, then plugin searches for following function in roottable and call it if scripted.
function onRemoteExecReply(token,result)
{
//token - internal number used for identifying streams
//result - the value returned from client
}
Update:
Now, you can use
GetRemoteValue("a") + GetRemoteValue("b")
inside the RemoteExec function. (parameter one)
Let us see what this is:
GetRemoteValue("a") will fetch the value of global variable a from client roottable to server.
GetRemoteValue("b") will fetch the value of global variable b.
GetRemoteValue("a")+GetRemoteValue("b") will perform an addition on client environment whatever may be variables a and b.
Similary the operations +, -, *, / are valid. Unary minus (-) operator also works.
Rules:
1. The userdata (that returned by GetRemoteValue, CallRemoteFunc, etc) must be the left operand and the integer, float, etc must be on right. This is because of the property of metamethods _add, _sub, _mul, _div, _modulo. So
3 + GetRemoteValue("b") // is not valid
GetRemoteValue("b") + 3 // is valid
2. Concatenation cannot be performed.
GetRemoteValue("A") + " is the value of variable A" //leads to error
CallRemoteFunc( GetRemoteValue("format"), "%d is the value of a", GetRemoteValue("a") ) //is valid
Complete Example
RemoteExec(CallRemoteFunc(GetRemoteValueEx(GetRemoteValue("GUI"),"GetScreenSize")),FindPlayer(0),true,
function(val){::print("The remote screenSize is "+val)});
output:
[SCRIPT] The remote screenSize is (640, 480, 0)
RemoteExec(GetRemoteValueEx(CallRemoteFunc(GetRemoteValueEx(GetRemoteValue("GUI"),"GetScreenSize")),"Y")*0.96,FindPlayer(0),true,
function(val){::print("screenSize.Y * 0.96 is "+val)});
output:
[SCRIPT] screenSize.Y * 0.96 is 460.8
Note: I don't know, but it happens once in a while passing wrong values and server crashes.
update:
fixed crash occuring when trying to send clientscript data that is too long.
fixed another crash when reading data clientscript data.
i have added proper if statement to check size and index before reading them, like this:
case 's':
if (size < index + 3)return 0;//for reading len
len = swap2(*(uint16_t*)(data + index + 1));
//Check if len is less than size. otherwise it crash server.
if (size < index + 3 + len ) { return 0; }
sq->pushstring(v, (char*)data + index + 3, len); k = 1 + 2 + len; break;
Habi well done, I've been waiting a long time, I can't wait, if there are any questions, I will feedback here.
Thank you
Update
#1: Found and fixed the bug. i have been 'memcpy' more than size and it was crashing server. it is now fixed
#2: Added _get and _call metamethods. See Example
local Console = GetRemoteValue("Console");
RemoteExec( Console.Print("Greetings from Liberty City"), player )
(https://i.imgur.com/oS2CzaE.jpg)
the second example is little messy:
local RayTrace = GetRemoteValue("RayTrace");
RemoteExec( RayTrace(Vector(-1073.56, 63.5817, 11.2329),Vector(-1081.5, 104.404, 11.263),15).Collided,player,true,print)
[SCRIPT] true
When you do GetRemoteValue("getroottable")(), the _call metamethod is evoked and when you get like Console.Print, there _get metamethod will be evoked.
Big-ExampleThis is client side script i took from:
Quote from: Kelvin Garcia Mendoza on Nov 05, 2020, 06:09 PM_label <- null;
function Script::ScriptLoad()
{
local
screenSize = ::GUI.GetScreenSize(),
label = ::GUILabel( ::VectorScreen( ( screenSize.X * 0.005 ), ( screenSize.Y * 0.96 ) ), ::Colour( 255, 255, 255 ), format( "Hey, %s. Welcome to the server!", ::World.FindLocalPlayer().Name ) );
label.FontName = "Verdana";
label.FontSize = ( screenSize.X * 0.2 );
label.FontFlags = GUI_FFLAG_BOLD;
label.TextAlignment = GUI_ALIGN_LEFT;
::_label = label;
}
and when changed
function onPlayerJoin(player)
{
local table= GetRemoteValue("getroottable")();
local screenSize = table.GUI.GetScreenSize();
local label = table.GUILabel( table.VectorScreen( ( screenSize.X * 0.005 ), ( screenSize.Y * 0.96 ) ), table.Colour( 255, 255, 255 ), table.format( "Hey, %s. Welcome to the server!", table.World.FindLocalPlayer().Name ) );
RemoteExec(SetRemoteValue("mylabel",label),player);
local mylabel=GetRemoteValue("mylabel"); //no neeed of '()' as it is not function
RemoteExec(SetRemoteValueEx(mylabel,"FontName","Verdana"),player);
RemoteExec(SetRemoteValueEx(mylabel,"FontSize", 20),player);
local consttable=GetRemoteValue("getconsttable")();
RemoteExec(SetRemoteValueEx(mylabel,"FontFlags",consttable.GUI_FFLAG_BOLD),player);
RemoteExec(SetRemoteValueEx(mylabel,"TextAlignment",consttable.GUI_ALIGN_RIGHT),player);
}
when called this result:
(https://i.imgur.com/GyBwFnx.jpg)
How is it..?
PS (for newbies, if anybody): You have to load remexec04rel32. Otherwise you get 'Error: the index 'GetRemoteValue' does not exist'
I got Error: spawn cmake ENOENT when I used vs code to convert dll. I'm very sorry, I was working before and didn't have time to test, I may need to try to convert plugin by myself again.
The error spawn cmake ENOENT is discussed here (https://github.com/microsoft/vscode-cmake-tools/issues/350#issuecomment-379042041).
btw, are you compiling the plugin from source?
This is an area I have never touched, but I slowly carved, understand, I saw the tutorial on the network installed mingw64 and gcc, I configured the environment variables according to the tutorial, in cmd test gcc -v is OK, then I do not know what to do, in vs code or display the previous error, I'm really not good at this. And I don't know what source code is.
If on windows, download ninja-win zip from https://github.com/ninja-build/ninja/releases.
Put it in c:\ninja\
Add c:\ninja to PATH environment variable
Close VScode and open again.
Do Ctrl+Shift+P and click CMake:Reset
(https://i.imgur.com/4qqVzgt.png)
Again open Command Palette (Ctrl+Shift+P) and run CMake:Select a Kit. Choose GCC xx mingw-32 xx
Now you can successfully build plugin. To build :
From Command Palette run CMake: Select Variant and choose Release.
Then run CMake: Configure
And finally CMake: Build
If successfully, on windows explorer out/binaries you can see the plugin built by vscode.
(https://i.imgur.com/CIqqlcQ.png)
Note: Ninja builds it on folder build originally. It is then copied to out/binaries
Great, thank you so much, with your help, I successfully generated the dll file.
Console display: [MODULE] Remote Exec __REMEXEC_VERSION__ by habi loaded.
I will use this plugin according to the information.
Sorry that was a later addition to source code which produced the strange result. It escaped my notice.
I will update the source and binaries.
Find this line (701) main. cpp
fputs("Remote Exec __REMEXEC_VERSION__ by
and replace __REMEXEC_VERSION__ by v1.1.1
fputs("Remote Exec v1.1.1 by
To make it work in linux at the same time, do the same to line ( 704 )
EDIT: Source and binaries updated. Added github (https://github.com/habi498/Remote-Exec) link too.
Why did I return userdata 0x00~~? Can you check it for me..
client: abc<-Vector(1,2,3);
server: GetRemoteValueEx(GetRemoteValue("abc"),"Z"); return userdata 0x00~~
plugin dll: https://file.io/z0TLnJrM1LO4
GetRemoteValue always return 'userdata'.
print(GetRemoteValue(..)) will show 'userdata 0x..'
1. To obtain value from client in one step is not possible because server has to wait until result arrives.
2. Our main function is 'RemoteExec'.
See:
client: abc<-Vector(1,2,3);
server:
QuoteRemoteExec( GetRemoteValueEx(GetRemoteValue("abc"),"Z"), FindPlayer(0), true, function(val){ print("The Z co-ordinate is "+val); } );
The parameter
true tell client to send back the result.
The
fourth parameter function will be called when the result arrives which take time.
you can replace 'one parameter function' with 'print' itself:
QuoteRemoteExec(GetRemoteValueEx(GetRemoteValue("abc"),"Z"), FindPlayer(0), true, print );
So 'print' will be called with the result:
[SCRIPT] 3
This replacement with 'print' will be useful for testing purposes.
The userdata returned is actually a C++ array whose length increases with number of GetRemoteValue used. If you use two GetRemoteValue, then the array contain almost double number of elements.
This pointer/array being used by plugin is not visible to squirrel.
Hello habi, I want to call another player's client function directly through the player's client and return the value, how can I achieve this?
The client has a get function that takes a string as its argument
I made a cross transfer function on the server, but it was very difficult, I sent exec text on the client side to execute this function
Hi PSL, it is a great idea to get values from another client.
I will check if there is any standard way of doing it and modify code.
Hi Habi. In addition to the client sends text to the server, and then the server compiles and executes the text, such a client-side call to the server is problematic. When the transmitted text needs variables, it is necessary to escape quotes, nesting quotes will cause problems, and the server will report an error that the variable does not exist.
In addition to sending executable text, there are other ways to call server-side functions directly, which has a similar effect.
Quote from: PSL on Nov 01, 2024, 03:55 AMHi Habi. In addition to the client sends text to the server, and then the server compiles and executes the text, such a client-side call to the server is problematic. When the transmitted text needs variables, it is necessary to escape quotes, nesting quotes will cause problems, and the server will report an error that the variable does not exist.
In addition to sending executable text, there are other ways to call server-side functions directly, which has a similar effect.
Hi PSL, i have not yet made function to call server side functions from client. But here is Remote-Exec v1.1.2 in which client can call other client's functions and get back the return value.
Remote Exec v1.1.2
- Fixed infinite loop in client side caused when passing array
RemoteExec(SetRemoteValue("a",[100,200]),FindPlayer(0),true,print) - Fixed arrays returned from client having null values for half the indexes and original array starts after null.
- RemoteExec now supports tables.
Example: RemoteExec(SetRemoteValue("a", {b=3, c=4, d="okay", e=2.3, f=true, n=null, m={f=1}}), FindPlayer(0)).
Supported data types are: null, bool, integer, float, string, Vector, EntityVector, Quaternion, array, and table.
These data types can be transported between server and client. Tables will exclude keys or values that are functions or classes. - Types such as Player, Vehicle, Building, RayTrace, Colour, GUIElement, GUIButton, GUICanvas, GUICheckbox, GUIEditbox, GUILabel, GUIListbox, GUIMemobox, GUIProgressBar, GUIScrollbar, GUISprite, GUIWindow can also be returned from a client.
When returned, they are in the form of a table consisting of key-value pairs. - Fixed GetRemoteValueEx returning "index not exist" when the object is an array.
- Changed the environment object when compiling a string to the root table instead of the class Server, because it was executed inside Server::ServerData.
- Added all functions: GetRemoteValue, GetRemoteValueEx, SetRemoteValue,SetRemoteValueEx,CallRemoteFunc,CallRemoteFuncEx client-side for helping one client call functions of other. The resultant objects are passed to the function 'PeerExec' which sends it to the target-client.
- Fixed "Error getting squirrel object" when Boolean is returned.
- Fixed setting variables when boolean to true/false instead of 0/1.
How to call client side function from another client?
There is this new function called PeerExec
Quote from: PSL on Oct 30, 2024, 09:18 AMHello habi, I want to call another player's client function directly through the player's client and return the value, how can I achieve this?
Suppose you have a function 'test' in clientside:
function test(a,b)
{
}
You are player with id 1 and want to call 'test' in player with id 0 and return value:
PeerExec( GetRemoteValue("test")(15,20), 0, function(result){
print( result );
} );
//15=a, 20=b. 0=player with id 0.
//execution continues but the function is stored and invoked when the result from client 0 arrives.
DocumentationPeerExec( [superblob], target-player-id, func )
[superblob] : One returned by functions like GetRemoteValue, SetRemoteValue, etc.
target-player-id : The ID of the player in which you want to execute the logic.
func : An optional function. If provided will be called with the result of logic you executed in the target-player's script.
For full documentation, see files inside.
Examples client-side- PeerExec( GetRemoteValue("Console").Print("Hello World"), 0 )
Prints 'Hello World' in blue colour in client-0 PeerExec(GetRemoteValue("RayTrace")(Vector(-337.56, -525.145, 12.7615), Vector(-349.419, -537.796, 12.8069),15), 0, function(res){
if(res.Collided){ //This is valid because the result is transported as a table with key-value pairs.
print("Collided");
print(format(\"Position of Collision:(%f,%f,%f) \", res.Position.X,res.Position.Y, res.Position.Z));
if(res.Entity.Type==2)print("Collision with - building");
}
}
Result: debuglog.txt
MSG: Collided
MSG: Position of Collision:(-343.119232,-531.075500,12.782783)
MSG: Collision with - building
DebuggingAny errors are logged in debuglog.txt in %appdata%/VCMP/04beta folder
Downloads (mediafire)
(https://i.imgur.com/ziz8dUO.png) (https://www.mediafire.com/file/8ruvpg5hsyw20pg/remexec-v1.1.2.7z/file)
You can get the source (https://www.mediafire.com/file/e0i70rx1ex9qwcv/remexec-v1.1.2-source.7z/file) of this plugin also.
You can read the usage here (http://18.132.205.100/remexec/Usage.html) online and Bytecode Documentation here (http://18.132.205.100/remexec/streamdoc.html) also.
Hi Habi, What a surprise! I did not expect that the suggestions I made were adopted and successfully implemented into such a powerful function. Sincerely thank you heart and professionalism, this plug-in is now invincible! Hats off to you, great plugin creator!
Thank you for listening carefully to my suggestions and taking the trouble to turn them into such practical features, praise for your dedication!
I can't wait to play with this plugin, I will report the results here.
Hi PSL,
I'm glad that you liked it. You are very much welcome.
Hi Habi, I want to implement it on the client side: UI.Sprite("test").hide();
In Server Side:RemoteExec(CallRemoteFunc(GetRemoteValueEx(GetRemoteValueEx(GetRemoteValue("UI"),"Sprite"),"test"),"hide"),player);
error:remexec (remote): the index 'rawget' does not exist
How do I achieve this?
RemoteExec(CallRemoteFunc(GetRemoteValueEx(CallRemoteFunc(GetRemoteValueEx(GetRemoteValue("UI"),"Sprite"),"test"),"hide")),player);
error:remexec (remote): the index 'fetch' does not exist
This is very close to the answer, I can not find why the failure.
UI.Sprite("test").hide();
local func= GetRemoteValueEx(GetRemoteValue("UI"),"Sprite")
CallRemoteFuncEx(func, GetRemoteValue("UI"), "test")
Quote from: PSL on Nov 20, 2024, 09:54 AMRemoteExec(CallRemoteFunc(GetRemoteValueEx(CallRemoteFunc(GetRemoteValueEx(GetRemoteValue("UI"),"Sprite"),"test"),"hide")),player);
error:remexec (remote): the index 'fetch' does not exist
This is very close to the answer, I can not find why the failure.
Hi PSL, this is close to answer. It can be fixed by using CallRemoteFuncEx. Then you can pass
UI as environment object (this) of the function UI.Sprite. Otherwise you are calling UI.Sprite with roottable as environment object. Many variables coded inside function UI.Sprite will be tried to fetched from roottable instead of class UI.
So the complete correct answer may be:
local func= GetRemoteValueEx(GetRemoteValue("UI"),"Sprite");
local obj= CallRemoteFuncEx(func, GetRemoteValue("UI"), "test"); //environment object=GetRemoteValue("UI")
CallRemoteFuncEx(GetRemoteValueEx(obj, "hide"), obj); //again careful about environment object this = obj =UI.Sprite("test")
I hope this will do the work. Seeing that codes will get bigger there is metamethods available on GetRemoteValue. The interesting alternative:
GetRemoteValue("UI").Sprite("test").hide();
Above code will automatically expand itself.
Please tell me if these worked.
Hi Habi,This approach is feasible: GetRemoteValue("UI").Sprite("test").hide();
However, this method is not feasible
local func= GetRemoteValueEx(GetRemoteValue("UI"),"Sprite");
local obj= CallRemoteFuncEx(func, GetRemoteValue("UI"), "test"); //environment object=GetRemoteValue("UI")
CallRemoteFuncEx(GetRemoteValueEx(obj, "hide"), obj); //again careful about environment object this = obj =UI.Sprite("test"
still prompt remexec (remote): the index 'rawget' does not exist
But thank you for helping me out!
Hi Habi,I found that when the length of the array is more than 310, the length of the array is 315, and it cannot be returned from the client to the server
Hi PSL, thank you for interest in the plugin. Streams in vc-mp server has a limitation (https://forum.vc-mp.org/index.php?topic=9283.0) that stream length is limited by 4095 bytes even though more bytes correctly arrive at server.
I will see what can be done. May be splitting the packet and joining serverside.
Hi PSL, the problem with arrays of length more than 310 is resolved:
RemoteExec v1.1.3- Streams of any length can be send. The plugin splits it into different chunks and send to client.
- Now Server can send and receive arrays of large lengths (1000 or even 10,000) by internally splitting and rejoining streams.
- Optimized stream length by using short integer types (2 bytes) wherever possible
Downloads(https://i.imgur.com/nA8AEXI.png) (https://www.mediafire.com/file/zktriyey03phalj/remexec-v1.1.3.7z/file)
You can get the updated source (https://www.mediafire.com/file/lsdgm0v0ovhgk9u/remexec-v1.1.3-source.7z/file) here.
sorry but i dont understand this plugin allows you to use client side scripts with normal server scripts ?
Thanks for asking. This plugin allows one from server-script to
1. Call client-side functions in client-side scripts
Explanation: Usually on serverside:
local buffer=Stream();
buffer.StartWrite();
buffer.WriteInt(100);
buffer.WriteString("Hello");
buffer.SendStream(player); //Send stream to a valid player
and on client-side:
function Server::ServerData(stream)
{
local i=stream.ReadInt();
switch(i)
{
case 100: local str=stream.ReadString();
::foo(str);
case 101 : //Another function or code
...
}
function foo(msg)
{
Console.Print(msg); //just for example
}
Now using plugin, one can possibly reduce these codes to
local str="Hello";
local buffer=GetRemoteValue("foo")(str); //buffer will be created as userdata. nothing send yet!
RemoteExec(buffer, player); //Call foo(str) client-side if possible. plugin will internally create the stream and send to client.
//The client-side script which comes with the plugin reads the stream and will execute the 'action': in this case is call the 'foo' function with str='Hello'.
I hope everybody understand.
Oh okey thanks
RemoteExec v1.1.4- Blob instances can be send and received
- Fixed "Invalid ChunkID" on 64-bit windows server (and possibily corresponding Linux server) when using split-streams.
- Limited amount of chunks send to not more than 5 per ServerFrame
Downloads(https://i.imgur.com/0ZKDCWl.png) (https://www.mediafire.com/file/dc0gme1omvxf0u5/remexec-v1.1.4.7z/file)
You can get the updated source (https://www.mediafire.com/file/5cg5vo90u6f80k4/remexec-v1.1.4-source.7z/file) here.
VirusTotal scan report of binaries- 1/63 link (https://www.virustotal.com/gui/file/267484208baa635ee6833204c85cbfc00c0fd4ec42c6a8b180ef415803188d65)
Example Usage//Written from memory of recent testing
local f=file("image.bmp", "rb");
local c=f.readblob(f.len()); // c is a blob
f.close();
RemoteExec(GetRemoteValue("DrawBitMap")(c), FindPlayer(0)); //calling DrawBitMap( c ) - a client side function in player with ID 0 's space
For information about DrawBitMap, see this (https://forum.vc-mp.org/index.php?topic=9572) topic.
Hi Habi.
This plugin works well, I've been using it, I'm having some problems right now.
shop <- null;
class Shop {
a = null;
b = null;
constructor(a,b){
}
}
The client has a slot A and a Shop class
I want to implement a = Shop(a,b); But it failed.
My code:
local userData = ::SetRemoteValue( ::GetRemoteValue("shop"), ::CallRemoteFunc( ::GetRemoteValue("Shop"), name, cargo ) );
::RemoteExec(userData, player);
Hi PSL,
I am glad to know that plugin is working fine.
Your code change to this and try:
local userData = ::SetRemoteValue( "shop", ::CallRemoteFunc( ::GetRemoteValue("Shop"), name, cargo ) );
::RemoteExec(userData, player);
Thank you. The code you provided worked
Remote Exec v1.1.6 ReleasedWe are pleased to announce the release of
Remote Exec v1.1.6 for VC:MP servers. This version includes improvements and fixes along with the necessary client-side script files for proper functionality.
Changelog:v1.1.6 (includes v1.1.5 changes, which was not released) - Fixed client errors when an empty table is passed.
- If the player instance parameter is null in RemoteExec:
RemoteExec(SetRemoteValue("a", 1000), null)
It will execute on all connected clients in one go. - Clients can now send valid Squirrel data types (string, integer, float, blob, etc.) to the server with an identifier.
PassDataToServer(identifier, data)
to send data. The server-side callback
onClientData(player, identifier, data) (identifier can be numbered 1,2,3,...)
will be executed. - New function RemoteOpen to 'dofile' a nut file in client-side. This has limitations..
RemoteOpen("path/to/nut", player)
transfers a NUT script file as a string and compiles it on the client. However, this does not affect class functions like GUI::KeyPressed, which still only call the old callback. - Clients can now execute server functions using new client-side function 'Exec'. eg.
Exec(GetRemoteValue("print")("Have a nice day"))
will print text on server console
Download: (https://i.imgur.com/6y7KxvB.png) (https://www.mediafire.com/file/748y8ht43hja64p/remexec-v1.1.6.7z/file) (410.75 KB) (mediafire)
Virus-total scan of 7zip: (1/63) (https://www.virustotal.com/gui/file/019155506187e845915a1f7195e80fb4344a18a41697134eb2db10ef21df2aff)
Source-code: here (https://www.mediafire.com/file/ez6h4dsusk0tgac/remexec-v1.1.6-source.7z/file) (153.23 KB, mediafire)
For installation and usage details, refer to the provided documentation.
Thank you for your interest in remote-exec.
I can't wait to use it. Well done, Habi bro!
thank you PSL
Hello, Hibi.
An error occurred with GetRemoteValue("print")("abc") on the client, typeof( GetRemoteValue("print")("abc") ) This returns type null.
When I use Exec(GetRemoteValue("print")("Have a nice day")) the client throws an error PeerExec: superblob expected but got null
local userData = CallRemoteFunc( GetRemoteValue("print"),"123");
Exec( userData ); //This is effective
Hi PSL,
There was a problem with _call metamethod of superblob, that it will fail if the 'this' parameter is not table(eg.roottable). I have fixed the problem, now GetRemoteValue("")() can be used anywhere( table, class or instance) :
Player::PlayerDeath, Player::PlayerShoot, all events of Player ( this = Player, a class )
Like Player, it is available across places where 'this' is class like GUI, KeyBind, Script or Server.
This is updated in the following file:
Download PeerExec.nut (https://www.mediafire.com/file/ncwul8wjpmq7meb/PeerExec.nut/file)
I hope this will solve the problem
After my testing, this problem has been solved
thank you for testing.