Godot: Einige Verwendungen von "Klassenname" können unerwartet zu zyklischen Fehlern führen

Erstellt am 26. Aug. 2018  ·  69Kommentare  ·  Quelle: godotengine/godot

Windows 10 64-Bit - Godot 3.1 Alpha

Bearbeiten - Problem verfeinert, um sich auf zyklische Fehler zu konzentrieren.

Bestimmte Verwendungen von class_name können zyklische Fehler in Situationen erzeugen, in denen keine zyklischen Referenzen vorhanden sind, und manchmal sogar keine anderen Referenzen außerhalb der angegebenen.

Ich habe dies am häufigsten im Tool-Skript bemerkt, wenn is für einen Klassenvergleich verwendet wurde, aber es scheint manchmal in normalen Skriptsituationen zu passieren.

Die Neuerstellung in einem Beispielprojekt ist mir entgangen.

godot master_2018-08-27_00-47-02

bug 3.2 confirmed high priority gdscript

Hilfreichster Kommentar

Das Update, an dem ich gearbeitet habe, ist immer noch WIP und verursacht Abstürze. Ich bin nicht sicher, ob ich eine so große Änderung in der Beta-Phase zusammenführen kann, daher wird dies wahrscheinlich später in einer Version 3.2.x geschehen.

Alle 69 Kommentare

Es funktioniert, wenn Sie dem Basisskript einen Klassennamen geben und diesen in der Erweiterungszeile verwenden.
Ich erhalte auch den Fehler, wenn ich zuerst Dateinamen verwende (https://github.com/godotengine/godot/blob/master/modules/gdscript/gdscript_parser.cpp#L4947), aber er verschwindet auch und kommt nicht zurück, nachdem es einmal funktioniert hat (wie in, nachdem ich die erwähnte Problemumgehung verwendet habe)

@ PetePete1984 Cool, danke Pete. So soll es dann verwendet werden?

Während ich dies noch einmal überprüfte und testete, schaute ich mir die Methode get_class() und fragte mich, ob sie Node2D zurückgeben sollte. Der is CustomClass Teil gibt _true_ zurück, aber is_class("CustomClass") ist andererseits _false_.

CC @reduz @vnen @willnationsdev

Ich würde nicht sagen, dass es beabsichtigtes Verhalten ist, insbesondere nicht mit einer Fehlermeldung, die zyklische Einschlüsse impliziert, wo es keine gibt.
get_class() und is_class() verwirren mich im Allgemeinen, können das nicht wirklich kommentieren. Die Quelle könnte dieses Rätsel auf lange Sicht lösen, aber bisher hat mir is gereicht.

@vnen Wäre dies etwas, das eine klarere Fehlermeldung benötigt?

@ PetePete1984 Ja, is war jetzt in 3.1 eine erstaunliche Sache. Obwohl ich auf eine Situation gestoßen bin, in der ich gerne die neuen match wie match custom_thing.get_class() und mit mehreren Zeichenfolgen verglichen hätte. Aber nichts Kritisches, nur Lesbarkeit und weniger Tipparbeit.

@avencherus Sie könnten in der Lage sein,

match custom_thing.get_script():
    <typename>: stuff # script classes
    <typename>: stuff
    _: match custom_thing.get_class():
        "Node": stuff # engine classes

Ich bin nicht sicher, warum es diesen Fehler gibt, ich muss untersuchen.

@willnationsdev Ich get_script() basiert, zumindest für mich gibt er ein GDScript-Objekt [GDScript:1057] .

@vnen Danke vnen. X) Einige andere seltsame Dinge scheinen vor sich zu gehen, als ich zurückkam, um diese Vorschläge auszuprobieren, um zu sehen, ob ich Ihnen bessere Informationen geben könnte. Ich werde gleich daran ziehen und es wieder aufbauen und damit herumspielen. Sehen Sie nach, ob noch etwas hinzuzufügen ist. Möglicherweise bin ich auf dem Weg auch auf ein anderes Problem gestoßen.

@avencherus Die "Klassennamen" von

class_name CustomType
match get_script():
    CustomType:
        print("I am a CustomType!") # should print

@willnationsdev Oh ordentlich, ich

@vnen Ja, einige zusätzliche Falten in der Geschichte. Lassen Sie mich sehen, wie gut ich sie artikulieren kann.

Erstens funktioniert Petes Lösung, wenn einer Basisklasse ein class_name erscheint alles in Ordnung. Was mir aufgefallen ist, ist, dass es zur Hälfte funktioniert, wenn ich zur Basisklasse zurückkehre und die class_name CustomBase herausziehe, die ich hinzugefügt habe. Es wird beim Hinzufügen von Knoten nicht mehr in der Knotenliste angezeigt, aber is funktioniert und es treten keine seltsamen Fehler auf.

Um dies zu bestätigen, habe ich die Schritte zum Erstellen eines erweiterten Skripts base2.gd -> custom2.gd neu erstellt. Verwenden Sie dann in custom.gd class_name CustomClass2 , aber keine Klassennamen in der Basisklasse.

Ein weiteres Problem trat auf. Die Knotenliste hatte die erste, wurde jedoch mit einem Symbol mit der Aufschrift "Fehler" aufgelistet.

godot master_2018-08-27_20-01-26

Also habe ich die erste Basisklasse so modifiziert, dass beide class_name . Aber wieder seltsame Ergebnisse.

