Godot: Melhores nós personalizados do EditorPlugin

Criado em 7 ago. 2016  ·  121Comentários  ·  Fonte: godotengine/godot

Os nós criados pela função add_custom_type no EditorPlugin têm o script selecionado atribuído a ele ao serem adicionados. Isso os torna quase inúteis, pois você só pode usar as funções definidas nesse script em outros nós.

Isso é completamente diferente de outros nós e torna os complementos de nó praticamente inúteis/muito mais irritantes de usar.

feature proposal plugin usability

Comentários muito úteis

Pelo que entendi a expectativa é ter a possibilidade de criar nós customizados que irão se comportar como nós embutidos, ou seja, devem ter as seguintes funcionalidades:

  • Ícone personalizado, identificador personalizado
  • Instanciável através do widget Add node (e acho que via script, então exposto ao Global Scope?)
  • Ter uma API personalizada codificada por meio de um script (por exemplo RedNode2D estenderia Node2D e teria uma modulação vermelha definida por meio de um script personalizado)
  • Em seguida, este nó personalizado deve se comportar como um nó interno, ou seja, o usuário deve ser capaz de instancia-lo sem nenhum script (a API personalizada não seria exposta diretamente ao usuário, assim como para o script interno em que é codificado em C++) e anexar um script a ele que estenderia o nó personalizado (por exemplo extends RedNode2D ).

Essa seria a expectativa "natural" ao declarar um nó personalizado e seria um recurso muito poderoso; Deduzo do exposto que não funciona dessa maneira até agora, em parte devido a decisões de design. Se houver uma maneira de ter uma funcionalidade como a que descrevi acima, tenho certeza de que teria muitos aplicativos. O assetlib estaria cheio de nós personalizados que fazem muito trabalho fora da caixa e podem ser usados ​​como se fossem embutidos.

Reabrindo até que haja um consenso sobre o que pode/deve ser feito ou não.

Todos 121 comentários

Eu não entendo o que você quer dizer

@reduz quando você adiciona na cena um nó que é um tipo criado por um plugin, ele já tem o script do plugin anexado. Portanto, é impossível adicionar outro script com comportamento personalizado.

Claro que não, isso é por design principal e não mudará.

Em 7 de agosto de 2016 18:11, "George Marques" [email protected] escreveu:

@reduz https://github.com/reduz quando você adiciona à cena um nó que um
tipo criado por um plugin, ele já possui o script do plugin anexado. assim
é impossível adicionar outro script com comportamento personalizado.


Você está recebendo isso porque foi mencionado.

Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment -238108767,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z29F5q8PaoBv4OrzAUayzrfNjfHyZks5qdkoUgaJpZM4JejbZ
.

Isso é triste. Mas você sempre pode adicionar o script ao pai ou a um filho.

Fechando como não vai corrigir.

Posso estar entendendo algo errado, mas se seu tipo personalizado for um script,
como ele não será incluído no nó criado? Não faz sentido para
ser diferente

Em 7 de agosto de 2016 21:52, "George Marques" [email protected] escreveu:

Isso é triste. Mas você sempre pode adicionar o script ao pai ou a um filho.

Fechando como não vai corrigir.


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment -238120392,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z27Zo4Ixvo4APSC4Fxf5ZqCJRsAxXks5qdn3igaJpZM4JejbZ
.

Eu acho que precisaria da capacidade de ter dois (ou mais) scripts por nó, embora isso realmente não faça muito sentido.

Godot originalmente apoiou isso, mas foi mais problema do que vantagem

Em 7 de agosto de 2016 22:36, "George Marques" [email protected] escreveu:

Eu acho que precisaria da capacidade de ter dois (ou mais) scripts por
node, embora isso realmente não faça muito sentido.


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment -238123729,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z27jidVZl-hHWW3G_ESr8Cqj3eX7Eks5qdogRgaJpZM4JejbZ
.

O problema é que os nós personalizados são quase inúteis, pois não são realmente "nós personalizados", são apenas nós de base com um script predefinido e um ícone diferente.
O que eu esperava dos "nós personalizados" é que eu pudesse estender o nó para usar o que estiver definido no script. Cenário de exemplo:
Eu tenho um nó personalizado chamado Test que é filho de Sprite e adiciona uma função test() que retorna true . Em seguida, gostaria de criar um novo nó de teste, atribuir um script a ele e usar a função test() .
Isto é impossível.

Eu acho que de volta à cena para herdar + script para estender o combo então.

Bem, ser um nó predefinido com um script predefinido e um ícone diferente é IMO
bastante personalizado, mas se você realmente quiser colocar seu próprio código personalizado
lá, você sempre pode herdar os que vem com o nó. Poderíamos
tornar isso um pouco mais fácil a partir da interface do usuário, se realmente desejado.

Em segunda-feira, 8 de agosto de 2016 às 10h40, Dominik Banaszak [email protected]
escreveu:

O problema é que os nós personalizados são quase inúteis, pois não são realmente
"nós personalizados", eles são apenas nós base com um script predefinido e diferentes
ícone. Eu acho que de volta à cena para herdar + script para estender o combo então.


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment -238240130,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z27eHoXwgr6buF6CCAHfxwx1dKkCiks5qdzHhgaJpZM4JejbZ
.

Eu adoraria se pudesse ser automatizado/facilitado através da interface do usuário.

Pelo que entendi a expectativa é ter a possibilidade de criar nós customizados que irão se comportar como nós embutidos, ou seja, devem ter as seguintes funcionalidades:

  • Ícone personalizado, identificador personalizado
  • Instanciável através do widget Add node (e acho que via script, então exposto ao Global Scope?)
  • Ter uma API personalizada codificada por meio de um script (por exemplo RedNode2D estenderia Node2D e teria uma modulação vermelha definida por meio de um script personalizado)
  • Em seguida, este nó personalizado deve se comportar como um nó interno, ou seja, o usuário deve ser capaz de instancia-lo sem nenhum script (a API personalizada não seria exposta diretamente ao usuário, assim como para o script interno em que é codificado em C++) e anexar um script a ele que estenderia o nó personalizado (por exemplo extends RedNode2D ).

Essa seria a expectativa "natural" ao declarar um nó personalizado e seria um recurso muito poderoso; Deduzo do exposto que não funciona dessa maneira até agora, em parte devido a decisões de design. Se houver uma maneira de ter uma funcionalidade como a que descrevi acima, tenho certeza de que teria muitos aplicativos. O assetlib estaria cheio de nós personalizados que fazem muito trabalho fora da caixa e podem ser usados ​​como se fossem embutidos.

Reabrindo até que haja um consenso sobre o que pode/deve ser feito ou não.

+1
Este foi um dos primeiros grandes obstáculos para mim quando tentei portar um projeto existente de "OtherEngine(tm)" para Godot. Tipos personalizados, como @akien-mga explicados acima, devem se comportar como qualquer outro tipo integrado após o registro.

Por favor, explique de que maneira você acredita que eles não

Em 8 de agosto de 2016 11h50, "Ralf Hölzemer" [email protected] escreveu:

+1
Este foi um dos primeiros grandes obstáculos para mim quando tentei portar um
projeto existente de "OtherEngine(tm)" para Godot. Tipos personalizados, como
@akien-mga https://github.com/akien-mga explicado acima, deve apenas
comportar-se como qualquer outro tipo embutido após o registro.


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment -238261603,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z25PJzv9w7iXO350tRF3FcEuYQYUKks5qd0IrgaJpZM4JejbZ
.

Como já foi dito anteriormente, a maior desvantagem no momento é que os tipos personalizados são pouco mais do que uma maneira rápida de instanciar o tipo base desse script e atribuir o script apropriado a essa instância. Isso torna impossível estender esse nó no editor com outro script - como você pode fazer com tipos internos.

Mas também é impossível construir árvores de herança com nós personalizados nas caixas de diálogo "Criar novo nó/recurso" porque eles só aparecem nessas árvores quando você os registra com um tipo integrado como pai via add_custom_type.

Por exemplo, vamos supor que eu queira herdar todos os meus tipos personalizados em meu projeto de um único tipo base.

base.gd

extends Node
export (Color) var color

type_a.gd

extends base.gd

type_b.gd

extends base.gd

Como está agora, eu tenho que registrar esses tipos assim. Neste caso, o segundo argumento de add_custom_type tem que ser "Node", caso contrário eles não aparecerão nas caixas de diálogo.

func _enter_tree():
    add_custom_type("Base", "Node", preload("base.gd"), preload("base.png"))
    add_custom_type("TypeA", "Node", preload("type_a.gd"), preload("type_a.png"))
    add_custom_type("TypeB", "Node", preload("type_b.gd"), preload("type_b.png"))

... e este é o resultado.

add_node_flat

Embora seja bom poder registrar tipos personalizados como este, as caixas de diálogo não refletem a natureza da herança desses tipos como outros tipos internos. Para qualquer tipo embutido, posso olhar para aquela árvore e ver rapidamente com o que estou lidando. Posso, por exemplo, ter certeza de que Sprite é um Node2D e, portanto, herda todas as funções fornecidas pelo Node2D. O mesmo não acontece com os tipos personalizados.

Agora, se os tipos personalizados pudessem ser totalmente registrados no escopo global, como @akien-mga mencionado acima, as coisas seriam muito mais simples de entender e usar.

Primeiro, você pode herdar de um tipo personalizado referenciado pelo nome do tipo em vez do caminho/nome do arquivo.

base.gd

extends Node
export (Color) var color

type_a.gd

extends Base

type_b.gd

extends Base

... então, o registro dos tipos personalizados poderia ser simplificado assim. Observe o segundo parâmetro ausente de add_custom_type.

func _enter_tree():
    add_custom_type("Base", preload("base.gd"), preload("base.png"))
    add_custom_type("TypeA", preload("type_a.gd"), preload("type_a.png"))
    add_custom_type("TypeB", preload("type_b.gd"), preload("type_b.png"))

... e você obteria uma visão geral muito melhor nas caixas de diálogo "Criar novo nó/recurso":

add_node_tree

... e, claro, a capacidade de estender esses tipos no editor com um script personalizado:

custom_type_no_script

... que também seria referenciado pelo nome do tipo em vez do nome/caminho do script

extends Base

Aqui está o exemplo de plugin acima para brincar.
addons.zip

Ah, entendo .. essas duas coisas definitivamente devem ser corrigidas, juntamente com
adicionando suporte de herança ao diálogo de criação de script

Em 8 de agosto de 2016 13:54, "Ralf Hölzemer" [email protected] escreveu:

Como já foi dito anteriormente, a _maior desvantagem_ no momento é que
tipos personalizados são pouco mais do que uma maneira rápida de instanciar o tipo base
desse script e atribua o script apropriado a essa instância. Isto
torna impossível estender esse nó no editor com outro script -
como você pode fazer com tipos embutidos.

Mas também é impossível construir árvores de herança com nós personalizados em
as caixas de diálogo "Criar novo nó/recurso" porque elas só aparecem nesses
árvores quando você as registra com um tipo embutido como pai via
add_custom_type.

Por exemplo, vamos supor que eu queira herdar todos os meus tipos personalizados no meu
projeto de um único tipo base.

_base.gd http://base.gd_

estende o nó
exportar (Cor) var color

_type_a.gd http://type_a.gd_

estende base.gd

