Перейти к содержимому


Фотография

Love2d. Способы реализации удаленного выполнения Lua-скриптов.

love2d скрипт потоки

  • Авторизуйтесь для ответа в теме
Сообщений в теме: 16

#1 Оффлайн   Zer0Galaxy

Zer0Galaxy
  • Гуру
  • Сообщений: 1 228
  • Уровень сигнала: 0%
  • В игре: 0 час. 0 мин.

Награды

   5                              

Отправлено 13 Сентябрь 2016 - 17:44

Две недели назад я начал изучать платформу для создания двумерных игр Love2d. Не скажу, что знаю ее уже досконально, но некоторое представление имеется. В первую очередь меня интересовала возможность создания многопользовательских игр, в которых игроку предстояло бы создавать программы. Под управлением этих программ должны работать некие игровые объекты. Не имеет значения, будут ли это космические корабли, бороздящие просторы вселенной, или роботы, роющие алмазики в шахтах, суть игры остается неизменной – определить, чья программа эффективнее.

В данной теме я хотел бы поделиться своими наработками в этом направлении и выслушать мнение людей, которые возможно интересовались этой же проблемой.

Для начала сформулирую основные задачи:

1)      Сетевой обмен. Поскольку игра многопользовательская, она должна быть построена по принципу «клиент-сервер», т.е. должна быть реализована клиентская часть, предоставляющая игроку игровой интерфейс, и серверная, на которой будет реализована игровая механика. Поэтому первой задачей я назвал бы реализацию сетевого обмена между клиентом и сервером.

2)      Возможность исполнения на сервере lua-скрипров, написанных игроками. Может и не стоило бы выделять это в отдельную задачу (все мы слышали про функцию load) если бы не одно «но». Скрипт, что бы там ни было написано, не должен блокировать работу сервера. Как, к примеру, парировать работу такого скрипта?

while true do end

Он напрочь завесит сервер, если не принять мер.

3)      Параллельное выполнение скриптов. Один скрипт может выполняться несколько часов или даже дней. Это не означает, что остальные скрипты должны ждать своей очереди. Тут нам на помощь придут потоки (threads). Поток – довольно дорогое удовольствие и при большом количестве потоков на сервере могут возникнуть проблемы, но другого способа обеспечить распараллеливание я не знаю. Об особенностях реализации потоков и способах обмена между потоком и основной программой я бы хотел поговорить.

 

А можно мне модерку на эту тему, что б тут флудосрач не разводили?



#2 Оффлайн   LeshaInc

LeshaInc
  • Пользователи
  • Сообщений: 1 207
  • Уровень сигнала: 15,5%
  • В игре: 117 час. 1 мин.
  • ГородЛуна

Награды

                       

Отправлено 13 Сентябрь 2016 - 18:17

Сетевой обмен

 

Нужно в первую очередь определиться с целью обмена. А некоторых случаях нужно использовать UDP, в некоторых TCP.

 

Насчет луа-скриптов от игроков: исполнять их в любом случае надо на сервере. Пока неизвестно на чем будет написан сервер нельзя точно сказать как прервать блокирование такого потока, ограничение по ресурсам и прочие хитрости. Конечно можно написать сервер и на самом love2d, но скорость будет хромать. love2d не предназначен для высоконагруженных серверов, это фреймворк для 2д игр.



#3 Оффлайн   Kartze

Kartze
  • Пользователи
  • Сообщений: 435
  • Уровень сигнала: 40,57%
  • В игре: 306 час. 24 мин.

Награды

              

Отправлено 13 Сентябрь 2016 - 18:29

Насчет потоков - в ОС же есть какой-то козырь, типа, поток на несколько компов.
Вайлтруду тоже нужно побеждать методом ОС - если комп будет забивать свою часть потока, он крашится с TLWY.
Только вот... Я и понятия не имею, как это все реализовано. Нужно прямо ковырять сырцы, боюсь я.
И вот вопросик - как будет работать всякая чушь типа файловой системы, ограниченного размера озу у каждого компа, etc?
Надо уж понять, как будет работать главная фича(тм) игрульки.

#4 Оффлайн   NEO

NEO
  • Пользователи
  • Сообщений: 1 748
  • Уровень сигнала: 4,82%
  • В игре: 36 час. 25 мин.
  • ГородСолнце

Награды

   3                        

Отправлено 13 Сентябрь 2016 - 18:31

