Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for good server-side language that will allow players to upload code that can be executed

I had an idea of a program I want to write, but which language would be best is my problem.

If I have a car racing game and I want to allow users to submit code for new interactive 3D race tracks (think of tracks such as found in the Speed Racer movie), vehicles and for their autonomous vehicles, so, they would create the AI for their car that will enable the car to determine how to handle hazards.

So, I need a language that will run fast, and as part of a world map that the server has of all the possible races available, and their various states.

I am curious if this would be a good reason to look at creating a DSL in Scala, for example?

I don't want to have to restart an application to load new dlls or jar files so many compiled languages would be a problem.

I am open to Linux or Windows, and for the languages, most scripting languages, F#, Scala, Erlang or most OOP I can program in.

The user will be able to monitor how their vehicle is doing, and if they have more than one AI uploaded for that car, when it gets to certain obstacles they should be able to swap one AI program for another on demand.

Update: So far the solutions are javascript, using V8, and Lua.

I am curious if this may be a good use for a DSL, actually 3 separate ones. 1 for creating a racetrack, another for controlling a racecar and the third for creating new cars.

If so, would Haskell, F# or Scala be good choices for this?

Update: Would it make sense to have different parts end up in different languages? For example, if Erlang was used for the controlling of the car and Lua for the car itself, and also for the animated racetrack?

like image 796
James Black Avatar asked Oct 18 '09 01:10

James Black


People also ask

Which server-side language is fastest?

Efficient: NodeJS works faster than most other server-side coding languages. In essence, even a complicated program will execute fast on a NodeJS powered backend. This fast response makes NodeJS a reliable choice for web app development.

Is Python a good server-side language?

It has a basic syntax that is easy to work with and enhance. Python is a fantastic language for developing server and desktop applications, but it isn't ideal for mobile computing. As a result, Python is used in just a tiny number of smartphone applications.

Is Java server-side good?

Server-side programming languages Server-side developers can use many programming languages, including: Java: Java is an object-oriented programming language that developers can use for a variety of purposes, including software and application development.

What is server-side programming languages?

A language used to develop programs that are executed by the server. PHP and Java servlets are examples of server-side programming languages. See server-side script, PHP and servlet.


2 Answers

Your situation sounds like a good candidate for Lua.

  • You need sandboxing: This is easy to do in Lua. You simply initialize the users' environment by overwriting or deleting the os.execute command, for instance, and there is no way for the user to access that function anymore.
  • You want fast: Check out some of the Lua benchmarks against other languages.
  • Assumably you need to interoperate with another language. Lua is very easy (IMO) to embed in C or C++, at least. I haven't used LuaInterface, but that's the C# binding.
  • Lua has first-order functions, so it should be easy to swap functions on-the-fly.
  • Lua supports OOP to some extent with metatables.
  • Lua's primary data structure is the table (associative array) which is well-suited to sparse data structures like integrating with a world map.
  • Lua has a very regular syntax. There are no funny tricks with semicolons or indentation, so that's one less thing for your users to learn when they are picking up your language -- not to mention, using a well-documented language takes away some of the work you have to do in terms of documenting it yourself.

Also, as @elviejo points out in a comment, Lua is already used as a scripting language in many games. If nothing else, there's certainly some precedent for using Lua in the way you've described. And, as @gmonc mentions, there is a chance that your users have already used Lua in another game.


As far as how to integrate with Lua: generally, your users should simply need to upload a Lua script file. To grossly oversimplify, you might provide the users with available functions such as TurnLeft, TurnRight, Go, and Stop. Then, the users would upload a script like
Actions = {} -- empty table, but you might want to provide default functions 
function Actions.Cone()
    TurnLeft()
end

function Actions.Wall()
    Stop()
    TurnRight()
    TurnRight()
    Go()
end

Then server-side, you would might start them off with a Go(). Then, when their car reaches a cone, you call their Actions.Cone() function; a wall leads to the Actions.Wall() function, etc. At this point, you've (hopefully) already sandboxed the Lua environment, so you can simply execute their script without even much regard for error checking -- if their script results in an error, no reason you can't pass the error on directly to the user. And if there aren't any errors, the lua_State in your server's code should contain the final state of their car.


Better example

Here's a standalone C file that takes a Lua script from stdin and runs it like I explained above. The game is that you'll encounter Ground, a Fence, or a Branch, and you have to respectively Run, Jump, or Duck to pass. You input a Lua script via stdin to decide how to react. The source is a little long, but hopefully it's easy to understand (besides the Lua API which takes a while to get used to). This is my original creation over the past 30 minutes, hope it helps:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

