Ваша ситуация звучит как хороший кандидат на Lua.
- Вам нужна песочница: это легко сделать на Lua. Вы просто инициализируете пользовательскую среду, перезаписывая или удаляя, например, команду
os.execute
, и у пользователя больше нет возможности получить доступ к этой функции.
- Вы хотите быстро: ознакомьтесь с некоторыми из эталонных тестов Lua по сравнению с другими языками< /а>.
- Предположительно, вам нужно взаимодействовать с другим языком. Lua очень легко (IMO) встроить, по крайней мере, в C или C++. Я не использовал LuaInterface, но это привязка C#.
- В Lua есть функции первого порядка, поэтому должно быть легко менять функции на лету.
- Lua в некоторой степени поддерживает ООП с метатаблицами.
- Основной структурой данных 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
Затем на стороне сервера вы можете начать их с Go()
. Затем, когда их машина достигает конуса, вы вызываете их функцию Actions.Cone()
; стена ведет к функции Actions.Wall()
и т. д. К этому моменту вы (надеюсь) уже изолировали среду Lua, поэтому вы можете просто выполнить их сценарий, даже не обращая особого внимания на проверку ошибок — если их сценарий приводит к ошибке, нет причин, по которым вы не можете передать ошибку непосредственно пользователю. И если ошибок нет, lua_State
в коде вашего сервера должно содержать конечное состояние их автомобиля.
Лучший пример
Вот отдельный файл C, который берет скрипт Lua из стандартного ввода и запускает его, как я объяснил выше. Игра заключается в том, что вы столкнетесь с землей, забором или веткой, и вам нужно соответственно бежать, прыгать или пригибаться, чтобы пройти. Вы вводите сценарий Lua через стандартный ввод, чтобы решить, как реагировать. Исходный код немного длинноват, но, надеюсь, его легко понять (помимо Lua API, к которому нужно привыкнуть). Это мое оригинальное творение за последние 30 минут, надеюсь, оно поможет:
#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;
}
Соберите вышеуказанное на 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!
person
Mark Rushakoff
schedule
20.10.2009
unsafePerformIO
в их коде!). С другой стороны, это было бы очень сложно для пользователей, которые плохо разбираются в программировании. - person David   schedule 18.10.2009