À partir du 1er novembre 2024, dans la version 32.00, nous stabilisons le langage Verse dans sa version 1. Nous vous recommandons de mettre à niveau votre projet à la fois pour des raisons de stabilité et pour qu'il soit plus facile de mettre à niveau votre code de manière incrémentielle à l'occasion des futures mises à jour du langage Verse. Cette mise à niveau est facultative. Votre version actuelle du projet continuera toujours à fonctionner avec une ancienne version de Verse. Toutefois, il se peut que vous ayez besoin de mettre à niveau votre projet vers une version plus récente de Verse à un moment donné si vous souhaitez en mettre en ligne une itération plus récente.
Depuis sa première version publique, nous avons continué à faire évoluer le langage Verse. Ces changements ont été déployés de manière transparente pour les utilisateurs, sans qu'il soit nécessaire de mettre à niveau vers une nouvelle version du langage. Nous pensons que cela va continuer, que la plupart des changements du langage seront compatibles avec sa version précédente et que les utilisateurs pourront toujours en profiter à chaque nouvelle mise à jour de l'UEFN.
Cependant, certaines modifications de langage ne sont pas rétrocompatibles et peuvent nécessiter des modifications de votre code pour que le code soit compilé. De telles modifications incompatibles avec les versions antérieures ne seront déclenchées que si l'utilisateur met à niveau son projet de manière à cibler la nouvelle version linguistique.
Des avertissements apparaîtront chaque fois que vous enregistrerez du code qui n'est pas rétrocompatible et indiqueront que le comportement de votre code est obsolète dans les versions plus récentes du langage. Par exemple, si vous continuez à utiliser des pratiques de codage qui ne sont pas compatibles avec la nouvelle version du langage Verse, vous recevrez des avertissements concernant votre code.
Si votre projet se compile en V0 sans aucun avertissement d'obsolescence, vous pouvez effectuer une mise à niveau vers V1 sans aucune modification du comportement de votre code. Lorsque vous ouvrirez un projet V0 dans l'UEFN 32.00 et qu'il se compilera sans aucune erreur ni avertissement, l'éditeur vous demandera si vous souhaitez effectuer une mise à niveau.

