Перейти к контенту

Язык Lua. Общие вопросы программирования


Рекомендуемые сообщения

С чего начинать и где взять.

 

Установка Lua:
http://www.amk-team.ru/forum/index.php?showtopic=11584&p=629106

 

Руководство «Программирование на языке Lua», третье издание:
http://www.amk-team.ru/forum/index.php?showtopic=11584&p=905308

Изменено пользователем Kirgudu
Ссылка на комментарий

Ну я рассматриваю этот вопрос конкретно в рамках Сталкера и его Луа, просто в Сталкере в свякзе с Lua-перехватчиком появляется возможность читать и редактировать память игры по адресами, в связи с чем я вот и смотрю можно ли чего хорошего из этого добиться помимо уже достигнутого. Другое дело что в том же сталкере все эти объекты Lua-биндовские, но наверняка какая нибудь связь между луа-биндовским и реальным движковым (си-шным) объектом существует.

Изменено пользователем *Shoker*

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

Ссылка на комментарий

Вот такой вопрос возник, связанный с Lua\Lua-Биндом. 

 

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

 

    local xml = CScriptXmlInit()
    xml:ParseFile ("ui_mm_main.xml")

 

 

 

Который используется для чтения параметров объектов из xml-файлов.

Переопределить его мне не составило проблем, я просто написал:

 

 

function CScriptXmlInit:ParseFile(name)
  get_console():execute("ParseFile")
  get_console():execute(tostring(name))
end

 

 

И в итоге все вызовы этой функции стали перенаправляться в мою.

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

 

Метод local original_func = CScriptXmlInit.ParseFile и его вариации само собой мне не подошли, и привели к вылету pure virtual function call.

 

Осуществимо ли задуманное в сталкере средствами штатного Lua\Lua-бинда? 

 

Такое тоже не получилось:

class "CScriptXmlInit_orig" (CScriptXmlInit)
function CScriptXmlInit:ParseFile(name)
  get_console():execute("ParseFile")
  get_console():execute(tostring(name))
  return CScriptXmlInit_orig:ParseFile(name)
end
Изменено пользователем *Shoker*

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

Ссылка на комментарий

@*Shoker*,

надеюсь self не забывал передавать? :)

Конструкция с запоминанием функции абсолютно корректна и должна работать.

Изменено пользователем abramcumner
Ссылка на комментарий

Нет, а как можно передать его явно? 
Такое не заработало:

 

 

local original_func = CScriptXmlInit.ParseFile
 
function CScriptXmlInit:ParseFile(name)
   get_console():execute("ParseFile")
   get_console():execute(tostring(name))
   original_func.self = self -- это функция - вылет
    return original_func(name)
-- return original_func(self, name)  -- pure virtual - вылет
end

 

 

Здесь тоже не получилось:

 

 

class "CScriptXmlInit_orig" (CScriptXmlInit)
 
function CScriptXmlInit:ParseFile(name)
 get_console():execute("ParseFile")
 get_console():execute(tostring(name))
 
 local orig_obj = CScriptXmlInit_orig()
 orig_obj.self = self
 return orig_obj:ParseFile(name)
end

 

Ругнулось что вызываю nil-функцию. 

 

 

Изменено пользователем *Shoker*

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

Ссылка на комментарий

@*Shoker*,

можно сделать так:

function create_xml()
  local xml = CScriptXmlInit()
  xml.PrevParseFile = xml.ParseFile
  xml.ParseFile = function (self, name)
    get_console():execute("ParseFile")
    get_console():execute(tostring(name))
    get_console():execute(type(self))
    return self.PrevParseFile(self, name)
  end	
  return xml
end

local xml = create_xml()
xml:ParseFile("test.xml")
Изменено пользователем abramcumner
Ссылка на комментарий

Хм, смысл именно в том чтобы избежать необходимости редактировать ориг. файлы и заменять в них CScriptXmlInit() на create_xml(), хотя метод интересный придумал, но что то не могу переварить как его применить без замены класса на функцию в коде. 



В принципе на мою текущую задачу хватит и того, что я написал (мне не обязательно иметь доступ к ориг. функции, хочу заменить функцию best_weapon() из класса game_object) но вообще для будущих целей такое может понадобится, чтобы например расширить функционал имеющихся функций. Вся соль как раз в том, чтобы не трогать ориг. файлы, а просто подменить содержание функции на другое. 

Изменено пользователем *Shoker*

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

