Помощь - Поиск - Пользователи - Календарь
Полная версия: Очищение шарда от мусора
Город Мастеров > РЕДАКТОРЫ > Neverwinter Nights 2 Obsidian Toolset
Vanes
возможно где-то такое уже предлагалось, но я, честно говоря, такие вещи искать не привык - проще самому написать smile.gif

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

как пример, я рассматривал такой вариант: харбит локи, который собирает итемы + отдельные харбиты на каждом лутбеге... хотелось лучше smile.gif

придумал я вот что...
при создании каждого лутбега или в момент выкидывания игроком шмотки на землю на эти объекты создается своего рода ссылка... а именно - вейпоинты в отдельной локации, на которых хранитятся данные по этому объекту... само собой в локе есть харбит, которые по очереди эти вейпоинты чекает...
т.е. в итоге вместо кучи харбитов получаем один...
с одной стороны, за одним харбитом и следить проще... да к тому же время у меня из внешней бд запрашивается - а одно обращение в 10 сек к БД, это все таки не 100...
с другой, время выполнения скрипта понятно что дольше, да и не понятно вообще насколько все это оптимальней получается smile.gif

если кто что может подсказать по сути вопроса - буду рад...
ну или может кто свои системы писал...

собственно скрипты:

процедура, которая создает вейпоинт-ссылку
Neverwinter Script Source

void CreateGarbageLink( object oObject, int nDestroyTime )
{
    object oItem = CreateObject( OBJECT_TYPE_WAYPOINT, GARBAGE_WP, GetLocation( GetObjectByTag( GARBAGE_LOCATION )) );
    SetLocalObject( oObject, "oGarbageLink", oItem );
    SetLocalObject( oItem, "oGarbageItem", oObject );
    if( nDestroyTime>235900 ) nDestroyTime = 235900; // новый день
    SetLocalInt( oItem, "nDestroyTime", nDestroyTime );
}


харбит локи
Neverwinter Script Source

void main( )
{
    int nCurrentTime = GetTime( );
    int nDestroyTime;
    object oGarbageItem;
    int nDebugI = 0;

    object oWP = GetFirstObjectInArea( );
    while( oWP!=OBJECT_INVALID && nDebugI<300 ){
        nDestroyTime = GetLocalInt( oWP, "nDestroyTime" );
        if( nDestroyTime>=0 ){ // если нет переменной nDestroyTime, значит это не GARBAGE_WP
            if( nDebugI>250 ){ // если мусора больше 250 вещей - удаляем все подряд
                oGarbageItem = GetLocalObject( oWP, "oGarbageItem" );           
                DeleteLocalObject( oGarbageItem, "oGarbageLink" );
                DestroyObject( oGarbageItem );
                DeleteLocalObject( oWP, "oGarbageItem" );
                DeleteLocalInt( oWP, "nDestroyTime" );
                DestroyObject( oWP );       
            }else if( nDebugI>150 ){ // если мусора больше 150 вещей - удаляем итемы ( лутпаки не трогаем )
                oGarbageItem = GetLocalObject( oWP, "oGarbageItem" );
                if( GetObjectType( oGarbageItem )==OBJECT_TYPE_ITEM ){
                    DeleteLocalObject( oGarbageItem, "oGarbageLink" );
                    DestroyObject( oGarbageItem );
                    DeleteLocalObject( oWP, "oGarbageItem" );
                    DeleteLocalInt( oWP, "nDestroyTime" );
                    DestroyObject( oWP );                   
                }
            }else if( nDestroyTime<=nCurrentTime ){
                oGarbageItem = GetLocalObject( oWP, "oGarbageItem" );           
                DeleteLocalObject( oGarbageItem, "oGarbageLink" );
                DestroyObject( oGarbageItem );
                DeleteLocalObject( oWP, "oGarbageItem" );
                DeleteLocalInt( oWP, "nDestroyTime" );
                DestroyObject( oWP );
            }
        }
        oWP = GetNextObjectInArea( );
        nDebugI++;
    }
}


скрипт на OnUnacquire модуля
Neverwinter Script Source