#define FAIL 0
#define SUCCESS 1

/* Possible states for the player */
enum STATE {
    RUNNING,
    JUMPING,
    DUCKING
};

/* Possible obstacles */
enum OBSTACLE {
    GROUND,
    FENCE,
    BRANCH
};

/* Using global vars here for brevity */
enum STATE playerstate = RUNNING;
enum OBSTACLE currentobstacle = GROUND;

/* Functions to be bound to Lua */
int Duck(lua_State *L)
{
    playerstate = DUCKING;
    return 0; /* no return values to Lua */
}

int Run(lua_State *L)
{
    playerstate = RUNNING;
    return 0;
}

int Jump(lua_State *L)
{
    playerstate = JUMPING;
    return 0;
}

/* Check if player can pass obstacle, offer feedback */
int CanPassObstacle()
{
    if ( (playerstate == RUNNING && currentobstacle == GROUND) )
    {
        printf("Successful run!\n");
        return SUCCESS;
    }
    if (playerstate == JUMPING && currentobstacle == FENCE)
    {
        printf("Successful jump!\n");
        return SUCCESS;
    }
    if (playerstate == DUCKING && currentobstacle == BRANCH)
    {
        printf("Successful duck!\n");
        return SUCCESS;
    }
    printf("Wrong move!\n");
    return FAIL;
}

/* Pick a random obstacle */
enum OBSTACLE GetNewObstacle()
{
    int i = rand() % 3;
    if (i == 0) { return GROUND; }
    if (i == 1) { return FENCE; }
    else { return BRANCH; }
}

/* Execute appropriate function defined in Lua for the next obstacle */
int HandleObstacle(lua_State *L)
{
    /* Get the table named Actions */
    lua_getglobal(L, "Actions");
    if (!lua_istable(L, -1)) {return FAIL;}
    currentobstacle = GetNewObstacle();

    /* Decide which user function to call */
    if (currentobstacle == GROUND)
    {
        lua_getfield(L, -1, "Ground");
    }
    else if (currentobstacle == FENCE)
    {
        lua_getfield(L, -1, "Fence");
    }
    else if (currentobstacle == BRANCH)
    {
        lua_getfield(L, -1, "Branch");
    }

    if (lua_isfunction(L, -1))
    {
        lua_call(L, 0, 0); /* 0 args, 0 results */
        return CanPassObstacle();
    }
    return FAIL;
}

int main()
{
    int i, res;
    srand(time(NULL));
    lua_State *L = lua_open();

    /* Bind the C functions to Lua functions */
    lua_pushcfunction(L, &Duck);
    lua_setglobal(L, "Duck");

    lua_pushcfunction(L, &Run);
    lua_setglobal(L, "Run");

    lua_pushcfunction(L, &Jump);
    lua_setglobal(L, "Jump");

    /* execute script from stdin */
    res = luaL_dofile(L, NULL); 
    if (res)
    {
        printf("Lua script error: %s\n", lua_tostring(L, -1));
        return 1;
    }

    for (i = 0 ; i < 5 ; i++)
    {
        if (HandleObstacle(L) == FAIL)
        {
            printf("You failed!\n");
            return 0;
        }
    }

    printf("You passed!\n");

    return 0;
}

Build the above on GCC with gcc runner.c -o runner -llua5.1 -I/usr/include/lua5.1.

And pretty much the only Lua script that will pass successfully every time is:

Actions = {}

function Actions.Ground() Run() end
function Actions.Fence() Jump() end
function Actions.Branch() Duck() end

which could also be written as

Actions = {}
Actions.Ground = Run
Actions.Fence = Jump
Actions.Branch = Duck

With the good script, you'll see output like:

Successful duck!
Successful run!
Successful jump!
Successful jump!
Successful duck!
You passed!

If the user tries something malicious, the program will simply provide an error:

$ echo "Actions = {} function Actions.Ground() os.execute('rm -rf /') end" | ./runner 
PANIC: unprotected error in call to Lua API (stdin:1: attempt to index global 'os' (a nil value))

With an incorrect move script, the user will see that he performed the wrong move:

$ echo "Actions = {} Actions.Ground = Jump; Actions.Fence = Duck; Actions.Branch = Run" | ./runner 
Wrong move!
You failed!
like image 116
Mark Rushakoff Avatar answered Jan 01 '23 22:01

Mark Rushakoff


Why not JavaScript or EcmaScript? Google's V8 is a really nice sandboxed way to do this. I remember it being really really easy. Of course, you will have to write some bindings for it.

like image 42
Daniel A. White Avatar answered Jan 01 '23 22:01

Daniel A. White