Nicht alles wird in der Knotenliste angezeigt, und dann hat das Schlüsselwort is nur für einen von ihnen true zurückgegeben. Obwohl Sie in diesem Screenshot sehen können, dass die Knotenliste CustomClass2 erkennt, gibt is CustomClass2 im Code dahinter false zurück.

godot master_2018-08-27_20-05-11

Es scheint, als würden viele Dinge auf den Kopf gestellt oder bleiben hinter den Kulissen. Schwer vorherzusagen, was es mit meinem begrenzten Wissen anstellen könnte.

Hoffentlich hilft das. X)

Bearbeiten Ignorieren Sie diesen Kommentar. Ich hatte nicht bemerkt, dass class_name in 3.0.6 nicht implementiert ist. Dieses Problem bezieht sich sowieso auf einen 3,1-Build.

class_name scheint in 3.0.6 kaputt zu sein. Ich werde ein separates Thema machen, aber:

image

@ bfishman-Skriptklassen sind in 3.0.x keine Funktion. Deshalb funktioniert es nicht.

Ich habe gerade folgendes versucht und jede Version hat funktioniert. Alle Skriptklassen wurden im CreateDialog angezeigt, die Skripte wurden gut kompiliert, die Szene wurde erfolgreich ausgeführt usw.

Mit einer Szenenhierarchie wie dieser:

  • Knoten (base.gd)

    • Knoten (abgeleitet.gd)

Skript:

# res://base.gd
extends Node
class_name BaseNode
func _ready():
    print("base")

# res://derived.gd
extends BaseNode
extends "base.gd" # I tried both of these 'extends' lines and they each worked
class_name DerivedNode # I tried with and without this line
func _ready():
    print("derived")

Jedes Mal, wenn ich den Test durchführte, wurde er gedruckt

base
derived
base

...so wie es sollte.

Mein Vorschlag wäre, zu versuchen, den Datei-Cache Ihres Editors zu leeren (wenn sich während der Programmierung / Aktualisierung der Engine möglicherweise Änderungen an der Art und Weise ergeben, in der der Datei-Cache gespeichert wurde, könnte dies die Dinge irgendwie durcheinander bringen, bis Sie ihn löschen).

@willnationsdev Danke fürs anschauen, ich werde das ausprobieren. Sind das die Dateien aus dem AppData / Roaming-Ordner? Ich werde weitermachen und das Ganze vorerst klären. Wenn ja, fragen Sie sich, ob ich etwas Spezifischeres löschen sollte?

@avencherus Ich bin nicht ganz sicher. Ich erinnere mich nur daran, dass @karroffel etwas darüber erwähnt hat, als ich zuvor einige Korrekturen zum

Getestet unter https://github.com/godotengine/godot/commit/1093c0ff51b980634dffdd9618eaa53061da6419
Ich sehe keinen Fehler, aber der Knoten wird im Dialogfeld "Neuen Knoten erstellen" nicht angezeigt.

Ich erhalte auch den Fehler, der im ursprünglichen Beitrag angezeigt wird (Windows x64 Godot 3.1 alpha):

image

Dies geschieht jedoch in einem anderen Kontext. Ich habe 3 Skripte, die jeweils ein anderes class_name , und jedes von ihnen erweitert Node2D. Der Fehler tritt nur auf, wenn eines der Skripte mit dem Operator is verweist. Zum Beispiel if some_var is Incomer . Das Seltsame ist jedoch, dass es kein Problem gibt, wenn dasselbe Skript auf den anderen Klassennamen verweist. Und wenn das andere Skript auf den betreffenden Klassennamen verweist, ist dies ebenfalls kein Problem.

Es gibt also eine Klasse A, Klasse B, Klasse C. Wenn ClassC mit dem Operator is ClassA verweist, tritt beim Laden ein Fehler auf. Wenn ClassC auf ClassB verweist, kein Fehler. Wenn ClassB auf ClassA verweist, liegt kein Fehler vor.

Keines der Skripte befindet sich in derselben Szene, und alle Knoten sind Geschwister (keine Ahnenbeziehung).

@AlexHolly Gleiche Situation jetzt auch bei mir. Der Fehler scheint verschwunden zu sein, aber ja, Klassen werden nicht im Fenster zum Hinzufügen von Knoten angezeigt, wenn kein Basisskript vorhanden ist, das auch class_name .

Dies ist in Alpha 3.1 c320d93

Ein kleines Beispiel mit "is". Das gleiche kann passieren, wenn Sie "as" verwenden.
Dies wurde auch von @Oranjoose erwähnt.
cycle.zip

Keines der Skripte befindet sich in derselben Szene, und alle Knoten sind Geschwister (keine Ahnenbeziehung).

Dies hat nichts mit den Knoten in der Szene zu tun. Zyklen finden im Skript selbst statt.

Im Moment ist es ziemlich einfach, Zyklen zu erhalten, wenn is und as und wenn es passiert, ist es nicht wirklich ein Fehler, es ist so wie es ist. Ich werde versuchen, dies zu verbessern, aber nicht für 3.1. Der ursprüngliche Bericht ist ein Fehler, da der Code keine tatsächlichen Zyklen enthält.

Ich konnte den Fehler auch in 451e5fd nicht reproduzieren. Der Knoten wurde im Erstellungsfenster nicht angezeigt.

Ich kann bestätigen, dass dieses Problem in 0dbe014 (dem neuesten Master, den ich gezogen habe) nicht vorhanden ist. Wir können dieses Problem wahrscheinlich schließen.