void main( )
{
    object oItem = GetModuleItemLost( );
    object oPC = GetModuleItemLostBy( );
    object oNewOwner = GetItemPossessor( oItem );   
   
    // проверяем только вещи игроков + вещь должна быть именно выложена, а не удалена
    if( GetIsPC( oPC ) && oItem!=OBJECT_INVALID && oNewOwner==OBJECT_INVALID ){
        int nCurrentTime = GetTime( );
        CreateGarbageLink( oItem, nCurrentTime+GARBAGE_DESTROY_DELAY );       
    }
}


скрипт на Acquire модуля (ну и по сути теже команды выполняются на скрипте OnDisturb лутбега, когда из него вытаскивают последнюю шмотку)
Neverwinter Script Source

void main( )
{
    object oItem = GetModuleItemAcquired( );

    object oGarbageLink = GetLocalObject( oItem, "oGarbageLink" );
    if( oGarbageLink!=OBJECT_INVALID ){
        DeleteLocalObject( oItem, "oGarbageLink" );
        DeleteLocalObject( oGarbageLink, "oGarbageItem" );
        DeleteLocalInt( oGarbageLink, "nDestroyTime" );
        DestroyObject( oGarbageLink );                   
    }
}
Lex
Цитата(Vanes @ Jan 4 2008, 23:32) *
придумал я вот что...
при создании каждого лутбега или в момент выкидывания игроком шмотки на землю на эти объекты создается своего рода ссылка... а именно - вейпоинты в отдельной локации, на которых хранитятся данные по этому объекту... само собой в локе есть харбит, которые по очереди эти вейпоинты чекает...
т.е. в итоге вместо кучи харбитов получаем один...

а что мешало при создании лутбега его запоминать (SetLocalObject) на какой-нить сторонний объект-анализатор (им у тебя локация выступает) и в ХБ этого объекта бешать по списку запомненных лутбегов? (попутно подчищая список, если какой-то лутбег перестал быть валидным). Или хранение так объекто - нагрузка для сервера?

ну или если влом подчищать - просто освобождать ячейку, чтобы следующий лутбег писался в нее, а не Количество Ячеек + 1.
Vanes
использование локи (как вариант еще был инвентарь нпц) удобен тем, что есть команды GetFirstObject/GetFirstItem... т.е. стек по сути формируется автоматически... с инвентарем сложнее, а вот при создании нового объекта в локе он добавляется в стек LIFO, так что я точно уверен где те объекты, которые надо удалить в первую очередь...
Edwin
Я не видел нвн 2-3 года, предупреждаю.

Но как мне кажется все это излишне. Сделать можно намного проще.
Создаем очередь FIFO через simply linked lists. При падении обьекта, добавляем в очередь поинтер на обьект.
Задаем максимальную длинну очереди либо константу (скажем 50-70) в зависимости от популярности шарда, либо делаем длинну динамичной, прямопропорциональной кол-ву игроков онлайн (скажем 5-20 лежащих объектов на 1го игрока, ну и тогда меняем длинну на онЕнтер игроков или как там...)
Соответственно когда упавших объектов на шарде становится больше заданого числа, самые старые объекты которые лежат уже несколько минут мы начинаем удалять. Что бы моментально доставать последний элемент, можно все это закодить через doubly linked circular lists, если хочешь.
Если обьект вовремя подобран - находим в очереди и удаляем поинтер. Чаще всего он будет в самом начале листа.
Все просто.

Кодится немножко дольше, зато оптимальнее, на мой взгляд, раз в сто.
Vanes
Цитата
Создаем очередь типа FIFO через simply linked lists. При падении обьекта, добавляем в очередь поинтер на обьект... Кодится немножко дольше, зато оптимальнее, на мой взгляд, раз в сто...

согласен
другое дело, что это нужно кодить smile.gif
да и речь идет, боюсь, не о 50-70, а скорее о 200-300 объектах... в этом плане я по крайней мере уверен, что локация столько объектов выдержит...

Добавлено через 2 минуты 9 секунд

Цитата
через doubly linked circular lists

вопрос - чем это реализовывать в тулсете ??? локалками ???
Edwin
QUOTE
вопрос - чем это реализовывать в тулсете ??? локалками ???

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

