• Прежде, чем задать вопрос, пожалуйста, убедитесь, что такой вопрос не задавался раньше. Старайтесь описать суть вопроса как можно подробней. • Прежде, чем опубликовать ответ на вопрос, пожалуйста, убедитесь, что обладаете необходимыми для этого знаниями. Старайтесь cформулировать суть ответа как можно лаконичней. • При желании ответить в приватном порядке, пожалуйста, воспользуйтесь ЛС. • При желании поблагодарить ответившего, пожалуйста, воспользуйтесь кнопкой "+" полезного сообщения.
Сообщения, не относящиеся к вопросам по скриптам Papyrus, ответам на них или уточнениям, являются оффтопом и могут быть удалены.
Красное солнце Есть вопросы по скриптам Papyrus? Пиши не в ЛС, а в эту тему.
Князь_Далик, для каждого маркера потребуется пара "квест. задача + алиас". Скрипт для любого кол-ва маркеров (насколько хватит алиасов, нужен тест):Е
Код
Scriptname _TESTTEST43 Extends ObjectReference ; Скрипт на контейнер.
Message Property pxNotNoted Auto ; Сообщение 1 ;0 - доступ к инвентарю сундука ;1 - забрать все в инвентарь игрока ;2 - добавить маркер
Message Property pxNoted Auto ; Сообщение 2 ;0 - доступ к инвентарю сундука ;1 - забрать все в инвентарь игрока ;2 - удалить маркер
Quest Property MMarker Auto MiscObject Property chestparts Auto Int Property piNoted = -1 Auto Hidden
EVENT OnActivate(ObjectReference akActionRef) GoToState("Empty") Int button IF piNoted < 0 button = pxNotNoted.Show() ELSE button = pxNoted.Show() ENDIF if !button Activate(Game.GetPlayer(), true) elseif button == 1 removeAllItems(Game.GetPlayer(), true) Game.GetPlayer().AddItem(chestparts) Delete() ELSEIF piNoted < 0 button = 0 WHILE button < 128 && (MMarker.GetAlias(button) AS ReferenceAlias).GetReference() ; Вместо 128 указать реальное кол-во алиасов. Напр., если последний номер равен 15, общее кол-во = 16. ; Алиасы должны иметь ID-номера строго по порядку от 0 до Х (0, 1, 2, 3, ..., X). ; Чтобы нумерация была строгой, алиасы нельзя удалять после создания. ; Квестовые задачи должны нумероваться строго по порядку от 0 до Х. button += 1 ENDWHILE IF button < 128 ; Вместо 128 указать свое число. piNoted = button (MMarker.GetAlias(button) AS ReferenceAlias).ForceRefTo(Self) MMarker.SetObjectiveDisplayed(button, true) ELSE Debug.MessageBox("Слишком много активных маркеров") ENDIF ELSE MMarker.SetObjectiveDisplayed(piNoted, false) (MMarker.GetAlias(piNoted) AS ReferenceAlias).Clear() piNoted = -1 ENDIF GoToState("") ENDEVENT
STATE Empty EVENT OnActivate(ObjectReference akActionRef) ENDEVENT ENDSTATE
Приветствую. Хотелось задать вопрос об одной проблеме, непонятной проблеме. Проблема такая. В лог папирус периодически кидает сообщение об ошибке:
Error: Cannot look at a None target stack: (00000014)].Actor.SetLookAt() - "" Line ? [Headtracking (B9007959)].HeadtrackingScript.OnUpdate() - "headtrackingscript.psc" Line 32
Есть код в скрипте:
Код
function OnUpdate()
if PlayerRef.IsWeaponDrawn() || PlayerRef.GetAnimationVariableBool("bIsRiding") || PlayerRef.GetAnimationVariableBool("IsFirstPerson") if PlayerRef.GetAnimationVariableBool("IsNPC") PlayerRef.SetLookAt(PlayerRef as objectreference, false) PlayerRef.ClearLookAt() PlayerRef.SetAnimationVariableInt("IsNPC", 0) endIf self.RegisterForSingleUpdate(1.00000) return elseIf !PlayerRef.GetAnimationVariableBool("IsNPC") PlayerRef.SetAnimationVariableInt("IsNPC", 1) endIf if game.GetCurrentCrosshairRef() != none && math.Abs(PlayerRef.GetHeadingAngle(game.GetCurrentCrosshairRef())) < 90 as Float PlayerRef.ClearLookAt() PlayerRef.SetLookAt(game.GetCurrentCrosshairRef(), false) else PlayerRef.ClearLookAt() PlayerRef.SetLookAt(PlayerRef as objectreference, false) endIf self.RegisterForSingleUpdate(0.250000) endFunction
И вроде как есть условие проверки на None: if game.GetCurrentCrosshairRef() != none ..но все равно периодически кидает указанную выше ошибку.
В чем здесь может быть проблема, может проверка какая другая нужна, может дополнительная?
modgms_user, нативные функции в этих скриптах выполняются очень медленно. А у тебя их досточно много между проверкой на None и установкой цели. Может, игрок успевает убрать прицел с цели, пока всё это выполняется. А даже если и не так, всё-равно лажа это всё. Автору надо разобраться с переменными. И сделать так, чтоб во всем скрипте был только один вызов GetCurrentCrosshairRef() с занесением результата в переменную:
нативные функции в этих скриптах выполняются очень медленно. А у тебя их досточно много между проверкой на None и установкой цели. Может, игрок успевает убрать прицел с цели, пока всё это выполняется.
Спасибо за наставление, посыл понятен. Действительно, автор другой, это redux-вариант мода Headtracking, что в сборке SLMP-GR, может ему тоже ссыль на ответ отправлю, или уже исправленный скрипт. Самостоятельно, в основном, только правки косяков в скриптах модов делались, которые авторы оставили по тем или иным причинам, чтобы игра стабильнее была. Подобные мысли про тормоза тоже были, но как-то не дошло, что значение Game.GetCurrentCrosshairRef() может измениться и занести заранее значение в переменную будет разумнее, ну и руки не дошли, поэтому, наверное, все же было полезно узнать здесь. Спасибо еще раз.
Добавлено (22 Декабря 2017, 09:05) --------------------------------------------- Приветствую еще раз. Есть другой вопрос по ошибке в скрипте. Есть скрипт из мода Worlds dawn, начинается так:
Event onEffectStart(Actor akTarget, Actor akCaster) ValueMod = self.GetMagnitude()/100.0
Бывает, порой часто, что кидает в лог следующую ошибку:
Error: Unable to call GetMagnitude - no native object bound to the script object, or object is of incorrect type stack: [None].XTD_FortifyDecimal.GetMagnitude() - "" Line ? [None].XTD_FortifyDecimal.OnEffectStart() - "xtd_fortifydecimal.psc" Line 4
Часто группа таких ошибок находится недалеко от конца лога, в той сессии, когда произошел вылет игры. Пробовал добавлять проверку "if self as XTD_FortifyDecimal", но не прокатывает. Что-то можно ещё сделать, проверку какую, или нужно в других частях мода искать причину?
Event onEffectStart(Actor akTarget, Actor akCaster) IF !akTarget RETURN ENDIF ValueMod = GetMagnitude()/100.0 if IsNegative ; ...
В процессе проверки нужно учитывать, что изменения не повлияют на уже запущенные скрипты. А вообще, я бы не рассчитывал на столь неуважительно обращающегося с weaponSpeedMult.
Изменение репутации для пользователя modgms_user
modgms_userOffline
Сообщение №2587
написано: 22 декабря 2017, 19:52
| Отредактировано: Multigone - 22 апреля 2020, 13:09
IF !akTarget тоже не прокатило, такая же ошибка в лог, только номер строки соответствующий, проверялось, естественно, с загрузкой игры, где мод ещё был выключен и скрипт еще не был загружен. Возникла дурацкая мысль и вопрос, связанный с этим. Если, допустим, сделать условие "if self.GetMagnitude()" и спрятать под ним остальную часть, выполнится ли та основная часть кода, до endif, если будет ошибка в этом условии или же тупо будет проигнорирована строка условия if и будут тупо выполняться все остальные строки под ним? Тоесть, будет первая строка условия "if self.GetMagnitude()" и под ней, допустим, три строки кода, а потом endif и в случае ошибки перепрыгнет сразу за endif или будет просто дальше выполнять те три строки кода. Интересно узнать, как будет работать в такой ситуации. Может еще что-то можно попробовать?
modgms_user, дались тебе эти мутные SKSE-шные скрипты "If" проверка, которую ты описал, от ошибки в логе не избавит. Потому что функция таки выполняется, а проверяется уже возвращенное из неё значение. Если функция возвращает Bool, то "if func()" - это то же самое, что "if func() == true". А если возвращает Int или Float, то, скоре всего, "if func()" - это то же самое, что "if func() != 0". Во всяком случае, в Си так, а в папирусе не проверял.
Dsion, немного дополню. В случае, если Х - переменная Bool, писать (IF X == true) нет никакого смысла.
Код
IF X ; Если Х истинно, то... IF X == true ; Если (X == true) истинно, то...
Переменная (X) и результат выражения (X == true) всегда имеют одинаковые значения, но во втором случае затрачивается лишнее действие на вычисление результата.
Multigone, в описанном выше моде Worlds dawn, в одном из скриптов видел условие "if target && target != NONE", а ведь по той же логике с условиями "if target" это то же, что и "target != NONE" и второе там избыточно и можно обойтись вместо этого просто условием "if target"? Считаю так, но мало ли, может в папирусе свои особенности еще какие есть.
По ошибке с self.GetMagnitude(), видимо все же, как писал выше о глупой идее, то даже если возникнет ошибка в условии "self.GetMagnitude()" и тогда будет пропущено всё, что стоит вложенное в это условие, до endif. Это конечно все равно будет вызывать ошибку и её регистрацию в логе, но по крайней мере можно предотвратить деструктивные изменения в дальнейшем скрипте, да и ошибка бы была в любом случае, но в условии, по крайней мере, не будет запущен спрятанный под условием код. Хотя бы как временное решение, меньше зло. Может еще что можно придумать, чтобы предотвратить ошибку с self.GetMagnitude() на OnEffectStart, в озвученном выше скрипте? Пробовал прятать код под условия "if self as XTD_FortifyDecimal", "if akTarget"(и предложенный обратный "if !akTarget" с return), но не сработало, так и выдает ошибку, вот, пока только временно, засунув в условие self.GetMagnitude(), хоть как-то предотвратить выполнение кода, точнее последствий его выполнения, в виде искасяченных статов неписей, но идеально было бы вообще найти решение без ошибки в лог. Видел моды, которые даже авторы годаим не могли довести до нормального состояния, а другие пользователи делали патчи, где в том числе и в скриптах исправляли казавшиеся неисправляемыми косяки, точно вспоминая LL мод Beeing Female и патч к нему, где автор писал[а] о множестве безрезультатных попыток исправить баги, которые рушили стабильность игры, были и другие моды с похожей историей, да и неофициальный патч к игре тоже имеет множество фиксов скриптов, на которые даже у разрабов игры руки не дошли.
modgms_user, идем, лучше, играть в WOW и писать аддоны для WOW, а? Там хоть нормальное API и код самого близзарда очень качественный. А по GetMagnitude() - ну возьми проверь, какое значение оно возвращает при ошибке. Если там ноль и ноль не является допустимым для работы остального скрипта, то можно сделать проверку на ноль.
Изменение репутации для пользователя modgms_user
modgms_userOffline
Сообщение №2592
написано: 25 декабря 2017, 17:48
| Отредактировано: Multigone - 22 апреля 2020, 13:11
По GetMagnitude в условии, сначала изменил скрипты, тестил, вроде видел только ошибку в условии и не было других, но потом, после более долгих тестов увидел две ошибка подряд:
Код
Error: Unable to call GetMagnitude - no native object bound to the script object, or object is of incorrect type stack: [None].XTD_ProcSelf.GetMagnitude() - "<native>" Line ? [None].XTD_ProcSelf.OnEffectStart() - "xtd_procself.psc" Line 7 Error: Unable to call GetMagnitude - no native object bound to the script object, or object is of incorrect type stack: [None].XTD_ProcSelf.GetMagnitude() - "<native>" Line ? [None].XTD_ProcSelf.OnEffectStart() - "xtd_procself.psc" Line 9
, т.е. после ошибки в условии. строка с присвоением, где тоже произошла записсанная в лог ошибка, также выполнялась. Это другой скрит, там их несколько таких с похожим присвоением. Получается, что все же, после ошибка в условии строка с условием просто игнорится, пишется ошибка в лог и продолжает выполнять дальше, по другому, эти две подряд ошибки, с указанием на обе строки с условием и присвоением, где было GetMagnitude , объяснить сложно. Сделал другим способом, опять же, меньшим злом, убрал первое условие с GetMagnitude и после строки присвоения сделал проверку, чтобы выполнять только если значение больше нуля, т.к. вспомнил, что совал debug.trace и помнится, числовые переменные просто были равны нулю, когда была ошибка в self.GetMagnitude(). Все же одна ошибка- меньшее зло и пропуск последующего кода, во первых, сэкономит время папируса и не будет тормозить выполнением кучи лишних команд, а во вторых, предотвратит возможные отрицательные последствия выполнения кода с неправильными значениями.
Опять же, если все же будут у кого умные мысли, как ещё можно проверить, чтобы и ошибки не было и выполнялось, когда можно, будет очень хорошо. Может где есть примеры скриптов модов, где есть похожие исправления, все же, многое как раз там и подсматривается, в разных неоф. патчах к разным модам, в скриптах самих модов.
modgms_user, обычно, если функции применять к none, они возвращают false, 0, "", none. Конкретно в том скрипте - не будет никакого влияния на глобальную и AV актера, если GetMagnitude() вернет 0.0. Там другая проблема. Если события старта и финиша срабатывают почти одновременно (например, когда продолжительность эффекта 0), то это может привести к возврату AV не в исходное состояние. Параноик-код должен выглядеть примерно так:
Конкретно в том скрипте - не будет никакого влияния на глобальную и AV актера, если GetMagnitude() вернет 0.0
Но код все равно будет выполняться и создаст лишнюю нагрузку впустую, выполнит рассчеты с неверным значением. В Worlds Dawn, из отрицательных эффектов, бывало, как раз ловил завышенные статы у компаньонов, когда они носили шмотки с чарами из этого мода.
А так, конечно, можно скрипт попробовать. Только там, в предложенном коде что-то не дошло. На onEffectFinish, понятно, цикл WHILE iLock < 2 крутится пока iLock меньше двух и не дойдет до конца onEffectStart где он станет равен 2, чтобы как раз описанную возможную ситуацию предотвратить, с нулевой длительностью эффекта, но на начале onEffectStart стоит WHILE iLock. WHILE iLock, это разве не крутить, пока переменная не примет какое-то значение, больше нуля? Или я просто запутался или там восклицательный знак перед iLock должен был быть, в начале onEffectStart, хотя цель наличия цикла в начале onEffectStart тоже не дошла.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №2595
написано: 26 декабря 2017, 12:53
| Отредактировано: Multigone - 26 декабря 2017, 12:59
modgms_user, финиш должен ждать окончания старта. Старт должен ждать финиш - в одном скрипте могут много раз срабатывать эти события, если в EffectItem заклинания есть какое-то периодически срабатывающее условие.
Код будет выполняться, но нагрузка там смешная. К тому же она уже заложена в функционал мода.
Чем защищенней код, тем в нем будет больше проверок. Я бы даже сказал, иногда, чтобы использовать одну строчку, которая что-то там по задумке делает, нужно обеспечить ее десятью защитами, чтобы она срабатывала только тогда и ровно столько раз... С другой стороны, если знаешь, что код будет выполняться только так, и никак иначе, и создавать лишние проверки нет нужды.
Изменение репутации для пользователя modgms_user
modgms_userOffline
Сообщение №2596
написано: 26 декабря 2017, 13:17
| Отредактировано: Multigone - 22 апреля 2020, 13:12
modgms_user, финиш должен ждать окончания старта. Старт должен ждать финиш
Ясно, свои особенности. Финиш понятно, там стоит цикл с WHILE iLock < 2 и пока выполняется начало эффекта, будет меньше двух, но на самом начале стоит цикл WHILE iLock, которому вроде как надо число отличное от нуля, чтобы выйти из цикла и продолжить, а iLock равно нулю изначально и в конце финиша. Или рассуждение ошибочно и там на самом деле должен стоять WHILE iLock, не WHILE !iLock? (речь про код предложенного примера скрипта и цикл в самом начале)
Вот не понятно, почему условие "if self as XTD_FortifyDecimal" не работает перед GetMagnitude(). Перед опробыванием последнего предложенного варианта скрипта засунул строку debug.trace перед return, чтобы, когда ошибка, выводила информацию о значении переменных. После очередного теста в игре смотрел лог и рядом с ошибкой с "Unable to call GetMagnitude" для XTD_FortifyDecimal была выведена отладочная вписанная строчка отладки: "XTD_FortifyDecimal > self=[XTD_FortifyDecimal ],ValueMod=0.000000". ValueMod, понятно, при ошибке с GetMagnitude() остался в значении ноль, но ведь self равен [XTD_FortifyDecimal ], т.е. вроде бы как self as XTD_FortifyDecimal должен был бы сработать в условии перед GetMagnitude(), но даже с ним, прямо перед GetMagnitude(), все равно отображалась ошибка.
Может как-то по другому надо условие прописать условие?
Multigone, сразу подвох какой-то почувствовал, еще перед тем, как что-то делать..., но все равно сделал. Сообщение отобразило 0.0000000, а в лог кинуло ошибку "Error: Unable to call GetMagnitude - no native object bound to the script object, or object is of incorrect type". Это такой ответ через предложенное действие, что при нулевой длительности происходит такое или просто для проверки? Показалось, что это ответ такой. Если все таки это был ответ, то было бы полезно услышать о механике в таких ситуациях, вроде раз ноль длительности, то эффект был удален сразу, то брать магнитуду уже было неоткуда или в таком роде, корректными словами. Также было бы полезно узнать, как же все таки предотвратить ошибку, раз проверка if self не работала.
modgms_user, как только эффект снимается с актера, он перестает существовать. А скрипт этого эффекта будет до тех пор, пока не выполнятся все уже запущенные события и функции. Поэтому if self будет (должен?) проходить проверку всегда. А чтобы работала GetMagnitude(), выходит, нужно наличие эффекта на актере. Ведь она возвращает не базовую магнитуду из EffectItem заклинания, а настоящую, с учетом всех его перков / сопротивлений.
Этим можно воспользоваться - если между стартом и финишем пройдет меньше 0.1 с, значит,.. 1) ...эффект имеет продолжительность 0... 2) ...или заклинание было снято принудительно, например, если актер в связанных скриптах имеет подобное:
Multigone, еще с предыдущей версии этого скрипта в игре столкнулся с одной очень неприятной проблемой, фпс стал падать с установленного 50-60-ти до 37-ми. Начало происходит сразу после начала тестов с той версией, где был добавлен while. Последний предложенный вариант уже постабильней, долго не падало, после хождений в Ривервуд, прохожденийя одной пещеры и только в пещерах Хелгена, там, где при обычном старте проходишь обучение, фпс опять упал до 38ми, м самое интересное, там, где валялись 4ре трупа(игра начата через альтернативный старт), в пещере перед мостом, где еще потом пауки и спящий медведь в нормальном старте, а в альтернативном у моста завален вход.
Сделал сохранение с просевшим фпс и потом сравнил с нормальным сохранением в Save Cleaner'е. В активных появились два скрипта XTD_FortifyDecimal. Для проверки конкретной причины в нихудалил их из активных клинером и сохранил. После загрузки сохранения с удаленными из активных указанными скриптами фпс вернулся до 60ти. Потом еще раз проверил, в том же месте, загрузил ближайшее нормальное, дошел до места и словил падение фпс, сделал сохранение, посмотрел, опять наличие двух экземпляров этого скрипта в активных, удалил оттуда и загруженное то же сохранение, но без экземпляров скрипта в активных, грузится в 60фпс, когда с ними сразу 38. Может на этом цикле while застревает?
Потом отредактировал этот скрипт, добавив туда несколько debug.trace'ов в разных частях, с переменными, но после нескольких повторных попыток загрузки последнего сохранения с нормальным фпс, без этого скрипта, пока поймать падение фпс не получилось, т.к., видимо, зачарования каждый раз генерируются разные и последний предложенный вариант постабильней предыдущего, падение может наблюдаться только с отдельными зачарованиями, не со всеми, с которыми грузится экземпляр этого скрипта. Поставлю шансы выпадения маг. вещей очень высокими и попробую еще попробовать побегать половить падение. Вообще странно, что и на мертвых телах эффекты действуюи, загружаются скрипты, потом может полезно будет добавить к ним, в esp, что-то вроде условия isdead 0, чтобы работали только на живых. Вот, какие данные можно получить в Save Cleaner'е об указанных активных скриптах, если это хоть что-то даст. Кинул ссылку на архив с текстовыми файлами, т.к. текста прилично, а у меня здесь что-то форматирование сообщения не работает, только на MG.( rgho.st/ private/8h2T7Vh9P/e8dbf8659152a8ea255a97962159b672 ), в ссылке убрать пробел перед private.
modgms_user, проверил на игроке, как при нулевой, так и при ненулевой продолжительности эффекта скрипт всегда завершает и старт, и финиш. Не знаю, в чем там у тебя дело. Во втором скрипте допущен маленький косячок, который при нулевой продолжительности дает теоретический шанс, что финиш все-таки сработает раньше старта, но в этом случае GetMagnitude() вернет 0 и AV не будет затронуто. Ничего критичного. В обоих случаях цикл крутится только тогда, пока выполняется код другого события. Чтобы цикл крутился вечно, нужно изначально допустить ошибку в логике - но при первом же тесте это будет выявлено. Ладно, вот тебе версия, где цикл гарантированно завершается не более чем через 2 секунды после срабатывания события финиша.
Код
Bool Property IsNegative Auto Bool Property AffectsGV Auto GlobalVariable Property affectedGV Auto
Float ValueMod Bool Kicked Int iLock = 80
Event onEffectStart(Actor akTarget, Actor akCaster) Utility.Wait(0.2) IF iLock <= 40 iLock -= 1000 RETURN ENDIF ValueMod = GetMagnitude() / 100.0 IF !ValueMod iLock -= 1000 RETURN ENDIF if IsNegative ValueMod = -ValueMod Endif If AffectsGV If akTarget == Game.GetPlayer() || akTarget.IsPlayerTeammate() Kicked = true affectedGV.Mod(ValueMod) Endif else if StatToMod == "weaponSpeedMult" && akTarget.GetActorValue(StatToMod) == 0.0 ValueMod += 1.0 endif akTarget.ModActorValue(StatToMod, ValueMod) endif iLock -= 40 Endevent
V Финиш ждет старт - безопасный возврат AV в исходное состояние. V Выполнение GetMagnitude() предотвращается, если эффект имеет слишком малую продолжительность - не будет ошибки в лог. V Цикл всегда завершается - гарантия возврата AV и отсутствия накапливающейся нагрузки. V C осторожностью (и тестами) можно использовать в эффекте, имеющем условия в EffectItem. X Возможная проблема с weaponSpeedMult остается - после снятия первого из 2х таких эффектов актер может быть замедлен.
Изменение репутации для пользователя modgms_user
modgms_userOffline
Сообщение №2604
написано: 29 декабря 2017, 06:37
| Отредактировано: Multigone - 22 апреля 2020, 12:50
проверил на игроке, как при нулевой, так и при ненулевой продолжительности эффекта скрипт всегда завершает и старт, и финиш. Не знаю, в чем там у тебя дело.
Так пока и не получилось повторить снова, нужные чары не сгенерировались, чтобы вызвать повторения бага с падением. Вот, только два сохранения, о которых писалось, в которых два экземпляра скриптов вызывали сильное падение фпс, с восстановлением после удаления их из активных.
Попробую третий вариант в следующем забеге по тому же маршруту в игре. В этом моде, на самом деле есть несколько скриптов, ошибки в которых происходят с тем же GetMagnitude(). Кроме xtd_fortifydecimal ошибки происходят так же в таких скриптах Worlds Dawn как: xtd_statpercentage, xtd_procself, xtd_alchattributepercent и XTD_ProcOnBlockBuff. В них, пока использованы простые проверки или пробую аналоги предлагаемых вариантов, возможно, после нахождения оптимального варианта, без ошибок в лог, непредвиденных изменений статов персонажей и падения фпс, можно будет уже использовать что-то конкретное. В может есть и другие проблемы и вопросы, многое по балансу и известно из отзывов пользователей оригинальной версии, но это пока второе.
Стоит ли в esp к некоторым эффектам добавить условие IsDead 0, чтобы избежать лишнего применения когда не надо или не требуется? Что-то уже пробую, вроде применения условия Health<100%, через esp, для эффекта ауры, восстановливающей здоровье союзных NPC. Насколько такие проверки избавят от проблем и повлияют на общую производительность? Если есть какая информация и особенности, будет полезно узнать.
А предложенный скрипт попробую обязательно, в следующей новой тестовой игре. Жаль, не вышло поймать падение с добавленной отладкой, из выводов только, что такое происходило только для определенных эффектах, на неписях и второй вариант предложенного скрипта стабильней первого, в этом плане.
- эффект с архетипом ValueMod не накладывается на уже мертвых актеров. - когда актер погибает, большинство эффектов снимаются, если в них не указано NoDeathDispel. С игрока - не всегда. - если для заклинания, кастуемого игроком, по результатам проверок условий и сопротивлений на другую цель не будет наложено ни одного эффекта, в верхнем углу появится сообщение "такой-то избегает действия того-то". - проверки в EffectItem происходят раз в секунду, в окне TargetConditions эффекта - один раз при наложении. Множество постоянных проверок нежелательно. - если условие TargetConditions не дает эффекту наложиться, его скрипт не инициализируется, требование DispelEffectsWithTheseKeywords не выполняется. - условие в EffectItem не препятствует наложению эффекта, просто "переключает" его состояние, при этом срабатывают события старта и финиша (соответствующее, скрипт продолжает работать); требование DispelEffectsWithTheseKeywords выполняется один раз в момент наложения; в отключенном состоянии он все еще определяется через HasMagicEffect(). - если заклинание имеет несколько эффектов, условия TargetConditions следующего эффекта начнут проверяться после того, как будут проверены у вышестоящего. - для эффектов Concentration условия в TargetConditions и EffectItem играют обратную роль (с СК.сом / не проверял / возможно, это только кажется из-за продолжительности большинства их в 1 секунду).
Multigone, спасибо, особенности полезно знать, чтобы не пихать куда попало чего не следует или наоборот.
Сделал один забег с измененным скриптом, пока чего-то такого не заметил, хоть и недолго бегал, только пара ошибок с этой же магнитудой, от пары других скриптов, но там тоже проверки стоят, когда в магнитуде ошибка. По измененному скрипту ничего в логе не показало. Падения фпс не было и вроде как, раз бесконечного цикла нет, не должно быть. А основном только другие недостатки высматривались. Подольше побегать, потом может быть можно будет применить и к другим нескольким перечисленным ранее скриптам примерно такие же проверки, чтобы предотвратить ошибку с магнитудой и не сломать ничего.
[b]Добавлено[/b] (06 Января 2018, 15:28) --------------------------------------------- Приветствую в очередной раз. Делал тесты скрипта и мода в целом. В моде нашел один ломающий характеристики неписей баг, но о нем позже.
1) По скрипту xtd_fortifydecimal. Смотрел в логе, сообщения об ошибках с GetMagnitude все равно встречаются. Появились кое какие размышления. В других скриптах этого мода, например в XTD_PlayerRecoveryScript, были также разные ошибки, например RegisterForSingleUpdate выдавал ошибку no native object bound... . В том случае я вставлял сразу перед RegisterForSingleUpdate проверку вроде "if target.HasMagicEffect(abRecovery.GetNthEffectMagicEffect(0))" и больше ошибок в логе не было. Так вот, относительно xtd_fortifydecimal, как магического эффекта и ранее обсуждавшейся ситуации возникновения ошибка с GetMagnitude из за снятия эффекта, несмотря на это, но выполнения строк скрипта до конца. Обдумывался вариант получить айди эффекта через что нибудь и засунуть его в строку "if target.HasMagicEffect(abRecovery.GetNthEffectMagicEffect(0))", вместо abRecovery. Но пока писал это сообщение подумал о более тупом способе и опробовал его на том тестовом заклинании и скрипте TEST777, что ранее предлагалось посмотреть. Условие "if self as xtd_fortifydecimal" возвращает TRUE и равно "[xtd_fortifydecimal <Active Efffect ## on ########>]", когда есть еффект, или "[xtd_fortifydecimal <None>]", когда его нет. Сначала подумал присвоить значение какой-нибудь переменной типа activemagiceffect, например ActEffect, но если ей присвоить значение через "ActEffect = self as xtd_fortifydecimal", в моем тестовом скрипте было "ActEffect = self as xtd_fortifydecimal", соответственно, в Debug.trace\messagebox такая переменная будет показывать значение None, но в моем тестовом скрипте условие "if ActEffect == None" все равно не выполнялось. Тогда решил сделать проверку через строковую. Создал "string EffString", потом присвоил, в тестовом скрипте TEST777, значение через "EffString=(self as TEST777) as string" и после была проверка if EffString=="[TEST777 <None>]", которая уже прошла, ведь строковое значение self as TEST777 отличалось, в случаях когда эффект был или его не было. Можно и без переменной, полагаю, просто условием " if ((self as TEST777) as string) == "[TEST777 <None>]" ". Может тупо так и предотвращать ошибку с следующим далее GetMagnitude? Может это можно прописать более быстрым вариантом? Кстати, какое условие легче и выполнится быстрее "if target.HasMagicEffect(SpellVisual.GetNthEffectMagicEffect(0))" или " if ((self as XTD_CombatBuffScript) as string) != "[XTD_CombatBuffScript <None>]" "?
2) Касательно описанной большой проблемой мода. Ранее писал, что замечал, что с модом у неписей косячились показатели и в одной из тестовой игр, видимо, увидел причину, которая их портит. В моде Worlds Dawn, кроме зачарований, есть еще РПГ атрибуты(сила, выносливость, проворность, ловкость, интеллект, мудрость,харизма), которые имеют свои эффекты. На игроке они работают нормально, но они также могут оказывать эффект и на неписей, вроде спутников, т.к. присутствуют в зачарованиях на вещах, которые можно одеть на тех же компаньонов. Так вот, просматривая характеристики компаньона, случайно(или не очень), увидел, в каком случае характеристики запарывались. Первое, что увидел, чрезвычайно большой бонус от характеристик, аномально большой. Своему персу, для тестов, установил все указанные атрибуты в значение 100, чтобы видеть и насколько они несбалансированы, что надо уменьшать, и в случае чего, вот такие баги. Посмотрел у спутника параметр AttackDamageMult, он был равен 1. Была шмотка с чарами +1 к силе, а сила здесь, одним из эффектов, имеет +к урону. Надел на спутника шмотку с +1 силы и увидел, что AttackDamageMult вырос с 1-го до 2.88, что, очевидно, мягко говоря перебор, соответственно, +10 к силе уже увеличивало до неприличных значений. Это при РПГ-атрибутах игрока в значении 100. Для сравнения, 100 силы у игрока увеличивает AttackDamageMult, если не ошибаюсь, до 1.77, но это 100 силы. Проверил, там же в игре, понизил все атрибуты до 50-ти, сбросом через Debug мода и +1 силы стало давать компаньону, в общем-то, в два раза меньший бонус к AttackDamageMult. Далее выяснил, тогда же, когда сбросил атрибуты, в какой ситуации AttackDamageMult остался измененным навечно. Когда менял атрибуты, то шмотка была надета на персонаже и когда шмотка была снята, эффект уменьшился только на величину, которая была при значении РПГ-атрибутов 50, и AttackDamageMult уже не вернулся в значение 1. Примерно понял, что эти дела присваиваются в скрипте xtd_alchattributepercent, сначала попробовал немного поменять в указанном скрипте код, в надежде исправить баг, не прокатило, в результате, не нашел ничего лучше, чем просто отрубить процесс для неписей, оставив только для игрока, после чего неписи перестали получать бонусы от плюсов к рпг-атрибутам на надетых на них шмотках, но и дикие прибавки и навечно измененные значения характеристик также исчезли, вроде onlyplayer рпг-атрибуты. Вообще, начал проверять эти дела после того, как увидел, что у спутника скорость в игре стала 1500 вместо ста и из шмоток была только та, что добавляла бонус от рпг-атрибута, притом значение росло по ходу игры, видимо, когда распределял атрибуты и в других ситуация, вроде переодевания шмоток и т.п. Думал, может чего накосячил в скриптах и вернул оригинальные, начал новую игру и проверил снова, с оригинальными были такие же дела. В XTD_AlchAttributePercent тоже есть вначале GetMagnitude в начале, тоже кидал те же ошибки иногда.
Может в XTD_AlchAttributePercent там какая ошибка есть в коде? Так-то код небольшой, и из XTD_AlchAttributePercent используется также и xtd_attributes, в котором задаются величины эффектов от рпг-атрибутов, баланс велечины которых - отдельный вопрос. Код скрипта могу кинуть, если надо, но вроде, как понял с xtd_fortifydecimal, исходники есть. Не знаю, какой именно атрибут игрока влиял на бонус от силы для непися, не проверил еще, полагаю та же сила 100, бонус которой каким-то образом перемножается с бонусом силы для непися. Может и onlyplayer атрибуты, с отключением кода для неписей, даже и лучше, но как бы это не повлияло на работоспособность многих эффектов от других зачарований. Видимо надо кучу debug-строк вставлять в скрипт и смотреть, что там чему равно.
modgms_user, проверил, возможно, (Self AS String != "[ScriptName ]") и даст необходимую проверку, наложен ли этот эффект на актера.
Код
if target.HasMagicEffect()
Не рекомендую, т.к. активных копий одного эффекта может быть больше 1 (некоторые архетипы позволяют это, напр., ValueMod). Один конкретный эффект уже исчез, но на актере есть и другие - проверка в скрипте первого будет положительна.
2)
Честно говоря, не хочется быть тестером.
Изменение репутации для пользователя modgms_user
modgms_userOffline
Сообщение №2608
написано: 7 января 2018, 19:40
| Отредактировано: Multigone - 22 апреля 2020, 12:54
Есть вопрос о скорости и затрачиваемых действиях в примере далее. Есть, допустим скрипт, в нем я, допустим, добавил необходимую проверку "IF self as string != "[Scriptname ]" ". Эта проверка по скрипту повторяется раз 5-10. Будет ли иметь смысл, с точки зрения скорости и затрачиваемого папирусом времени, добавить в начале определение переменной, например "string MEffectNone = "[Scriptname ] " и далее по скрипту заменить все проверки на "IF self as string != MEffectNone"? Будет ли это быстрее хоть как-то? Скомпилированный скрипт становится чуть меньше после таких изменений и часто это имеет смысл, особенно, когда много действий при присвоении выполняется, но здесь как-то не настолько прямо всё ясно.
Изменение репутации для пользователя Dsion
DsionOffline
Сообщение №2609
написано: 8 января 2018, 16:40
| Отредактировано: Dsion - 8 января 2018, 16:42
Multigone, чо-то у тебя реально странные представления о программах... Попрограммировал бы на Си...
modgms_user, возьми да замерь время выполнения первого и второго вариантов... В Utility Script, вроде, есть функция получения точного реального времени. Если будет слишком быстро выполняться, можно повторить тест 1000 раз или сколько нужно. Вряд ли у нас на форуме есть кто-то, кто понимает компилятор папируса достаточно хорошо, чтоб сразу сказать, какой вариант быстрее.
modgms_user, действительно, это быстрее. В среднем на 0.0000003 с (на моем компе). Но переменная, в отличие от литерала, занимает какую-то память, пока живет в отрезке кода, где была объявлена. Тогда предположу, что создание переменной и литерала - это примерно одно и то же, на это затрачивается опред. время.
Как я и сказал, в твоем случае это не имеет значения.
Форум » TES V: Skyrim » Мастерская » Вопросы по скриптам Papyrus (О скриптах Papyrus (Skyrim). Скриптеры не проходите мимо!)