Außerdem konnte ich es so gestalten, dass die Skriptklassen, die Skripte erweitern, immer noch im CreateDialog angezeigt werden, was immer noch ein Fehler war. PR ist oben verlinkt.

@willnationsdev Danke Will. X) Ich bin mit class_name auf verschiedene Probleme

Ich habe festgestellt, dass in einem Skript manchmal vage und nicht verwandte Fehler auftreten können, weil in einem Skript, auf das verwiesen wird, Fehler auftreten. Sie werden aussagekräftiger, wenn Sie das Täter-Skript öffnen, und wenn diese anderen behoben sind, werden sie ebenfalls gelöscht.

Ich werde das Thema des Beitrags jedoch neu anpassen, da dieser zyklische Fehler in seltsamen Situationen immer noch auftritt und beim Versuch, ihn neu zu erstellen, schwer zu fassen ist. Da ist also wahrscheinlich noch etwas dran, ich lasse es für vnen offen.

@avencherus Ich

Ich habe einige zyklische Referenzfehler festgestellt, die in meiner nächsten Arbeit aufgetreten sind, bei der ich mithilfe der statischen Typisierung sagen konnte, dass ich denselben Typ wie der Klassenname des Skripts zurückgegeben habe, aber wenn ich versucht habe, tatsächlich auf den Klassennamen zu verweisen des Skripts (um eine Instanz für die spätere Rückkehr in die Funktion zu erstellen) würde es nicht funktionieren, da das Skript auf sich selbst verweist und sich daher unendlich rekursiv laden muss.

Die Lösung, die ich gefunden habe, war, load(get_script().resource_path).new() . Ich weiß, ein ziemlicher Schluck, aber es ermöglichte dem Parser, die Daten sicher zu erstellen und den Kompilierungsprozess sicher zu durchlaufen, den Typnamen offiziell registrieren zu lassen und dann erst bei RUNTIME auf den Typ zu verweisen, wenn er vollständig initialisiert wurde.

Ich werde mich in regelmäßigen Abständen bemühen, es herauszufordern. Ich wünschte, ich könnte mehr Hilfe sein, aber ich stelle mir vor, dass diese warten müssen, bis diejenigen mit tiefem Wissen über ihre Implementierung an ihren eigenen Projekten arbeiten und diese Probleme mit dem Kopf voran angehen. Ich würde wetten, dass sie wissen würden, wo sie in dieser Situation ihre Ziele erreichen sollen.

Eine kurze Zusammenfassung einiger Probleme (diese werden in den kommenden Wochen veröffentlicht):

  1. Ich würde diese zyklischen Fehler bekommen, wenn ich obj is MyClass mache und es keine andere Verbindung oder Referenz zwischen den beiden gab. Obwohl ich nicht weiß, ob es den Szenenbaum scannt und seine Kinder als zyklische Referenzen zählt.
  2. Ich bin auch auf die von Ihnen beschriebenen Unannehmlichkeiten gestoßen. Ich wünschte, es wäre nicht so, weil es mit eingebauten / nativen Klassennamen in den gleichen Situationen gut funktioniert. Sie können also eine ganze Reihe von Code schreiben, um dieses Endziel zu erreichen, und denken, dass alles in Ordnung ist, bis Sie anfangen, Ihre benutzerdefinierten Typen hinzuzufügen, und Sie auf eine Hack- / Workaround- / ältere Methode zurückgreifen müssen, und was dann war der Wert davon, wenn nicht um ausführliche Pfadnamen zu vermeiden?
  3. Ich hatte diese Dinge fehlerfrei im Editor und führte sie während der Testläufe sauber aus, aber dann traten im exportierten Spiel Fehler und Ausfälle auf. Ein Beispiel unten (obwohl höchstwahrscheinlich nichts mit diesem Problem zu tun hat) ist, dass die Verwendung von class_name ihre Symbole im Build nicht finden konnte, aber keine Probleme bei Läufen und Tests des Editors.

gtc_2018-10-12_13-21-35

Insgesamt waren meine Erfahrungen mit class_name eine fast tägliche Begegnung mit vielen unvorhersehbaren, schwer zu erklärenden und schwer zu reproduzierenden Fehlern. Es wird viel Zeit damit verschwendet, herumzutanzen und zu versuchen, sie zu lösen.

Ich freute mich sehr auf sie und sie würden das Codieren bestimmter Dinge auf jeden Fall viel kompakter und lesbarer machen. Aus praktischen Gründen muss ich sie beiseite legen und die Verwendung in meinem aktuellen Projekt ablehnen.

Vielleicht in 4.0. X)

Ich werde zur alten Methode der Skriptpfade zurückkehren. Dabei wäre es nur meine eigene Präferenz, sie vollständig zu verwenden, um zufällige class_name Überraschungen zu vermeiden und den Code konsistenter zu halten.

Wie ich bereits sagte, ist es sehr einfach, Zyklen mit class_name zu erstellen, insbesondere wenn is und as . Mit Pfaden ist es weniger einfach, aber Sie könnten auch auf ähnliche Probleme stoßen. Das Problem ist, dass GDScript nie so verkabelt wurde, dass es zu stark vom Laden der Ressourcen abhängt. Ich habe einige Ideen, um dies zu beheben (insbesondere nur das Laden von Ressourcen zu ignorieren und Abhängigkeiten direkt zu analysieren), aber dies erfordert eine strukturelle Änderung des Parsers.

