Jump to content

Вопросы и ответы по MTA.


Recommended Posts

Пожалуйста, объясните кто-то что дает нам как бы ООП добавленное в 1.4, что нового можно сделать с помощью него, а то туторы понимаю, а что с ним делать не понимаю.

А еще оно, почему-то, работает 2 раза медленнее...

Результаты бенчмарков можно увидеть? В каком месте медленнее, какие тесты проводились и вообще откуда такие заявления?

Возможно, я не правильно замеряю время. Да и вообще, я сейчас запустил опять то, чем раньше это замерял... Результаты какие-то совсем странные. Раньше они были почти одинаковые, теперь совсем не одинаковые, 1-2 из 10 в случайном порядке вообще, почему-то, секунду выполняются...

Опишите правильный способ замера заодно.

Link to comment
  • Other Languages Moderators
Пожалуйста, объясните кто-то что дает нам как бы ООП добавленное в 1.4, что нового можно сделать с помощью него, а то туторы понимаю, а что с ним делать не понимаю.

А еще оно, почему-то, работает 2 раза медленнее...

Lua раз в 10 мделеннее чем asm и всё ровно на ней пишут.

Link to comment
getTickCount 

Разница во времени между участками кода и будет ответом.

Ну, тогда у меня всё правильно. Но странность с результатами всё же осталась... И ООП, всё же, медленнее, не в 2 раза, но медленнее.

Lua раз в 10 мделеннее чем asm и всё ровно на ней пишут.

Ну, и если бы оно реально в 2 раза медленнее было, можно было просто написать компилятор(как MoonScript) из такого ООП в процедурное. Это не так уж и сложно.

Link to comment
getTickCount 

Разница во времени между участками кода и будет ответом.

Ну, тогда у меня всё правильно. Но странность с результатами всё же осталась... И ООП, всё же, медленнее, не в 2 раза, но медленнее.

Lua раз в 10 мделеннее чем asm и всё ровно на ней пишут.

Ну, и если бы оно реально в 2 раза медленнее было, можно было просто написать компилятор(как MoonScript) из такого ООП в процедурное. Это не так уж и сложно.

Просто ООП в Lua работает как костыль, поэтому это и есть лишь имитация ООП, и никак иначе. Сравнение с MoonScript не совсем корректное, то о чём ты говоришь - не копилятор, а скорее конвертор, но мыль я твою понял. Конечно было бы хорошо иметь компилятор для Lua, который бы приводил всё в байткод как и сейчас.

Хотя, написать транслятор из C# в Lua с последующей компиляцией (mta_luac) тоже не плохой вариант :D

Link to comment

Просто ООП в Lua работает как костыль, поэтому это и есть лишь имитация ООП, и никак иначе. Сравнение с MoonScript не совсем корректное, то о чём ты говоришь - не копилятор, а скорее конвертор, но мыль я твою понял. Конечно было бы хорошо иметь компилятор для Lua, который бы приводил всё в байткод как и сейчас.

Хотя, написать транслятор из C# в Lua с последующей компиляцией (mta_luac) тоже не плохой вариант :D

Ну, я тоже не хотел это компилятором называть, но на сайте MoonScript'a написано

MoonScript is a dynamic scripting language that compiles into Lua.

А на сайте CoffeeScript'а тоже написано подобное

CoffeeScript is a little language that compiles into JavaScript.

А как C# сможет транслироваться в Lua, если в нем очень много того, что в Lua не возможно сделать ?

Link to comment
МунСкрипт как и КоффиСкрипт это всего лишь синтаксический сахар, чего вы тут напридумывали, компиляторы какие-то.

Синтаксический сахар, это когда в язык вводят разные(мб упрощенные) способы задать что-то(как в С++14 разделение 100'000'00), а Мун и Коффе скрипты - языка программирования, которые компилируются(я думаю, что можно это так назвать, если подразумевать некоторое трансформаировани в более "реальный" вид) в Lua

Да, относительно Lua, MoonScript это Lua c синтаксическим сахаром, но сам по себе он язык программирования.

Link to comment

Компиляция Lua скриптов никак не ускорит их выполнение, лишь загрузку. Текстовый скрипт и так переводится в байт код при загрузке.

На счет ООП в Lua - выполнение одной функции скорее будет быстрее процедурно (хотя тут зависит от того сколько у нас глобальных переменных, сколько функций в классе, и на каком уровне наследования находится функция). Тупо потому что при обращении, идет поиск функции в таблице по строковому названию:

