Od 1 listopada 2024 r., wraz z aktualizacją 32.00, stabilizujemy język Verse do wersji 1. Zalecamy aktualizację projektu zarówno ze względu na stabilność, jak i ułatwienie aktualizowania kodu na zasadzie przyrostowego aktualizowania w przypadku pojawienia się w przyszłości aktualizacji języka Verse. Ta aktualizacja jest opcjonalna; bieżąca wersja projektu będzie zawsze kontynuowała pracę na starszej wersji Verse. Mimo tego w przyszłości może dojść do sytuacji, w której konieczne będzie zaktualizowanie projektu do nowszej wersji Verse, jeśli zajdzie potrzeba przesłania jego nowszej iteracji.
Od czasu pierwszej publicznej premiery Verse rozwijaliśmy ten język, wzbogacając go o nowe elementy, a zmiany te były w przejrzysty sposób wprowadzane dla użytkowników bez konieczności aktualizacji języka do nowej wersji. Spodziewamy się kontynuacji tych działań, z dokonywaniem większości zmian języka z zachowaniem wstecznej kompatybilności z poprzednimi wersjami oraz wprowadzaniem ich dla użytkowników wraz z nowymi wersjami UEFN.
Jednak niektóre zmiany językowe nie są kompatybilne wstecznie i mogą wymagać zmian w kodzie w celu jego skompilowania. Takie niezgodne wstecz zmiany zostaną wywołane tylko wtedy, gdy użytkownik zaktualizuje swój projekt do nowej wersji językowej.
W nowszych wersjach języka pojawiają się ostrzeżenia za każdym razem, gdy zapiszesz kod, który nie jest wstecznie zgodny. Na przykład dalsze stosowanie praktyk kodowania, które nie są kompatybilne z nową wersją języka Verse, spowoduje wyświetlenie ostrzeżeń dotyczących kodu.
Jeśli projekt kompiluje się w wersji 0 bez żadnych ostrzeżeń o wycofaniu, możesz zaktualizować do V1 bez żadnych zmian w zachowaniu kodu. Gdy otworzysz w UEFN 32.00 projekt V0, który skompiluje się bez błędów lub ostrzeżeń, edytor wyświetli monit, czy chcesz zaktualizować.