Я писал специальный пакетный обработчик, регистрируешь пакет, определяешь в нём функции toBytes, fromBytes, в теле пакета реализуешь код который превращает байты в данные и наоборот, также функция handle которая принимает готовый пакет, структура пакета, 2 байта = длина пакета, 1 байт id пакета(количество байт зависит от количества id, 256 разных пакетов думаю хватит) , данные которые пойдут в fromBytes функцию. Тут желательно принцип ООП применять, в toBytes и fromBytes нужно передавать готовый буфер имеющий методы для конвертации из байт в данные и наоборот.


while true do end

debug.sethook, ей можно регулировать такие вещи.


Сообщение отредактировал NEO: 13 Сентябрь 2016 - 18:41


#5 Оффлайн   Zer0Galaxy

Zer0Galaxy
  • Автор темы
  • Гуру
  • Сообщений: 1 228
  • Уровень сигнала: 0%
  • В игре: 0 час. 0 мин.

Награды

   5                              

Отправлено 13 Сентябрь 2016 - 18:44

Сетевой обмен.

Love2d предоставляет несколько способов обмена по сети. Это и библиотека enet и библиотека LUBE. Тем не менее, я решил остановиться на стандартном TCP-сокете.

Начнем с сервера. Предположим мы хотим создать сервер, который будет принимать строку символов, как то ее преобразовывать (например, инвертировать символы) и возвращать обратно клиенту. Сделать это можно так:

Спойлер

 

И клиент:

Спойлер

 

Следует заметить, что обмен реализуется исключительно путем передачи строк. Причем если верить документации, функция может принимать первым параметром одно из трех значение:

- “*a” – читает из сокета, пока соединение не будет закрыто. Не совсем понял как это. А если я не собираюсь закрывать сокет в ближайшее время?

- “*l” – читает из сокета строку, которая должна завершаться символом «перевод строки». Сам символ «перевод строки» не передается. В результате возникает проблема, если мы попытаемся передать текст из нескольких строк (а при передаче скрипта так и будет). На приемной стороне текст будет разбит на строки и придется его снова собирать по каким то правилам. Есть конечно вариант на передающей стороне заменить символ перевода на какой ни будь другой, а на приемной стороне выполнить обратную замену.

- число – определяет количество байт, которые будут считаны из сокета. Этот вариант нам не очень подходит, поскольку мы не знаем количества принятых байт. Можно, конечно вычитывать по одному символу, но…

Короче, ни один из трех способов не устраивает меня в полной мере. Кто использовал сокеты, что думаете?



#6 Оффлайн   Zer0Galaxy

Zer0Galaxy
  • Автор темы
  • Гуру
  • Сообщений: 1 228
  • Уровень сигнала: 0%
  • В игре: 0 час. 0 мин.

Награды

   5                              

Отправлено 13 Сентябрь 2016 - 19:05

Нужно в первую очередь определиться с целью обмена. А некоторых случаях нужно использовать UDP, в некоторых TCP.
Обмен будет осуществляться как то так: Клиент отправляет команду с параметрами, сервер ее исполняет и возвращает результат.

Например: 

Клиент:  "залогиниться <username> <password>"
Сервер: "Ok"
Клиент: "получи_новый_скрипт <skript_name> while true do end"
Сервер: "Ok"
Клиент: "выполни_скрипт <skript_name>"
Сервер: "Error: Too long without yielding"

Ориентируюсь на TCP, т.к. более надежен. Об одновременном использовании обоих протоколов в пределах одной программы не думал.

 

Насчет луа-скриптов от игроков: исполнять их в любом случае надо на сервере. Пока неизвестно на чем будет написан сервер нельзя точно сказать как прервать блокирование такого потока, ограничение по ресурсам и прочие хитрости. Конечно можно написать сервер и на самом love2d, но скорость будет хромать. love2d не предназначен для высоконагруженных серверов, это фреймворк для 2д игр.
Предполагаю, что сервер будет на love исключительно из-за того, что там уже реализована физика взаимодействия твердых тел. А что скорость будет хромать, так вряд ли эту игрушку будут юзать более пяти игроков одновременно. Должно потянуть.

И вот вопросик - как будет работать всякая чушь типа файловой системы, ограниченного размера озу у каждого компа, etc? Надо уж понять, как будет работать главная фича(тм) игрульки.
Файловая система пока за пределами моих мечтаний. Это все таки не OpenComputers, а что-то на много проще. А вот ограничение ОЗУ это действительно проблема. Как ее решать, надеюсь придумаем со временем.

debug.sethook, ей можно регулировать такие вещи.
Пример приведи, пожалуйста. 
  • Kartze это нравится

#7 Оффлайн   qwertyMAN