Но если я его понимаю правильно, то нет, на весь шард должен быть один лист из 200-300 элементов и он должен быть глобальным.
Обычно "глобал" это синоним "плохо", но не в данном случае.
Не думаю что это займет очень много места в памяти. Что бы узнать примерно, можно посмотреть через std::cout<<300*sizeof(object*); (в том случае если в нвн юзают object для лута, я не знаю). Результат будет в байтах.
dumbo
Vanes, объекты вешай на локу, при входе первого PC в локу запускай само-повторяющийся скрипт проверки на "старье", при выходе последнего - останавливай. хб - зло.
Vanes
Цитата
Не думаю что это займет очень много места в памяти. Что бы узнать примерно, можно посмотреть через std::cout<<300*sizeof(object*); (в том случае если в нвн юзают object для лута, я не знаю). Результат будет в байтах.

не думаю что это реально организовать силами тулсета smile.gif

Цитата
Vanes, объекты вешай на локу, при входе первого PC в локу запускай само-повторяющийся скрипт проверки на "старье", при выходе последнего - останавливай. хб - зло.

да не вопрос... вместо харбита можно и псевдохарбит организовать.. вопрос не в этом...
вопрос в том, в каком виде хранить эти объекты ??? или точнее как их потом грамотно доставать для проверки...
Edwin
QUOTE
не думаю что это реально организовать силами тулсета smile.gif


Если ты про листы, то в чем может быть проблема? Мне просто интересно.
azathoth
тупо, просто, быстро: лист (приорити если важно время удаления), на объекты цеплять ссылки ясное дело не стоит -- игрок подберёт и отлогинится -- на инвалид обджекте ссылок на следующий не найти smile.gif поинты и инфой -- вариант. ссылка на первый+последний на локации или модуле.

объекты доставать так: если где-то кладётся мусор -- то в том же "онДроп" если превышен лимит на писят штук выбираем первый по ссылке с модуля и дестроим, обновляем ссылки. (тут конечно поле для творчества -- например динамическое кол-во объектов или можно проверить дестрой тайм и не удалять пока если мусора мало, а если дестрой тайм вышел, то проверить ещё и следующего и т.д)

во такая вот продвинутая система сборки -- не обещается что мусор будет удалён через указаное время и не обещается что он сколько-нибудь долго вообще пролежит.

по хорошему надо два списка -- брошеные итемы - мусор как он есть и лутбаги с очередью подлинней.

если же важно ДелетеТайм -- то к каждому ОнДропу прицеплять ДелайКомманд ЭкзекутСкрипт ДестройОбджектСелф.

вот и все идеи на заданую тему smile.gif
virusman
Цитата(Edwin @ Jan 5 2008, 06:43) *
Если ты про листы, то в чем может быть проблема? Мне просто интересно.
Эдвин, NWScript - это НЕ C++. Работа с памятью в НВН не предусмотрена, классы и STL там тоже напрочь отсутствуют. Чтобы советовать, как оптимальней что-то сделать в NWScript, надо хоть раз открыть тулсет.
Edwin
Херово, разработчики угробили потенциал ООП. Кто ж знал...
virusman
Цитата(Edwin @ Jan 5 2008, 12:59) *
Херово, разработчики угробили потенциал ООП. Кто ж знал...
Не угробили, а просто не реализовали. NWScript - это не урезанный C++, а самостоятельный язык программирования, со своим компилятором, байт-кодом и виртуальной машиной.
Existor
Цитата(Vanes @ Jan 4 2008, 23:32) *
придумал я вот что...при создании каждого лутбега или в момент выкидывания игроком шмотки на землю на эти объекты создается своего рода ссылка... а именно - вейпоинты в отдельной локации, на которых хранитятся данные по этому объекту... само собой в локе есть харбит, которые по очереди эти вейпоинты чекает...т.е. в итоге вместо кучи харбитов получаем один...

А что, если при создании каждого конкретного лутбега вешать отложенную на нужное время команду DestroyObject()?
У нас, насколько я помню, именно так и реализовано. То, что скидывают игроки, пропадает раз в 3 часа само собой врезультате релоада модуля. Прецендентов потери производительности врезультате "засирания" в НвН1 замечено нами не было. Хотя по э1 помню, была чистка вообще всех предметов, не помню как Валлео это реализовал, но могу глянуть.
Vanes
Цитата
А что, если при создании каждого конкретного лутбега вешать отложенную на нужное время команду DestroyObject()?