_type_b.gd http://type_b.gd_

estende base.gd

Como está agora, eu tenho que registrar esses tipos assim. Nisso
caso, o segundo argumento de add_custom_type deve ser "Node", caso contrário
eles não aparecerão nas caixas de diálogo.

func _enter_tree():
add_custom_type("Base", "Nó", preload("base.gd"), preload("base.png"))
add_custom_type("TypeA", "Node", preload("type_a.gd"), preload("type_a.png"))
add_custom_type("TypeB", "Node", preload("type_b.gd"), preload("type_b.png"))

... e este é o resultado.

[imagem: add_node_flat]
https://cloud.githubusercontent.com/assets/8785013/17486294/9bcc029c-5d90-11e6-81e6-6fce6b0e7cf0.png

Embora seja bom poder registrar tipos personalizados como este, o
diálogos não refletem a natureza da herança desses tipos como
outros tipos embutidos. Para qualquer tipo embutido, posso olhar para aquela árvore e
veja de relance com o que estou lidando. Posso, por exemplo, ter certeza de que
Sprite _é um_ Node2D e, portanto, herda todas as funções _fornecidas
por_ Node2D. O mesmo não acontece com os tipos personalizados.

Agora, se os tipos personalizados pudessem ser totalmente registrados no escopo global, como
@akien-mga https://github.com/akien-mga mencionado acima, as coisas seriam
ser muito mais simples de entender e usar.

Primeiro, você pode herdar de um tipo personalizado referenciado por _type name_
em vez do caminho/nome do arquivo.

_base.gd http://base.gd_

estende o nó
exportar (Cor) var color

_type_a.gd http://type_a.gd_

estende a base

_type_b.gd http://type_b.gd_

estende a base

... então, o registro dos tipos personalizados poderia ser simplificado como
isto. Observe o segundo parâmetro ausente de add_custom_type.

func _enter_tree():
add_custom_type("Base", preload("base.gd"), preload("base.png"))
add_custom_type("TypeA", preload("type_a.gd"), preload("type_a.png"))
add_custom_type("TypeB", preload("type_b.gd"), preload("type_b.png"))

... e você teria uma visão geral muito melhor na seção "Criar novo
Caixas de diálogo Nó/Recurso":

[imagem: add_node_tree]
https://cloud.githubusercontent.com/assets/8785013/17487264/619f4da0-5d94-11e6-880f-a00791e30125.png

... e, claro, a capacidade de estender esses tipos no editor com um
roteiro personalizado:

[imagem: custom_type_no_script]
https://cloud.githubusercontent.com/assets/8785013/17487807/b54aced2-5d96-11e6-90e5-ee838b6a1335.png

... que também seria referenciado por _type name_ em vez do script
nome/caminho

estende a base

Aqui está o exemplo de plugin acima para brincar.
addons.zip https://github.com/godotengine/godot/files/407291/addons.zip


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment -238299152,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z20FQioFVkVcvhhbvDQ7jQKv5De7Hks5qd19QgaJpZM4JejbZ
.

O que nunca acontecerá são scripts desaparecendo dos nós instanciados ou
sendo oculto, precisa ficar claro que o nó está com script, mas
adicionar um script a ele ainda permitirá substituir o script por um que
herda dele

Em 8 de agosto de 2016, 14h02, "Juan Linietsky" [email protected] escreveu:

Ah, entendo .. essas duas coisas definitivamente devem ser corrigidas, juntamente com
adicionando suporte de herança ao diálogo de criação de script

Em 8 de agosto de 2016 13:54, "Ralf Hölzemer" [email protected] escreveu:

Como já foi dito anteriormente, a _maior desvantagem_ no momento é que
tipos personalizados são pouco mais do que uma maneira rápida de instanciar o tipo base
desse script e atribua o script apropriado a essa instância. Isto
torna impossível estender esse nó no editor com outro script -
como você pode fazer com tipos embutidos.

Mas também é impossível construir árvores de herança com nós personalizados em
as caixas de diálogo "Criar novo nó/recurso" porque elas só aparecem nesses
árvores quando você as registra com um tipo embutido como pai via
add_custom_type.

Por exemplo, vamos supor que eu queira herdar todos os meus tipos personalizados no meu
projeto de um único tipo base.

_base.gd http://base.gd_

estende o nó
exportar (Cor) var color

_type_a.gd http://type_a.gd_

estende base.gd

_type_b.gd http://type_b.gd_

estende base.gd

Como está agora, eu tenho que registrar esses tipos assim. Nisso
caso, o segundo argumento de add_custom_type deve ser "Node", caso contrário
eles não aparecerão nas caixas de diálogo.

func _enter_tree():
add_custom_type("Base", "Nó", preload("base.gd"), preload("base.png"))
add_custom_type("TypeA", "Node", preload("type_a.gd"), preload("type_a.png"))
add_custom_type("TypeB", "Node", preload("type_b.gd"), preload("type_b.png"))

... e este é o resultado.

[imagem: add_node_flat]
https://cloud.githubusercontent.com/assets/8785013/17486294/9bcc029c-5d90-11e6-81e6-6fce6b0e7cf0.png

Embora seja bom poder registrar tipos personalizados como este, o
diálogos não refletem a natureza da herança desses tipos como
outros tipos embutidos. Para qualquer tipo embutido, posso olhar para aquela árvore e
veja de relance com o que estou lidando. Posso, por exemplo, ter certeza de que
Sprite _é um_ Node2D e, portanto, herda todas as funções _fornecidas
por_ Node2D. O mesmo não acontece com os tipos personalizados.

Agora, se os tipos personalizados puderem ser totalmente registrados no escopo global,
como @akien-mga https://github.com/akien-mga mencionado acima, coisas
seria muito mais simples de entender e usar.

Primeiro, você pode herdar de um tipo personalizado referenciado por _type name_
em vez do caminho/nome do arquivo.

_base.gd http://base.gd_

estende o nó
exportar (Cor) var color

_type_a.gd http://type_a.gd_

estende a base

_type_b.gd http://type_b.gd_

estende a base

... então, o registro dos tipos personalizados poderia ser simplificado como
isto. Observe o segundo parâmetro ausente de add_custom_type.

func _enter_tree():
add_custom_type("Base", preload("base.gd"), preload("base.png"))
add_custom_type("TypeA", preload("type_a.gd"), preload("type_a.png"))
add_custom_type("TypeB", preload("type_b.gd"), preload("type_b.png"))

... e você teria uma visão geral muito melhor na seção "Criar novo
Caixas de diálogo Nó/Recurso":

[imagem: add_node_tree]
https://cloud.githubusercontent.com/assets/8785013/17487264/619f4da0-5d94-11e6-880f-a00791e30125.png

... e, claro, a capacidade de estender esses tipos no editor com um
roteiro personalizado:

[imagem: custom_type_no_script]
https://cloud.githubusercontent.com/assets/8785013/17487807/b54aced2-5d96-11e6-90e5-ee838b6a1335.png

... que também seria referenciado por _type name_ em vez do script
nome/caminho

estende a base

Aqui está o exemplo de plugin acima para brincar.
addons.zip https://github.com/godotengine/godot/files/407291/addons.zip


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment -238299152,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z20FQioFVkVcvhhbvDQ7jQKv5De7Hks5qd19QgaJpZM4JejbZ
.

@reduz
Existe algum motivo técnico para deixar claro que o nó está com script e, em caso afirmativo, ele precisa ser um slot de script ocupado?

Parece-me uma maneira bastante desajeitada de indicar um tipo personalizado e acho que ninguém teria a ideia de que, substituindo o script atual em um nó, você obtém um script que estende o script que já estava lá. Não é assim que a extensão via script funciona para os tipos básicos.

E o que aconteceria se o usuário limpasse esse campo de script? O tipo personalizado volta ao script anterior ou volta completamente ao tipo base? Novamente, eu não acho que isso seria uma boa ideia.

Em vez disso, ele pode ser indicado como um tipo personalizado na árvore de nós ou no editor de propriedades por meio de uma cor diferente, algum ícone ou outra coisa, sem sacrificar o slot de script vazio.

O que nunca acontecerá são scripts desaparecendo dos nós instanciados, ou ficando ocultos. É preciso deixar claro que o nó é script, mas adicionar um script a ele ainda permitirá substituir o script por um que herda dele

O ponto aqui é que o script que define o nó personalizado _deve_ ser oculto, porque não é uma propriedade do nó _instanciado_, mas de seu tipo. Portanto, esse script deve conferir propriedades ao nó personalizado, mas deve ser tão invisível para o usuário do nó instanciado quanto as classes C++ de nós integrados. Ele forneceria uma API, mas não seria modificável, apenas extensível. Assim como quando você instancia um Sprite, você não recebe scenes/2d/sprite.cpp anexado como o script do nó instanciado, você não deve anexar my_custom_node.gd como o script modificável do nó personalizado da instância.

Agora, não sei se é tecnicamente _possível_ agora, mas seria o caso de uso natural AFAIU. Se você modificar o script do tipo personalizado, ele modificará o próprio tipo e, portanto, afetará todas as instâncias desse tipo. Mas os nós instanciados usando o tipo personalizado devem ter seu próprio script que extends CustomNode .

Eu acho que esse recurso precisaria que o Object tivesse um ponteiro adicional para o "tipo de script personalizado básico", porque você precisa dessa informação quando deseja remover um script de usuário dele (que na verdade deve substituí-lo pelo script base).
Depois de ter isso, o resto é uma questão de incluí-lo em todos os casos, pois pode apresentar vários efeitos colaterais. No final, haverá apenas um script anexado, apenas uma maneira diferente de lidar com isso.
Eu não sou um grande fã de herança em geral, mas é assim que eu faria.

Na verdade, esse ponteiro nem poderia ser necessário. Marcar o script seria suficiente, por exemplo, se você add_custom_type() com um script, o mecanismo pode definir um sinalizador na classe para que as informações fiquem disponíveis, como "ei, esta classe de script é uma extensão do tipo de mecanismo". A remoção de um script de usuário o substituiria pela primeira classe de script herdada marcada como "tipo personalizado" ou removê-lo se não houver nenhum.

Desculpe, sou contra ocultar um script se o nó tiver um script. Qual é o
ponto de simular algo que não é?

O fato de ter um script não significa que o slot esteja ocupado ou que precise de um
segundo script, porque você pode simplesmente criar um novo script herdando o
um existente.

O que podemos fazer, se você concordar, é ocultar o ícone do script na árvore de cena se
o script atribuído é aquele do tipo personalizado e faça o script
create dialog oferece automaticamente a herança na criação do script.
Isso seria suficiente?

Em 10 de agosto de 2016 23:01, "Marc" [email protected] escreveu:

Na verdade, esse ponteiro nem poderia ser necessário. Marcar o script seria
ser suficiente, por exemplo, se você add_custom_type() com um script, o mecanismo
pode definir um sinalizador na classe para que as informações estejam disponíveis, como "ei, isso
classe de script é uma extensão de tipo de mecanismo". A remoção de um script de usuário
em seguida, substitua-o pela primeira classe de script herdada marcada como "custom
type", ou remova-o se não houver nenhum.


Você está recebendo isso porque foi mencionado.

Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment -239055986,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z2xLGOhgMk__ZoRW1neRu1aRb5Qr_ks5qeoJogaJpZM4JejbZ
.