qwertyMAN
  • Пользователи
  • Сообщений: 1 427
  • Уровень сигнала: 0,14%
  • В игре: 1 час. 3 мин.
  • ГородCity17

Награды

                             

Отправлено 13 Сентябрь 2016 - 19:07

Может не надо делать связь с сервером?

Можно обычную одиночную игру сделать.



#8 Оффлайн   LeshaInc

LeshaInc
  • Пользователи
  • Сообщений: 1 207
  • Уровень сигнала: 15,5%
  • В игре: 117 час. 1 мин.
  • ГородЛуна

Награды

                       

Отправлено 13 Сентябрь 2016 - 19:40

- “*a” – читает из сокета, пока соединение не будет закрыто. Не совсем понял как это. А если я не собираюсь закрывать сокет в ближайшее время?

 

Заблокирует навечно, пока не встретит EOF.

 

- число – определяет количество байт, которые будут считаны из сокета. Этот вариант нам не очень подходит, поскольку мы не знаем количества принятых байт. Можно, конечно вычитывать по одному символу, но…

 

Во взрослых протоколах пишется в первых байтах размер сообщения. Например так:

<4 байта - размер сообщения как N: 15> <текст сообщения, N байт: something 12345>

Но в таком случае достаточно чтения одной строки, да.


Следует заметить, что обмен реализуется исключительно путем передачи строк

 

Строки, да, но внутри них мы можем писать бинарные данные, например длину сообщения ту же.



#9 Оффлайн   NEO

NEO
  • Пользователи
  • Сообщений: 1 748
  • Уровень сигнала: 4,82%
  • В игре: 36 час. 25 мин.
  • ГородСолнце

Награды

   3                        

Отправлено 13 Сентябрь 2016 - 19:41

Обмен будет осуществляться как то так: Клиент отправляет команду с параметрами, сервер ее исполняет и возвращает результат.

Например: 

Клиент:  "залогиниться <username> <password>"
Сервер: "Ok"
Клиент: "получи_новый_скрипт <skript_name> while true do end"
Сервер: "Ok"
Клиент: "выполни_скрипт <skript_name>"
Сервер: "Error: Too long without yielding"

Пример приведи, пожалуйста. 

 

function hook()

     coroutine.yield()

end

 

debug.sethook(hook, 100)

 

Каждые 100 инструкции будет вызываться coroutine.yield. в OC таким образом реализована защита от while true do и большой нагрузки цп.


  • Quant и Kartze это нравится

#10 Оффлайн   Totoro

Totoro
  • Хранители Кода
  • Сообщений: 1 735
  • Уровень сигнала: 0,29%
  • В игре: 2 час. 13 мин.

Награды

                                      

Отправлено 13 Сентябрь 2016 - 22:46

Предполагаю, что сервер будет на love исключительно из-за того, что там уже реализована физика взаимодействия твердых тел. А что скорость будет хромать, так вряд ли эту игрушку будут юзать более пяти игроков одновременно. Должно потянуть.

 

Там Box2D юзается для физики. Либа написана на C++, но можно воткнуть куда угодно практически (потому что врапперов к ней море).

Так что если знаком с каким-нибудь языком более подходящим для бекэнда, стоит его рассмотреть как вариант



#11 Оффлайн   Quant

Quant
  • Пользователи
  • Сообщений: 537
  • Уровень сигнала: 0,01%
  • В игре: 0 час. 4 мин.
  • Городinterface IQuant

Награды

     

Отправлено 14 Сентябрь 2016 - 19:51

function hook()

     coroutine.yield()

end

 

debug.sethook(hook, 100)

 

Каждые 100 инструкции будет вызываться coroutine.yield. в OC таким образом реализована защита от while true do и большой нагрузки цп.

Не хватает только ограничения кол-ва инструкций на игрока.Думаю,стоит сделать.



#12 Оффлайн   LeshaInc

LeshaInc
  • Пользователи
  • Сообщений: 1 207
  • Уровень сигнала: 15,5%
  • В игре: 117 час. 1 мин.
  • ГородЛуна

Награды

                       

Отправлено 14 Сентябрь 2016 - 19:59

Не хватает только ограничения кол-ва инструкций на игрока.Думаю,стоит сделать.

local coroutines = {}

coroutines[coroutine.create(function ()
  -- код игрока
end)] = 0  -- количество операций

debug.sethook(function ()
  local running = coroutine.running()
  if running then
    coroutines[running] = coroutines[running] + 100
    coroutine.yield(--[[ ... ]])
  end
end, 100)

что тут сложного?


Сообщение отредактировал LeshaInc: 14 Сентябрь 2016 - 20:04