Jeśli z jakiegoś powodu zajdzie u ciebie konieczność przejścia na wyższą lub niższą wersję, możesz to zrobić w ustawieniach projektu.
Click image to enlarge.
Możesz też otwierać pliki projektu z folderu projektów Fortnite i zmieniać wersję Verse pliku .uplugin .
Click image to enlarge.
Większość z tych elementów wycofanych toruje drogę dla przyszłych usprawnień w zakresie języka, natomiast nie zapewnia jeszcze żadnych korzyści dla użytkowników. Dwa wyjątki to kwalifikatory lokalne i porównywanie struktur.
Zmiany w V1
Niepowodzenie polecenia ustaw
Wyrażenie wykonywane przez set
nie może już kończyć się niepowodzeniem. Poprzednio kod wyglądał tak:
F():void=
var X:int = 0
set X = FailableExpression[]
Byłoby to dozwolone, a X
byłoby ustawione na dowolną wartość oszacowaną w wyniku FailableExpression
z ostrzeżeniem. W V1 jest to niedozwolone.
Aby można było naprawić kod, należy upewnić się, że wyrażenie nie może zakończyć się niepowodzeniem. Jednym z możliwych sposobów, aby to zrobić, jest następująca modyfikacja:
var X:int = 0
Value:= FailableExpression[] or DefaultValue
set X = Value
Niepowodzenie w kluczach literału mapy
Wcześniej klucze zapisane w kodzie w mapie mogły kończyć się niepowodzeniem:
map{ExpressionThatCannotFail=>Value}
Prostym przykładem jest map{ (0 = 0) =>0 }
, gdzie 0 = 0
zwraca niepowodzenie. Nie jest to już dozwolone.
Mieszanie separatorów średnika/przecinka/znaku nowego wiersza w blokach
Poprzednio mieszanie średników/przecinków/znaków nowego wiersza w oddzielaniu podwyrażeń było dozwolone, w efekcie powstawał kod jak poniżej:
A,
B
for (A := 0..2):
# more code here
Wewnętrzne usunięcie lukru składniowego z kodu, jak pokazano poniżej:
block:
A
B
for (A := 0..2):
# more code here
To oznacza, że obie definicje A
w bloku kodu nie wchodziły w konflikt ze sobą nawzajem, ponieważ istniał utworzony niejawny blok, który miał własny oddzielny zakres.
Jest to jednak zachowanie nieprawidłowe i zostało naprawione w najnowszej wersji języka Verse. Teraz ten sam kod traktuje każde podwyrażenie oddzielnie, dając w efekcie:
A
B
for (A := 0..2):
# more code here
Oznacza to, że pierwsze A i druga definicja A := 0..2
przesłaniają się wzajemnie i znaczenie jest niejednoznaczne.
Aby naprawić ten problem, obaj twórcy (i wszyscy, którzy polegają na tym zachowaniu) muszą przestać dodawać średniki/przecinki/znaki nowego wiersza do oddzielania podwyrażeń w całym swoim kodzie Verse.
Example:
PropPosition := Prop.GetTransform().Translation,
if(Round[PropPosition.Z] = Round[ROOT_POSITION.Z]) { break }
Sleep(0.0)
Należy to zmodyfikować w następujący sposób:
PropPosition := Prop.GetTransform().Translation # note the trailing comma here has been removed
if(Round[PropPosition.Z] = Round[ROOT_POSITION.Z]) { break }
Sleep(0.0)
Wcześniej w wersji 28.20
było generowane ostrzeżenie za każdym razem, gdy wykryto jakiekolwiek separatory mieszane. Jest to teraz niedozwolone w najnowszej wersji języka Verse.
Unikatowe zmiany specyfikatorów
Klasy ze specyfikatorem <unique>
wymagają teraz efektu konstrukcji <allocates>
. Na przykład wyrażenie class<unique><computes>
nie jest już dozwolone.
Kwalifikatory wartości lokalnych funkcji
Kwalifikator (local:)
można zastosować do identyfikatorów w funkcjach, aby odróżnić je od innych identyfikatorów.
For example:
ExternallyDefinedModuleB<public> := module:
ShadowX<public>:int = 10 # dodawane dopiero po opublikowaniu `ModuleC`
ModuleC := module:
using{ExternallyDefinedModuleB}
FooNoLocal():float=
ShadowX:float = 0.0
ShadowX
Powyższy kod wygeneruje błąd cieniowania, ponieważ ShadowX
jest niejednoznaczne (czy pochodzi z ExternallyDefinedModuleB.ShadowX
, czy ShadowX
w FooNoLocal
?).
Aby rozwiązać ten problem, możesz użyć kwalifikatora (local:)
, by jednoznacznie określić, do którego ShadowX
następuje odwołanie, jak w poniższym przykładzie:
ExternallyDefinedModuleA<public> := module:
ShadowX<public>:int = 10 # dodane dopiero po opublikowaniu `ModuleB`
ModuleB := module:
using{ExternallyDefinedModuleA}
FooLocal():float=
(local:)ShadowX:float = 0.0 #W tym miejscu można użyć kwalifikatora `local` do usunięcia dwuznaczności
(local:)ShadowX
Wcześniej było generowane ostrzeżenie, gdy wykryliśmy, że używasz słowa local
jako identyfikatora definicji danych, ponieważ jest to teraz zastrzeżone słowo kluczowe. W najnowszej wersji językowej użycie local
kończy się błędem, a jeśli chcesz użyć identyfikatora local
jako identyfikatora normalnej definicji danych, jego użycie musi być wyraźnie dopuszczone.
Oto inny przykład kwalifikatora lokalnego:
MyModule := module:
X:int = 1
Foo((local:)X:int):int = (MyModule:)X + (local:)X
W tym przykładzie, gdybyśmy nie określili kwalifikatora (local:)
, X
w Foo(X:int)
, spowodowałby to przesunięcie w cień definicji X:int = 1
bezpośrednio nad nią, ponieważ oba X
` identyfikatory są w tym samym zakresie. W związku z tym użycie kwalifikatora (local:)
pozwala nam odróżnić oba te elementy poprzez wyróżnienie X
w klauzuli parametrów argumentu Foo
jedynie w zakresie Foo
. To samo dotyczy również identyfikatorów X
w korpusie Foo
.
Pola publiczne w strukturach
Wszystkie pola w struct
muszą teraz być publiczne. Domyślnie dzieje się tak również w wersji V1. (użycie <public>
nie jest już konieczne).
V1 dodaje również możliwość porównywania dwóch struct
. Jeśli wszystkie pola struktury są porównywalne, można użyć =
, aby porównać dwie instancje struktury na zasadzie pole po polu. Na przykład:
vector3i := struct{X:int, Y:int, Z:int}
vector3i{X:=0, Y:=0, Z:=0} = vector3i{X:=0, Y:=0, Z:=0} # kończy się powodzeniem
vector3i{X:=0, Y:=0, Z:=0} = vector3i{X:=0, Y:=0, Z:=1} # kończy się niepowodzeniem, ponieważ wartość Z jest różna w obu instancjach