@reduz acho que seria bom o suficiente :smile:

@reduz Concordo, e não disse que precisávamos de um segundo roteiro. Eu só queria saber o que aconteceria se você adicionasse um script herdando o primeiro (o personalizado definido pelo plugin), mas depois decidisse removê-lo. Ele então reverteria o nó para um tipo de mecanismo básico sem nenhum script?

Suponho que poderíamos de alguma forma torná-lo mais amigável a esse respeito

Em 11 de agosto de 2016 06:10, "Marc" [email protected] escreveu:

@reduz https://github.com/reduz Eu concordo, e não disse que precisamos de um
segundo roteiro. Eu só queria saber o que aconteceria se você adicionasse um script
herdar o primeiro (o costume definido pelo plugin), mas depois decidir
remova. Ele então reverteria o nó para um tipo de mecanismo básico sem qualquer
roteiro então?


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment -239109334,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z26JUJ0gjaCFwlsIDsINWp3_nqliwks5qeubygaJpZM4JejbZ
.

Eu cavo a parte de extends pelo nó definido Type em vez do caminho descrito neste comentário https://github.com/godotengine/godot/issues/6067#issuecomment -238299152.

Mais algumas sugestões para adicionar:

  • node.get_type() em um tipo de complemento deve retornar o nome do tipo.

Exemplo:

add_custom_type("MyCustomNode", "Node2D", preload("my_custom_node.gd"), preload("icon.png"))

node.get_type() should return "MyCustomNode" instead of "Node2D"
  • Um plugin pode estender outro plugin por seu tipo

Exemplo:
O usuário A cria um plugin para um notificador de visibilidade mais preciso baseado em Node2D
add_custom_type("PreciseNotifier", "Node2D", preload("precise_notifier.gd"), preload("icon.png"))

Em seguida, o usuário B desenvolve um complemento Trigger com base no notificador preciso em OUTRA pasta de complementos com outra configuração.
add_custom_type("Trigger", "PreciseNotifier", preload("trigger.gd"), preload("icon.png"))
e no script trigger.gd ele deve estendê-lo com o nome do tipo também
extends PreciseAddon
Claro que o usuário deve adicionar os dois addons para usar o gatilho

Parece que um grupo deseja definir um tipo de nó personalizado sem um script como um que ainda deriva do tipo de nó personalizado no qual se baseia, enquanto o outro grupo deseja definir esse mesmo cenário como um nó que foi revertido para sua base. tipo de motor. Embora eu pertença ao primeiro grupo, também posso ver o ponto do último grupo em relação ao tipo personalizado ainda sendo "com script" e querendo deixar isso claro na interface do usuário.

Um compromisso pode ser ter um botão de interface do usuário adicional na linha do nó no dock da árvore de cena ao lado de seu ícone de script com um ícone de script++. Clicar nele passaria pela típica janela pop-up "Criar um script" com um script que já está herdando do tipo personalizado, por exemplo, extends Base ou extends "Base" . O script definido seria então criado e substituiria imediatamente qualquer que fosse o script predefinido. Assim, você ainda mostraria claramente que existe um script já existente no nó, mas também teria uma interface familiar para substituir facilmente esse script predefinido.

Essa proposta provavelmente seria menos intuitiva, pois ainda trata os nós personalizados de maneira um pouco diferente de suas contrapartes no mecanismo. Pensamentos?

Dando meus 2 centavos mais adiante nesta discussão, acho que o problema está no fato de que vários nós herdando um complemento compartilham o mesmo script original por padrão; Eu não me importo com a visibilidade do código, como Juan argumentou no início deste tópico, é uma escolha de design e também algo importante para tornar o comportamento do nó transparente para o desenvolvedor usando o complemento. Mas geralmente você deseja alterar o comportamento de diferentes nós no código e, no momento, a única maneira de fazer isso é removendo a referência do script original, criando um novo script e copiando e colando o código do script base. Você não pode nem save as o script do novo nó do addon para um novo arquivo .gd, pois isso mudará a referência para todos os outros nós usando o script original, então há esse copiar e colar em três etapas peculiaridade do procedimento.

Mais uma vez, não é tão complicado, é apenas que, neste caso em particular, a opção save as no editor GDScript não se comporta como eu esperaria, e acho que seria mais amigável para a interface do usuário ter um ' copy and save' no editor GDScript para permitir a personalização rápida de addons (e em termos de arquitetura, tornar este botão visível faz sentido, pois esta é uma boa abordagem na criação de jogos no Godot sem a necessidade de usar scripts herdados).

@henriquelalves Eu pensei que personalizar nós personalizados no código é basicamente herança? Tipo, extends "addons/thing/thing.gd" ? O script herdado ainda fará as mesmas coisas que a versão do complemento, desde que você saiba o que está substituindo. Não há necessidade de copiar/colar.

@Zylann Você está certo, mas geralmente não gosto dessa abordagem específica por causa da visibilidade do código e das peculiaridades de preenchimento automático (pelo menos na 2.1, ainda não a testei). E na maioria das vezes eu não quero substituir métodos, apenas alterar coisas específicas que não são variáveis ​​estendidas no script de complemento original. Isso é o que me incomoda no comportamento atual do save as , não consigo criar rapidamente a cópia de um script sem alterar cada referência de nó para tal script; e resolver isso de uma maneira amigável à interface do usuário resolve o problema original de ter vários nós para personalizar, além de ter visibilidade de código e tal (pelo menos no meu fluxo de trabalho, posso ser o único a pensar assim haha).

@henriquelalves bem, eu não suporto copiar/colar tbh xD E você também pode bifurcar o plugin com controle de versão e usá-lo em primeiro lugar.

@Zylann Forking um plugin está adicionando ainda mais etapas a algo que deveria ser simples, hahaha. Acho que vou ficar com a cópia e colagem manual se isso não for uma prioridade, mesmo que eu ainda ache o comportamento save as estranho.

@henriquelalves Copiar/colar IS forking ^^ mas se feito sem controle de versão, isso o prejudicará no futuro se o plug-in for atualizado.

O comportamento atual de ter um script anexado ao nó personalizado não oferece quase nenhum benefício em ter esse nó personalizado como um complemento versus simplesmente anexar o script ao nó. O único benefício é que ele aparece na caixa de diálogo do nó, o que não é realmente um benefício.

Estou no campo que diz que um nó personalizado deve se comportar como um tipo interno de primeira linha. Caso contrário, por que se preocupar em fazer/usar um addon para isso? Só para que você possa vê-lo na caixa de diálogo e não precisar clicar no botão adicionar script?