#13 Оффлайн   Zer0Galaxy

Zer0Galaxy
  • Автор темы
  • Гуру
  • Сообщений: 1 228
  • Уровень сигнала: 0%
  • В игре: 0 час. 0 мин.

Награды

   5                              

Отправлено 15 Сентябрь 2016 - 09:22

Конечно можно написать сервер и на самом love2d, но скорость будет хромать. love2d не предназначен для высоконагруженных серверов, это фреймворк для 2д игр.

Там Box2D юзается для физики. Либа написана на C++, но можно воткнуть куда угодно практически (потому что врапперов к ней море). Так что если знаком с каким-нибудь языком более подходящим для бекэнда, стоит его рассмотреть как вариант
Может ли кто подробно расписать реализацию  луа-скриптов из под С++ или какого то другого языка? Я одно время пытался этим заняться, но потом забросил.

#14 Оффлайн   Totoro

Totoro
  • Хранители Кода
  • Сообщений: 1 735
  • Уровень сигнала: 0,29%
  • В игре: 2 час. 13 мин.

Награды

                                      

Отправлено 15 Сентябрь 2016 - 11:41

Может ли кто подробно расписать реализацию  луа-скриптов из под С++ или какого то другого языка? Я одно время пытался этим заняться, но потом забросил.

 

На это дело дока есть, подробная, где-то на офф. сайте. Сам не могу расписать, потому что тоже до конца не разбирался.

Из C++ она цепляется напрямую, и это самый естественный способ её использования.

Из под Java / Scala можно заюзать либу типа JLua или прицепить Lua (например тот же Eris из OC) через JNI.



#15 Оффлайн   NEO

NEO
  • Пользователи
  • Сообщений: 1 748
  • Уровень сигнала: 4,82%
  • В игре: 36 час. 25 мин.
  • ГородСолнце

Награды

   3                        

Отправлено 15 Сентябрь 2016 - 12:40

Может ли кто подробно расписать реализацию  луа-скриптов из под С++ или какого то другого языка? Я одно время пытался этим заняться, но потом забросил.

Там стэк машина, читай lua С api, всё просто.

https://www.lua.org/...5.1/manual.html

методы начинаются на lua_

 

LuaState* L;

 

lua_pushinteger(L, 999);

lua_setglobal(L, "var");

 

Таким образом теперь есть глобальная переменная по имени var со значением 999.

Всё работает по принципу стэка, ты пушаешь туда что - то, а уже функциями работаешь с верхушки.


Сообщение отредактировал NEO: 15 Сентябрь 2016 - 12:45


#16 Оффлайн   Zer0Galaxy

Zer0Galaxy
  • Автор темы
  • Гуру
  • Сообщений: 1 228
  • Уровень сигнала: 0%
  • В игре: 0 час. 0 мин.

Награды

   5                              

Отправлено 15 Сентябрь 2016 - 12:52

function hook()

     coroutine.yield()

end

 

debug.sethook(hook, 100)

 

Каждые 100 инструкции будет вызываться coroutine.yield. в OC таким образом реализована защита от while true do и большой нагрузки цп.

Попытался выполнить такой код:

function hook(ev,linenum)
  linenum=linenum or ""
  io.write(ev.." "..linenum.." ")
end
 
debug.sethook(hook,"l",100)

for i=1,100 do
  io.write(i.." ")
end

Думал, хук будет хукать на каждые сто строк, т.е. пару раз за сто итераций цикла for. А не тут то было, на каждую строку хукает. Что не так делаю?



#17 Оффлайн   NEO

NEO
  • Пользователи
  • Сообщений: 1 748
  • Уровень сигнала: 4,82%
  • В игре: 36 час. 25 мин.
  • ГородСолнце

Награды

   3                        

Отправлено 15 Сентябрь 2016 - 13:24

Попытался выполнить такой код:

function hook(ev,linenum)
  linenum=linenum or ""
  io.write(ev.." "..linenum.." ")
end
 
debug.sethook(hook,"l",100)

for i=1,100 do
  io.write(i.." ")
end

Думал, хук будет хукать на каждые сто строк, т.е. пару раз за сто итераций цикла for. А не тут то было, на каждую строку хукает. Что не так делаю?

debug.sethook(hook, '', 100), будет каждые 100 инструкции, можно написать миллион инструкции в строке.


Сообщение отредактировал NEO: 15 Сентябрь 2016 - 14:10

  • Zer0Galaxy и Multirez это нравится





Темы с аналогичным тегами love2d, скрипт, потоки

Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 анонимных