Ссылка на комментарий

@*Shoker*,

если у класса функций немного, можно сделать что-то вроде такого(подменяется без правки других скриптов):

 

OldScriptXmlInit = CScriptXmlInit

class "MyScriptXml"
function MyScriptXml:__init()
  log("MyScriptXml ctor")
  self.xml = OldScriptXmlInit()
end

function MyScriptXml:ParseFile(name)
  log("ParseFile New")
  get_console():execute(tostring(name))
  get_console():execute(type(self)) 
  return self.xml:ParseFile(name)
end

--[[
 здесь реализуются все остальные функции
]]

_G.CScriptXmlInit = MyScriptXml
С game_object такое конечно не подходит.

 

Ну и честно говоря, я сомневаюсь, что с переопределением best_weapon боевка изменится. Я бы покопал в сторону своих экшенов для комбат_планера, ну и ai/common/weaponeffectiveness.efd, который используется в функции best_weapopn и который кстати учитывает расстояние до врага, тип оружия нпц, тип оружия врага :)

Изменено пользователем abramcumner
  • Нравится 1
Ссылка на комментарий

local func = CScriptXmlInit().ParseFile
function CScriptXmlInit:ParseFile(name)
  get_console():execute("ParseFile")
  get_console():execute(tostring(name))
  get_console():execute("flush")
  return func(self,name)
end

Charsi показал. Действительно заработало так как изначально и хотел. Моя ошибка была что скобки не написал и self соответственно не передавал\передавался не правильно.

abramcumner- тоже спасибище за код, хоть и не совсем то что нужно было но тоже интересный. Последний ещё не смотрел правда.

 

 Я бы покопал в сторону своих экшенов для комбат_планера, ну и ai/common/weaponeffectiveness.efd, который используется в функции best_weapopn и который кстати учитывает расстояние до врага, тип оружия нпц, тип оружия врага 

:) 

Я уже пишу простую боевую логику которая заставляет НПС сокращать дистанцию с врагом до боевой, так что не страшно. Это же я делаю чтобы написать свой менеджер оружия на замену best_weapon() без необходимости править ориг. скрипты. :)

Изменено пользователем *Shoker*
  • Нравится 3

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

Ссылка на комментарий

Мне нужно получить массив вида

aParam = {key1 = value1, key2 = value2...} 

И отсортировать его по value, далее получить первый элемент таблицы. Оба параметра типа 'number'.

local aParam = {}


for i=1,10 do
		local key = math.random(100)
		local value = math.random(100,200)
		table.insert(aParam.key, value) --//table.insert(aParam[i].key, value)
		table.sort(aParam)
end
print(aCond[1])

=>

bad argument #1 to 'insert' (table expected, got nil)

 

 

Даже без результата я знаю, что делаю не верно, ибо массив у меня выходит вида aParam = {key1 = value1}, {key2=value2}... 

Изменено пользователем Карлан
Ссылка на комментарий

@Карлан, у тебя банальная ошибка. Попробуй просто "человеческим языком" прочитать свой Lua-скрипт:

 

table.insert(aParam.key, value) - Вставить в (суб)таблицу (точнее добавить в конец) 'aParam.key' элемент 'value'.

 

- а теперь вопрос к написавшему сею строку: "А он позаботился создать эту (суб)таблицу, перед тем как в нее что-то добавлять?"

(собственно лог на это и указывает, говоря об отсутствии требуемой таблицы!)

А для твоей задумки требуется простое: aParam[key] = value - чтобы получить {key1 = value1, key2 = value2...}

 

Вот только вряд ли ты таким макаром получишь желаемое, т.к. key = math.random(100) может генерить далеко не эксклюзивные ключи и при их добавлении в {key1 = value1, key2 = value2...} у тебя уже имеющиеся будут затираться новыми...

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Всем доброго времени суток. Вроде в нужную тему пишу. Такая ситуация: 

Нужно по нажатию кнопки отрабатывать определённое действие.

Само действие уже написал давно, а вот как при помощи луа отрабатывать нажатие кнопки не знаю. Долгое гугленье выдало лишь это:

lua_pushinteger(lvm,KEY_A);
lua_setglobal(lvm,"KEY_A");
lua_pushinteger(lvm,KEY_;
lua_setglobal(lvm,"KEY_B");
lua_pushinteger(lvm,KEY_;
lua_setglobal(lvm,"KEY_B");
//And so on
Then define and register the isKeyDown function:

static int isKeyDown(lua_State *l)
{
     int key=luaL_checkint(l,1);

     lua_pushboolean(lvm,KEY[key]);

     return 1;
}

//...VM is initialized, etc.

//Now we register the functions
lua_pushcfunction(lvm,isKeyDown);
lua_setglobal(lvm,"isKeyDown");

Хотя не уверен, что это именно по-моему случаю. На сколько я понял в самом lua нет функции, которая бы считывала нажатие кнопки, быть может есть уже написанный вариант функции?

P.S. Пишу не для движка сталкера

Кидайте понты в предназначенных для этого местах.

@rosadman

Ссылка на комментарий

@Rosad,

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

Если же надо сделать это в Lua в его самостоятельном варианте, то придётся добавлять туда такие возможности самому. Причём это будет разумеется делаться по-разному для каждой платформы. Под виндой надо будет сделать Lua-обёртку над функциями API типа GetKeyState.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

Если вопрос всё же касается сталкера, то возможно поможет эта вещь:

http://www.amk-team.ru/forum/index.php?showtopic=6185&p=678277

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

Ссылка на комментарий

Ребят, кто подскажет как получить координаты мыши внутри сталкера?
(ПДА, Инвентарь, Главное меню и пр.)

З.Ы. Пытался получить через Lua самописной dll-кой, внутри которой была функция GetMousePos() {это Delphi}, но получал координаты, которые имели очень большую погрешность в зависимости от скорости передвижения мыши.

J4nJY55Swqo.jpg

Ссылка на комментарий

Gun12 
1) Не могу пропатчить
2) Даже если и пропатчить, то не наблюдаю нужного функционала.

Изменено пользователем ColR_iT
  • Нравится 1

J4nJY55Swqo.jpg

Ссылка на комментарий

 

Колбеки на клавиши и мышь.
[ТЧ/ЧН] Добавлены колбеки актора на нажатие/удержание/отпускание клавиш а также на вращение мышиного колеса и движение мыши. Коды колбеков:

нажатие - 123
отпускание - 124
удержание - 125
кручение колёсика мыши - 126
движение мыши - 127

Установка производится также, как и всех других колбеков в биндере:

self.object:set_callback(123, self.on_key, self) ... function actor_binder:on_key(key) log1("actor_binder:on_key "..key.." "..dik_to_bind(key) ) end
Снятие:

self.object:set_callback(123, nil)
Аргументы колбеков:


для клавиш - коды клавиш, для которых в скриптовом классе DIK_keys есть удобные обозначения. Среди прочего, там есть и коды для мышиных кнопок, т.е. таким образом будут ловиться также мышиные нажатия.
для колеса мыши аргумент - скорость вращения + 100000. Т.е. из аргумента надо вычесть 100000, чтобы получить нужное значение. У меня после вычитания всегда выходило +/-120
для движения мыши два аргумента - смещения мыши с последнего перемещения, также каждое + 100000. Это не координаты мыши, а выходит больше скорость перемещения.
Для предотвращения вылета при выходе из игры по Alt+F4 вызов данных колбеков на Alt заблокирован совсем. F4 разрешён только на нажатие.

 

Ссылка на комментарий

Gun12
Немного некрасивая реализация и нестабильная. Но все равно спасибо!
Придется искать более красивый выход из положения.

З.Ы. Хочу в ТЧ реализовать инфу о предмете при наведении курсора на него (как в ЗП). Вот для этого мне нужны координаты.

Изменено пользователем ColR_iT

J4nJY55Swqo.jpg

Ссылка на комментарий

[ТЧ/ЧН/ЗП] Добавлена функция получения расстояния до точки, на которую смотрим (игровой дальномер, который отображается под прицелом):

level.get_target_dist()
 

[ЧН] Добавлен метод определения объекта, на который смотрит камера. Метод добавлен к классу game_object, так что можно вызывать для любого клиентского объекта, хотя наверное самым разумным будет использовать актора. Пользуемся так:

local obj = db.actor:get_target_obj()
 

возвращает клиентский объект. Если ни на что не смотрим, то возвращает nil. Объекты без визуала так увидеть невозможно.

[ТЧ/ЗП] это-же реализовано в виде функции level.get_target_obj()

Изменено пользователем Gun12
Ссылка на комментарий

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   0 пользователей

    • Ни один зарегистрированный пользователь не просматривает эту страницу.
×
×
  • Создать...