@RodeoMcCabe O problema é que, sob o capô, os tipos personalizados ainda são scripts em camadas sobre um nó no mecanismo na prática, e isso não pode ser alterado, pois os nós de tipo personalizado não são compilados diretamente na origem do mecanismo. O que precisamos fazer é formular um conjunto concreto de etapas/recursos que permitiriam a esses nós com script simular , aos olhos do usuário, os comportamentos de um nó in-engine. Por exemplo...

  1. Adicionando o nó à janela "criar um nó" (concluído)
  2. Permitir que o usuário forneça uma "breve descrição" textual do nó para a janela "criar um nó" (não parece ser feito? - pelo menos, não faz parte de add_custom_type ).
  3. Permitindo que o usuário exiba hierarquias de nós e defina tipos personalizados abstratos na janela "criar um nó". Isso provavelmente envolveria adicionar um bool à função add_custom_type para saber se é um tipo abstrato ou não. O assistente "Criar um nó" precisaria ser atualizado para bloquear a criação de tipos personalizados abstratos adequadamente.
  4. Faça o nó SEEM como se NÃO tivesse um script.

    uma. O nó não deve ter um ícone "script está neste nó" na doca Cena. Para tornar as coisas mais transparentes, talvez devesse haver um ícone "este é um nó de tipo personalizado". Clicar nele pode levar o usuário diretamente ao script adicionado de tipo personalizado. Isso quebra a "imersão", mas seria um sacrifício necessário por razões de usabilidade (obviamente, você vai querer ver como um nó de tipo personalizado funciona, se quiser).

    b. A propriedade de script exibida no Inspetor deve, por padrão, mostrar-se vazia, a menos que o usuário carregue um script nela, caso em que o script deve derivar do tipo de script usado como tipo personalizado. No entanto, o usuário não deve saber a localização do arquivo de script do tipo personalizado (o conceito de que é um script deve ser ocultado). Isso significa que o nome da string para a classe personalizada deve ser reconhecido pelo analisador GDScript como as outras classes do mecanismo (não tenho certeza de quão fácil/difícil isso seria) ou deve haver algum tipo de função global para buscar o registro via o nome da classe, por exemplo, para o script em add_custom_type("MyClass", "Node", load(res://addons/git-repo/api/my_class.gd), load(res://addons/git-repo/icons/icon_myclass.svg) , o usuário pode fazer um script com extends MyClass ou extends custom("MyClass") .

    c. Se um usuário carregar um script derivado de tipo personalizado no nó, somente então o ícone "este nó tem um script" deve aparecer no dock Cena.

  5. Qualquer ícone de editor usado para o script deve ser adicionado ao bloco de categorias em vez do ícone de caixa branca atualmente usado para scripts (em property_editor.cpp ). Isso deve fazer parte da propriedade __meta__ Dicionário para o objeto de nó de tipo personalizado.

  6. Quando você clica em "adicionar um script" em um tipo personalizado, ele deve preencher previamente o campo "Herda" com qualquer método usado em 4b.
  7. Se você remover um script, o script de tipo personalizado ainda deve existir nos bastidores e NÃO ser removido. Os nós de tipo personalizado usariam efetivamente o script de tipo personalizado como um script de backup nos casos em que o script carregado estiver definido como nulo. Como tal, você ainda deve ver o ícone do editor de tipos básicos e as propriedades do script no encaixe Cena do Editor e no encaixe Inspetor. Já estou no processo de mesclar um recurso para substituir "Variáveis ​​de script" pelos nomes dos scripts reais, embora provavelmente precise ser atualizado se todas essas alterações forem adicionadas.
  8. Object::get_script() deve retornar null para nós com um script de tipo personalizado e nenhum script carregado.
  9. Object::get_property_list , e as funções análogas para métodos e sinais devem incluir o conteúdo do script de tipo personalizado, mesmo que não haja script carregado.
  10. Provavelmente seria necessária uma segunda função de objeto C++ como Object::get_custom_script() ou algo assim para que o mecanismo possa ver se há um script, mesmo que o lado do script não tenha conhecimento desse segundo script.
  11. As tentativas de carregar um script derivado de tipo não personalizado em um objeto devem falhar de forma limpa e relatar um erro (provavelmente um bool de referência &is_valid na função associada) para confirmar se o objeto tem permissão para fazer isso. Os cenários associados do Godot Editor que devem fornecer feedback sobre essas informações também precisariam ser atualizados para levar em conta isso.

Isso está apenas arranhando a superfície, mas acho que o tipo de comportamento que os usuários estão procurando é tão extenso (portanto, é bastante intenso). Queremos tornar a existência de tipos personalizados acessíveis, se necessário (portanto, tenha o ícone de tipo personalizado no encaixe Cena na linha do nó para visualizar seu script), mas também queremos ocultar sua existência o máximo possível para que possamos perceber como tipos no motor. Vai dar muito trabalho para realmente fazer isso direito, já que provavelmente vai quebrar as coisas em MUITOS lugares.

Isso soa bem? Tenho certeza de que há mais itens que estou perdendo, pois estou apenas ponderando um pouco. Se isso parece loucura, então me avise. ;-)

Edit: ah, mas a sugestão do reduz de apenas ocultar o ícone do script no dock Scene se o script corresponder ao script de tipo personalizado também pode ser valioso. Apenas, o método get_script() ainda não deve retornar nada. Talvez haja uma maneira de fazer isso sem ter que criar uma propriedade de script separada no próprio objeto? Idk, porque existem muitas suposições já na base de código para 1 script por objeto, que acho que queremos manter, mas que são difíceis de manter com o conceito de script custom_type .

Boas sugestões, bem pensadas. Acho que se tudo isso fosse implementado, daria o comportamento que estamos procurando, mas acho que quebrar a regra de 1 script por nó pode ser uma má notícia que pode repercutir em muitas partes inesperadas do código. Leve isso com um grão de sal, pois não conheço bem a base de código e meu C++ é medíocre. Reduz afirmou acima que eles originalmente tentaram ter mais de um script por nó e "foi mais problema do que valeu a pena", o que parece razoável para mim.

Os pontos de 1 a 4 são ótimos e acho que podem ser alcançados sem quebrar a regra de 1 script. Os tipos personalizados abstratos obviamente não são um problema, pois você não pode instanciá-los de qualquer maneira e, portanto, o usuário não pode adicionar um script a ele no editor. No entanto, é concebível que eles tentem fazer isso por meio de código, portanto, verificações e erros necessários teriam que ser implementados.

O ponto 6 também é bom, e é aqui que acho que podemos nos safar com isso. A criação de um novo script conforme o ponto 6 alterará o script atualmente anexado ao nó personalizado para o novo script (derivado). O script antigo (base) é removido do nó. Como o novo script anexado é derivado do original, todas as funcionalidades permanecem. Costumo fazer isso, onde tenho uma classe base (abstrata ou não) e anexo scripts derivados aos nós. A diferença aqui é que o novo script pode ter que dizer extends "res://addons/path/to/base-script.gd" em vez de simplesmente o nome do nó personalizado, porque o tipo personalizado não tem mais esse script anexado .... Embora pensando bem, remove_custom_type() não foi chamado e o script anexado ainda deriva do antigo, então talvez isso não seja necessário? Por favor, esclareça-me sobre este ponto.

Os pontos 7, 8 e 9 são bons e provavelmente não muito difíceis, mantendo a regra de 1 script. 10 não é necessário se mantivermos a regra de 1 script. 11 é bom, pois é assim que os nós internos se comportam se você tentar anexar um script a eles que não estenda o tipo de nó.

De qualquer forma, parece muito trabalho, e já estamos na versão beta, então acho que isso será para 3.1 ou até 3.2 (não olhei o roteiro recentemente).

@RodeoMcCabe Sim, isso definitivamente não seria para 3.0.

quebrar a regra de 1 script por nó pode ser uma má notícia que pode repercutir em muitas partes inesperadas do código

Exatamente meus pensamentos. Estou pensando em uma interface pública na qual o Objeto está ciente de seu script de backup personalizado, mas outros objetos não sabem disso e simplesmente percebem o Objeto como tendo um único script. O truque seria editar o setter e o getter para a propriedade do script. O getter deve verificar se há null. Se for nulo, deve retornar o script de backup. O setter também deve verificar novamente se qualquer novo script estende o script de backup, caso contrário, ele deve relatar uma falha de alguma forma.

Os tipos personalizados abstratos obviamente não são um problema, pois você não pode instanciá-los de qualquer maneira e, portanto, o usuário não pode adicionar um script a ele no editor.

Não há tipos abstratos no lado do script (afaik). Você está dizendo que sabe como fazer um script abstrato? O método can_instance é exposto ao lado de scripts, mas tudo o que ele faz é verificar se o script em si é válido e, se for uma ferramenta, se o ScriptServer tem scripts habilitados no momento. Não tem nada a ver com a abstração do tipo de script, eu não acho.

Você precisa ser capaz de verificar se a classe é abstrata para que o método CreateDialog::_update_search saiba quando deixar o texto em cinza/não selecionável, etc.

Para sua informação, criei um problema sobre a parte abstrata do problema (#13401).

Acho que no geral seria possível se tivéssemos apenas um membro privado backup_script adicionado ao tipo Object e, em seguida, usá-lo para fazer as verificações de propriedade script .

O que eu faço em meus nós personalizados é herdar um script base, que torna o script de nó personalizado vazio por padrão...


A herança automática afetará o próprio plug-in e não será possível fazer mais de um sem duplicar o plug-in, certo?.

O Multiscript foi adicionado pela segunda vez este ano e foi fácil matá-lo novamente (levantando vários problemas).


Permitir uma cena como base para o nó personalizado em vez de um script pode deixar a raiz livre de scripts.

O que eu faço em meus nós personalizados é herdar um script base, que torna o script de nó personalizado vazio por padrão...

Desculpe, você está dizendo que isso de alguma forma afeta a abstração ou alguma outra sugestão que fiz anteriormente? Não estou vendo onde isso se conecta...

A herança automática afetará o próprio plugin e não será possível fazer mais de um sem duplicar o plugin, certo?

Você está tentando dizer que tentar incluir o plugin na pasta /addons/ duas vezes e habilitá-los na seção Plugin das Configurações do Projeto causaria problemas de alguma forma (quero dizer, isso parece bastante normal se você adicionar plugins personalizados tipos. Não é possível ter vários tipos personalizados definidos com o mesmo nome).

Não tenho certeza do que você quer dizer com "não será possível fazer mais de um sem duplicar o plugin". Você pode criar várias instâncias de um nó de tipo personalizado muito bem (?) já que ele apenas criará o nó e anexará automaticamente o script de tipo personalizado definido. Minha sugestão envolveria alterar o processo de criação de script do CreateDialog para fazer ...

  1. Deixe o script interno do nó decidir se o nó pode ser instanciado ou não (abstrato).
  2. Crie um tipo de nó integrado.
  3. Defina o script personalizado como a propriedade backup_script do nó (não exposta à API de script).
  4. Deixe o próprio código Object do nó lidar com a tarefa de enganar todos os outros para que vejam o backup_script como a propriedade script oficial no objeto.
  5. Atualize os metadados para o ícone do editor
  6. Atualize os metadados para a breve descrição (?)

...em vez de...

  1. Crie o nó interno.
  2. Anexe o script de tipo personalizado como a propriedade script .
  3. atualize os metadados do ícone do editor personalizado.

O Multiscript foi adicionado pela segunda vez este ano e foi fácil matá-lo novamente (levantando vários problemas).

Eu concordo. Eu acho que objetos multiscript seria uma má ideia neste momento (e nem é realmente necessário de qualquer maneira). Não é isso que estou sugerindo. Na visualização pública, Object ainda deve ter apenas 1 script, mas recomendo ter um script de backup disponível que assuma o papel de ser o script (assim se atribui à propriedade script ) sempre que a propriedade principal script for definida como null / unloaded, etc. Isso nos permitirá suportar "tipos personalizados" de forma mais eficaz sem alterar a interface da base de código para a classe Object. Podemos então ter apenas um setter/getter dedicado para essa propriedade de script de backup que permite que o código (como o código que atribui scripts de tipo personalizado em CreateDialog ) adicione ou remova sua existência. Dessa forma, é uma modificação opcional de como a propriedade script funciona e resultará em comparativamente menos alterações necessárias no mecanismo.

Eu acho que uma nova opção de menu contextual nos nós resolveria esse problema "Substituir script por herdado" isso poderia até ter um submenu com todos os scripts detectados que herdam do atual e um "Novo script" no final, ao clicar nele o novo script A caixa de diálogo deve exibir o caminho do script no campo "extends".

Não é apenas mais fácil e transparente adicionar uma ferramenta de edição "Substituir e herdar script"? Quero dizer, isso é apenas um problema porque quando criamos um nó Addon, esperamos que ele seja sem script - mas nós addon são apenas nós personalizados que você está adicionando à árvore Create Node, e o usuário deve saber disso. De uma perspectiva de UX (mas não sou especialista), não acho que devemos sacrificar a transparência por conveniência.

@MarianoGnu @henriquelalves Nenhum deles é realmente o mesmo. A implicação de um "tipo personalizado" é que você está simulando um tipo de nó no mecanismo. Isso implicaria que o próprio script não pode ser removido. A funcionalidade que ele imbui no nó está embutida nele, da mesma forma que você não seria capaz de remover o Node2D-ness de um Node2D para fazê-lo agir como um Node puro.

O popular post votado de Akien acima cobre detalhes semelhantes:

O ponto aqui é que o script que define o nó personalizado deve ser ocultado, porque não é uma propriedade do nó instanciado, mas de seu tipo. Portanto, esse script deve conferir propriedades ao nó personalizado, mas deve ser tão invisível para o usuário do nó instanciado quanto as classes C++ de nós integrados. Ele forneceria uma API, mas não seria modificável, apenas extensível.

Se criarmos alguma ferramenta de editor para facilitar coisas de "substituir script por herdado", isso seria legal, mas nenhuma das funcionalidades deve ser capaz de ver as camadas de hierarquia de script no script de tipo personalizado ou abaixo dele, pois é suposto para simular o comportamento "incorporado".

Na verdade, para que o conteúdo seja acessível a partir de gdscript_parser e outros conteúdos de script, pode ser melhor garantir que as informações de tipo personalizado sejam incluídas no singleton ClassDB em vez de apenas EditorNode::get_editor_data().get_custom_types() pois módulos não terão acesso a essas informações, mas realmente deveriam ter acesso a elas.

eu não tenho nenhum problema pessoal em ter o script exposto, isso é realmente uma questão de terminologia e filosofia, de acordo com o que você mencionou, o que poderia ser feito é adicionar uma nova classe ao ClassDB e adicionar uma propriedade de script a essa classe em vez de o nó e a classe devem verificar se o script de métodos existe e chamá-los antes de chamar sua classe pai. Acredito que seja possível, mas quebraria a compatibilidade com versões anteriores se não fosse feito antes do RC1

@willnationsdev Entendo, não concordo totalmente com os tipos personalizados sendo tratados como nós no mecanismo. Para mim, o 'poder' dos Editor Addons está na facilidade de criar um "pacote" de nós personalizados e ferramentas de edição e compartilhá-lo via github; todas essas ferramentas e nós são, na verdade, apenas cenas e scripts que você pode copiar e colar, mas Godot fornece a API Addon para facilitar isso. Quando eu o usei pela primeira vez, eu também esperava que os Addons fossem sem script, mas apenas porque o próprio mecanismo parecia tratá-los como nós no mecanismo, e isso é um problema de UX, não arquitetural. O que eu acho que corrigiria isso é:

  1. Os tipos personalizados na árvore Criar nó são exibidos com uma cor diferente (indicando claramente que são tipos personalizados).
  2. Quando você os adiciona à sua cena, o ícone do script está lá, mas ligeiramente transparente (indicando que eles têm um script padrão com eles, mas podem ser substituídos). Clicar no ícone de script mostraria o script de tipo personalizado no editor.
  3. O botão "Adicionar script" em tipos personalizados preencheria automaticamente a opção "Herdar" com o script de tipo personalizado.

Mais uma vez, eu definitivamente não sou especialista, então minha suposição original de Custom-Types != In-Engine Nodes pode estar errada; Além disso, sua solução é a mais clara que vi neste tópico, então entendo totalmente se o desenvolvimento da Godot for dessa maneira.

EDIT: eu li novamente, e minha "solução" é basicamente suas primeiras 6 etapas de solução, hahaha.

@henriquelalves @MarianoGnu Acho que uma mistura desses certamente seria necessária. Ter a classe de tipo customizada adicionada ao ClassDB é uma obrigação imo. Realmente amando todas as três sugestões que você teve Henrique. Especialmente a ideia 2 (muito melhor do que minha sugestão de ícone de tipo personalizado separado). E concordo com você que precisamos garantir que "O QUE são os tipos personalizados" permaneça transparente até certo ponto. Eu sinto que um equilíbrio precisa ser mantido: as pessoas devem ser capazes de entender se algo é um tipo personalizado E o que isso significa, mas também devemos fazer o máximo que pudermos para que os tipos personalizados pareçam tipos de mecanismo.

@willnationsdev Peguei isso do assetlib, movi o código do nó personalizado para um script "base":
colisão_path_2d-1-modified.zip

O problema imediato que vejo nisso é que o plugin carrega o script, e esse script é único, se eu adicionar outro nó personalizado, ele terá _o mesmo_ script.

Então, o que uma substituição de script significa para o plugin nesse caso? (talvez nada, não tenho certeza).

Se não houver problemas para substituir um script (o modo de ferramenta pode não ser satisfatório em alguns casos), o menu para nós personalizados pode adicionar uma entrada de "estender script personalizado" para fazer esse processo de substituição.

@henriquelalves @eon-s Acho que estamos pensando as mesmas coisas. Estou de acordo com isso sendo um problema de UX mais do que qualquer coisa. Até agora, sou parcial com essa abordagem porque acho que é manter as coisas o mais simples possível, o que é sempre bom IMO.

Se não houver problemas para substituir um script (o modo de ferramenta pode não ser satisfatório em alguns casos), o menu para nós personalizados pode adicionar uma entrada de "estender script personalizado" para fazer esse processo de substituição.

Eu acho que, como o script de extensão precisa herdar do script do plug-in, substituí-lo não seria um problema. Mas, novamente, não estou muito familiarizado com a base de código. De qualquer forma, dei meus 2 centavos, vou deixar para os verdadeiros devs daqui ;)

@willnationsdev Desculpe, me confundi com as coisas abstratas. Minhas classes base "abstratas" simplesmente têm uma instrução print em _init() para me dizer se eu a instanciei por acidente ....

Apenas para entrar aqui, os tipos de nós personalizados devem se comportar absolutamente como os tipos de mecanismo, incluindo a configuração de um script personalizado, a capacidade de referenciar e herdar por nome no GDScript e a incapacidade de remover o script base do tipo. Isso imita o comportamento dos nós implementados pelo mecanismo, promovendo consistência interna e facilidade de uso.

Em relação à questão de mostrar que é um nó "personalizado", proponho que o nó tenha uma entrada no menu suspenso do Inspetor acima de "Mostrar na Ajuda" que mostre o arquivo de script base do objeto. Do ponto de vista do usuário e do desenvolvedor, você deve saber que é um nó personalizado apenas usando-o (quem mais o adicionou ao projeto?), e o objetivo dos nós "personalizados" (IMO) é permitir a definição de tipos no GDScript que são indistinguíveis dos tipos de motor embutidos.

@Web-eWorks Na verdade, estou trabalhando nisso (neste exato momento) e consegui uma parte decente disso (ainda tenho alguns caminhos a percorrer). Configurei um script de backup na classe Object e criei armazenamento para tipos personalizados no ClassDB juntamente com a atualização dos métodos EditorPlugin para usar a nova API. Ainda tenho que fazer atualizações nas funções relacionadas do ClassDB (coisas como can_instance e get_parent_class , etc.) e atualizar todas as coisas do Editor / CreateDialog.

@willnationsdev , deve-se notar que o registro no ClassDB também significa que as pessoas que criam plugins devem prefixar suas classes para evitar colisões ^^"

@Zylann Sim, isso seria necessário, infelizmente.

Neste ponto, acho que resolvi a maioria das ligações e alterações principais. É apenas uma questão de atualizar as classes Editor, CreateDialog e EditorHelp / DocData agora (e o compilador GDScript).

Como mencionei antes.. Ainda não acho que a solução proposta seja boa.
Por favor, verifique comigo antes de tentar algo que provavelmente será
rejeitado.

Em 7 de fevereiro de 2018 20:05, "Will Nations" [email protected] escreveu:

@Zylann https://github.com/zylann Sim, isso seria necessário,
Infelizmente.

Neste ponto, acho que resolvi a maioria das ligações e núcleos
alterar. É apenas uma questão de atualizar o Editor, CreateDialog e
classes EditorHelp / DocData agora.


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-363893711 ,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z2xIYRcs0BFDqTyiFwqlhQWTqjEZtks5tSgIVgaJpZM4JejbZ
.

@reduz Bem, venho tentando levar em conta as preocupações que você expôs anteriormente.

Não estou implementando nenhum tipo de sistema multi-script. Também não estou fazendo scripts mascarados como objetos ClassInfo no ClassDB. Tudo o que fiz até agora foi anexar um script (via RefPtr) às hierarquias de herança no ClassDB. A classe Object só usará um "backup_script" sempre que a atribuição de script regular tentar infringir a hierarquia de herança do script de backup.

Oh eu vejo .. qual é o caso de uso para isso então?

Em 7 de fevereiro de 2018 20:32, "Will Nations" [email protected] escreveu:

@reduz https://github.com/reduz Bem, eu tenho tentado levar em
conta as preocupações que você expôs anteriormente.

Não estou implementando nenhum tipo de sistema multi-script. eu também não sou
fazendo scripts mascarados como objetos ClassInfo no ClassDB. Tudo que eu tenho
feito até agora é anexar um script (via RefPtr) à herança
hierarquias no ClassDB. A classe Object só usará um
"backup_script" sempre que a atribuição de script regular tenta infringir
na hierarquia de herança do script de backup.


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-363900920 ,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z2yn68Iy6AgAKJHZ4qImH4UBAm5skks5tSghSgaJpZM4JejbZ
.

O caso de uso é para quando alguém deseja introduzir um novo tipo de Node no mecanismo usando um EditorPlugin, mas não deseja que o tipo de script desse nó seja editável (ele deseja que a interação com ele imite um tipo no mecanismo ). Então, por exemplo, se eu tentar get_script() em um nó apenas com seu script de backup, ele retornará null. Se eu tentar set_script(null) , o script será definido para o script de backup. Se eu tentar set_script(a_script) , ele só atribuirá o script com êxito se o novo script estiver na hierarquia de herança do script de backup.

Para UX, pretendo fazer com que o ícone do script apareça no editor como um ícone transparente se apenas o script de backup estiver presente. Nesse caso, o botão para adicionar um script ainda será um botão "adicionar um script" em vez de um botão "remover script", e clicar nele preencherá o texto com o nome do tipo (embora possa ser necessário fazer ele será preenchido com o caminho do script se o usuário alterar o tipo de script para GDScript / VisualScript, etc.). Depois que um script diferente for atribuído, o ícone transparente ficará opaco novamente. Clicar no ícone do script em ambos os casos levaria você ao código-fonte do script ativo (o código-fonte do script de backup se nenhum outro script estiver presente).

Eu tenho que admitir que eu realmente não vejo o benefício disso, então novamente qual é o
casos de uso específicos que você está pensando?

Em 7 de fevereiro de 2018 20:46, "Will Nations" [email protected] escreveu:

O caso de uso é para quando alguém deseja introduzir um novo tipo de Node para
o mecanismo usando um EditorPlugin, mas eles não desejam que o tipo de script
esse nó seja editável (eles querem que a interação com ele imite um
tipo no motor). Então, por exemplo, se eu tentar get_script() em um nó
com apenas seu script de backup, ele retornará nulo. Se eu tentar
set_script(null), então o script é definido para o script de backup. Se eu
tente set_script(a_script), então ele só irá atribuir com sucesso
o script se o novo script estiver na hierarquia de herança do backup
roteiro.

Para UX, pretendo fazer com que o ícone do script apareça no editor como um
ícone transparente se apenas o script de backup estiver presente. Nesse caso, o
botão para adicionar um script ainda será um botão "adicionar um script" em vez de um botão
botão "remover script", e clicar nele irá pré-preencher o texto com o nome
do tipo (embora eu possa precisar preenchê-lo com o caminho do script
se o usuário alterar o tipo de script para fora do GDScript / VisualScript,
etc.). Uma vez atribuído um script diferente, o ícone transparente
tornar-se-ia opaco novamente. Clicar no ícone de script em ambos os casos
levá-lo ao código-fonte do script ativo (o código-fonte do script de backup se
nenhum outro script está presente).


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-363904934 ,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF-Z26oeOMT4HpjzDsX8eygMSeUhbTgVks5tSgurgaJpZM4JejbZ
.

O caso de uso de alto nível é permitir que plugins (EditorPlugins, o sistema PluginScript/SubModule) definam tipos de nós personalizados 'à prova de falhas'. Atualmente, o sistema de tipo personalizado é uma fábrica fina para "script em um nó", que tem vários problemas de fluxo de trabalho e usabilidade se você estiver tentando criar novos tipos de nó, o mínimo dos quais é a completa incapacidade de fácil, intuitiva e eficazmente estenda o nó personalizado com código de jogo (ao contrário dos nós integrados). Um problema mais urgente é a incapacidade de criar nós personalizados que herdam de outros nós personalizados.

Alguns casos de uso específicos são para criar nós de baixo nível: talvez uma implementação de voxel GridMap baseada em cubos de marcha para terrenos destrutíveis, como Minecraft ou qualquer outro sistema de terreno usando cubos de marcha/contorno duplo; tipos de controle personalizados (contêiner de menu circular, como implementado em muitos jogos modernos, qualquer tipo de controle de baixo nível que seja alto o suficiente para estar fora da especificação do mecanismo); e qualquer lugar que você queira construir um plugin que registre novos nós. Em cada um desses casos, você geralmente deseja adicionar um script personalizado para lidar com o código de jogo e que ele seja separado do código de "implementação" (escrito em GDScript/GDNative).

Acho que o que está falhando em ser comunicado aqui é que o objetivo é fazer com que os nós personalizados se comportem como nós de mecanismo sem ter que escrever um módulo de mecanismo e compilar nele.

Essa melhoria não é necessariamente impulsionada por um recurso específico (embora existam muitos), mas sim pela lógica de "o modo atual é retrógrado, frágil e tedioso". Se implementado totalmente, esse sistema permitiria um método extremamente poderoso de estender os tipos internos do mecanismo de GDScript / GDNative sem a necessidade de recompilar o mecanismo. Do ponto de vista do design, isso é literalmente uma melhoria direta em relação ao sistema atual.

Se você quiser um caso de uso específico depois de tudo isso: todo o ecossistema do plugin / AssetLibrary .
Esse é o escopo do que se beneficia dessa mudança.

Ok, então aqui está um exemplo explícito:

Eu tenho um plugin no qual estou trabalhando, godot-skills , que apresenta uma variedade de novos tipos de nós:

Efeito: nodificação de um Functor
Targeter: semelhante, mas apenas encontra e coleta outros nós
Habilidade: combina hierarquias de Targeters e Effects para encontrar nós e aplicar efeitos a todos eles
SkillUser: "possui" várias Skills

Eu gostaria que cada um desses nós fosse coisas que os usuários pudessem criar e adicionar a uma cena diretamente. No entanto, cada um desses nós é projetado para servir como um tipo base. Eles não têm muitas funcionalidades prontas para uso e devem ter um script de derivação colocado em qualquer nó com o qual estariam envolvidos. Para casos de uso como esses, pode ser útil criar um nó do qual você não deseja que o usuário possa remover um conjunto específico de funcionalidade de script. Por exemplo, quero impedir que os usuários coloquem um script não derivado do Targeter em qualquer nó do Targeter que eles adicionarem à cena. Isso ocorre porque há uma funcionalidade instantânea que as Skills obtêm ao ter Targeters como filhos (semelhante aos nós Area2D e CollisionShape2D).

O fluxo de trabalho atual exige que os usuários...

  1. Adicionar um nó de tipo personalizado
    2a. Remova o script anexado a ele e clique no botão adicionar um script OU
    2b. Defina a propriedade do script no nó
  2. Encontre na janela de diálogo onde o EditorPlugin está mantendo o script de tipo personalizado que você deseja derivar.

Este sistema permitiria que você substituísse tudo isso por apenas:

  1. Adicione um tipo de nó personalizado.
  2. Adicionar como script (que começa automaticamente a derivar o script de tipo personalizado)

Os usuários poderiam adicionar dinamicamente seus próprios tipos personalizados que derivam os tipos no mecanismo (para usabilidade mais simples). Também reforçaria a segurança da funcionalidade do plug-in, reforçando a presença da funcionalidade de script no nó em questão. Atualmente, os usuários podem facilmente remover o script e quebrar as coisas (não é desejável). Além disso, se alguém quiser "limpar" o script no nó, esse nó não deve perder sua funcionalidade de tipo personalizado (este é um grande problema). Ele deve voltar a ter o script de tipo personalizado.

Ok, então uma atualização. Atualmente tenho o seguinte.

  • O ClassDB agora pode adicionar e remover tipos personalizados diretamente.
  • O EditorPlugin tem métodos de tipo personalizado semelhantes que adicionam e removem não apenas o tipo personalizado, mas outros dados relacionados ao editor, como o ícone. Esses métodos são conectados a um novo sinal que é emitido sempre que EditorPlugin é alternado entre ativo/inativo.
  • Os GDScripts agora podem herdar corretamente diretamente dos nomes dos tipos personalizados para herdar do script.
  • A doca de cena criará um ícone de script transparente quando o script atual corresponder ao script de tipo personalizado do nó. Clicar nele abrirá o script de tipo personalizado no editor. Enquanto estiver nesse estado, o botão "adicionar um script" é exibido em vez do botão "remover um script". Se selecionado, este botão preencherá previamente o campo "Herda" com o nome do script de tipo personalizado (se não for nulo).
  • Qualquer tentativa de remover um script fará com que o script de tipo personalizado seja reatribuído como o valor do script. Assim, para remover o script, você deve primeiro limpar o valor do script de tipo personalizado com set_custom_script(RefPtr()); .
  • A caixa de diálogo criar um nó mostra corretamente os relacionamentos de herança e nós abstratos para tipos personalizados.
  • O arquivo project.godot é preenchido com todos os tipos personalizados para que os jogos executados possam configurá-los em main.cpp antes do início do resto do jogo.

Restantes tarefas a serem concluídas...

  • Permitir que os usuários gerem documentos de API de classe para tipos personalizados.
  • Corrija um bug separado que impede os usuários de editar o campo Inherits em script_create_dialog.cpp .
  • Encontre uma maneira de adicionar e remover dinamicamente tipos personalizados do mapa/matriz global GDScript *
  • Implementar suporte de tipo personalizado no VisualScript

* Na verdade, tenho algumas perguntas sobre isso.

Primeiro, só vejo add_global_constant / _add_global no arquivo gdscript_compiler.cpp sem nenhum meio de remover globais da classe GDScriptLanguage. Ele é completamente reinicializado sempre que singletons são adicionados ou removidos? Como os identificadores globais são editados dinamicamente? Isso seria para que os usuários pudessem fazer MyNode.static_func() sem ter que carregar o script em uma variável primeiro.

Enquanto estou nisso, sinto que o GDScript da Godot poderia se beneficiar muito com a introdução do namespace, especialmente como parte dessa mudança. Teríamos que encontrar o delimitador certo para marcá-los, mas você pode acabar com as preocupações sobre colisões de nomes de tipos de mecanismo e plug-in ao criar seus próprios scripts. Por exemplo, supondo que \ seja o delimitador de escolha...

extends Node # an in-engine type.
extends \ # triggers an error if left alone, but would prompt a dropdown of the plugin API names for auto-completion as well as the names of any scripts in the current project that are not part of a plugin.
extends \MyPlugin\ # triggers an error if left alone, but would prompt a dropdown of the scripted types that exist for the plugin
extends \MyNode # extends my_node.gd somewhere in res://
extends \MyPlugin\MyNode # extends my_node.gd somewhere in res://addons/[my_plugin_something?]/

func _ready():
    print(\MyNode.CONSTANT) # would print CONSTANT in the current project's my_node.gd script

De qualquer forma, tudo isso ^ são apenas idéias sendo lançadas no momento. Se o namespace fosse introduzido, você poderia até ter scripts automaticamente associados a um nome com base no nome do arquivo usando o sinal resource_saved em EditorNode . Eles NÃO seriam necessariamente tipos personalizados (no sentido de que você não pode remover o script do objeto), mas eles seriam acessíveis apenas pelo nome, o que seria extremamente útil e intuitivo. Os scripts podem até substituir a nomeação automática padrão ( filename.capitalize().replace(" ", "") ?) fornecendo um título com namespace no topo, por exemplo, \MyPlugin\mynode . Agora, de repente, "\MyPlugin\mynode" é um identificador global para esse script.

Aqui está um trecho do meu progresso até agora.

@willnationsdev por favor não escolha \ , já é usado para escape e multilinha. . , : ou :: parecem melhores.

@Zylann Eu planejava usar o delimitador como um prefixo para todos os nós que também fossem adicionados ao projeto. Então, por exemplo, um script em res://container.gd não gostaria de ter colisões com a classe Container real. Se usássemos um ponto (.), então ficaria assim.

var engine_type = Container.new()
var script_type = .Container.new()
var plugin_script_type = .MyPlugin.Container.new()

Alguém tem objeções a esse tipo de formato?

Editar:

Isso pode ter problemas nas funções de classe derivadas, embora chamem o método do pai dentro delas:

func _virtual_method():
    ._virtual_method() # parent stuff
    # my stuff

Hmm... isso representa um problema para constantes e/ou variáveis? Caso contrário, podemos apenas supor que os parênteses significam que é uma superfunção e, caso contrário, é um possível identificador de namespace.

Honestamente, eu adiaria o namespace por enquanto - ele poderia ser introduzido mais tarde, e eu prefiro colocar o sistema atual o mais rápido possível. Também precisaríamos de um sistema _realmente_ bem pensado para registro automático de nomes, possivelmente estendendo-se a uma reformulação de toda a estrutura organizacional do complemento, o que é uma quantidade razoável de trabalho e está além do escopo desta questão.

Pessoalmente, prefiro que o nome de um script 'auto-registrado' seja controlado por uma declaração no arquivo, ou seja

register <NAME> extends <PARENT>

ou uma sintaxe semelhante baseada no prólogo extend <NAME> atual que já está presente para GDScript.

EDIT: Eu também queria perguntar como a atribuição de scripts derivados de um pai (digamos Spatial) para um filho personalizado (digamos Sprite3D->CustomType) será tratada? Isso já funciona para tipos de mecanismo, e restringir scripts atribuídos a serem derivados do próprio tipo personalizado não funcionará muito bem.

@Web-eWorks Justo. Trabalharei no aperfeiçoamento da API atual e, em seguida, abrirei um novo problema para namespaces assim que o PR for enviado.

Se eu entendi bem o que @Web-eWorks significa, ainda tenho esta pergunta: como você vai contornar o fato de que um Object só pode ter um único script? Como eles serão... "programáveis"? Além disso, registrar-se no ClassDB nada mais é do que um identificador global em termos de uso para programadores e designers.

@Zylann O que fiz no meu fork foi criar uma propriedade custom_script para Object . Ele só se torna significativo se um valor for atribuído a ele, mas se um script for atribuído a ele, ele servirá como um script / restrição de backup sobre qual pode ser a propriedade script principal. Limpar script o definirá custom_script , e se você atribuir um novo Script a script , ele só será atribuído com sucesso se o Script A instância custom_script . E tudo isso é gerenciado por Object nos bastidores, então no que diz respeito ao mecanismo, Object s ainda têm apenas 1 script real.

O conteúdo do ClassDB tem apenas um mapa secundário de tipos personalizados que são registrados, mapeando o próprio script e algumas outras informações para o nome que você atribuiu a ele. Em seguida, ele fornece esse nome e sua hierarquia de herança com métodos de herança relacionados ( get_class_list , is_parent_class , get_parent , etc.). E isso é feito como um sinalizador opt-in para alguns dos métodos. get_class_list agora terá um sinalizador bool onde inclui apenas tipos personalizados se você passar true como um segundo parâmetro. É assim que evita quebrar a compatibilidade com o resto do motor.

@willnationsdev então, com um sistema que faz com que os scripts se comportem como classes internas, o que está impedindo os usuários de querer que todos os seus scripts e complementos sejam considerados cidadãos de primeira classe, como as classes internas, e abandonem a maneira "antiga"?

Ah. A maneira como os scripts funcionam atualmente é que você pode colocar um script que extends Node em um VBoxContainer , e ainda funciona bem. Se a implementação atual quebrar esse comportamento para tipos personalizados, haverá alguns problemas - existe alguma maneira de manter o comportamento do script personalizado enquanto tem um script 'normal' derivado diretamente de um tipo de mecanismo?

@Zylann É exatamente por isso que quero introduzir namespaces para que scripts e scripts de plug-ins possam ser integrados com segurança por meio de nomes sem colidir com tipos no mecanismo. Não haveria nada impedindo as pessoas de usar apenas o novo caminho e ignorar o antigo. E eu realmente acho que seria melhor no geral. É trabalhoso ter que usar um caminho explícito todas as vezes.

@Web-eWorks Não tenho certeza se estou seguindo aqui, mas...

Os tipos personalizados funcionam especificamente como tipos no mecanismo para herança. Portanto, se você estender de um tipo personalizado, será como se estivesse estendendo de uma ramificação completamente diferente da hierarquia do mecanismo. Ex. se eu criar um tipo personalizado MyNode que estenda Node , não poderei colocar esse script em um VBoxContainer assim como não posso colocar um Node2D "em" um VBoxContainer . Este seria realmente o comportamento pretendido.

Agora, com o conceito de namespace, você idealmente teria scripts nomeados que NÃO são tipos personalizados. Então, nesse caso, eu poderia criar um script que estendesse Node e colocá-lo em Node , VBoxContainer AND MyNode . Isso faz sentido?

Então, o que estou dizendo é se você criar um tipo personalizado MyNode herdando, digamos MeshInstance , instanciar um nó dele no editor e tentar adicionar um script herdando Spatial para o nó digitado MyNode , isso funcionará corretamente? Ele funciona corretamente com nós de 'motor', e esse é o comportamento que precisamos emular.

Deve ser independente de namespace, pois é mais uma questão de garantir que o script do tipo personalizado seja chamado independentemente do ponto na hierarquia de herança do script 'nível de usuário'.

@Web-eWorks Sim, isso funcionaria. Cada entrada de "primeiro nível" no mapa ClassDB de custom_types terá um link de volta para um tipo no mapa classes , caso contrário ocorrerá um erro e o tipo personalizado será não criou. Isso garante que a cadeia de herança seja preservada ao mover de tipos personalizados de volta para os tipos de mecanismo até Object .

@willnationsdev Só para ter certeza - se você adicionar um método _ready em MyNode e um nó pronto em seu script de usuário que deriva de Spatial, ele será chamado como Spatial._ready(), MeshInstance._ready(), MyNode._ready(), script._ready() ? (Ou qualquer pedido em que _ready seja despachado.)

Eu ainda mantenho minha opinião de que isso é desnecessário e confuso. Esse problema precisa ser resolvido a partir da interface do usuário do editor, não do mecanismo principal.

@reduz Isso não é algo que pode ser resolvido apenas com a interface do Editor. Não se você quiser controlar a manipulação do script no objeto pelos usuários. Parece-me que esse é um recurso que muitas pessoas estão querendo configurar.

Você está sugerindo que o gdscript_compiler deve referenciar o conteúdo em EditorData para configurar novos identificadores globais para tipos de script, em vez de rastreá-los todos no ClassDB e permitir que o ClassDB gerencie todas as informações de herança no mecanismo?

Certamente há uma parte que precisa ser resolvida da perspectiva da interface do editor, mas também há uma parte que precisa ser resolvida no núcleo. Adicionar tipos personalizados ao mecanismo, tipos _real_ da perspectiva do ClassDB, é um recurso muito poderoso e, em última análise, necessário. No que diz respeito à confusão, ainda sustento que não é mais confuso do que o sistema atual, e muito provavelmente menos.

@Web-eWorks Eu concordo. Fazer com que os dados de herança sejam rastreados no editor seria muito mais confuso na minha opinião. E isso resultaria em soluções estranhas, pois esse tipo de informação não existiria mais uma vez que você executasse o jogo sem o editor (e é por isso que eu realmente tive que começar a carregar as informações em project.godot para carregá-las no ClassDB na inicialização. Nenhum EditorPlugins para adicionar os tipos personalizados estava causando falha na compilação dos GDScripts ao executar a cena).

@Web-eWorks E para responder à sua pergunta anterior, sim, isso funciona corretamente.

No meu cenário de teste, eu tenho Node.gd que está estendendo GDSkillsEffect > GDSkillsAPI > Node , e os métodos _ready implementados em cada script são acionados no devido ordem: API, Efeito, Node.gd.

No momento, estou enfrentando um erro de loop infinito de algum tipo, sempre que dois scripts tentam herdar de scripts de tipo personalizado por nome. Ex. se Node.gd tiver extends GDSkillsEffect e gdskills_effect.gd tiver extends GDSkillsAPI , tentar modificar e salvar gdskills_effect.gd ou gdskills_api.gd fará com que o editor infinitamente "carregar" e depois travar. Esse é provavelmente o meu maior bug no momento.

@willnationsdev Ahh, não, estou falando de Node.gd estender Node , _not_ GDSkillsEffect . Se _isso_ funcionar, então está tudo bem.

Por exemplo, aqui está uma representação da árvore de cena:

-> User Script:
  extends Node
  func _ready(): pass

@Web-eWorks Ah, entendo o que você quer dizer. Bem, deveria funcionar, mas acabei de testar e parece que minha lógica em Object::set_script() está bloqueando por algum motivo, então esse é um bug que preciso corrigir. XD Está falhando porque detectou que Node não deriva o script de tipo personalizado (o que é verdade, yay), mas não deveria estar falhando nesse caso, lol.

@Web-eWorks Como mencionei, isso NÃO é algo que precisa ser alterado no ClassDB.

Eu realmente não acho que isso precise ser resolvido no núcleo, pois cada linguagem de script lida com isso de maneira diferente. Você pode criar facilmente uma nova classe no Mono e ela funcionará. Para GDScript pode ser um simples caso de expor um arquivo de script como um global pré-carregado e pronto. Uma solução de tamanho único, como proposta no PR, definitivamente não é o caminho a seguir.

@willnationsdev Agradeço seu esforço, mas isso já foi discutido sem fim e o consenso é que:

  • Adicionar um tipo personalizado é diferente para cada linguagem de script, portanto, hackear algo no ClassDB, que realmente serve apenas para registrar coisas C++, NÃO é o caminho a seguir.
  • Antes de ir tão longe, podemos melhorar a usabilidade da interface do usuário para casos em que você deseja estender o script de um nó personalizado, para que ele apenas crie uma herança simples.
  • Em geral, adicionar hacks ao mecanismo principal para lidar com casos de canto nunca é o caminho a seguir. O Core precisa permanecer livre de hacks.

@willnationsdev Para referência, o comportamento do mecanismo é que qualquer script que estende _alguma coisa_ igual ou anterior na hierarquia de herança pode ser adicionado a um nó. Assim, um script que extends Spatial pode ser adicionado a um MeshInstance mas não a um Control ou Node , pois nenhum dos dois é ou herda de Spatial . Este é um comportamento que deve ser replicado. (Sem pressão...)

@reduz Mas criar uma nova classe no Mono a adiciona à hierarquia de herança do mecanismo? Ou a caixa de diálogo Criar nó do editor? Talvez seja necessário abrir uma nova edição que defina de forma concisa qual é o propósito disso, porque acho que não estamos falando da mesma coisa aqui.

O objetivo das modificações do ClassDB é permitir o registro de novos tipos de Nodes (ou Recursos) sem a necessidade de recompilar o mecanismo. Não para adicionar novos globais personalizados no GDScript, embora seja um problema tangencial em que @willnationsdev esteja trabalhando na mesma ramificação.

O objetivo disso não é adicionar hacks, mas criar um _system_ bem projetado para estender os tipos do mecanismo.

@Web-eWorks A hierarquia de herança do mecanismo é para C++, não para scripts. Tentar misturar os dois é conceitualmente errado para começar.

Talvez o mal-entendido seja que a caixa de diálogo criar nó faz parecer que uma nova classe foi adicionada, portanto, pode ser uma boa ideia marcar esses tipos personalizados como contendo claramente um script.

@Web-eWorks Se você estiver usando Mono, parecerá transparente como se uma nova classe fosse adicionada, porque é uma nova classe. Para GDScript, como as classes são arquivos por padrão, isso não pode ser feito dessa maneira, então a maneira de fazer isso pode ser adicionar um novo global com uma interface do usuário dedicada para configurá-lo (como temos para carregamentos automáticos singleton) ... mas ainda é uma classe de script, não uma classe de mecanismo.

@willnationsdev Meu ponto principal nisso é que acho errado fazer parecer que você está adicionando novas classes reais ao mecanismo, porque elas não são. Está aberto à confusão. É apenas um nó com um script, então, em vez de ocultar o script, acho que a coisa certa a fazer é torná-lo mais visível na caixa de diálogo de criação.

@reduz Bem, é isso. Node+Script é uma cena. O mecanismo add_custom_type deve se comportar como Mono, registrando uma 'nova classe', mesmo que não seja tecnicamente uma 'classe' por qualquer padrão. Se houver uma maneira de fazer isso sem precisar tocar no ClassDB, sou todo ouvidos.

Além disso, @akien-mga sugeriu que na visualização da árvore da cena, poderíamos ocultar os scripts de nós personalizados, para evitar confundir os usuários sobre eles terem criado esse script e editado por engano (mas ainda mostrá-lo no inspetor na parte inferior) .

Nesses nós, adicionar um script abrirá a caixa de diálogo de criação em um modo de herança, portanto, ainda será bastante transparente para o fluxo de trabalho do usuário, enquanto fica claro que é um nó personalizado e não faz parte do mecanismo.

@willnationsdev Alguma objeção para eu abrir uma nova questão mais concisa detalhando especificamente o escopo da implementação?

@Web-eWorks Node + Script não é uma cena, nós em um layout de árvore são uma cena. Você também pode adicionar tipos de recursos personalizados, não apenas nós.

E não, não deve se comportar como registrar uma nova turma. Precisa ficar bem claro que é uma classe C++ com um script pré-adicionado.

@Web-eWorks Sim, isso não é problema para mim. Por favor, mencione-me para que eu receba um ping se você fizer isso. Não tem certeza se precisamos de um problema separado?

Veja por outro ponto de vista. Seu argumento é fazer com que pareça ao usuário como se você estivesse estendendo os tipos de mecanismo com novos tipos de mecanismo.

Meu ponto de vista é que você está estendendo os tipos de mecanismo com scripts, não com novos tipos de mecanismo. E que o usuário não é burro e precisa saber disso.

@reduz O que eu quis dizer sobre Node+Script foi que esse mecanismo já estava coberto por meio da instanciação de Scenes.

Talvez eu esteja entendendo mal a implementação do Mono, mas as classes Mono ainda não são Scripts?

@reduz Concordo principalmente com você, também quando você disse que adicionar um script a um nó personalizado simplesmente proporia herdá-lo. Mas como você espera que isso funcione com os tipos personalizados GDNative?

@reduz Um dos nossos objetivos, porém, é permitir que scripts de tipo personalizado, esses scripts pré-atribuídos colocados nas classes C++, não sejam removíveis. Isso é algo que não pode ser feito no contexto do editor, pois você sempre pode remover um script em tempo de execução (a menos que queira preservar essa funcionalidade e proteger apenas um script de tipo personalizado em tempo de design no editor)

Eu certamente estaria aberto a um método alternativo. De qualquer forma, a implementação mais fácil é fazer com que o Objeto atribua scripts condicionalmente a si mesmo (como fiz na minha implementação) verificando alguma classe de registro de terceiros (seja o ClassDB, ProjectSettings, EditorData ou quem sabe o que mais) . Torna-se então muito fácil para o próprio editor verificar com esse terceiro e exibir as coisas de maneira diferente (também como fiz na minha implementação). Não seria muito trabalho, mas não acho que mover o registro para outro contexto que não seja o ClassDB.

^ Esse compromisso seria aceitável? Caso contrário, você terá que microgerenciar todos os locais possíveis em que Object recebe um script atribuído para verificar com o terceiro. Isso seria muito mais complexo.

A implementação que fiz foi muito clara até agora sobre quais "tipos" são scripts e quais não são. Afinal, você ainda pode ver e acessar claramente o script associado aos tipos personalizados no dock de cena no vídeo que compartilhei.

@willnationsdev Eu entendo o que você está tentando fazer, mas não acho que isso possa ser feito de forma limpa. Está escondendo uma complexidade que não tem motivo para ser escondida, de uma forma que nunca funcionará totalmente como esperado.

@Zylann Acho que é o mesmo, mas a) o script é interno do gdnative b) ele usa um método interno ao gdnative. Eu não estou familiarizado o suficiente com ele honestamente para dizer.