moo() - это то же самое что и _G["moo"]()

Но смысл в том что за счет большей абстракции в ООП, общая логика для достижения того же результата будет меньше (уже есть примеры, freecam переписанный на ооп в несколько раз меньше, с тем же функционалом)

В ирке я выдвинул на обсуждение небольшое изменение нынешней структуры метатаблиц. А именно: перенос наследственности на уровень таблицы класса и перенос свойств (переменных) туда же, для тех кто шарит, мой пример будет понятен:

Element = { 
  setHealth = ..., 
  getHealth = ..., 
  health = { 
    __set = ... 
    __get = ... 
  }, 
  ... 
} 
Vehicle = { 
  func = ..., 
  ... 
} 
  
setmetatable ( Vehicle, { __index = Element } ) 

Это и ускорит поиск, по сравнению с нынешним; упростит наследование от элементов МТА; упростит создание своих свойств объекта.

Link to comment

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

  
setElementPosition(value, split(dataTable[1]["playerPosition"], ",")[1], split(dataTable[1]["playerPosition"], ",")[2], split(dataTable[1]["playerPosition"], ",")[3]) 
  

Вместо этого:

  
local string = dataTable[1]["playerPosition"] 
local splitString = split(string, ",") 
setElementPosition(value, splitString[1], splitString[2], splitString[3]) 
  

Это самый ближний пример, порой мои конструкции получаются очень длинными

Вопрос:

Влияет ли мой подход на производительность лучше или хуже? Что предпочитаете вы?

Link to comment
Народ, я люблю использовать сложные конструкции вместо кучи переменных, например, это:
  
setElementPosition(value, split(dataTable[1]["playerPosition"], ",")[1], split(dataTable[1]["playerPosition"], ",")[2], split(dataTable[1]["playerPosition"], ",")[3]) 
  

Вместо этого:

  
local string = dataTable[1]["playerPosition"] 
local splitString = split(string, ",") 
setElementPosition(value, splitString[1], splitString[2], splitString[3]) 
  

Это самый ближний пример, порой мои конструкции получаются очень длинными

Вопрос:

Влияет ли мой подход на производительность лучше или хуже? Что предпочитаете вы?

Влияет. Ты 3 раза вычисляешь одно и то же(split(dataTable[1]["playerPosition"], ",")).

Можно, кстати, так

  
local splitString = split(dataTable[1]["playerPosition"], ",") 
setElementPosition(value, splitString[1], splitString[2], splitString[3]) 
  

Link to comment

Elengar, Да, я знаю, что так можно, я в качестве примера специально более громоздкую конструкцию привел. А не выполняется ли функция, которая присвоена переменной каждый раз, когда обращаются к переменной? Я об этом. А о том, что на первый взгляд первый вариант кажется более ресурсоемким я и сам догадался :D

UPD:

Не выполняется, проверил:

  
function retRandom() 
    return math.random(1, 9999) 
end 
  
local count = retRandom() 
  
print (count) 
print (count) 
print (count) 
print (count) 
  

Link to comment
Elengar, Да, я знаю, что так можно, я в качестве примера специально более громоздкую конструкцию привел. А не выполняется ли функция, которая присвоена переменной каждый раз, когда обращаются к переменной? Я об этом. А о том, что на первый взгляд первый вариант кажется более ресурсоемким я и сам догадался :D

UPD:

Не выполняется, проверил:

  
function retRandom() 
    return math.random(1, 9999) 
end 
  
local count = retRandom() 
  
print (count) 
print (count) 
print (count) 
print (count) 
  

Для простеньких тестов в чистом Lua есть os.clock(), а в МТА getTickCount()

Сохраняешь результат этой функции в переменную до нужных операций, после - от нового результата выполнения функции этот результат .

local t = getTickCount() 
  
local splitString = split(dataTable[1]["playerPosition"], ",") 
setElementPosition(value, splitString[1], splitString[2], splitString[3]) 
  
outputChatBox(getTickCount() - t) 

Только для замера их нужно выполнять в цикле, иногда и по 1000 раз, т.к. результат выполнения десятка простых операций может дать 0.

Link to comment

Для простеньких тестов в чистом Lua есть os.clock(), а в МТА getTickCount()

Сохраняешь результат этой функции в переменную до нужных операций, после - от нового результата выполнения функции этот результат .

local t = getTickCount() 
  