Si vous souhaitez effectuer une mise à niveau ou une rétrogradation ultérieurement pour une raison quelconque, vous pourrez le faire dans les paramètres de votre projet.
Click image to enlarge.
Vous pouvez également ouvrir les fichiers de projet à partir du dossier Projets Fortnite et modifier la version de Verse des fichiers .uplugin.
Click image to enlarge.
La plupart des obsolescences ouvrent la voie à de futures améliorations de langage et ne constituent encore aucun avantage pour les utilisateurs. Les deux exceptions sont les qualificateurs locaux et la comparaison de struct.
Modifications dans la V1
Échec dans l'ensemble
L'expression qu'un set
exécute n'est plus autorisée à échouer. Auparavant, le code :
F():void=
var X:int = 0
set X = FailableExpression[]
était autorisé, et X
aurait été défini sur la valeur évaluée par FailableExpression
avec un avertissement. Dans la V1, cela n'est pas autorisé.
Afin de corriger votre code, vous devrez vous assurer que l'expression ne peut pas échouer. Une façon possible de procéder est d'effectuer la modification suivante :
var X:int = 0
Value:= FailableExpression[] or DefaultValue
set X = Value
Échec dans les clés littérales de mappage
Auparavant, les clés littérales d'un mappage pouvaient échouer :
map{ExpressionThatCannotFail=>Value}
Un exemple simple était map{ (0 = 0) =>0 }
, où 0 = 0
échouait. Cela n'est plus autorisé.
Mélanger les séparateurs point-virgule/virgule/nouvelle ligne pour les blocs
Auparavant, le mélange de points-virgules/virgules/retours à la ligne pour séparer les sous-expressions était autorisé et avait pour conséquences le code ci-dessous :
A,
B
for (A := 0..2):
# more code here
Il est en cours de désucrage interne vers le code indiqué ci-dessous :
block:
A
B
for (A := 0..2):
# more code here
Cela signifiait que les deux définitions de A
dans le bloc de code n'entraient pas en conflit l'une avec l'autre, car un bloc implicite à étendue séparée était créé.
Cependant, ce comportement est incorrect et a été corrigé dans la dernière version du langage Verse. Maintenant, le même code traite chaque sous-expression séparément, avec le résultat suivant :
A
B
for (A := 0..2):
# more code here
Cela signifie que le premier A et la seconde définition de A := 0..2
se font maintenant concurrence et que le sens est ambigu.
Afin de résoudre ce problème, les créateurs (et tous ceux qui s'appuient sur ce comportement) doivent arrêter de mélanger points-virgules/virgules/nouvelles lignes pour séparer les sous-expressions, dans tout leur code Verse.
Example:
PropPosition := Prop.GetTransform().Translation,
if(Round[PropPosition.Z] = Round[ROOT_POSITION.Z]) { break }
Sleep(0.0)
Devrait être modifié en :
PropPosition := Prop.GetTransform().Translation # note the trailing comma here has been removed
if(Round[PropPosition.Z] = Round[ROOT_POSITION.Z]) { break }
Sleep(0.0)
Auparavant, à partir de 28.20
, un avertissement était généré chaque fois que des séparateurs mixtes étaient détectés. Cela est désormais interdit dans la dernière version du langage Verse.
Changements de spécificateur unique
Les classes avec le spécificateur <unique>
nécessitent désormais l'effet de construction <allocates>
. Par exemple, class<unique><computes>
n'est plus autorisé.
Qualificateurs locaux de fonction
Le qualificateur (local:)
peut être appliqué aux identificateurs dans les fonctions pour les distinguer des autres identificateurs.
For example:
ExternallyDefinedModuleB<public> := module:
ShadowX<public>:int = 10 # ajouté uniquement après la publication de `ModuleC`
ModuleC := module:
using{ExternallyDefinedModuleB}
FooNoLocal():float=
ShadowX:float = 0.0
ShadowX
Le code ci-dessus produirait une erreur d'ombrage, car ShadowX
est ambigu (est-ce qu'il provient de ExternallyDefinedModuleB.ShadowX
ou de ShadowX
dans FooNoLocal
?)
Afin de résoudre ce problème, vous pouvez utiliser le qualificateur (local:)
pour indiquer clairement à quel ShadowX
il est fait référence, comme dans l'exemple ci-dessous :
ExternallyDefinedModuleA<public> := module:
ShadowX<public>:int = 10 # ajouté uniquement après la publication de `ModuleB`
ModuleB := module:
using{ExternallyDefinedModuleA}
FooLocal():float=
(local:)ShadowX:float = 0.0 #The `local` qualifier can be used here to disambiguate
(local:)ShadowX
Auparavant, nous émettions un avertissement lorsque nous détections que vous utilisiez le mot local
comme identificateur de définition de données, car il s'agit désormais d'un mot-clé réservé. Dans la dernière version du langage, l'utilisation de local
génère une erreur, et si vous souhaitez utiliser l'identificateur local
comme identificateur de définition de données normal, son utilisation doit être explicitement qualifiée.
Voici un autre exemple de qualificateur local :
MyModule := module:
X:int = 1
Foo((local:)X:int):int = (MyModule:)X + (local:)X
Dans cet exemple, si nous ne spécifiions pas le qualificateur (local:)
, le X
dans Foo(X:int)
masquerait la définition X:int = 1
directement au-dessus, puisque les deux identificateurs X
sont dans la même étendue. Ainsi, l'utilisation du qualificateur (local:)
nous permet de lever l'ambiguïté entre les deux, en rendant le X
dans la clause de paramètre d'argument de Foo
spécifique à l'étendue de Foo
. La même chose s'applique aux identificateurs X
dans le corps de Foo
.
Champs publics dans les struct.
Tous les champs de struct
doivent désormais être publics. Par défaut, c'est également le cas à partir de la V1 (l'utilisation de <public>
n'est plus nécessaire).
La V1 permet également de comparer deux struct
. Si tous les champs d'une struct. sont comparables, vous pouvez alors utiliser =
pour comparer deux instances de la struct. champ par champ. Par exemple :
vector3i := struct{X:int, Y:int, Z:int}
vector3i{X:=0, Y:=0, Z:=0} = vector3i{X:=0, Y:=0, Z:=0} # réussit
vector3i{X:=0, Y:=0, Z:=0} = vector3i{X:=0, Y:=0, Z:=1} # échoue, car Z est différent entre les deux instances