Remote Exec - An alternative to Streams

Started by habi, Jul 18, 2023, 02:48 PM

Previous topic - Next topic

habi2

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.

PSL

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.


habi2

#17
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.

Documentation
PeerExec( [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

Debugging
Any errors are logged in debuglog.txt in %appdata%/VCMP/04beta folder

Downloads (mediafire)
           
You can get the source of this plugin also.

You can read the usage here online and Bytecode Documentation here also.

PSL

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.

habi2

Hi PSL,
I'm glad that you liked it. You are very much welcome.

PSL

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?

PSL

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.

habi2

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.

PSL

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!

PSL

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

habi2

Hi PSL, thank you for interest in the plugin. Streams in vc-mp server has a limitation 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.

habi2

#26
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



You can get the updated source here.

[TDA]Speed

sorry but i dont understand this plugin allows you to use client side scripts with normal server scripts ?

habi2

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.