1 points par GN⁺ 2023-09-18 | 1 commentaires | Partager sur WhatsApp
  • « Caves of Qud » a mené une validation technique pour se débarrasser de sa longue dépendance à Unity et construire/démarrer le cœur du jeu dans Godot ; l’objectif prioritaire est d’abord de le faire tourner en mode ASCII+tuiles sans VFX ni UI modernes
  • Le travail a été divisé entre l’import des assets de tuiles, le portage des assemblages C# principaux et la mise en place du rig de rendu et d’entrée ; les anciens fichiers de tuiles BMP ont été convertis en PNG puis chargés dans Godot
  • Les 5 641 erreurs de la build initiale ont été réduites en déplaçant GeneratedCode, ConsoleLib, Genkit, Language, HistoryKit, Newtonsoft JSON, CodeDom, etc., tandis que la surface de dépendance à UnityEngine a été progressivement réduite à des stubs
  • Les usages de Color, GameObject, AudioSource, Debug.Log et Screen de Unity ont été traités via UnityEngineReplacer et des classes de remplacement, tandis que les couches chargen et presentation, plus proches de PlayFab et de l’UI Unity, ont été temporairement retirées ou laissées comme candidates à une séparation en modules glue
  • Au final, le cœur du jeu en C# d’environ 500 000 lignes démarre désormais dans Godot, fournit des frames et attend des entrées, mais le renderer, le harnais d’entrée ainsi que le rigging des VFX, du son et de l’UI restent à faire

Étendue du travail de portage de Unity vers Godot

  • Le portage se divise en trois branches
    • Import des assets : intégrer les assets de tuiles dans le projet Godot
    • Portage des assemblages principaux : déplacer XRL Application, qui constitue le moteur principal du jeu hors Unity, ainsi que le GameManager côté moteur
    • Mise en place du rig de rendu : relier l’affichage et les entrées une fois le cœur démarré
  • Un projet Godot « mobile » a été créé et le contenu des textures de Qud a été copié dans le dossier racine du projet
  • Comme Godot ne traitait pas les anciens fichiers .bmp, les fichiers incluant les tuiles ASCII ont été convertis en masse en PNG
  • Après conversion, les assets se chargeaient, mais il fallait environ 30 secondes avant de voir apparaître l’indicateur de progression de l’import

Réduire les erreurs de build tout en déplaçant les assemblages du cœur

  • Après avoir copié XRL Application, un projet et une solution C# ont été générés dans Godot, et l’état initial produisait 5 641 erreurs
  • Des bibliothèques génériques comme ConsoleLib et Genkit ont été déplacées en bloc, tandis que l’ancienne solution de sprites/atlasing Kobold devait être importée fichier par fichier selon les besoins
  • KoboldJSON, simple bibliothèque de sérialisation JSON, a été déplacée telle quelle
  • Une substitution globale des 85 points d’usage de Color a ramené les erreurs à 4 700
  • L’ajout du dossier manquant GeneratedCode a inclus les résultats de génération de code des classes par événement, réduisant les erreurs à 1 557
    • Caves of Qud s’appuie sur une architecture qui génère le code de classes d’événements très verbeuses afin d’obtenir de meilleures performances et une surface d’événements fortement typée

Nettoyage des dépendances à Unity et de la couche glue

  • Embark Builder et la création de personnage chargen contenaient beaucoup de code d’UI Unity ; ils ont donc été retirés de la validation technique ASCII initiale
    • Il n’existe pas encore de version console, mais la validation initiale peut être testée en chargeant une sauvegarde ou via un démarrage aléatoire
  • Le dossier Game sert majoritairement de glue entre Unity et le jeu, mais comme certains sous-dossiers tels que CodeGeneration ne relèvent pas de cette glue, la direction choisie a été de les déplacer vers une racine distincte ou un dossier Platform
  • Le portage des bibliothèques Language et HistoryKit a fait tomber les erreurs à 454, aidé par le fait que la séparation jeu/glue existait déjà, même imparfaitement
  • Les grandes catégories d’erreurs restantes concernaient CodeDom/Roslyn, PlayFab, Harmony, certains problèmes liés au compilateur, ainsi que la surface UnityEngine qui fuyait vers la couche jeu
  • Le code lié à PlayFab a été temporairement commenté et reste candidat à un déplacement dans un module glue

Stubs de remplacement de l’API Unity et différences du C# de Godot

  • Color32, type de couleur basé sur des bytes, a reçu rapidement une implémentation de remplacement
  • Un dossier UnityEngineReplacer a été créé et seule la surface nécessaire a été implémentée au fil des erreurs de compilation, sans s’appuyer sur la documentation ou le code de référence de Unity
  • La création d’un stub GameObject a transformé l’erreur « GameObject inconnu » en erreurs plus concrètes sur les champs et méthodes requis, ce qui a permis de cartographier la surface d’interface réellement utilisée par le jeu
  • Pour AudioSource, les membres accédés ont été ajoutés un à un en suivant la liste d’erreurs, jusqu’à compléter l’interface de portage AudioSource effectivement utilisée par le jeu
  • Les autres surfaces traitées comprenaient notamment
    • un shim de remplacement pour Debug.Log
    • une implémentation de remplacement pour Screen
    • le portage d’une bibliothèque de méthodes d’extension IsNullOrEmpty
    • la gestion des références à Math et de la différence entre PI et Pi
    • la gestion de la différence de casse entre X, Y de Godot
    • le nettoyage des imports incorrects de System.Drawing.Color et System.Numerics.Vector3 ajoutés par l’IDE
  • Newtonsoft JSON a été résolu en ajoutant le package NuGet dans Visual Studio, et CodeDom via le package NuGet CodeDom

