Andrey07071977 18 Опубликовано 20 Декабря 2011 (изменено) Некоторое время назад malandrius описал как создать тестовый полигон для скриптов. Если интересно, вот немного модифицированная версия. Добалена возможность исполнять отдельную функцию и передавать в нее аргументы - что очень помогает при тестировании, например callbacks. --[[ Call functions in protected environment (original: http://www.amk-team.ru/forum/index.php?showtopic=6458#entry258260) @param string sType - "file" or "chunk". Required. TODO: "chunk" functionality @param string sName - file path. Optional. Path of the file to load relative to bin, will use default (aa_test.script) if nil. @param boolean bFunc - execute one function with arguments. Optional. By default will execute function test(...) @param table tArgs - arguments for function above. Optional. TODO: find out why ... didn't work. @return object oResult - function execution results (if any) --]] function sandbox(sType, sName, bFunc, tArgs) local sStatus, oResult = pcall(exec, sType, sName, bFunc, tArgs) if sStatus == false then --ODS("~C07[~T] ~C0C[ERROR] ~C07in ~C0Asandbox()~C07 call - ~C0B"..tostring(sResult).."~C07") --// Ouput to screen or log else return oResult end end --[[ Execute file or chunk (original: http://www.amk-team.ru/forum/index.php?showtopic=6458#entry258260) @param string sType - "file" or "chunk". Required. TODO: "chunk" functionality @param string sName - file path. Optional. Path of the file to load relative to bin, will use default (aa_test.script) if nil. @param boolean bFunc - execute one function with arguments. Optional. By default will execute function test(...) @param table tArgs - arguments for function above. Optional. TODO: find out why (...) didn't work. --]] function exec(sType, sName, bFunc, tArgs) local t = tArgs or {} if sType == "file" then if sName then local sReturn = assert(loadfile(sFilePath)) if type(sReturn) == "function" then if bFunc then sReturn() test(t) --// execute specific function with arguments t else sReturn() end else --ODS("~C07[~T] ~C0C[ERROR] ~C07in ~C0Aexec()~C07 call - ~C0B"..tostring(sReturn).."~C07") --// Ouput to screen or log return end else local sFilePath = "..\\gamedata\\scripts\\aa_test.script" local sReturn = assert(loadfile(sFilePath)) if type(sReturn) == "function" then if bFunc then sReturn() test(t) else sReturn() end else --ODS("~C07[~T] ~C0C[ERROR] ~C07in ~C0Aexec()~C07 call - ~C0B"..tostring(sReturn).."~C07") --// Ouput to screen or log return end end elseif sType == "chunk" then --// TODO: chunk functionality return else --ODS("~C07[~T] ~C0C[ERROR] ~C07in ~C0Aexec() ~C07call - invalid sType: ~C0B"..tostring(sType).."~C07") --// Ouput to screen or log end end Примечания - используя Lua перехватчик от alpet, который помимо всего прочего (alpet спасибо!), позволяет выводит строки в одельную консоль и сдвигать ее на второй монитор. Callback: function on_actor_hit(oObj, fAmount, vDirection, oWho, iBoneIndex) aa_util.sandbox("file", "..\\gamedata\\scripts\\aa_test1.script", true, {oObj, fAmount, vDirection, oWho, iBoneIndex}) end aa_test1.script: function test(tbl) oObj, fAmount, vDirection, oWho, iBoneIndex = unpack(tbl) local sWhoName = oWho:character_name() local sWpn = oWho:active_item():section() or oObj:active_item():section() local sBodyPart = aa_util.get_body_part(iBoneIndex) local fActorHealth = oObj.health if fActorHealth <= 0.5 then oObj.health = 1 end -- вевести все на экран или в лог (я использую Lua перехватчик, поэтому вызовы закомментировал - думаю разберетесь) --[[ ODS("~C07[~T] ~C0E[INFO] ~C06Actor hit details: ----------------------------~C07") ODS("~C07[~T] ~C0E[INFO] ~C07Hit by: ~C0B"..sWhoName.."~C07") ODS("~C07[~T] ~C0E[INFO] ~C07Amount: ~C0D"..string.format("%2.1f", fAmount*100).."~C07") ODS("~C07[~T] ~C0E[INFO] ~C07Body P: ~C0B"..sBodyPart.."~C07") ODS("~C07[~T] ~C0E[INFO] ~C07Health: ~C0B"..string.format("%2.1f", fActorHealth*100).."~C07") ODS("~C07[~T] ~C0E[INFO] ~C07Weapon: ~C0B"..sWpn.."~C07") --]] end П.С. Если будут проблемы - пишите, помогу отладить. Прежде всего - спасибо за x-ray extensions и справочник по функциям! Трудно представить сколько времени и усилий было затрачено. Вопросы: 1. При использовании оператора ... у меня выдавалась ошибка по типу no such operator defined. Пришлось использовать table, хотя во многих скриптах этот оператор используется. Чем может быть вызвано? 2. Если будет время, напиши небольшой how-to по xray extensions (r18). Видел люди выкладывали то что извеснто на данный момент, но там далеко не все. Изменено 20 Декабря 2011 пользователем Andrey07071977 Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 20 Декабря 2011 Функция exec принимает аргументом sName, по наличию которого вызывается функция assert, но в нее передается неопределенный аргумент sFilePath Пардон, невнимательно повырезал функции Luacap - у меня sFilePath назначается в ExpandPath(sName), потом идет проверка на существование файла FileExists(sFilePath) Андрей Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 20 Декабря 2011 xStream И вообще, лучше б отписался по сендбоксу. У тебя критика конструктивная получается. :-P Полностью с тобой согласен, бери пример Насчет венгерки - у каждого свои стандарты. Главное чтоб они были и их придерживались, а детали это уже не важно - кому как легче. Artos Насчет проблемы с оператором '...' - что-то непонятно.. Точно так и делал... Теперь думаю что зря я грешил на (...). Вечером перепроверю, хотя по сути использование таблицы - теже помидоры только вид сбоку, но задело - надо разобраться. Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 7 Января 2012 Ну то что не пропадут даром - не сомневайся . Лично для себя вижу много чего интестного, как и для мода, так и просто поучиться. Поэксперементирую, напишу фидбэк подробней. Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 7 Января 2012 (изменено) xStream Вчера наконец нашел время пограть с sandbox/timers, вот небольшой фидбэк: 1. В таймерах строка local self.trigger_time = time_global() + time_seconds * 1000 изменил на (убрал local) self.trigger_time = time_global() + time_seconds * 1000 2. Можно-ли регистрировать функцию калбэка находящююся в классе? Хотел инкапсулировать определенный функционал в классе, но не срабатывает регистрация типа: event("actor_hit"):register(sample_class:on_actor_hit) 3. Заметил интерсную особенность - если вызывать мою песочницу из твоих калбэков, то файл перезагрузит сам себя на лету. Т.О. можно делать изменения не выходя из игры и в protected environment Изменено 7 Января 2012 пользователем Andrey07071977 Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 7 Января 2012 (изменено) код симбиона охрененно трудно сопроводжаемый не автором - не согласен. Неделю ковыряюся в кодах смбиона, все отлично читается и воспринимается, код достаточно хорошо прокомментирован. Изменено 7 Января 2012 пользователем Andrey07071977 Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 7 Января 2012 (изменено) Artos забыл добавить required brain.script в начале модуля, от того и происходит - под снос, plz Изменено 7 Января 2012 пользователем Andrey07071977 Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 7 Января 2012 Artos тут уже ты перебираешь, она сюда и выложила первый вариант без манула, для так сказать предварительного просмотра Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 8 Января 2012 Gun, код то выложи Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 10 Января 2012 (изменено) 7.9 держи Изменено 10 Января 2012 пользователем Andrey07071977 Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 11 Января 2012 (изменено) Перечитав тему, примерно так представляются требования для универсального хранилища: 1. У каждого bindable объекта есть метод save(…). Метод знает как проверять и сохранять данные в зависимости от типа (number, table, etc…). 2. Данные сохраняются в специально созданный объект хранилище. Pstor не используется (оставим для оригинального функционала) 3. По мере надобности (лимит 8К?) создаются дополнительный(е) хранилища (transparent to end user) и присоединяются к родительскому объекту наравне с уже созданным 4. Объект хранилище содержит информацию про тот объект которому принадлежит (parent object) 5. Данные можно получить методом obj:read() который пройдет по всем созданным хранилищам данного объекта и считает нужную информацию. 6. Есть некий универсальный (ни кому не принадлежащий) объект с методами save() and read() который можно использовать в случаях когда нет логического родителя – примерно то что сделала xStream, как я понял. Если что не так выразил поправьте и дополните - пытаюсь разобраться с хранилищами П.С. Сервер глючит не по детски Изменено 11 Января 2012 пользователем Andrey07071977 Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 11 Января 2012 malandrinus, Как я понимаю, класс может иметь только один метод-подписчик: mt.__call = self.method_to_call Как быть в ситуациях когда в классе несколько методов которые необходимо подписать на разные события? Например, есть класс "actor_hit_effect", в нем два метода-подписчика - один на actor_hit, другой на item_use. Или же я что-то недопонял? Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 11 Января 2012 (изменено) xStream, спасибо, перечитаю твой пост и пройдусь по замыканиям, пока что я туплю не по детски на эту тему... Такое впечатление, что крутится где-то в голове но пока не могу расставить точки над i. То есть, для моего примера необходимо создать два метода? function object_execute(obj) local _proxy = obj local function _call(...) return _proxy:execute(...) end return _call end function object_execute_1(obj) local _proxy = obj local function _call(...) return _proxy:execute_1(...) end return _call end Да, я знаю про что ты говорила Понял, спасибо. Но теорию все равно нужно поднатаскать.. уж больно много пробелов Изменено 11 Января 2012 пользователем Andrey07071977 Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 11 Января 2012 (изменено) Kamikazze, Во-вторых эта твоя "оптимизация" привела к тому, то ты не узнаешь, если сериализованная таблица вылезла за размеры хранилища. Разве это не проверка перед сохранением? for key, val in pairs(storage) do lua_type = type(val) num_type = allowed_types_rev[lua_type] err = num_type == nil if not err then -- calculate variable len for saving elm_len = 1 + string.len(key) + 1 if lua_type == 'boolean' then elm_len = elm_len + 1 elseif lua_type == 'number' then elm_len = elm_len + 4 else if lua_type == 'table' then val,err = table.serialize(val) if err or val:len() >= max_packet_len then --/ тип данных или длина строки недопустимы --log("save:var_name=[%s],err=[%s]:<%s>", key, err, "Warning!") val,err = "",true end end elm_len = elm_len + val:len() + 1 end if not err then --/ check room to save if len + elm_len > max_packet_len then -- element is full of data -- create new element to store variables -- ugly hook, but fastest solution :) tail_pk = new_storage_element() len = elm_len else -- still have room to save len = len + elm_len end --write variable to tail tail_pk:w_u8(num_type) tail_pk:w_stringZ(key) if lua_type == 'boolean' then tail_pk:w_u8(val) elseif lua_type == 'number' then tail_pk:w_float(val) else tail_pk:w_stringZ(val) end end end end Изменено 11 Января 2012 пользователем Andrey07071977 Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 11 Января 2012 (изменено) Что если проверять при каждом перемещении в хранилище на этапе разработке/тестировании - по идее, все bottlenecks должны быть найдены на этих стадиях. А уже в финале оставить лишь проверку перед сохранением, в крайнем случае какие-то данные не сохранятся. malandrinus, примерно так и преставлял, потом приведенный пример сбил с толку. class "some_luabind_class" function some_luabind_class:__init() local mt = getmetatable(self) mt.__call = self.method_to_call end function some_luabind_class:method_to_call(arg1, arg2) end local slot_desc = {signal = "signal_name", fun = some_luabind_class()} Изменено 11 Января 2012 пользователем Andrey07071977 Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 11 Января 2012 (изменено) malandrinus, если с обычном методом ты имеешь ввиду пример с глобальной функцией - то там все понятно. Не совсем понял про методы класса - думаю имеет смысл перенести пример, который ты привел позже, в первый пост. Пример довольно наглядный Изменено 11 Января 2012 пользователем Andrey07071977 Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 11 Января 2012 Artos, компрессор-сериализатор это о котором ты здесь писал? Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 11 Января 2012 Artos, выложишь доработанный? Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 13 Января 2012 Есть нечто, объявленное как class "XXX" (YYY). Чем является XXX? Биндером, наследником, чем-то другим? Чем-то другим - метатаблицей . Вообще, это напоминает спор о венгерке... Жаль что в том обилии полезностей, что выложила xStream ты усмотрел только лишь названия классов. Поделиться этим сообщением Ссылка на сообщение
Andrey07071977 18 Опубликовано 14 Января 2012 (изменено) xStream, Поясни работу проверки зависаний (hangCheck()). Попытался вывести в лог сообщение о зависании, но так и не получилось, хотя насиловал код и саму игру как только мог. Колбэки зависали, это видно по выводам в дополнительную консоль из luacap алпета. Вызов поставлен в top level event trigger – на пример в actor_binder:on_item_use(itm) идет следующий вызов event(”item_use”):hangCheck():trigger({itm = itm}) , затем в методе подписчике выставляю e:setFingerprint(”on_item_use is hanging blah blah….”) . Сами ивенты работают прекрасно. Также, по версиям файлов – так как работа над всем этим хозяйством продолжается, почему бы тебе не использовать github.com для source control. Очень удобный интерфейс, простота использования, все доступно онлайн, подсветка изменений версий кода, apps for iphone/ipad/android/etc… Люди заинтересованные в модифицировании имеют возможность сделать так называемую ”вилку” (fork) твоего кода в свою репозитори, при этом будет видно откуда была сделана вилка (кто оригинальный разраб). Ну и тд и тп ☺ Добавлено через 46 мин.: malandrinus У меня своя реализация, я её активно использую - выкладывай . Перепробовал уже с пяток разных методов, ни один не нравится, последнее на чем остановился это то с чего начал (1/uninitialized). С assert к сожалению ты прав, не всегда срабатывает, хотя наиболее изящный, на мой взгляд, способ. П.С. Поддерживаю Monnoroch, только немного наоборот: strict_subscribe с вылетами, а subscribe, если уже подписались, просто выводит в лог сообщение (чтоб не гадать почему колбэк не срабатывает) и нечего не делает. Изменено 14 Января 2012 пользователем Andrey07071977 Поделиться этим сообщением Ссылка на сообщение