当前位置:  开发笔记 > 编程语言 > 正文

寻找良好的服务器端语言,允许玩家上传可执行的代码

如何解决《寻找良好的服务器端语言,允许玩家上传可执行的代码》经验,为你挑选了2个好方法。

我对我想要编写的程序有所了解,但哪种语言最好是我的问题.

如果我有一个赛车游戏,我想让用户提交新的交互式3D赛道(想想Speed Racer电影中的曲目),车辆和自动驾驶汽车的代码,那么,他们会创建AI他们的汽车将使汽车能够确定如何处理危险.

所以,我需要一种能够快速运行的语言,并且作为服务器具有所有可用种族的世界地图的一部分,以及它们的各种状态.

我很好奇,例如,这是否是在Scala中创建DSL的一个很好的理由?

我不想重新启动一个应用程序来加载新的dll或jar文件这么多编译语言会有问题.

我对Linux或Windows开放,对于语言,大多数脚本语言,F#,Scala,Erlang或大多数OOP我可以编程.

用户将能够监控他们的车辆如何运行,并且如果他们为该车辆上载了多个AI,当遇到某些障碍时,他们应该能够根据需要将一个AI程序换成另一个AI程序.

更新:到目前为止,解决方案是javascript,使用V8和Lua.

我很好奇这是否适用于DSL,实际上是3个独立的DSL.1用于创建赛道,另一个用于控制赛车,第三个用于创建新车.

如果是这样,那么Haskell,F#或Scala会是一个很好的选择吗?

更新:让不同的部分以不同的语言结束是否有意义?例如,如果Erlang用于控制汽车,Lua用于汽车本身,还用于动画赛道?



1> Mark Rushako..:

你的情况听起来像是Lua的一个很好的候选人.

你需要沙盒:这在Lua很容易.例如,您只需通过覆盖或删除os.execute命令来初始化用户的环境,用户就无法再访问该功能.

你想要快速:查看一些针对其他语言的Lua基准测试.

可能你需要与另一种语言互操作.Lua非常容易(IMO)嵌入C或C++,至少.我没有使用LuaInterface,但这是C#绑定.

Lua具有一阶函数,因此应该可以轻松地即时交换函数.

Lua 在某种程度上支持OOP与metatables.

Lua的主要数据结构是表(关联数组),它非常适合稀疏数据结构,例如与世界地图集成.

Lua有一个非常规则的语法.没有带有分号或缩进的有趣技巧,所以当用户拿起你的语言时,用户学习的东西就少了一些 - 更不用说,使用记录良好的语言会带走你必须完成的一些工作.自己记录的条款.

另外,正如@elviejo在评论中指出的那样,Lua已经在许多游戏中被用作脚本语言.如果不出意外,以你所描述的方式使用Lua肯定有一些先例.并且,正如@gmonc所提到的,您的用户可能已经在另一个游戏中使用过Lua.


至于如何与Lua集成:通常,您的用户应该只需要上传Lua脚本文件.要严重过于简单化,你可能会为用户提供可用的功能,例如TurnLeft,TurnRight,Go,和Stop.然后,用户将上传类似的脚本

Actions = {} -- empty table, but you might want to provide default functions 
function Actions.Cone()
    TurnLeft()
end

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

然后服务器端,你可能会用a启动它们Go().然后,当他们的汽车到达一个圆锥体时,你会调用它们的Actions.Cone()功能; 墙壁通向Actions.Wall()功能等.此时,您(希望)已经沙箱化了Lua环境,因此您可以简单地执行其脚本而不必过多考虑错误检查 - 如果它们的脚本导致错误,则不您无法直接将错误传递给用户的原因.如果没有任何错误,lua_State服务器代码中的代码应包含其汽车的最终状态.


更好的例子

这是一个独立的C文件,它从stdin获取Lua脚本并像我上面解释的那样运行它.游戏是你会遇到地面,栅栏或树枝,你必须分别跑,跳或鸭子通过.您通过stdin输入Lua脚本来决定如何做出反应.源代码有点长,但希望它很容易理解(除了需要一段时间才能习惯的Lua API).这是我过去30分钟的原创作品,希望它有所帮助:

#include 
#include 
#include 
#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;
}

用GCC构建上面的GCC gcc runner.c -o runner -llua5.1 -I/usr/include/lua5.1.

几乎每次成功通过的唯一Lua脚本是:

Actions = {}

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

也可以写成

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

使用好的脚本,您将看到如下输出:

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

如果用户尝试恶意攻击,程序将只提供错误:

$ 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))

使用不正确的移动脚本,用户将看到他执行了错误的移动:

$ echo "Actions = {} Actions.Ground = Jump; Actions.Fence = Duck; Actions.Branch = Run" | ./runner 
Wrong move!
You failed!


Lua已经在几个视频游戏中用作嵌入式语言.以下是使用它的游戏列表:http://en.wikipedia.org/wiki/Category:Lua-scripted_video_games因此,LUA可能不是完美的解决方案.但可以肯定的是,它并不坏.

2> Daniel A. Wh..:

为什么不使用JavaScript或EcmaScript?谷歌的V8是一个非常好的沙盒方式来做到这一点.我记得它真的很容易.当然,你必须为它编写一些绑定.

推荐阅读
mobiledu2402851377
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有