Jusqu’au démarrage complet dans Godot

  • Quand les erreurs ne sont plus tombées qu’à 11, les problèmes restants concernaient le code de compilation dynamique C# de la gestion des mods ; ce n’était pas indispensable, mais suffisamment complexe pour rester jusqu’à la fin
  • Après traitement de l’étape de linkage et des erreurs de champs dans les stubs, environ 500 000 lignes de C# ont pu être compilées
  • L’étape suivante consistait à créer un petit renderer et un harnais d’entrée pour démarrer les assemblages du cœur, avec pour objectif de rendre le jeu exécutable en mode ASCII+tuiles
  • Une scène vide a été créée dans Godot, GameManager.cs a été attaché au nœud principal, et GameManager devait hériter de Node avec du code partial
  • _Ready dans Godot a été utilisé comme équivalent de Awake dans Unity, et _Process comme équivalent de Update
  • Pendant l’initialisation, le load path et la gestion des mods ont été portés, puis un problème où le resolver de types ne retrouvait pas les types par leur nom a été traqué à coups de printf
  • La cause était la gestion des dynamic assembly
    • comme les mod assembly étaient dynamiques, l’inspection de l’assembly principal excluait les dynamic assembly
    • dans l’éditeur Godot, l’assembly principal du jeu était lui aussi dynamique et se retrouvait donc exclu de la recherche de types
  • Après correction, le démarrage complet a réussi, et le cœur du jeu de 500 kloc fournit désormais des frames en attendant les entrées
  • Le travail restant a été résumé par « just work », mais en réalité il reste un volume important de travail sur les VFX, le son et le rigging de l’UI

1 commentaires

 
GN⁺ 2023-09-18
Avis Hacker News
  • Ce jeu semble utiliser presque entièrement un moteur maison, Unity ne servant que de couche d’abstraction matérielle et de cadre pour le portage ; en termes de difficulté de portage, on dirait donc presque le cas idéal
    Il existe étonnamment beaucoup de jeux de ce type, mais bien sûr cela ne représente pas la plupart des titres Unity

    • Oui. Dans une interview, il a été dit que Qud tournait alors dans Unity comme une application console
      Je ne sais pas si c’est encore le cas après la refonte de l’UI, mais si oui, j’ai toujours trouvé étrange qu’ils ne l’aient pas porté vers MonoGame pour économiser sur les coûts
    • Je vois cela comme le résultat où les composants de base d’Unity deviennent presque tous inutiles à long terme
      Android est similaire : le système d’exploitation finit par ne servir qu’à charger des bibliothèques remplaçant des choses comme la détection de caméra ou le chiffrement, jusqu’au jour où l’on réalise que l’OS n’est en fait guère plus qu’une fine couche de métal et un bootloader
  • https://nitter.net/unormal/status/1703163364229161236

  • Waouh, c’est vraiment chouette. C’est aussi intéressant de pouvoir voir ce processus de portage étape par étape, et je suis surpris que le temps nécessaire soit plutôt raisonnable

    • Godot a beaucoup moins de fonctionnalités, mais je trouve qu’il est vraiment facile à apprendre
    • J’aimerais voir comment ils ont recréé dans Godot l’ambiance visuelle propre à Caves of Qud
  • S’il y a autant de code custom et que la structure utilise moins les fonctionnalités de l’éditeur, on pourrait aussi utiliser une bibliothèque de rendu plutôt qu’un moteur

    • Quand on veut sortir un jeu sur plusieurs plateformes à la fois, devoir gérer soi-même le code de rendu, de son et d’entrée pour chaque plateforme devient vite lassant
      Avec un moteur en dessous, on obtient tout ça gratuitement. Avec Unity, il peut aussi y avoir un coût
    • Ils utilisent déjà une bibliothèque de rendu. Elle s’appelle « Unity »
  • Si vous voulez savoir ce qu’en pense Brian, cette vidéo est intéressante : https://www.youtube.com/watch?v=U03XXzcThGU
    J’y ai beaucoup appris à l’époque

  • Ça me rappelle la récente controverse autour de TypeScript de DHH
    Imaginer faire un tel portage sans typage statique : à chaque changement, il faudrait compiler, lancer et chercher les plantages. Dans ces moments-là, on est vraiment reconnaissant d’avoir construit le tout avec un langage facile à refactorer et une bonne architecture

  • Je n’ai pas de compte Twitter, qu’est-ce qui se passe ?