С 1 ноября 2024 года в выпуске 32.00 мы стабилизируем язык Verse до первой версии. Рекомендуем обновить проект для обеспечения стабильности и для упрощённого и поэтапного обновления кода в случае появления очередных обновлений языка Verse. Это обновление необязательно — ваша текущая версия проекта всегда будет работать и на более ранней версии Verse. Однако в будущем может потребоваться обновить проект до более новой версии Verse, если вы захотите выгрузить его новую итерацию.
С момента первого публичного релиза языка Verse мы продолжаем его дополнять и развивать, и все изменения без проблем доходят до пользователей, и нет необходимости обновлять язык до новой версии. Мы надеемся, что это не изменится. Большинство изменений вносятся таким образом, чтобы они были обратно совместимы с предыдущими версиями языка, а пользователи получали их вместе с новыми версиями UEFN.
Однако некоторые языковые изменения не поддерживают обратную совместимость и для компиляции кода могут потребоваться соответствующие изменения. Изменения без поддержки обратной совместимости будут внесены только в том случае, если пользователь обновит свой проект до новой версии языка.
Каждый раз при сохранении кода без обратной совместимости будут появляться предупреждения о том, что поведение вашего кода не поддерживается в новых версиях языка. Например, такие предупреждения начнут всплывать, если вы продолжите использовать методы кодирования, не совместимые с новой версией языка Verse.
Если ваш проект скомпилируется в версии 0 без каких-либо предупреждений об устаревшем коде, вы можете обновить его до версии 1 без каких-либо изменений в поведении кода. Если вы откроете проект версии 0 в UEFN 32.00 и он скомпилируется без ошибок или предупреждений, редактор предложит вам выполнить обновление.
Если вы захотите выполнить обновление или откат по какой-либо причине, вы можете сделать это в настройках проекта.
Click image to enlarge.
Вы также можете открыть файлы проекта в папке «Проекты Fortnite» и изменить версию Verse в файле .uplugin .
Click image to enlarge.
Большинство устаревших данных подготавливают пространство для последующих обновлений языка и не представляют важности для пользователей. Два исключения — это локальные классификаторы и сравнение структур.
Изменения в версии 1
Ошибка в set
Выражение, которое выполняется в блоке set, больше не приводит к ошибке. Предыдущий код:
F():void=
var X:int = 0
set X = FailableExpression[]
Допускался такой вариант, и для X можно было задать любое значение FailableExpression, полученное с предупреждением. В версии 1 это невозможно.
Чтобы исправить код, нужно убедиться, что выражение не завершится с ошибкой. Один из способов сделать это — внести следующие изменения:
var X:int = 0
Value:= FailableExpression[] or DefaultValue
set X = Value
Ошибка в буквенных ключах ассоциативного массива
Раньше буквенные ключи ассоциативного массива могли завершаться с ошибкой:
map{ExpressionThatCannotFail=>Value}
Простой пример: map{ (0 = 0) =>0 }, где 0 = 0 выдаёт ошибку. Это было исправлено.
Одновременное использование в блоках точки с запятой, запятой и перехода на новую строку
Раньше разрешалось одновременно использовать для разделения подвыражений точки с запятой, запятые и переходы на новую строку, что делало допустимым код наподобие следующего:
A,
B
for (A := 0..2):
# more code here
Был удалён «синтаксический сахар» до кода, как указано ниже:
block:
A
B
for (A := 0..2):
# more code here
Это означало, что ни одно из двух определений A в блоке кода не конфликтовало с другим, поскольку был создан неявный блок, который имел собственную отдельную область видимости.
Однако это некорректное поведение и оно было исправлено в новой версии языка Verse. Теперь тот же код фактически означает обработку каждого подвыражения по отдельности, то есть:
A
B
for (A := 0..2):
# more code here
Это означает, что первое выражение A и второе определение A := 0..2 теперь затеняют друг друга и результат обработки будет неоднозначным.
Чтобы решить эту проблему, авторам (и всем, кто полагается на прежнюю интерпретацию кода) придётся перестать одновременно использовать писать фрагменты, где они одновременно используют точку с запятой, запятую и переход на новую строку для разделения подвыражений, во всём своём коде Verse.
Example:
PropPosition := Prop.GetTransform().Translation,
if(Round[PropPosition.Z] = Round[ROOT_POSITION.Z]) { break }
Sleep(0.0)
Необходимо было внести следующие изменения:
PropPosition := Prop.GetTransform().Translation # note the trailing comma here has been removed
if(Round[PropPosition.Z] = Round[ROOT_POSITION.Z]) { break }
Sleep(0.0)
Раньше, начиная с версии 28.20, при обнаружении одновременного использования разделителей всплывало предупреждение. В новой версии языка Verse это недопустимо.
Изменения спецификатора unique
Теперь для классов со спецификатором <unique> требуется эффект конструкции <allocates>. Например, использование class<unique><computes> больше недопустимо.
Классификаторы local для функций
Классификатор (local:) можно применять к идентификаторам внутри функций, чтобы различать их с другими идентификаторами.
For example:
ExternallyDefinedModuleB<public> := module:
ShadowX<public>:int = 10 # добавляется только после публикации `ModuleC`
ModuleC := module:
using{ExternallyDefinedModuleB}
FooNoLocal():float=
ShadowX:float = 0.0
ShadowX
Приведённый выше код может выдать ошибку затенения, поскольку ShadowX выдаёт неоднозначное значение (оно из ExternallyDefinedModuleB.ShadowX или ShadowX внутри FooNoLocal?)
Чтобы устранить эту ошибку, можно использовать классификатор (local:), чтобы было понятно, какой ShadowX имеется в виду, как в примере ниже:
ExternallyDefinedModuleA<public> := module:
ShadowX<public>:int = 10 # добавляется только после публикации `ModuleB`
ModuleB := module:
using{ExternallyDefinedModuleA}
FooLocal():float=
(local:)ShadowX:float = 0.0 # Здесь можно использовать классификатор `local` для устранения неоднозначности
(local:)ShadowX
Раньше при обнаружении использования слова local в качестве идентификатора определения данных всплывало предупреждение, поскольку оно являлось зарезервированным ключевым словом. В новой версии языка использование local приведёт к ошибке, и, если вы хотите использовать идентификатор local в качестве обычного идентификатора определения данных, его использование должно быть явно уточнено.
Вот ещё один пример классификатора local:
MyModule := module:
X:int = 1
Foo((local:)X:int):int = (MyModule:)X + (local:)X
В этом примере, если бы мы не указали классификатор (local:), X в Foo(X:int) затенил бы определение X:int = 1 выше, поскольку оба идентификатора X находятся в одной области видимости. Использование классификатора (local:) позволяет устранить неоднозначность этих идентификаторов, сделав X в спецификаторе параметра аргумента Foo специфичным только для области видимости Foo. То же самое относится к идентификаторам X в теле Foo.
Открытые поля в struct
Все поля в struct теперь должны быть открытыми. По умолчанию это также относится к версии 1. (больше не нужно использовать <public>).
В версии 1 также добавлена возможность сравнивать две структуры struct. Если все поля struct можно сравнивать, то, чтобы сравнить два экземпляра структуры, для каждого поля можно использовать =. Например:
vector3i := struct{X:int, Y:int, Z:int}
vector3i{X:=0, Y:=0, Z:=0} = vector3i{X:=0, Y:=0, Z:=0} # выполнено успешно
vector3i{X:=0, Y:=0, Z:=0} = vector3i{X:=0, Y:=0, Z:=1} # выдаёт ошибку, поскольку Z в двух экземплярах отличается