С 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 в двух экземплярах отличается