Wahrscheinlich wird es in den nächsten Versionen richtig gelöst, da es kein guter Zeitpunkt ist, sich damit zu beschäftigen. class_name wird vorerst eine "geringere Funktion" sein. In einigen Fällen können Sie es weiterhin verwenden, jedoch nicht so umfangreich wie erwartet.

@vnen Hey. Willkommen zurück. X)

Danke für die Antwort und den Zeitplan.

Ja, deshalb muss ich es erstmal aufbewahren. Mir war etwas langsam klar, dass es keine so reibungslose, passende oder natürliche Integration war. (Ich bekam Hinweise darauf, als ich alle Einträge in der Projektdatei sah.)

Ich nehme an, es scheint ein "geringeres" Merkmal zu sein, aber es wird einige sehr schwerwiegende Vorteile haben, wenn die Falten herausgearbeitet werden können. Ich freue mich wirklich darauf und spüre seinen Verlust, nachdem ich es bereits benutzt habe. Es ist definitiv ein guter Weg für GDScript.

Eine wichtige Sache, die mir fehlen wird, ist die Möglichkeit, auf Hinweise zurückzugreifen, wenn eine benutzerdefinierte Klasse mit Ihren neuen Typhinweisen kombiniert wird. var thing : NewThing

Wenn ich über ein paar Tage eine große Klasse mache und vielleicht ein paar Tage später, wenn ich sie zum ersten Mal benutze, erinnere ich mich nicht zu 100% an die Namen jeder Funktion, bis ich sie ein paar Mal benutzt habe. Das Erhalten dieser Hinweise war für mich ein unerwarteter und bedeutender Produktivitätsschub. Ich konnte viel länger in einem Bereich bleiben und arbeiten.

Sicherlich ist der Kern des Problems, wie Sie sagen, einfache Zyklen, aber ich denke, meine schlimmsten Erfahrungen waren, dass derzeit einige der Fehler nicht auf die richtigen Stellen hinweisen. Es ist jetzt einige Wochen her, aber ich hatte Situationen, in denen ich eine benutzerdefinierte Klasse verwendet habe und für ein paar Tage alles in Ordnung war. Dann schrieb ich etwas mehr Code, der diese benutzerdefinierte Klasse aufrief, und irgendwann während der Entwicklung bekam ich die Zyklusfehler. In einigen Fällen waren diese Fehler nicht hilfreich, um zu erklären, wo der Fehler auftrat. Um es zu finden, musste ich nacheinander alle Verwendungen von Klassennamen suchen und entfernen, bis der Fehler aufhörte.

Nur wenige derartige Vorfälle haben einen Großteil der Gewinne zurückerobert. Ich fürchte, ich könnte mir vorstellen, irgendwo in 30.000 Zeilen ein solches Problem auszulösen.

Der einzige Vorfall, der mich dazu brachte, sie alle zu reißen, war der, bei dem die Zyklusfehler nur im Export-Build auftraten und nicht verwandte Skriptfehler auslösten. Ich glaube, man hat gesagt, dass die Symboltexturen nicht gefunden wurden, aber das war es wirklich nicht, und es hat sich geklärt, als ich einige Verwendungen von class_name aufgegeben habe. Ich vermute, dass der Klassenname fehlgeschlagen ist und der Fehler in der folgenden Zeile aufgetreten ist.

Ich habe es manchmal gesehen, wenn Fehler in der Zeile über oder unter der Ursache auftreten.

Es ist wirklich schwer für mich und mein Nullwissen hier, die Quelle vieler dieser Probleme zu lokalisieren. Vieles davon steht mir einfach hinter dem Vorhang, und ich bin dankbar, dass Sie etwas davon entziffern können.

In 3.1 gab es viele ungewöhnliche Ereignisse mit den Warnungen und Fehlern. Ich frage mich also, ob das Problem das Problem selbst oder ein Problem mit der Fehlerberichterstattungslogik ist. Ich weiß noch nicht genau, wo ich anfangen soll, und ich kann nur hoffen, dass ein Teil davon hilfreich ist und ich sie mit der Zeit möglicherweise auf kleine Projekte eingrenzen kann.

EDIT: Nevermind, irgendwie habe ich die zyklische Inklusion einfach gelöst, indem ich es einfach nicht getan habe ...
Die globalen Klassen in project.godot werden beim Starten des Editors ohnehin überschrieben.

@vnen oder @avencherus Es wäre gut, das OP mit einer klaren Beschreibung dessen zu aktualisieren, worum es bei diesem Fehler am Ende geht, da es ansonsten eine lange Diskussion ist, es zu lesen, bevor man eine gute Vorstellung davon hat.

@ akien-mga Ich bin mir nicht mehr sicher, welchen Status es hat oder was ich konkret darüber schreiben soll.

Wenn ich mich recht erinnere, gibt es zumindest Teile davon. Die erwarteten zyklischen Fehler als Einschränkung von GDScript in seiner gegenwärtigen Form und dann unerwartete Fehler, die in kleinen Projekten schwer zu isolieren und zu reproduzieren sind (manchmal aufgrund ungenauer Fehlermeldungen).

Da es sich nicht um eine Funktion handelt, die ich derzeit verwende, habe ich den Fortschritt nicht verfolgt. Ich denke, einige Dinge hier und da wurden seit dieser Zeit behoben.

Auf einen Blick in diesen anderen Fragen sieht es so aus, als würde es um Änderungen in GDScript gehen. Mit den Überarbeitungen auf 3.2. Wenn das der Plan ist, dann wäre er nicht mehr unter dem Meilenstein von 3.1.