@reduz Você está dizendo que não quer permitir nenhuma forma de criação de restrições baseadas em script em objetos? Porque eu poderia mover a lógica de verificação para o próprio Editor e isso daria a você a verificação em tempo de design das restrições com a mesma facilidade (alterações da interface do usuário, como você diz), mas elas não funcionariam em tempo de execução, então as pessoas ainda seriam potencialmente capaz de mudar as coisas uma vez que o jogo está em execução. Isso funcionaria melhor para você? Eu ainda prefiro poder verificar as coisas em tempo de execução ...

@willnationsdev que tipo de restrições baseadas em script você deseja fazer?

As mesmas restrições sobre as quais a propriedade de script personalizado tem sido desde o início: impor que o script atribuído deriva algum outro script.

Eu recomendo ocultar o ícone do script para o script estendido na hierarquia da cena e no caso de alguém clicar no botão "Adicionar script" em vez de herdar a classe base do nó que herda o script atacado. É transparente e não precisa mexer com o ClassDB

Então, apenas revisando algumas das informações em script_language.h , sinto que poderia realmente mover o novo conteúdo que adicionei em ClassDB para a classe ScriptLanguage e criar um tipo de ScriptDB singleton que só é criado se a linguagem de script pretende usá-lo. E porque object.cpp já inclui script_language.h , ele seria capaz de fazer o seguinte em set_script(const RefPtr &p_script) ...

  1. verifique se p_script é de fato um script
  2. verifique a qual idioma p_script pertence
  3. entregar p_script e Object da instância custom_script para ScriptDB para o ScriptLanguage associado,
  4. obter uma resposta do ScriptDB sobre se o p_script pode ser atribuído ao Object dadas as restrições implícitas no custom_script no Object instância.