local splitString = split(dataTable[1]["playerPosition"], ",") 
setElementPosition(value, splitString[1], splitString[2], splitString[3]) 
  
outputChatBox(getTickCount() - t) 

Только для замера их нужно выполнять в цикле, иногда и по 1000 раз, т.к. результат выполнения десятка простых операций может дать 0.

На счет подставить в цикл реально крутая и простая идея, но я тоже не додумывался о таком, а то много что замеряю и дает 0.

Link to comment

Народ, вопрос к тем, кто использует серверные таблицы для хранения данных игроков. Является ли такой способ получения данных на клиенте оптимальным? А то его использование приводит к костылям при работе с интерфейсом.

Триггер с клиента на сервер с запросом данных -> обработка и триггер с сервера на клиент с возвращением данных

Это, пока что единственное обстоятельство, которое не дает пользоваться серверными таблицами, ведь порой нужно получить результат в одной функции, а этот способ подразумевает две.

Link to comment
Триггер с клиента на сервер с запросом данных -> обработка и триггер с сервера на клиент с возвращением данных

Я сделал так что при всех изменениях на сервере запускаются триггеры на клиент с измененными данными.

Интересно узнать, может есть метод более эффективнее.

Link to comment
Народ, вопрос к тем, кто использует серверные таблицы для хранения данных игроков. Является ли такой способ получения данных на клиенте оптимальным? А то его использование приводит к костылям при работе с интерфейсом.

Триггер с клиента на сервер с запросом данных -> обработка и триггер с сервера на клиент с возвращением данных

Это, пока что единственное обстоятельство, которое не дает пользоваться серверными таблицами, ведь порой нужно получить результат в одной функции, а этот способ подразумевает две.

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

Ты хочешь чтобы у тебя функция делала запрос на сервер и сразу же возвращала результат (аля mysql_query в PHP\плагине)? - А ты в курсе, что это возможно только блокировкой твоего потока в целях ожидания пока пакет дойдёт до сервера, далее пройдёт обработка запроса, пойдёт пакет обратно и лишь только тогда поток разблокируется?

Все скрипты выполняются в одном потоке.

Касательно mysql_query из модуля MTA MySQL: пока запрос выполняется и ожидается возврат результата - поток на сервере стоит. Именно поэтому рекомендуется использовать встроенные функции, так как там есть возможность повесить каллбек. Конечно же на сервере это не так страшно как на клиенте.

Link to comment

Ну неправда же.

Вполне можно сделать чтобы функция делала запрос к серверу, получала ответ и выдавала результат там где выполняется - coroutine. Для db функций тоже можно использовать. В итоге все будет очень красиво и удобно, но для этого нужно чтобы обработчики событий выполнялись в короутинах, соответственно addEventHandler лучше обернуть, вместе с removeEventHandler и т.д.

Принцип таков:

- вызывается событие (ткнули в кнопку рефреш в окне, например);

- создается новый короутин;

- короутин запускается с аргументами события;

- где-то понадобилось запросить данные с сервера, вызывается функция, скажем getServerData();

- getServerData делает triggerServerEvent на сервер, записывает в промежуточную таблицу (например requests) что такой-то короутин ждет ответа от сервера;

- сервер обрабатывает запрос, отвечает с triggerClientEvent

- клиент ловит ответ, берет из таблицы requests короутин который этот ответ ждал, передает в него результат и продолжает его (coroutine.resume)

В итоге в коде все будет оч красиво:

  
addEventHandler ( "onClientGuiClick", refreshbutton, function () 
    ... 
    local data = getServerData () -- в этой функции сделается запрос к серверу и вернутся данные, выполнение остановится, пока данные не придут 
    -- заполняем гуи 
    ... 
end, false ) 
  

Для примера, вот небольшой враппер для db функций, где db.query возвращает результат там где выполняется, а не в колбек: тык

local users = db.query ( "select * from users" ); 

А тут пример враппера с короутинами для евентов (правда чуть кривой): тык

Link to comment
Ну неправда же.

Что именно не правда? Что поток замораживается во время выполнения или что?

Вполне можно сделать чтобы функция делала запрос к серверу, получала ответ и выдавала результат

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

Link to comment

Костыль? Это то, для чего короутины вообще существуют. Невозможно в Lua добавить потоки, в привычном их виде, Lua не thread-safe. Да и смысла нет, весь API абсолютно event based, все скрипты - это обработчики каких-либо событий. Сами по себе они не существуют.

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...