Es ist wahrscheinlich in Ordnung, dies zu schließen, es sei denn, vnen verwendet es für die Buchhaltung oder wenn Sie es bevorzugen, um auf die bevorstehenden doppelten Probleme zu verweisen, wenn 3.1.0 stabil landet.

Das Feature ist ein Usability-Gewinn, an dem ich interessiert bin, daher werde ich es höchstwahrscheinlich in Version 3.2 erneut besuchen und alle Ergebnisse veröffentlichen.

Nun, das sollte nicht geschlossen werden, nein, die schiere Menge an doppelten Berichten zeigt definitiv, dass es etwas zu beheben gibt :)

Ich habe die folgende Fehlermeldung erhalten, die für mich beim Aktualisieren eines Projekts von 3.0 auf 3.1 problematisch ist. Bisher funktionierte der folgende Code:

extends Node2D
export(String, FILE, "*.gd") var _class_name = "res://Test.gd"
onready var SomeClass = load(_class_name)

func foo():
    for c in get_children() :
        if c is SomeClass : 
            do_stuff()

Wenn ich den Code in ändere:

extends Node2D
class_name SomeClass

func foo():
    for c in get_children() :
        if c is SomeClass : 
            pass

Ich erhalte folgende Fehlermeldung:

Analysefehler: Die Verwendung eines Namens in der Klassendatei ist nicht zulässig (erstellt eine zyklische Referenz).

Dies ist frustrierend für mich, da die von mir gesuchten untergeordneten Knoten alle von dieser Klasse erben und mit anderen untergeordneten Knoten gemischt sind, die dies nicht tun. Ist die Möglichkeit, eine Überprüfung für andere Instanzen einer Skriptklasse einzugeben, die nicht auf diese Weise funktionieren soll, und gibt es eine andere Möglichkeit, wie ich dies tun sollte?

@Diaspater Ich denke, alles was Sie tun müssen, ist if c is SomeClass in if c is get_script() ändern. Beide Optionen führen eine Laufzeitprüfung durch, aber für die Version SomeClass muss das Skript zum Zeitpunkt des Editors erneut geladen werden (was zu einer zyklischen Referenz führt), während die Methode get_script() nicht versucht, etwas zu tun Redaktionszeit.