Isso nos permitiria manter ClassDB limpo de quaisquer modificações e manter object.h limpo (além de um setter/getter por custom_script ). Também evita complicações desnecessárias das linguagens de script que não precisam depender de Godot para definir identificadores e namespaces (como GDScript e VisualScript precisariam, ao contrário de C#, C++, Python, etc.).

Então tudo o que você precisa fazer é definir ScriptServer métodos que podem realizar verificações de identificador/espaço de nomes em todas as linguagens de script aplicáveis ​​para substituir a funcionalidade experimental ClassDB de confirmação de tipos personalizados / herança de tipos personalizados hierarquias. Bastante fácil.

Isso soa como uma alternativa aceitável @reduz?

Apenas adicionando minha voz aqui. Acabei de começar a trabalhar com Godot e, quando li sobre addons de tipo personalizado, realmente pensei que estaria criando um novo tipo base reutilizável. Como quando você cria um KinematicBody você pode anexar um script a ele, mas ele ainda faria todas as coisas KinematicBody .

Isso é reforçado de duas maneiras:

  1. Eles são chamados de tipos. Enquanto as linguagens diferem em se um Tipo é extensível ou não (javascript: sim, golang: não, python: sim), um tipo que você define geralmente é extensível se os tipos de linguagem de primeira classe forem extensíveis. Em Godot, os tipos de primeira classe são extensíveis, mas os tipos personalizados não (pelo menos não da mesma maneira). Chamá-los de outra coisa, como cenas pré-fabricadas ou cenas de modelo, ajudaria a marcá-los como diferentes.
  1. Eles aparecem na mesma árvore que os nós de primeira classe na janela 'Criar novo nó'. Isso implica que você os use da mesma maneira. Ter uma seção separada para 'Prefabs' ou 'Modelos' ou como você quiser chamá-los novamente os chamaria de diferentes.

@JPTeasdale Infelizmente, neste momento, a maior preocupação é a implementação, não tanto a questão "como você define isso". E os tipos personalizados Godot SÃO extensíveis (são apenas scripts). O editor ainda não tem o suporte de código para exibir relacionamentos de herança entre tipos personalizados na caixa de diálogo de criação de nó, mas os dados estão disponíveis. Eu também não vejo um motivo para renomeá-los de "tipo personalizado" para outra coisa. "Prefab" e "template" não são termos realmente apropriados, nem são cenas em primeiro lugar (são apenas scripts, puros e simples).

eu acho que é muito mais simples do que a solução pretendida:

  1. Adicione uma propriedade oculta no inspetor à classe Object chamada "custom_type_script" e atribua o script personalizado para selecionar essa propriedade em vez de Script
  2. Ao tentar estender o nó verifique se esta propriedade é nula, caso contrário, estenda este script em vez da classe do nó (escrevendo extend "res:/path/to/script.gd")
  3. Altere get_script_instance para apontar para a instância do script personalizado se o script do nó for nulo

@MarianoGnu Bem, em termos de criar as alterações do editor, é mais simples de fazer apenas preenchendo automaticamente a propriedade script e evitando que ela se torne nula em primeiro lugar (porque o editor só olha para o script , e não precisamos encontrar toda vez que ele referenciar a propriedade script e modificar esse código se tudo o que fizermos for alterar o valor de script ) .

Com isso dito, parte do objetivo de refazer esse processo é permitir que linguagens de script em geral optem por usar identificadores em vez de caminhos de arquivo para localizar classes de script. Essa é a única razão pela qual o conceito $#$ ScriptDB ou modificações ClassDB foram sugeridos em primeiro lugar. Mas agora vejo por que Juan tem se oposto tanto às mudanças ClassDB , daí a sugestão de armazenar as informações apenas na API de script. Ele contém todas as informações na linguagem de script individual.

Uma combinação poderia ser feita, em vez de armazenar o script invisível no objeto armazená-lo no ScriptDB, adicionar um pré-passe ao leitor de script para substituir " extend CustomClassName" por "extend "res:/path/stored/inScriptDB.gd " no pré-compilador do GdScript, porque ter o script fora da hierarquia de herança do script é muito problemático (a hierarquia deve ser uma linha reta de baixo para a raiz, ter uma ramificação leva à confusão)

porque ter o script fora da hierarquia de herança do script é muito problemático (a hierarquia deve ser uma linha reta de baixo para a raiz, ter uma ramificação leva à confusão)

@MarianoGnu Talvez algum mal-entendido aqui. Em que ponto você acha que não existe uma linha reta de herança? Até onde eu implementei as coisas, sempre há uma hierarquia de herança muito clara entre os scripts. Eu não mudei nada sobre como as hierarquias de herança funcionam. Acabei de tornar possível mapear um determinado script para um StringName e procurá-lo em um banco de dados de algum tipo.

E se já estamos fazendo isso, não há razão para substituir o texto do script de volta para um caminho no compilador GDScript. Tudo o que o compilador faz é atribuir uma instância Script a uma variável script . Se eu carreguei o script através do método ResourceLoader::load(path) ou através da busca com Class/ScriptDB::get_script(namespace_and/or_identifier) não importa.

Só queria mencionar que, como um novo usuário do Godot, criei um plugin com a impressão de que meu "Nó personalizado" do plugin funcionaria como um nó embutido. Ou seja, quando eu o selecionei na lista de nós, esperava obter um nó sem um script, mas com a funcionalidade que eu tinha script no plugin sendo herdado já embutido (como é para os nós embutidos). Apenas pensei que deveria dar outra opinião de alguém que acabou de chegar (embora pareça que a discussão aqui já foi extensa).

Como um "nó personalizado" é apenas um script, qual é a diferença de apenas atribuir o script a um nó embutido? O que o recurso de nó personalizado deve fazer?

@MCrafterzz Foi discutido que deve haver a capacidade de nós personalizados para adicionar um script sobre um nó personalizado criado a partir de um plug-in.

Atualmente o nó personalizado é apenas um nó criado com um script já anexado e ícone e nome já alterados.

@willnationsdev Até onde você chegou ao implementar esse recurso.
Eu realmente gostaria que esse recurso estivesse aqui antes do 3.1, será uma adição realmente incrível.
Para o sistema de plugins e complementos Godot.

Não quero pressionar ninguém. Então, por favor, não leve isso para o trabalho.

Estou implementando um novo back-end para o sistema de tipo personalizado inteiramente. O novo permite que os usuários façam toda a funcionalidade original, além de fazer com que o botão Add-a-Script adicione um novo script que estende o script personalizado por padrão (em vez de abrir o script personalizado) e faz com que você não pode remover o script personalizado (você teria que usar o comando do editor Change Type, assim como qualquer outro tipo de mecanismo).

@swarnimarun

Além disso, permitirá que os usuários registrem tipos em um global que fornece acesso a mapeamentos de nome de tipo para caminho de arquivo. O GDScript será capaz de perceber esses mapeamentos como nomes de tipos globais essencialmente simples. Além disso, os tipos não precisam ser personalizados para serem registrados e os tipos podem ser scripts ou cenas.

Até agora, implementei o novo back-end e reconfigurei a funcionalidade de script de tipo personalizado original. Atualmente estará trabalhando em novos recursos. A partir de uma semana a partir de agora, provavelmente. Estou ocupado esta semana.

@willnationsdev Não se preocupe, se for 3.1, ficarei contente.
E percebi que poderia dar um pouco de trabalho.
Mantenha o bom trabalho.

Atualmente, o editor tem a capacidade de estender facilmente o script de qualquer nó:

extend

O próprio nó atualmente se parece com isso:

2

E a principal preocupação da @reduz era esconder o fato de já haver um script anexado. Por um lado, faz sentido não esconder isso do usuário. Mas, por outro lado, nós personalizados quase sempre terão scripts anexados. Sem scripts, nós personalizados são apenas nós regulares existentes com ícones personalizados e nenhuma funcionalidade extra adicionada.

E mesmo que você possa estender o script personalizado, é muito irritante que os nós personalizados simples tenham a mesma aparência que os nós personalizados estendidos.

Então, aqui está minha solução simples: quando o script de um nó personalizado é o mesmo que o script na definição do nó personalizado, o ícone do script deve ser esmaecido, assim:

3

Significado:

4

Pessoal, exemplo da vida real: Se eu tiver muitas notas personalizadas do mesmo tipo, cada script personalizado para sua própria instância, o que acontece se eu quiser alterar o script de nó personalizado base? Eu te digo: O PIOR, porque preciso modificá-lo, E todas as outras instâncias de acordo, entregando grandes chances de erros humanos e de digitação.

Você não quer esconder o script? Tudo bem, então mostre o script custom_node E o script do nó do projeto.

@aaronfranke Na minha opinião, esta é a melhor solução. Mesmo cenas instanciadas podem se beneficiar disso.

@zatherz et al, agora que o #30697 foi implementado, o que mais pode ser melhorado? Existe mais alguma coisa em https://github.com/godotengine/godot/issues/6067#issuecomment -238250383 que é importante ter?

Fechando conforme corrigido por #30697. Embora a proposta original no OP elaborada em https://github.com/godotengine/godot/issues/6067#issuecomment -238250383 não tenha sido implementada, isso não acontecerá devido às preocupações de @reduz em https:// github.com/godotengine/godot/issues/6067#issuecomment -239060186.

Esta página foi útil?
0 / 5 - 0 avaliações