не делаю того, за чем не могу проследить smile.gif
где, например, гарантия того, что DelayCommand просто не затеряется и вообще не выполнится ???
если уж самое стабильное - харбит, и тот не каждые 6 сек запускается, в случае сильной загруженности сервака, то что уж говорить про DelayCommand, который мы 10 минут назад запустили smile.gif
и еще такой вопрос... как прервать выполнение этой команды, если предмет был поднят раньше времени ???

Добавлено через 1 минуту 52 секунды

Цитата
Прецендентов потери производительности врезультате "засирания" в НвН1 замечено нами не было.

не знаю как общая производительность, но то что локация грузится намного дольше, если в ней кучу итемов набросать на пол - это проверено smile.gif
Existor
Цитата(Vanes @ Jan 5 2008, 15:47) *
не делаю того, за чем не могу проследить где, например, гарантия того, что DelayCommand просто не затеряется и вообще не выполнится ???

Практика НвН1 показывает, что все работает нормально. В нвн2 - покажет она же.
Цитата
если уж самое стабильное - харбит, и тот не каждые 6 сек запускается, в случае сильной загруженности сервака

В нвн1 в случае сильной загруженности сервака ХБ не пропадает(по крайней мере не сталкивался), а увеличивается время разницы между срабатыванием. Например увеличивается с 6ти до 10 секунд реалтайма.
Цитата
то что уж говорить про DelayCommand, который мы 10 минут назад

Учитесь доверять машине =)
Цитата
как прервать выполнение этой команды, если предмет был поднят раньше времени ???

Суть метода в том, что создается контейнер с определенным временем жизни, который будет уничтожен со всем оставшимся в нем содержимым, когда его время придет. На содержимом его никаких отложенных дестроев нет.
Lex
Цитата(Existor @ Jan 5 2008, 15:25) *
А что, если при создании каждого конкретного лутбега вешать отложенную на нужное время команду DestroyObject()?

с этим бывают проблемы, если двигать игровое время. Хотя на шардах это не актуально.
Цитата(Vanes @ Jan 5 2008, 15:47) *
и еще такой вопрос... как прервать выполнение этой команды, если предмет был поднят раньше времени ???

а зачем? время придет - удалится, если есть чему удаляться. Нет - ну и слава богу smile.gif
Vanes
я про ситуацию, когда шмотку выкинули, мы на нее повесили DestroyObject через 5 минут, скажем... а за эти 5 минут шмотку подобрали...
вот в этой ситуации возможно будет отменить удаление шмотки ???
virusman
Цитата(Vanes @ Jan 5 2008, 17:09) *
я про ситуацию, когда шмотку выкинули, мы на нее повесили DestroyObject через 5 минут, скажем... а за эти 5 минут шмотку подобрали...
вот в этой ситуации возможно будет отменить удаление шмотки ???
Почему бы и нет? При назначении DelayCommand повесить на шмотку переменную, а на OnItemAcquired её снимать. Если переменная снята - скрипт удаления не удалит шмотку.
Lex
так это.. вешай не на шмотку, а на контейнер. Ты же под все выкидываемое контейнер делаешь (лутбэг).. или я что-то пропустил? Вешай на контейнер исполнение простенькой функции отчистки + удаление контейнера.
Vanes
ну по сути понятно...
осталось убедиться, что DelayCommand не сбивается при больших значениях времени задержки...
Existor
НвН1: 3 минуты - в полевых условиях полет нормальный. А больше, имхо, смысла и нет откладывать. Игрокам хватит 3 минуты времени, чтобы понять, нужно ли им содержимое лутбэга.
Если речь идет про дроп с игрока при смерти - так он пропадать не должен вообще. Если игрок дропнул вещь - бывает, но обычно не напрягает(тоесть сознательным завалом локаций дропом обычно никто не занимается, да и не так это страшно во всех возможных смыслах). Основной мусор создается дропом с мобов, а вот с ним задерженный дестрой контейнера справляется на ура.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.
Invision Power Board © 2001-2018 Invision Power Services, Inc.