@willnationsdev Ich verstehe, dass dies eine gültige Lösung ist (oder eine Problemumgehung für mein Problem, als ich nach dem Schreiben meines ursprünglichen Kommentars feststellte, dass der erste Weg noch funktioniert.

DummySomeClass.gd
extends Node2D
class_name DummySomeClass

func foo():
    pass


SomeClass.gd
extends DummySomeClass
class_name SomeClass

func foo():
    for c in get_children() : 
        if c is DummySomeClass: 
            pass

Davon abgesehen verstehe ich Ihre Erklärung, warum es derzeit einen Fehler gibt. Mit mehreren Lösungen oder Problemumgehungen für dieses Problem denke ich, dass dies kein wesentlicher Fehler ist, der behoben werden muss, aber dennoch ein Fehler, den ich gerne irgendwann in der Zukunft behoben sehen würde.

Nach der Verwendung dieser Methode in etwas komplexeren Anwendungen scheint dies andere zyklische Fehler an anderen Stellen in anderen gekoppelten Skripten zu verursachen, sodass dies wahrscheinlich keine gute Lösung / Problemumgehung für das Problem ist.

Dies mag eine naive Frage sein, aber sollten wir diese nichtzyklische Einschränkung nicht beseitigen.
Ich meine, andere Sprachen wie Java, C #, C ++ usw. können problemlos mit Typen umgehen ...

@harraps das wird gemacht (wie ich ein paar Mal im Thread gesagt habe), aber es erfordert einige grundlegende Änderungen in der Art und Weise, wie GDScript verdrahtet ist. Ich werde dies jetzt nicht anfassen, da wir kurz vor der Veröffentlichung stehen und diese Änderung wahrscheinlich die Kompatibilität beeinträchtigen wird.

Falls andere darauf stoßen, habe ich eine andere Instanz eines Fehlers im Zusammenhang mit "zyklischen Referenzen" gefunden, der sich jedoch von den anderen hier aufgeführten unterscheidet.

Wenn Sie eine Klasse mit einer statischen Factory-Methode erstellen, die auf den Namen der aktuellen Klasse im Rückgabewert verweist, werden keine Fehler im Editor selbst gemeldet. Sobald der Editor geschlossen wird, wird eine Fehlermeldung angezeigt dass Ressourcen noch verwendet werden.

extends Reference
class_name MyClass

static func make() -> MyClass:
    # can't even use get_script() for static funcs, but that's a separate issue
    var c = load("res://my_class.gd").new()
    return c

Sie erhalten dann diesen Fehler:

ERROR: SelfList<class GDScriptFunction>::List::~List: Condition ' _first != 0 ' is true.
   At: .......\godot\core/self_list.h:111
ERROR: SelfList<class GDScript>::List::~List: Condition ' _first != 0 ' is true.
   At: .......\godot\core/self_list.h:111
WARNING: ObjectDB::cleanup: ObjectDB Instances still exist!
     At: core\object.cpp:2093
Leaked instance: GDScript:17060 - Resource name:  Path: res://my_class.gd
Leaked instance: GDScriptNativeClass:1058
ERROR: ResourceCache::clear: Resources Still in use at Exit!
   At: core\resource.cpp:425

Reposting von # 944,

Ich stoße auch regelmäßig auf zyklische GDscript-Abhängigkeiten. Hier sind einige Anwendungsfälle, in denen ich derzeit gezwungen bin, auf untypisiertes GDscript zurückzugreifen:

  1. Meine Charaktere verwenden ein ActorController , das verschiedene Move s ausführt (wie Zustände in einer Zustandsmaschine). Das ActorController leitet _physics_process() und dergleichen an das aktive Move . Umgekehrt greift der Zug auf die ActorController zu, um zu einem anderen Move ActorController zu wechseln oder auf Eigenschaften (wie Sprunghöhe, Laufgeschwindigkeit usw.) zuzugreifen.

  2. Dieselbe Situation mit meinem MoveRepository - das Repository speichert wiederverwendbare Move s, aber die Move müssen auch auf das Repository zugreifen, wenn sie weitere Move abrufen möchten um es in ihre ActorController auszuwählen

actor-framework

Dies ist in C # oder C ++ kein Problem, aber für GDscript (mit optionaler statischer Typisierung) muss ich auf Varianten zurückgreifen (dynamische Typisierung) oder mithilfe von Ereignissen und dergleichen unnötige Indirektionen erstellen.

Ich habe auch dieses Problem. Ich habe ein Setup, das ähnlich, aber einfacher ist.
Die Klasse TurnManager hat eine Variable vom Typ Actor und jedes Actor hat einen typisierten Verweis auf TurnManager
Ich verwende nicht einmal is Ich habe buchstäblich nur die Variablen deklariert und es reicht aus, um diesen Fehler zu provozieren.
Verwenden der neuen stabilen Version 3.1 unter Linux 64-Bit.

image

Bin gerade darauf gestoßen. Scheint verwandt zu sein.

image

Sehr seltsam.

image

Auch ich scheine darauf zu stoßen. Ich habe mich gefragt, ob es daran liegt, dass ich die Skripte größtenteils von Objekten getrennt habe. Ich habe eine Basisattributklasse, die den Knoten erweitert, und PrimaryAttribute und SecondaryAttribute, die ihn erweitern, und dann 12 PrimaryAttribute-Knoten und einen SecondaryAttribute-Knoten. Dem Editor scheint es aber nicht zu gefallen? Auch wenn das Spiel gut läuft, wenn ich es spiele.

Bemerkenswerterweise habe ich die Ressourcenpfade für die Klassennamen ausgetauscht, und das hat dazu geführt, dass die Dinge ungefähr 5 Minuten lang einwandfrei funktionierten, bevor sie mir ohne Grund wieder Fehler gaben. : /

Hmm. Die Fehler scheinen mit der Reihenfolge zu tun zu haben, in der die Dinge in das Editorfenster geladen werden? Ich kann sie dazu bringen, wegzugehen, indem ich Dateien in der Reihenfolge schließe und wieder öffne, in der sie erben. Also wahrscheinlich eine Art Problem damit, Dinge in einigen Dateien nicht zu deklarieren. : /

Bearbeiten: Eigentlich nein, es spielt keine Rolle, in welcher Reihenfolge ich Dateien öffne oder ob ich überhaupt andere Dateien geöffnet habe. Wenn ich eine dieser Dateien zum ersten Mal lade, werden keine Fehler angezeigt und erst, wenn ich sie ändere, werden alle Fehler angezeigt. : /

@ Angular-Angel Ich habe festgestellt, dass ein Neustart von Godot die Fehler behebt. Es ist enttäuschend, dass ich in Godot noch keine statische Eingabe mit benutzerdefinierten Klassen / Typen verwenden kann, ohne dass bizarre Fehler auftreten.

"Nur" das Projekt zu schließen / wieder zu öffnen hat mir gereicht. Umschalt + Strg + Q (zur Projektliste gehen), Eingabeaufforderung bestätigen und erneut auf das Projekt doppelklicken. Immer noch ein bisschen frustrierend, aber man gewöhnt sich daran (bis es behoben ist).

Tut mir leid, aber ich bin auch ein bisschen frustriert und wusste nichts über diese Problemumgehung, da ihr kommentiert habt. Ich habe eine Weile aufgehört, meinen Code einzugeben, aber ich vermisse ihn immer noch VIEL.

Einverstanden. Dies wurde sehr schnell zu einer sehr wichtigen Angewohnheit für mich und andere. Wird wahrscheinlich sehen, ob die Problemumgehung für den Neustart für den Moment ausreicht. (Godot, der schnell anfängt, wird großartig sein) Am 16. Mai 2019, 8:27 Uhr, schrieb Ricardo Alcantara [email protected] : Entschuldigung , aber ich bin auch ein bisschen frustriert und wusste nichts über diese Problemumgehung, seit ihr Kommentare abgegeben habt Ich habe eine Weile aufgehört, meinen Code einzugeben, aber ich vermisse ihn immer noch VIEL.

- Sie erhalten dies, weil Sie einen Kommentar abgegeben haben. Antworten Sie direkt auf diese E-Mail, zeigen Sie sie auf GitHub an oder schalten Sie den Thread stumm.

Godot 3.1.1 (nicht mono)
Stack.zip

minimal reproduzierbares Beispiel

https://cdn.discordapp.com/attachments/477544613511692358/584811385838632977/unknown.png

Bitte jemand repariert dies.

image

Das Laden funktioniert einwandfrei, das Vorladen nicht

Beachten Sie, dass in StackList.gd tatsächlich ein nicht erfasster Skriptfehler vorliegt. Insbesondere ist es ein Syntaxfehler in der Wörterbuchschlüsseldeklaration. Es wird jedoch erst abgefangen, wenn das Wörterbuch in eine Konstante geändert wurde.

Ich wollte nur notieren, dass ich heute auch den Fehler "is" class_name habe.

Ich habe wieder object.has_method ("name") verwendet, anstatt zu testen, ob das Objekt className ist

Ich habe diesen in 3.1.1 oft getroffen und bin durch Reifen gesprungen, um ihn zu vermeiden.
Ich hoffe, es wird in 3.2 behoben!

Ich bitte darum, keine Probleme ohne neue Informationen zu lösen. Wir alle wissen, dass dies passiert, haben bereits viele Beispiele und werden nicht auf magische Weise mit weiteren Kommentaren verschwinden.

Ich versuche derzeit, dies bei @JavaryGames zu beheben. Die Lösung ist bereits im Gange. Ich bin mir nicht sicher, ob es zu 3.2 wird, da es eine große Änderung ist (musste etwas neu verdrahten, wie GDScript intern funktioniert) und wir stehen kurz vor der Veröffentlichung, aber vielleicht können wir es in 3.2.1 oder so integrieren. Wird definitiv in 4.0 behoben.

Das Update, an dem ich gearbeitet habe, ist immer noch WIP und verursacht Abstürze. Ich bin nicht sicher, ob ich eine so große Änderung in der Beta-Phase zusammenführen kann, daher wird dies wahrscheinlich später in einer Version 3.2.x geschehen.

@vnen Gibt es einen Zweig mit Korrektur für diesen Fehler, den wir kompilieren und testen können?

Ich bin mir nicht sicher, ob weitere Informationen an dieser Stelle hilfreich sind, aber eine Problemumgehung (die bei mir funktioniert hat) besteht darin, die class_name der problematischen Klasse zu ändern und sie dann wieder zu ändern. Das lässt es scheinen, Cache-bezogen zu sein.

Es passierte mir in einer Zeile, in der ich ein Klassenmitglied mit as umwandelte, nachdem ich die Signatur einer Methode der Klasse geändert hatte, in die die Variable umgewandelt wurde, aber bevor ich die eigentliche Methode korrigieren konnte. Nachdem die Methode korrigiert wurde, gab die Zeile diesen Fehler weiter aus und hörte erst auf, als ich den Namen der Besetzungsklasse endgültig in etwas anderes änderte und ihn dann wieder änderte.

@vnen Gibt es einen Zweig mit Korrektur für diesen Fehler, den wir kompilieren und testen können?

Ja, ich habe es in meiner öffentlichen Gabel: https://github.com/vnen/godot/commits/gdscript-no-cycles

Ich bin mir nicht sicher, ob weitere Informationen an dieser Stelle hilfreich sind, aber eine Problemumgehung (die bei mir funktioniert hat) besteht darin, die class_name der problematischen Klasse zu ändern und sie dann wieder zu ändern. Das lässt es scheinen, Cache-bezogen zu sein.

Möglicherweise werden im Editor einige Caching-Artefakte angezeigt, da während der Bearbeitung ständig alles neu geladen wird. Wenn Sie dieses Problem erreichen, funktioniert es höchstwahrscheinlich nicht, wenn Sie es ausführen, selbst wenn Sie es im Editor fehlerfrei erhalten.

https://github.com/godotengine/godot/issues/38265 scheint ein doppelter Bericht mit einigen Details zur Reproduktion zu sein.

Wann wird dieses Update in der Hauptzeile erscheinen?
Es ist super nervig, weil ich Typ-Save-Skripte verwende und sehr oft auf dieses Problem stoße.
Heute bin ich in eine nicht lösbare Situation geraten.

extends Resource
class_name WfcSlotHistory

func _init(slot:WfcSlot):
    pass
extends Resource
class_name WfcSlot

function saveHistory():
   var history:WfcSlotHistory = WfcSlotHistory.new(self)
   ...

res: //assets/wfc/WfcSlotHistory.gd : 5 -
modules / gdscript / gdscript. cpp: 576 - Methode fehlgeschlagen. Rückgabe: ERR_PARSE_ERROR

@MikeSchulze In diesem Fall WfcSlot sollte wahrscheinlich nichts über WfcSlotHistory wissen. Die Aktion save sollte sich wahrscheinlich auf Letzteres beziehen.

(Dieses Verhalten / dieser Fehler ist jedoch ärgerlich, verstehen Sie mich nicht falsch.)

@ Jeto143 danke für deine Antwort, ich habe mein Problem gelöst, indem ich alle Slot-Mitglieder manuell in die SlotHistory kopiert habe.
Hoffentlich wird dieser Fehler behoben

Hallo Entwickler, wann wird dieser lange ... lange Fehler endlich behoben sein?

Zuerst brauche ich mehrere Konstruktoren für eine Klasse, aber das ist nicht erlaubt, aber warum?
Zweiter Versuch Ich benutze die statische Funktion, um dieses Problem zu lösen, aber das funktioniert auch nicht.

Ich habe eine Klasse wie diese (einfaches Beispiel)
`` ``
erweitert Ressource
Klassenname ClassA

_init (WertA: int, WertB: int):
Drucke (WertA, WertB)

statische Funktion von (Wert: int) -> Klasse A:
Rückgabe ClassA.new (Wert, Wert)
`` ``

`` ``
var o: ClassA = ClassA.new (1,2) # funktioniert einwandfrei

var o2: ClassA = ClassA.of (2) # erzeugt den Fehler

`` ``

Die Verwendung der statischen Funktion führt zu diesem Fehler.
"Parser-Fehler: Die Verwendung eines eigenen Namens in der Klassendatei ist nicht zulässig (erstellt eine zyklische Referenz)"

Dies blockiert mich also, eine Klasse zu schreiben, um mehrere Konstruktoren zu verwenden, die in modernen Sprachen Standardverhalten sind.

Ich verwende derzeit eine hackige Problemumgehung wie diese
`` `
statische Funktion von (Wert: int) -> Klasse A:
var clazz = load ("res: //../../ClassA.gd")
return clazz.new (Wert, Wert)
`` ``

Freundliche Grüße
Mike

Hallo Entwickler, wann wird dieser lange ... lange Fehler endlich behoben sein?

Es wird in 4.0 als Teil des GDScript-Rewrite gelöst.

Funktioniert dies auch für statische Funktionen, wenn dies behoben ist?

class_name Cls

static func f():
    print(Cls)

@vnen also wir sind auf der 3.2.X Version, können wir bald eine Lösung erwarten?

@ Ploppy3 Diese Korrekturen sind auf massive Änderungen zurückzuführen, die mit dem Umschreiben von GDScript einhergehen, und es ist wahrscheinlich nicht möglich, sie auszuwählen. Sie müssen auf 4.0 aktualisieren, wenn Sie diese Korrekturen wünschen.

Ich habe dieses Problem auch hier sind meine beiden Skripte.

class_name Entity extends Area2D

export var resource : Resource

onready var sprite   = get_node("sprite")
onready var collider = get_node("collider")

func _process(delta: float) -> void:
    if sprite   == null: sprite   = get_node("sprite")
    if collider == null: collider = get_node("collider")
    if resource is EntityConfig:
        sprite.frame = wrapf(sprite.frame+resource.gfx_speed, resource.gfx_start, resource.gfx_start+resource.gfx_count)
class_name EntityConfig extends Resource

export var gfx_image   := ""
export var gfx_start   := 0
export var gfx_speed   := 1.0
export var gfx_count   := 0
export var gfx_xoffset := 0.0
export var gfx_yoffset := 0.0
export var gfx_xsize   := 16.0
export var gfx_ysize   := 16.0
export var hit_xoffset := 0.0
export var hit_yoffset := 0.0
export var hit_xsize   := 16.0
export var hit_ysize   := 16.0

func new()->Area2D:
    var entity = Entity.new()
    entity.sprite            = Content.load_texture(gfx_image)
    if entity.sprite != null:
        entity.sprite.frame      = gfx_start
        entity.sprite.position.x = gfx_xoffset
        entity.sprite.position.y = gfx_yoffset
        entity.sprite.hframes    = entity.sprite.texture.get_width () / gfx_xsize
        entity.sprite.vframes    = entity.sprite.texture.get_height() / gfx_ysize

    entity.collider.position.x      = hit_xoffset
    entity.collider.position.y      = hit_yoffset
    entity.collider.shape.extents.x = hit_xsize / 2
    entity.collider.shape.extents.y = hit_ysize / 2
    return entity

Ich habe dieses Problem gerade bei der Arbeit an meinem Schlusssteingruppenprojekt in Godot 3.2.3 entdeckt. Für unsere Kollisionsrückrufe haben wir ungefähr Folgendes:

extends Area2D

func _on_Throwable_body_entered(body: Node) -> void:
    if body is Player:
        if body.pick_up():
            queue_free()

Wir möchten also if body is Player überprüfen, bevor wir spielerspezifische Methoden aufrufen. Das Problem ist, dass Player möglicherweise verfügbar ist oder nicht, selbst wenn dies im globalen Bereich erfolgt, unabhängig davon, ob es über class_name oder preload -ed deklariert wurde. Dies geschieht auch dann, wenn Player unser Skript nicht vorlädt, um eine offensichtliche zirkuläre Abhängigkeit zu verursachen.

Wir arbeiten derzeit daran, indem wir einfach sicherstellen, dass Player das einzige ist, was in der Kollisionsmaske von Area2D , und überhaupt nichts im Code überprüfen. Zuerst überprüften wir if body.name == "player" .

Ich bin froh zu erfahren, dass daran gearbeitet wird, auch wenn es lange dauert, und ich hoffe, dass alles gut geht.

Ich hatte ein ähnliches Abhängigkeitsproblem, als ich dadurch kein Builder-Muster mit einer statischen Methode implementieren konnte:

class_name MyClass

static func build() -> MyClass:
  var new_instance  = MyClass.new()
  ...
  return new_instance

Die hier beschriebene Problemumgehung zum Laden der Klasse aus dem Quelldateipfad ist nett, erfordert jedoch, dass der Dateibaum nicht geändert wird, ohne den Quellcode zu ändern.

Ich benutze diesen Trick, um den aktuellen Quelldateipfad auch in statischen Methoden zu haben (in denen get_script () nicht verfügbar ist):

static func build() :
    var new_instance = load(GodotExt.current_script_path()).new()
    ...
    return new_instance

mit

class_name GodotExt

static func current_script_path():
    return get_stack()[1].source    <- return usable script path

Dieser Trick, um die aktuelle Klasse zu erhalten, scheint von überall zu funktionieren.
Es ist roh und kann verwendet werden, um ähnliche zyklische Abhängigkeitsprobleme zu vermeiden, die auf die globale Abhängigkeitsbehebung warten.

hi @AliBouarab schöner Trick

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen