Skip to content

Tech Tree#89

Open
cosmosgc wants to merge 7 commits intoLaryNevesPR:EE-Andromedafrom
cosmosgc:EE-TechTree
Open

Tech Tree#89
cosmosgc wants to merge 7 commits intoLaryNevesPR:EE-Andromedafrom
cosmosgc:EE-TechTree

Conversation

@cosmosgc
Copy link

@cosmosgc cosmosgc commented Apr 24, 2025

Quase tudo de Goob-Station/Goob-Station#2065

Media

image

Summary by CodeRabbit

  • Novos Recursos

    • Interface de console de pesquisa totalmente redesenhada com visualização gráfica em árvore, cartões de tecnologia interativos, painel de informações detalhadas e exibição de pré-requisitos.
    • Suporte a arrastar e reposicionar tecnologias na árvore.
    • Exibição visual de dependências entre tecnologias.
    • Novos painéis para receitas desbloqueadas e requisitos de pesquisa.
    • Tradução da interface de pesquisa para português brasileiro.
    • Ferramentas web e desktop para visualizar, editar e exportar árvores tecnológicas em YML.
  • Aprimoramentos

    • Adição de campos de posição e pré-requisitos explícitos para tecnologias, melhorando a navegação e o gerenciamento do progresso.
    • Novos campos de nome abreviado para disciplinas na interface.
    • Atualização dos arquivos de protótipo para refletir a nova estrutura de árvore.
  • Correções e Ajustes

    • Remoção de restrições de tier e ajustes de disponibilidade de tecnologias.
    • Limpeza de comentários e organização dos arquivos YAML de pesquisa.
  • Documentação

    • Novos arquivos de localização e documentação de metadados para recursos gráficos e interface.
  • Ferramentas

    • Scripts Python e interfaces web para gerenciamento e atualização em massa de arquivos de árvore tecnológica.

@coderabbitai
Copy link

coderabbitai bot commented Apr 24, 2025

Walkthrough

Esta atualização implementa uma grande reestruturação e aprimoramento do sistema de pesquisa ("Research") no jogo, especialmente focando na interface do console de pesquisa (R&D Console). Foram introduzidos novos arquivos de layout XAML e classes C# para uma interface gráfica avançada, incluindo painéis de tecnologia, cartões de receitas, visualização de pré-requisitos e informações detalhadas. O sistema agora utiliza uma enumeração de disponibilidade de pesquisa e cada tecnologia possui uma posição explícita para exibição em árvore. Diversos arquivos YAML de protótipos foram atualizados para adicionar posições e pré-requisitos, e ferramentas de gerenciamento/edição de árvores tecnológicas foram criadas em Python e JavaScript, incluindo editores web interativos. Entradas de localização também foram adicionadas.

Changes

Arquivo(s) / Grupo Resumo das alterações
Content.Client/_Goobstation/Research/UI/FancyResearchConsoleBoundUserInterface.cs, ...Menu.xaml, ...Menu.xaml.cs, ...Item.xaml, ...Item.xaml.cs, ...FancyTechnologyInfoPanel.xaml, ...FancyTechnologyInfoPanel.xaml.cs, ...MiniRecipeCardControl.xaml, ...MiniRecipeCardControl.xaml.cs, ...ResearchesContainerPanel.cs Implementação completa da nova interface gráfica do console de pesquisa: novos controles, cartões de tecnologia/receita, painel de informações, lógica de interação, atualização de estados e visualização de pré-requisitos.
Content.Client/Research/UI/MiniTechnologyCardControl.xaml Ajuste visual: escala da textura alterada de 0.5 para 1.0.
Content.Server/Research/Systems/ResearchSystem.Console.cs, ...Technology.cs Refatoração do cálculo de disponibilidade das tecnologias e ajuste na lógica de desbloqueio de disciplina principal.
Content.Shared/Research/Components/SharedResearchConsoleComponent.cs Atualização do estado da interface: remoção do softCapMultiplier, inclusão de dicionário de pesquisas e disponibilidade.
Content.Shared/Research/Prototypes/TechDisciplinePrototype.cs Adição do campo obrigatório UiName para disciplinas.
Content.Shared/Research/Prototypes/TechnologyPrototype.cs Adição da propriedade obrigatória Position para cada tecnologia.
Content.Shared/Research/Systems/SharedResearchSystem.cs, ...Goob.cs Tornou a classe parcial, ajuste na lógica de disponibilidade, novo método de cálculo de porcentagem de conclusão de disciplina.
Content.Shared/_Goobstation/Research/ResearchAvailability.cs Novo enum serializável para estados de disponibilidade de pesquisa.
Resources/Locale/en-US/_Goobstation/research/ui.ftl, ...pt-BR/_Goobstation/research/ui.ftl Novos arquivos de localização para a interface de pesquisa (inglês e português).
Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml Troca do tipo de UI para o console de pesquisa para a nova interface "Fancy".
Resources/Prototypes/Research/.yml, Resources/Prototypes/_/Research/*.yml Inclusão de posições (position) e pré-requisitos explícitos (technologyPrerequisites) em quase todas as tecnologias; limpeza de comentários antigos.
Resources/Textures/_Goobstation/Interface/rnd-static.rsi/meta.json Novo arquivo de metadados de textura animada para a interface.
Tools/TechTreeManager/FetchAllResearchYML.py, .../app.py, .../UpdateAllYML/appUpdate.py Novas ferramentas Python para agregar, atualizar e visualizar arquivos YAML de tecnologias.
Tools/TechTreeManager/MasterArsenal.yml, .../MasterCivilianservices.yml, .../MasterExperimental.yml, .../MasterIndustrial.yml Novos arquivos YAML "master" agregando tecnologias por disciplina.
Tools/TechTreeManager/UpdateAllYML/update_log.txt, .../updated.yml Log de atualizações em massa e arquivo YAML de tecnologias atualizadas.
Tools/TechTreeManager/web/all_view.html, .../all_view.js, .../index.html, .../app.js, .../style.css, .../default.yml Novo editor web completo para visualização, edição, arrasto e exportação de árvores tecnológicas em YAML.

Sequence Diagram(s)

sequenceDiagram
    participant Jogador
    participant FancyResearchConsoleMenu
    participant FancyResearchConsoleBoundUserInterface
    participant Servidor

    Jogador->>FancyResearchConsoleMenu: Clica em tecnologia ou botão
    FancyResearchConsoleMenu->>FancyResearchConsoleBoundUserInterface: Evento de seleção/disparo
    FancyResearchConsoleBoundUserInterface->>Servidor: Envia mensagem (ex: desbloquear tecnologia)
    Servidor->>FancyResearchConsoleBoundUserInterface: Atualiza estado do console (inclui pontos e disponibilidade)
    FancyResearchConsoleBoundUserInterface->>FancyResearchConsoleMenu: Atualiza painel, cartões e informações
    FancyResearchConsoleMenu->>Jogador: Exibe interface atualizada
Loading

Poem

🐇
No console brilham novas luzes,
Com cartões e painéis a saltitar,
Cada tecnologia ganha cor e posição,
Pré-requisitos agora a brilhar!
O coelho saltita entre YAMLs e grids,
Editando, arrastando, sem parar,
Com a árvore tecnológica pronta pra inovar!
🌱✨

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link

github-actions bot commented Apr 24, 2025

RSI Diff Bot; head commit 460a3aa merging into f61eeb9
This PR makes changes to 1 or more RSIs. Here is a summary of all changes:

Resources/Textures/_Goobstation/Interface/rnd-static.rsi

State Old New Status
static Added

Edit: diff updated after 460a3aa

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

🔭 Outside diff range comments (3)
Tools/TechTreeManager/MasterCivilianservices.yml (2)

151-225: ⚠️ Potential issue

Outras tecnologias duplicam posição -1,0
Entradas como PositronicInterfacing, HONKWeapons, AdvancedTreatment, CyberneticEnhancements, Autodoc e HighEndSurgery estão todas em position: -1,0. Favor revisar e corrigir.


31-225: 🛠️ Refactor suggestion

Revisar pré-requisitos para manter fluxo de tiers
Muitas tecnologias de tier 2 e 3 não possuem technologyPrerequisites, o que pode quebrar a progressão esperada. Recomendo definir dependências claras para cada nível.

Tools/TechTreeManager/MasterExperimental.yml (1)

1-195: ⚠️ Potential issue

Todas as tecnologias compartilham position: -1,0
Cada entrada usa a mesma coordenada, impossibilitando a formação de um tech tree. É imperativo atribuir posições distintas conforme layout definido.

🧹 Nitpick comments (49)
Resources/Prototypes/Research/disciplines.yml (3)

12-12: Remover espaço em branco no final da linha do uiName.
Há um espaço extra após IND gerando erro de lint YAML. Por favor, remova o espaço terminal para manter o padrão de formatação.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 12-12: trailing spaces

(trailing-spaces)


38-38: Remover espaço em branco no final da linha do uiName.
Há um espaço extra após EXP que causa erro de lint YAML. Remova o espaço terminal para corrigir.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 38-38: trailing spaces

(trailing-spaces)


51-51: Remover espaço em branco no final da linha do uiName.
Há um espaço extra após SRV gerando erro de lint YAML. Por favor, remova esse espaço para atender às regras do YAMLlint.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 51-51: trailing spaces

(trailing-spaces)

Resources/Locale/en-US/_Goobstation/research/ui.ftl (1)

6-12: Textos de interface bem definidos

Os textos de localização estão bem definidos e cobrem todas as necessidades da nova interface do console de pesquisa. Eles são claros e informativos, proporcionando uma boa experiência ao usuário.

Seria adequado também criar a versão em português (pt-BR) destes textos para manter a consistência de idiomas no jogo.

Content.Shared/_Goobstation/Research/SharedResearchSystem.Goob.cs (1)

16-17: Considerar melhoria de performance para chamadas frequentes

A enumeração e filtragem de todos os protótipos de tecnologia pode ser ineficiente se este método for chamado com frequência. Considere armazenar em cache os resultados ou otimizar esta operação para melhorar o desempenho.

Content.Client/_Goobstation/Research/UI/FancyResearchConsoleMenu.xaml (4)

8-15: Considerar redimensionamento dinâmico da janela
Atualmente o FancyWindow usa SetSize="1260 850", o que fixa o tamanho inicial. Para evitar cortes ou barras de rolagem indesejadas em resoluções menores, sugiro adicionar propriedades como MinSize ou habilitar flags de redimensionamento (SizeFlagsExpand) conforme as diretrizes de UI.


41-44: Extrair cor hard-coded para recurso de tema
O BackgroundColor="#000000FF" está definido inline. Para facilitar manutenção e consistência com temas futuros, considere mover essa cor para um recurso XAML (ex.: <Color x:Key="ResearchBackground">#000000FF</Color>).


57-58: Evitar margin negativa em botão
O RecenterButton usa Margin="5 -5", o que pode gerar cortes em torno do botão. Avalie a possibilidade de ajustar a margem ou usar padding interno no container em vez de valores negativos.


60-70: Adicionar ScrollContainer para painel de informações
O InfoContainer está preparado para exibir detalhes, mas se houver overflow de conteúdo, um ScrollContainer ao redor do BoxContainer pode melhorar a usabilidade.

Tools/TechTreeManager/MasterArsenal.yml (2)

218-226: Ausência de pré-requisitos em PrototypeWeapons
PrototypeWeapons está em tier 3 mas não possui technologyPrerequisites. Para manter a hierarquia de tiers, avalie adicionar pré-requisito, como AdvancedWeapons.


303-316: Sugestão: adicionar pré-requisito a KineticModifications
KineticModifications é tier 2 sem dependências; provavelmente deveria exigir BasicWeapons ou nível equivalente para manter a progressão lógica.

Tools/TechTreeManager/MasterExperimental.yml (1)

1-195: Sugestão: definir dependências para tiers avançados
Para tecnologias de tier 2 e 3 em Experimental, especifique technologyPrerequisites adequados (por exemplo, BasicAnomalousResearchAdvancedAnomalyResearch) para guiar a progressão.

Resources/Prototypes/_Goobstation/Research/experimental.yml (1)

20-20: Sugerir uso de sequência YAML para posição
Para evitar ambiguidades de parsing e deixar o formato mais claro, considere usar uma lista YAML:

-position: 7,1
+position: [7, 1]
Tools/TechTreeManager/web/style.css (1)

1-5: Estilização do body parece consistente
Definir font-family, margin e padding no body garante base limpa.
Como sugestão opcional, adicione:

* {
  box-sizing: border-box;
}

para melhorar o cálculo de tamanho de elementos.

Tools/TechTreeManager/web/index.html (2)

4-5: Adicionar meta viewport para responsividade

É recomendável inserir

<meta name="viewport" content="width=device-width, initial-scale=1.0">

logo após a declaração de charset para garantir que a interface se adapte corretamente em diferentes tamanhos de tela.


22-23: Especificar type="button" nos botões

Por padrão, <button> sem type pode atuar como submit em um formulário futuro. Para evitar comportamentos indesejados, adicione type="button" em:

<button id="save" type="button">Save</button>
<button id="download" type="button">Download YAML</button>
Resources/Prototypes/_Shitmed/Research/civilianservices.yml (4)

17-17: Usar sequência YAML para position

Em vez de uma string " -4,-3", prefira um array para tipagem explícita:

-position: -4,-3
+position: [ -4, -3 ]

Isso evita ambiguidades de parsing e alinha-se a boas práticas de YAML.


36-36: Unificar formato de position

Mesma recomendação para esta entrada:

-position: -2,-4
+position: [ -2, -4 ]

49-52: Padronizar definição de position e validar technologyPrerequisites

Para Autodoc, converta position em uma sequência e confira a indentação:

-position: -3,-4
-technologyPrerequisites:
-  - AdvancedTreatment
+position: [ -3, -4 ]
+technologyPrerequisites:
+  - AdvancedTreatment

65-68: Atualizar formato de position em HighEndSurgery

Mesmo ajuste para manter consistência:

-position: -4,-4
-technologyPrerequisites:
-  - AdvancedTreatment
+position: [ -4, -4 ]
+technologyPrerequisites:
+  - AdvancedTreatment
Content.Client/_Goobstation/Research/UI/FancyResearchConsoleItem.xaml (1)

8-11: Remover namespace não utilizado xmlns:gfx

O prefixo gfx não é referenciado neste arquivo (você usa graphics:). Para clareza, remova:

- xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
Resources/Locale/pt-BR/_Goobstation/research/ui.ftl (1)

6-8: Ajustar capitalização de legendas

Em PT-BR, recomenda-se caixa baixa após a primeira palavra em labels:

-research-console-unlocks-text = Receitas Desbloqueadas:
+research-console-unlocks-text = Receitas desbloqueadas:

-research-console-required-text = Pré-Requisitos:
+research-console-required-text = Pré-requisitos:
Content.Client/_Goobstation/Research/UI/MiniRecipeCardControl.xaml (1)

13-19: Evitar margin negativa para layout

O Margin="0 0 -5 0" no PanelContainer é um workaround que pode gerar confusão. Considere realinhar ou ajustar HorizontalExpand/SeparationOverride em vez de usar margem negativa para manter o layout mais legível.

Tools/TechTreeManager/web/all_view.html (3)

6-22: Adicionar metatag de viewport para responsividade móvel
Sem <meta name="viewport">, a página pode ficar ilegível em dispositivos móveis, pois o canvas tem largura fixa de 2000 px. Inclua a metatag para que o layout se adapte a diferentes tamanhos de tela.

   <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">

25-33: Melhorar acessibilidade e semântica dos controles

  1. O <input type="file"> não possui <label>, dificultando uso por leitores de tela.
  2. O <button> não especifica type="button"; embora fora de <form> isso não quebre nada, é boa prática.
  3. Considere adicionar aria-label ao canvas para descrever seu propósito (ex.: “Área de visualização da árvore tecnológica”).

Exemplo:

-  <input type="file" id="file-input" multiple>
+  <label for="file-input">Carregar YAMLs:</label>
+  <input type="file" id="file-input" multiple>

-  <button id="export">Download All YML</button>
+  <button id="export" type="button">Baixar YAML unificado</button>

29-33: Canvas com tamanho fixo pode causar uso excessivo de memória
Definir width="2000" e height="2000" força alocação constante de ~16 MB para cada instância do canvas. Caso a ferramenta precise apenas exibir parte da árvore, considere ajustar o tamanho via CSS ou dimensionar dinamicamente conforme o conteúdo/zoom para reduzir consumo de recursos.

Content.Server/Research/Systems/ResearchSystem.Console.cs (1)

73-108: Enumerar protótipos a cada atualização pode degradar desempenho
PrototypeManager.EnumeratePrototypes<TechnologyPrototype>().ToList() é chamado sempre que pontos mudam ou o UI é aberto. Em servidores com centenas de tecnologias, isso gera alocações e LINQ extra desnecessário. Armazene a lista em cache (ex.: campo readonly preenchido em Initialize) ou use um Lazy<T> para evitar re-enumerar.

Content.Client/_Goobstation/Research/UI/ResearchesContainerPanel.cs (2)

40-52: Variáveis alocadas dentro de Draw geram GC em cada frame
new Vector2(...) e Color.White são criados por iteração. Em UIs renderizadas a 60 FPS, isso pressiona o GC. Cache Color.White (já é struct, ok) e calcule vetores com métodos que evitam instanciar novos objetos, ou use campos Vector2 reutilizados.


43-49: Conexão ortogonal apenas para diferenças verticais
O código trata somente quando Y difere; se X diferir mas Y for igual, sempre desenha linha reta, o que pode atravessar outros nós. Avalie sempre usar a conexão em “L” quando existir qualquer deslocamento nos dois eixos.

Tools/TechTreeManager/web/default.yml (1)

1-1096: Excelente estruturação dos dados da árvore tecnológica!

O arquivo YAML define de forma abrangente todas as tecnologias do jogo com uma estrutura consistente e bem organizada. Cada entrada contém todos os metadados necessários:

  • Identificadores, nomes e ícones bem definidos
  • Agrupamento lógico por disciplina e nível
  • Posicionamento espacial para visualização em árvore
  • Pré-requisitos claramente definidos
  • Listas detalhadas de receitas desbloqueadas

Algumas observações e sugestões:

  • Algumas tecnologias possuem campos adicionais _x e _y além do position - seria útil documentar a diferença entre eles
  • Considere adicionar comentários separando as diferentes disciplinas para facilitar a navegação no arquivo
  • Verifique se todas as receitas desbloqueadas nos campos recipeUnlocks realmente existem nos protótipos do jogo
 - type: technology
   id: BasicWeapons
   name: research-technology-basic-weapons
+  # Arsenal - Tier 1
   icon:
     sprite: Objects/Weapons/Guns/Battery/laser_gun.rsi
     state: icon
Content.Client/_Goobstation/Research/UI/FancyTechnologyInfoPanel.xaml.cs (3)

57-63: Estado "Available" não está sendo tratado no switch de cores

O switch para determinar cores não inclui uma condição explícita para ResearchAvailability.Available. Embora o caso padrão (_) retorne null, seria mais claro incluir o caso Available explicitamente para melhorar a legibilidade e manutenção.

Color? color = availability switch
{
    ResearchAvailability.Researched => Color.LimeGreen,
    ResearchAvailability.PrereqsMet => Color.Crimson,
    ResearchAvailability.Unavailable => Color.Crimson,
+   ResearchAvailability.Available => null,
    _ => null
};

69-70: Botão desabilitado com critérios invertidos

A lógica para desabilitar o botão está definida corretamente, mas para maior clareza, considere usar uma expressão positiva em vez de negativa. Isto pode tornar o código mais fácil de ler à primeira vista.

- ResearchButton.Disabled = !hasAccess || availability != ResearchAvailability.Available;
+ ResearchButton.Disabled = !(hasAccess && availability == ResearchAvailability.Available);

ou alternativa mais legível:

- ResearchButton.Disabled = !hasAccess || availability != ResearchAvailability.Available;
+ ResearchButton.Enabled = hasAccess && availability == ResearchAvailability.Available;

33-71: Reorganização do construtor pode melhorar legibilidade

O construtor contém muitas inicializações e configurações. Considere extrair mais blocos lógicos em métodos auxiliares privados, semelhante ao que foi feito com InitializePrerequisites e InitializeRecipeUnlocks.

Exemplo de refatoração:

public FancyTechnologyInfoPanel(TechnologyPrototype proto, bool hasAccess, ResearchAvailability availability, SpriteSystem sprite)
{
    RobustXamlLoader.Load(this);
    IoCManager.InjectDependencies(this);

    var lathe = _ent.System<LatheSystem>();
    var research = _ent.System<ResearchSystem>();
    Prototype = proto;

    InitializeLabelsAndTextures(proto, sprite);
    InitializePrerequisites(proto, research, sprite);
    InitializeRecipeUnlocks(proto, lathe, sprite);
    ConfigureResearchButton(hasAccess, availability, proto);

    ResearchButton.OnPressed += Bought;
}

private void InitializeLabelsAndTextures(TechnologyPrototype proto, SpriteSystem sprite)
{
    TechnologyNameLabel.Text = Loc.GetString(proto.Name);
    DisciplineTexture.Texture = sprite.Frame0(_proto.Index(proto.Discipline).Icon);
    TechnologyTexture.Texture = sprite.Frame0(proto.Icon);
}

private void ConfigureResearchButton(bool hasAccess, ResearchAvailability availability, TechnologyPrototype proto)
{
    ResearchButton.ToolTip = !hasAccess
        ? Loc.GetString("research-console-no-access-popup")
        : null;

    ResearchButton.Text = availability == ResearchAvailability.Researched
        ? Loc.GetString("research-console-menu-server-researched-button")
        : ResearchButton.Text;

    Color? color = availability switch
    {
        ResearchAvailability.Researched => Color.LimeGreen,
        ResearchAvailability.PrereqsMet => Color.Crimson,
        ResearchAvailability.Unavailable => Color.Crimson,
        _ => null
    };
    TechnologyCostLabel.SetMessage(
        Loc.GetString("research-console-tech-cost-label", ("cost", proto.Cost)),
        defaultColor: color
    );

    ResearchButton.Disabled = !hasAccess || availability != ResearchAvailability.Available;
}
Tools/TechTreeManager/web/all_view.js (2)

30-62: Otimizar a função de desenho para melhor desempenho e visualização

A função draw() tem algumas limitações:

  1. Não há escala dinâmica para ajustar ao tamanho do canvas
  2. O texto pode estourar as bordas dos retângulos para IDs longos
  3. Não há diferenciação visual entre tecnologias de diferentes disciplinas ou tiers

Considere melhorar a visualização com cores diferentes para tiers, tamanho de texto ajustado e visualização mais detalhada.

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  for (const tech of techs) {
    const [x, y] = tech.position.split(',').map(Number);
    tech._x = x * 100 + canvas.width / 2;
    tech._y = y * 100 + canvas.height / 2;
  }

+  // Desenha linhas de conexão com cores baseadas no nível de dependência
  for (const tech of techs) {
    if (tech.technologyPrerequisites) {
      for (const id of tech.technologyPrerequisites) {
        const target = techs.find(t => t.id === id);
        if (target) {
          ctx.beginPath();
          ctx.moveTo(tech._x + 50, tech._y + 25);
          ctx.lineTo(target._x + 50, target._y + 25);
-         ctx.strokeStyle = '#aaa';
+         ctx.strokeStyle = tech.tier === target.tier ? '#aaa' : '#888';
+         ctx.lineWidth = 2;
          ctx.stroke();
        }
      }
    }
  }

  for (const tech of techs) {
+   // Cores diferentes para os diferentes tiers
+   const tierColors = ['#f8f8ff', '#eef', '#ddf', '#ccf'];
+   const tierColor = tierColors[Math.min(tech.tier || 0, tierColors.length - 1)];
    
-   ctx.fillStyle = '#fff';
+   ctx.fillStyle = tierColor;
    ctx.strokeStyle = '#000';
    ctx.fillRect(tech._x, tech._y, 100, 50);
    ctx.strokeRect(tech._x, tech._y, 100, 50);
    
    ctx.fillStyle = '#000';
-   ctx.fillText(tech.id, tech._x + 5, tech._y + 20);
+   // Trunca IDs longos
+   const displayId = tech.id.length > 12 ? tech.id.substring(0, 10) + '...' : tech.id;
+   ctx.font = '12px Arial';
+   ctx.fillText(displayId, tech._x + 5, tech._y + 20);
+   
+   // Adiciona o tier e o custo
+   ctx.font = '10px Arial';
+   ctx.fillText(`T${tech.tier} (${tech.cost})`, tech._x + 5, tech._y + 40);
  }
}

101-108: Adicionar feedback visual ao exportar

A função de exportação não fornece feedback visual ao usuário após a exportação, o que pode confundir os usuários sobre se a operação foi bem-sucedida.

function exportYML() {
  const yaml = jsyaml.dump(techs, { lineWidth: -1 });
  const blob = new Blob([yaml], { type: "text/yaml" });
  const link = document.createElement("a");
  link.href = URL.createObjectURL(blob);
  link.download = "combined_tech.yml";
  link.click();
+  
+  // Mostrar feedback ao usuário
+  const status = document.createElement("div");
+  status.textContent = "Arquivo exportado com sucesso!";
+  status.style.position = "fixed";
+  status.style.bottom = "20px";
+  status.style.right = "20px";
+  status.style.padding = "10px";
+  status.style.backgroundColor = "#4CAF50";
+  status.style.color = "white";
+  status.style.borderRadius = "5px";
+  document.body.appendChild(status);
+  
+  // Remover o feedback após alguns segundos
+  setTimeout(() => {
+    document.body.removeChild(status);
+  }, 3000);
}
Tools/TechTreeManager/UpdateAllYML/appUpdate.py (2)

24-25: Importação desnecessária em local incomum.

A importação do módulo io está posicionada no meio do código, quando deveria estar agrupada com as outras importações no início do arquivo.

-import io

E adicione esta linha no início do arquivo junto com as outras importações:

 import os
 import yaml
+import io

26-67: Lógica de atualização de arquivos bem implementada, mas poderia ser documentada.

A função update_file possui uma implementação cuidadosa para preservar a formatação YAML, mas a abordagem específica de serialização (escrevendo cada item individualmente e removendo os colchetes) poderia ser melhor documentada para facilitar a manutenção futura.

Considere adicionar um comentário explicativo mais detalhado sobre o motivo desta abordagem personalizada:

-            # Dump each item individually
+            # Serialização individual de cada item para manter formatação consistente
+            # e garantir que cada tecnologia fique em sua própria seção YAML.
+            # Esta abordagem preserva a estrutura dos arquivos originais.
Content.Client/_Goobstation/Research/UI/FancyResearchConsoleBoundUserInterface.cs (2)

20-25: Melhore o formato do comentário de migração.

O comentário que explica a migração de ResearchConsoleMenu para FancyResearchConsoleMenu é útil, mas está muito longo para uma linha de comentário inline.

-    private FancyResearchConsoleMenu? _consoleMenu;  // Goobstation R&D Console rework - ResearchConsoleMenu -> FancyResearchConsoleMenu
+    // Parte do Goobstation R&D Console rework - Substitui ResearchConsoleMenu
+    private FancyResearchConsoleMenu? _consoleMenu;

65-80: Otimização da atualização de estado pode ser melhorada.

A verificação para evitar atualizações desnecessárias é uma boa prática, mas a estrutura de código com múltiplos retornos e condicionais aninhados pode ser simplificada.

 protected override void UpdateState(BoundUserInterfaceState state)
 {
     base.UpdateState(state);

     if (state is not ResearchConsoleBoundInterfaceState castState)
         return;

     // Goobstation checks added
     // Thats for avoiding refresh spam when only points are updated
-    if (_consoleMenu == null)
-        return;
-    if (!_consoleMenu.List.SequenceEqual(castState.Researches))
-        _consoleMenu.UpdatePanels(castState.Researches);
-    if (_consoleMenu.Points != castState.Points)
-        _consoleMenu.UpdateInformationPanel(castState.Points);
+    if (_consoleMenu != null)
+    {
+        // Atualiza painéis apenas se a lista de pesquisas mudou
+        if (!_consoleMenu.List.SequenceEqual(castState.Researches))
+            _consoleMenu.UpdatePanels(castState.Researches);
+            
+        // Atualiza painel de informações apenas se os pontos mudaram
+        if (_consoleMenu.Points != castState.Points)
+            _consoleMenu.UpdateInformationPanel(castState.Points);
+    }
 }
Tools/TechTreeManager/app.py (2)

1-5: Remova importação não utilizada do módulo ttk.

O módulo ttk está sendo importado mas não é utilizado no código.

 import os
 import yaml
 import tkinter as tk
-from tkinter import ttk, messagebox
+from tkinter import messagebox
🧰 Tools
🪛 Ruff (0.8.2)

4-4: tkinter.ttk imported but unused

Remove unused import: tkinter.ttk

(F401)


69-75: Considere adicionar escala configurável para o grid.

A função display_grid usa um tamanho fixo de 100x100 para cada célula. Seria útil ter a possibilidade de ajustar este tamanho.

 def display_grid(self):
+    # Tamanho de cada célula
+    cell_size = 100
+    
     for (x, y), label in self.grid_data.items():
-        screen_x = x * 100
-        screen_y = y * 100
-        self.canvas.create_rectangle(screen_x, screen_y, screen_x + 100, screen_y + 100, fill="lightblue")
-        self.canvas.create_text(screen_x + 50, screen_y + 50, text=label, anchor="center")
+        screen_x = x * cell_size
+        screen_y = y * cell_size
+        self.canvas.create_rectangle(screen_x, screen_y, screen_x + cell_size, screen_y + cell_size, fill="lightblue")
+        self.canvas.create_text(screen_x + cell_size/2, screen_y + cell_size/2, text=label, anchor="center")
Tools/TechTreeManager/FetchAllResearchYML.py (1)

6-34: Considere refatorar a lógica de travessia de diretórios em um módulo compartilhado.

A função collect_ymls implementa uma lógica de travessia de diretórios similar à encontrada em outros scripts (app.py, appUpdate.py). Esta funcionalidade poderia ser extraída para um módulo comum para evitar duplicação.

Você poderia criar um módulo comum (common_utils.py) com uma função para encontrar arquivos alvo:

# Novo arquivo: common_utils.py
import os

def find_target_files(target_files, base_path=None):
    """
    Encontra arquivos alvo em diretórios Research.
    
    Args:
        target_files: Conjunto de nomes de arquivos a serem encontrados
        base_path: Caminho base opcional (padrão: path relativo ao Prototypes)
        
    Returns:
        Lista de tuplas (caminho_completo, nome_arquivo)
    """
    if base_path is None:
        base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 
                                               "..", "..", "Resources", "Prototypes"))
    
    result = []
    direct_research = os.path.join(base_path, "Research")
    
    # Check direct Research folder
    if os.path.isdir(direct_research):
        for file in os.listdir(direct_research):
            if file in target_files:
                result.append((os.path.join(direct_research, file), file))
    
    # Check each subfolder in Prototypes for Research
    for folder in os.listdir(base_path):
        full_path = os.path.join(base_path, folder, "Research")
        if os.path.isdir(full_path):
            for file in os.listdir(full_path):
                if file in target_files:
                    result.append((os.path.join(full_path, file), file))
    
    return result

E então usar no script atual:

 import os
 import yaml
+import common_utils
 
 TARGET_FILES = {"arsenal.yml", "civilianservices.yml", "experimental.yml", "industrial.yml"}
 
 def collect_ymls():
     result = {name: [] for name in TARGET_FILES}
-    start_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "Resources", "Prototypes"))
-    direct_research = os.path.join(start_path, "Research")
-
-    def process_dir(path):
-        for file in os.listdir(path):
-            if file in TARGET_FILES:
-                full_path = os.path.join(path, file)
-                try:
-                    with open(full_path, "r", encoding="utf-8") as f:
-                        data = yaml.safe_load(f)
-                        if isinstance(data, list):
-                            result[file].extend(data)
-                except Exception as e:
-                    print(f"Failed to read {full_path}: {e}")
-
-    # Check direct Research folder
-    if os.path.isdir(direct_research):
-        process_dir(direct_research)
-
-    # Check each subfolder in Prototypes for Research
-    for folder in os.listdir(start_path):
-        full_path = os.path.join(start_path, folder, "Research")
-        if os.path.isdir(full_path):
-            process_dir(full_path)
+    
+    target_files = common_utils.find_target_files(TARGET_FILES)
+    
+    for full_path, file_name in target_files:
+        try:
+            with open(full_path, "r", encoding="utf-8") as f:
+                data = yaml.safe_load(f)
+                if isinstance(data, list):
+                    result[file_name].extend(data)
+        except Exception as e:
+            print(f"Failed to read {full_path}: {e}")
 
     return result
Content.Client/_Goobstation/Research/UI/FancyResearchConsoleItem.xaml.cs (2)

24-26: Evite campos públicos: transforme-os em propriedades somente-leitura

Expor Prototype, SelectAction e Availability como campos públicos viola o encapsulamento e facilita modificações acidentais vindas de fora do controle. Prefira propriedades init-only ou get-only para tornar a API mais segura.


90-93: Chame base.DrawModeChanged() no override

Sem a chamada ao método base, a lógica interna de Button que depende dessa notificação pode falhar (por exemplo, alteração de estado visual padrão).

 protected override void DrawModeChanged()
 {
+    base.DrawModeChanged();
     OnDrawModeChanged?.Invoke();
 }
Tools/TechTreeManager/web/app.js (2)

68-81: Melhore performance criando um mapa de busca para pré-requisitos

Dentro do duplo for, cada find é O(n²). Para árvores grandes, o render travará. Monte um dicionário id → tech uma única vez:

 const idMap = Object.fromEntries(techs.map(t => [t.id, t]));
 ...
        const target = idMap[prereqId];

109-121: Throttle o draw() durante o arraste usando requestAnimationFrame

Chamar draw() a cada mousemove (que pode disparar >100 vezes/seg) é custoso. Armazene um flag e desenhe na próxima animação.

 let needsRedraw = false;
 ...
 canvas.addEventListener("mousemove", (e) => {
   if (!dragging) return;
   ...
-  draw();
+  needsRedraw = true;
 });
 
 function loop() {
   if (needsRedraw) {
     draw();
     needsRedraw = false;
   }
   requestAnimationFrame(loop);
 }
 loop();
Content.Client/_Goobstation/Research/UI/FancyResearchConsoleMenu.xaml.cs (2)

66-68: Erro de digitação em _draggin

O campo booleano possui typo; use _dragging para coerência com restante do código e melhor legibilidade.


170-176: Atualize posição única, não cada filho individualmente

Durante o arraste do “canvas”, cada child é movido e, depois, quando Recenter() ou outro redraw ocorrer, a posição relativa será recalculada novamente, causando deriva acumulada. Considere armazenar apenas _position global e recalcular posições de todos os filhos no draw/UpdatePanels, similar ao que foi feito na classe JS.

Tools/TechTreeManager/UpdateAllYML/updated.yml (1)

1-1120: Unificação de coordenadas: simplificar position, _x e _y
Cada entrada declara position (às vezes como string, às vezes numérico) e também _x/_y, o que pode gerar discrepâncias de manutenção.
Recomendo migrar para um único objeto de coordenadas, por exemplo:

position:
  x: 4
  y: 0

e remover os campos _x e _y redundantes.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f61eeb9 and 460a3aa.

⛔ Files ignored due to path filters (1)
  • Resources/Textures/_Goobstation/Interface/rnd-static.rsi/static.png is excluded by !**/*.png
📒 Files selected for processing (51)
  • Content.Client/Research/UI/MiniTechnologyCardControl.xaml (2 hunks)
  • Content.Client/_Goobstation/Research/UI/FancyResearchConsoleBoundUserInterface.cs (1 hunks)
  • Content.Client/_Goobstation/Research/UI/FancyResearchConsoleItem.xaml (1 hunks)
  • Content.Client/_Goobstation/Research/UI/FancyResearchConsoleItem.xaml.cs (1 hunks)
  • Content.Client/_Goobstation/Research/UI/FancyResearchConsoleMenu.xaml (1 hunks)
  • Content.Client/_Goobstation/Research/UI/FancyResearchConsoleMenu.xaml.cs (1 hunks)
  • Content.Client/_Goobstation/Research/UI/FancyTechnologyInfoPanel.xaml (1 hunks)
  • Content.Client/_Goobstation/Research/UI/FancyTechnologyInfoPanel.xaml.cs (1 hunks)
  • Content.Client/_Goobstation/Research/UI/MiniRecipeCardControl.xaml (1 hunks)
  • Content.Client/_Goobstation/Research/UI/MiniRecipeCardControl.xaml.cs (1 hunks)
  • Content.Client/_Goobstation/Research/UI/ResearchesContainerPanel.cs (1 hunks)
  • Content.Server/Research/Systems/ResearchSystem.Console.cs (2 hunks)
  • Content.Server/Research/Systems/ResearchSystem.Technology.cs (1 hunks)
  • Content.Shared/Research/Components/SharedResearchConsoleComponent.cs (2 hunks)
  • Content.Shared/Research/Prototypes/TechDisciplinePrototype.cs (2 hunks)
  • Content.Shared/Research/Prototypes/TechnologyPrototype.cs (2 hunks)
  • Content.Shared/Research/Systems/SharedResearchSystem.cs (5 hunks)
  • Content.Shared/_Goobstation/Research/ResearchAvailability.cs (1 hunks)
  • Content.Shared/_Goobstation/Research/SharedResearchSystem.Goob.cs (1 hunks)
  • Resources/Locale/en-US/_Goobstation/research/ui.ftl (1 hunks)
  • Resources/Locale/pt-BR/_Goobstation/research/ui.ftl (1 hunks)
  • Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml (1 hunks)
  • Resources/Prototypes/Nyanotrasen/Research/experimental.yml (2 hunks)
  • Resources/Prototypes/Research/arsenal.yml (13 hunks)
  • Resources/Prototypes/Research/civilianservices.yml (6 hunks)
  • Resources/Prototypes/Research/disciplines.yml (4 hunks)
  • Resources/Prototypes/Research/experimental.yml (11 hunks)
  • Resources/Prototypes/Research/industrial.yml (16 hunks)
  • Resources/Prototypes/_Arcadis/Entities/Objects/Computers/recipes.yml (1 hunks)
  • Resources/Prototypes/_EE/Research/civilianservices.yml (1 hunks)
  • Resources/Prototypes/_Goobstation/Research/arsenal.yml (3 hunks)
  • Resources/Prototypes/_Goobstation/Research/civilianservices.yml (1 hunks)
  • Resources/Prototypes/_Goobstation/Research/experimental.yml (1 hunks)
  • Resources/Prototypes/_Lavaland/Research/arsenal.yml (1 hunks)
  • Resources/Prototypes/_Shitmed/Research/civilianservices.yml (4 hunks)
  • Resources/Textures/_Goobstation/Interface/rnd-static.rsi/meta.json (1 hunks)
  • Tools/TechTreeManager/FetchAllResearchYML.py (1 hunks)
  • Tools/TechTreeManager/MasterArsenal.yml (1 hunks)
  • Tools/TechTreeManager/MasterCivilianservices.yml (1 hunks)
  • Tools/TechTreeManager/MasterExperimental.yml (1 hunks)
  • Tools/TechTreeManager/MasterIndustrial.yml (1 hunks)
  • Tools/TechTreeManager/UpdateAllYML/appUpdate.py (1 hunks)
  • Tools/TechTreeManager/UpdateAllYML/update_log.txt (1 hunks)
  • Tools/TechTreeManager/UpdateAllYML/updated.yml (1 hunks)
  • Tools/TechTreeManager/app.py (1 hunks)
  • Tools/TechTreeManager/web/all_view.html (1 hunks)
  • Tools/TechTreeManager/web/all_view.js (1 hunks)
  • Tools/TechTreeManager/web/app.js (1 hunks)
  • Tools/TechTreeManager/web/default.yml (1 hunks)
  • Tools/TechTreeManager/web/index.html (1 hunks)
  • Tools/TechTreeManager/web/style.css (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
Content.Shared/_Goobstation/Research/SharedResearchSystem.Goob.cs (1)
Content.Shared/Research/Systems/SharedResearchSystem.cs (1)
  • SharedResearchSystem (12-303)
Tools/TechTreeManager/FetchAllResearchYML.py (3)
Tools/TechTreeManager/web/app.js (1)
  • yaml (22-22)
Tools/TechTreeManager/web/all_view.js (1)
  • yaml (102-102)
Tools/TechTreeManager/UpdateAllYML/appUpdate.py (1)
  • process_dir (76-80)
Content.Shared/Research/Systems/SharedResearchSystem.cs (1)
Content.Shared/_Goobstation/Research/SharedResearchSystem.Goob.cs (1)
  • SharedResearchSystem (12-25)
Content.Client/_Goobstation/Research/UI/FancyResearchConsoleBoundUserInterface.cs (2)
Content.Client/_Goobstation/Research/UI/FancyResearchConsoleMenu.xaml.cs (4)
  • FancyResearchConsoleMenu (76-92)
  • SetEntity (94-95)
  • UpdatePanels (97-116)
  • UpdateInformationPanel (118-160)
Content.Shared/Research/Components/SharedResearchConsoleComponent.cs (2)
  • ConsoleUnlockTechnologyMessage (18-21)
  • ResearchConsoleBoundInterfaceState (39-43)
Tools/TechTreeManager/UpdateAllYML/appUpdate.py (3)
Tools/TechTreeManager/web/app.js (1)
  • yaml (22-22)
Tools/TechTreeManager/web/all_view.js (1)
  • yaml (102-102)
Tools/TechTreeManager/FetchAllResearchYML.py (1)
  • process_dir (11-21)
🪛 YAMLlint (1.35.1)
Resources/Prototypes/Research/disciplines.yml

[error] 12-12: trailing spaces

(trailing-spaces)


[error] 38-38: trailing spaces

(trailing-spaces)


[error] 51-51: trailing spaces

(trailing-spaces)

🪛 Ruff (0.8.2)
Tools/TechTreeManager/app.py

4-4: tkinter.ttk imported but unused

Remove unused import: tkinter.ttk

(F401)

🔇 Additional comments (101)
Resources/Prototypes/Research/disciplines.yml (1)

25-25: Campo uiName adicionado corretamente para Arsenal (SEC).
A sintaxe está correta e sem espaços extras. Esse ajuste alinha o protótipo à nova propriedade do TechDisciplinePrototype.

Content.Shared/Research/Systems/SharedResearchSystem.cs (9)

12-12: Classe transformada em parcial para suportar extensões

A declaração da classe foi modificada para partial, permitindo que a funcionalidade seja estendida em outros arquivos. Isso facilita a separação de responsabilidades e organização do código.


76-77: Verificação de restrição de tier comentada

A verificação de tier foi comentada como parte da reformulação do Console R&D do Goobstation. Isso remove as verificações de disciplina principal, potencialmente alterando a mecânica de jogo ao permitir que mais tecnologias estejam disponíveis independentemente do tier.

É importante verificar se esta alteração foi intencional e se ela não causará desequilíbrio na progressão do jogo. Confirme que outras partes do sistema levam em conta esta mudança de comportamento.


157-158: Substituição de AddMarkup por AddMarkupOrThrow

O método AddMarkup foi substituído por AddMarkupOrThrow, que lançará exceções quando ocorrerem erros de markup em vez de falhar silenciosamente.

Esta é uma mudança positiva que facilita a detecção de erros durante o desenvolvimento.


166-167: Substituição de AddMarkup por AddMarkupOrThrow

O método AddMarkup foi substituído por AddMarkupOrThrow para garantir que erros de markup não sejam ignorados.


172-173: Substituição de AddMarkup por AddMarkupOrThrow

O método AddMarkup foi substituído por AddMarkupOrThrow para garantir que erros de markup sejam detectados imediatamente.


177-179: Substituição de AddMarkup por AddMarkupOrThrow

Continuação da padronização do uso de AddMarkupOrThrow em vez de AddMarkup para melhorar a detecção de erros.


183-183: Substituição de AddMarkup por AddMarkupOrThrow

Mais uma substituição de AddMarkup por AddMarkupOrThrow para consistência e melhor tratamento de erros.


188-190: Substituição de AddMarkup por AddMarkupOrThrow

Substituição consistente de AddMarkup por AddMarkupOrThrow na listagem de receitas desbloqueadas.


194-196: Substituição de AddMarkup por AddMarkupOrThrow

Última substituição de AddMarkup por AddMarkupOrThrow para garantir consistência em todo o método GetTechnologyDescription.

Content.Server/Research/Systems/ResearchSystem.Technology.cs (1)

88-88:

Details

❓ Verification inconclusive

Confirmação necessária sobre a alteração do comportamento da disciplina principal.

A remoção da chamada para TrySetMainDiscipline modifica o comportamento do sistema quando uma nova tecnologia é desbloqueada. Isto parece ser parte da implementação da árvore tecnológica, mas é importante entender como as disciplinas principais são agora gerenciadas.

Algumas questões a considerar:

  • Como as disciplinas principais são agora determinadas sem esta chamada?
  • Esta mudança foi testada para garantir que não causa efeitos colaterais inesperados?
  • Seria útil adicionar um comentário mais detalhado explicando a razão desta alteração para futuros desenvolvedores.

🏁 Script executed:

#!/bin/bash
# Verificar como as disciplinas principais são gerenciadas em outros lugares do código
echo "Procurando por referências à MainDiscipline no código:"
rg "MainDiscipline" --type cs

Length of output: 1268


Confirmação necessária: Gestão de MainDiscipline após remoção de TrySetMainDiscipline

Antes de aprovar, precisamos entender como a disciplina principal está sendo definida sem aquela chamada:

  • Em Content.Shared/Research/Systems/SharedResearchSystem.cs
    • Método TrySetMainDiscipline ainda atribui component.MainDiscipline = prototype.Discipline.
  • Em Content.Server/Research/Systems/ResearchSystem.Technology.cs
    • A chamada a TrySetMainDiscipline(prototype, serverEnt.Value) foi comentada.
    • Há atribuição direta de component.MainDiscipline = null e cópia de otherDb.MainDiscipline.
  • Na UI (Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs) a label de disciplina principal depende desse valor.

Pontos a validar:

  • Qual fluxo substitui a lógica original de TrySetMainDiscipline no servidor?
  • Há testes que garantam que a disciplina principal seja atualizada corretamente ao desbloquear novas tecnologias?
  • Sugiro adicionar um comentário resumindo a razão dessa alteração e documentar o novo comportamento para futuros mantenedores.
Resources/Prototypes/_Lavaland/Research/arsenal.yml (1)

14-14: Adição de posicionamento na árvore tecnológica.

A adição do atributo position: 5,1 está alinhada com a reestruturação da árvore tecnológica, permitindo um posicionamento preciso desta tecnologia na nova interface do console de pesquisa.

Content.Shared/Research/Prototypes/TechDisciplinePrototype.cs (1)

49-54: Campo UiName adicionado corretamente para suportar a nova UI.

A adição do campo UiName para exibir nomes curtos nos botões de disciplina está bem documentada e implementada corretamente com o atributo required: true, garantindo que todas as disciplinas forneçam este valor.

Resources/Prototypes/_EE/Research/civilianservices.yml (1)

12-12: Posicionamento adicionado para visualização na árvore tecnológica.

A adição do atributo position: -1,-4 está correta e consistente com as mudanças em outros arquivos de protótipos de pesquisa, permitindo o posicionamento espacial desta tecnologia na nova interface.

Content.Shared/Research/Prototypes/TechnologyPrototype.cs (2)

76-81: Propriedade Position adicionada corretamente para o sistema de árvore tecnológica.

A implementação da propriedade Position com um setter privado é uma boa prática para garantir imutabilidade após a inicialização. A documentação XML está clara e a marcação como campo obrigatório (required: true) garante que todas as tecnologias terão uma posição definida na interface.


1-82:

Details

✅ Verification successful

Verificar possíveis tecnologias sem posição definida

Como a propriedade Position agora é obrigatória, é importante garantir que todos os protótipos de tecnologia existentes no projeto tenham esta propriedade definida, caso contrário, poderá haver erros durante a inicialização do jogo.


🏁 Script executed:

#!/bin/bash
# Verificar protótipos de tecnologia sem a propriedade "position" definida
echo "Procurando por protótipos de tecnologia sem posição definida..."
rg -l "- type: technology" Resources/Prototypes/ | xargs rg -l "id: " | xargs grep -L "position: " | sort

Length of output: 66185


🏁 Script executed:

#!/bin/bash
# Verificar protótipos de tecnologia sem 'position' definido
echo "Procurando arquivos YAML de protótipos de tecnologia sem 'position:'..."
rg -l "^\s*-\s*type:\s*technology" Resources/Prototypes/ --glob '*.yml' | xargs grep -L "^\s*position:" | sort

Length of output: 271


Verificação concluída: todas as tecnologias têm Position definido

Não foram encontrados protótipos type: technology sem a propriedade position: nos arquivos YAML em Resources/Prototypes. Não há ajustes adicionais necessários.

Resources/Prototypes/_Goobstation/Research/arsenal.yml (3)

24-24: Coordenadas de posição adicionadas corretamente!

A adição de coordenadas de posição para a tecnologia Gygax parece apropriada para a visualização da árvore tecnológica na nova interface do console de pesquisa.


39-39: Posicionamento consistente para ExplosiveMechAmmunition

A posição 5,3 parece bem alinhada com o layout geral da árvore de tecnologia, permitindo uma visualização adequada dos relacionamentos com outras tecnologias.


64-65: Coordenadas e pré-requisitos bem definidos para Durand

A posição 4,3 para Durand, combinada com seu pré-requisito (Gygax em 4,4), cria uma relação visual lógica na árvore de tecnologias, onde Durand aparece acima de seu pré-requisito Gygax.

Content.Shared/_Goobstation/Research/ResearchAvailability.cs (1)

14-21: Enumeração bem definida para estados de disponibilidade de pesquisa

A enumeração ResearchAvailability está bem estruturada com quatro estados claramente definidos que representam os diferentes níveis de disponibilidade de uma tecnologia (Pesquisada, Disponível, Pré-requisitos Atendidos e Indisponível). A definição como serializável e serializável para rede permitirá uma comunicação eficiente entre cliente e servidor.

Resources/Textures/_Goobstation/Interface/rnd-static.rsi/meta.json (3)

5-8: Dimensões da textura parecem apropriadas

As dimensões de 1284x724 pixels são adequadas para uma textura de interface de usuário de console de pesquisa.


9-20: Configuração de animação adequada

A configuração da animação "static" com quatro frames e delay uniforme de 0.05 segundos parece apropriada para um efeito visual de estática.


3-4:

Details

❓ Verification inconclusive

Verificar a fonte original da textura

A atribuição de direitos autorais menciona que a textura foi obtida do Pinterest, que é um agregador de conteúdo e não uma fonte original. Seria mais adequado identificar e creditar o criador original da textura para garantir compliance com a licença CC-BY-SA-3.0.


🌐 Web query:

Qual a fonte original da imagem com PIN https://www.pinterest.com/pin/681450987343974739/?

💡 Result:

Para identificar a fonte original de uma imagem no Pinterest, é importante seguir alguns passos, pois muitas vezes as imagens são compartilhadas sem créditos ou podem ter sido retiradas de suas fontes originais. Vamos analisar a imagem referenciada pelo PIN 681450987343974739:

1. Verificação do Pinterest

  • O link leva a uma página do Pinterest, onde normalmente estão disponíveis informações como:
    • Quem salvou o PIN
    • Descrição da imagem
    • Fonte (o site de onde a imagem pode ter sido originalmente pinada)

2. Análise da Fonte Apresentada

No caso desse PIN específico, navegando até a página, observa-se:

  • Muitas vezes, a imagem pode não ter um link claro para a fonte original, principalmente se foi carregada diretamente por um usuário.
  • Se houver um link "visit", "ir para o site", ou "salvo de...", clique nele para ver se redireciona para a fonte.
  • Se a imagem foi apenas "Enviada por usuário", provavelmente não há fonte original listada.

3. Pesquisa Reversa de Imagem

Se o Pinterest não indicar a fonte:

  • Faça o download da imagem (se permitido).
  • Use ferramentas de busca reversa de imagem (como Google Imagens, TinEye) para tentar localizar outros sites que publicaram a mesma imagem.
  • Muitas vezes, a fonte original pode ser um site de fotografia, um blog, uma loja virtual, ou um perfil em rede social.

4. Resultado de Consulta Direta (Resumo)

Ao acessar o PIN 681450987343974739:

  • Não há indicação direta de fonte original na página Pinterest.
  • O PIN foi salvo por um usuário e não há link para um site externo de onde a imagem foi retirada.
  • Provavelmente a imagem foi enviada diretamente ao Pinterest (upload feito pelo usuário).

Como Encontrar a Fonte Original

  1. Clique em “Salvo de” (caso disponível): Isso pode levar ao site original.
  2. Faça uma busca reversa da imagem: Baixe a imagem e use Google Imagens ou TinEye para encontrar possíveis fontes originais.
  3. Procure marca d’água ou texto na imagem: Às vezes, indica o autor ou o site de origem.

Resumo Final

A fonte original da imagem do PIN 681450987343974739 não está indicada na página do Pinterest. Para identificar a origem, recomenda-se usar busca reversa de imagem. Se precisar de ajuda com a busca reversa, me envie uma descrição da imagem ou, se possível, um link direto para a imagem em alta resolução — assim posso instruí-lo sobre como realizar esse procedimento.


Verificar fonte original da textura

A atribuição em Resources/Textures/_Goobstation/Interface/rnd-static.rsi/meta.json atualmente aponta apenas para o Pinterest, que é um agregador e não garante identificação do autor original. Para cumprir a licença CC-BY-SA-3.0, é necessário:

  • Realizar busca reversa de imagem (Google Imagens, TinEye) com o arquivo de textura.
  • Se encontrar o site ou perfil do criador, atualizar o campo "copyright" com o nome do autor e a URL original.
  • Se não for possível localizar a fonte, documentar no repositório o método de pesquisa e o resultado obtido.
Content.Client/_Goobstation/Research/UI/FancyResearchConsoleMenu.xaml (3)

1-6: Verificação de cabeçalho e licença
O cabeçalho SPDX está consistente e segue a mesma licença do projeto.


15-32: Layout do painel de topo está claro
A disposição vertical/horizontal e o uso de um placeholder (<Control VerticalExpand="True"/>) estão corretos e garantem que o rótulo e o display de níveis se ajustem corretamente.


45-57: Configuração do container de pesquisas
O uso de AnimatedTextureRect contendo o ResearchesContainerPanel com RectClipContent="True" e MouseFilter="Pass" está correto para suportar arraste e zoom.

Resources/Prototypes/Research/civilianservices.yml (6)

31-34: Adição de posição e pré-requisito em BasicCybernetics
Excelente inclusão de position: -1,-2 e technologyPrerequisites: [BasicElectronics]. Isso alinha o protótipo ao novo layout.


60-61: Adição de posição em BasicElectronics
Bom trabalho definindo position: 0,-2 para o nó inicial de eletrônica.


85-88: Adição de posição e pré-requisito em BasicLifeImprovements
position: -2,-3 e dependência de BasicCybernetics estão corretos para a sequência de pesquisa.


108-109: Adição de posição em HONKMech
position: -4,-5 posiciona corretamente o nó HONKMech, favor confirmar sem pré-requisitos intencionais.


124-126: Adição de posição em AdvancedLifeImprovements
position: 0,-5 e softCapContribution configurada adequadamente.


148-150: Adição de posição e pré-requisito em AdvancedTranslation
position: -2,-5 e dependência CyberneticEnhancements satisfazem a lógica de progressão.

Tools/TechTreeManager/MasterExperimental.yml (1)

176-187: Pré-requisito cross-discipline em ModsuitsTech
ModsuitsTech requer AdvancedTacsuits (Arsenal). Confirme se dependências entre disciplinas são suportadas e se o ID está correto.

Resources/Prototypes/Research/industrial.yml (16)

15-18: Verificar desbloqueio e posição de SalvageEquipment.
Foi adicionado o recipeUnlock MechEquipmentDrill e a posição -1,0. Confirme se o ID do recipe está correto e se esta coordenada não conflita com outros nós do UI.


34-35: Confirmar posição de AdvancedPowercells.
A coordenada -2,3 foi atribuída para este nó. Verifique se ela está de acordo com o layout pretendido e não gera sobreposição.


47-47: Validar posição de MechanicalCompression.
A posição -3,2 foi adicionada; assegure-se de que está alinhada no grid do UI.


63-63: Validar posição de IndustrialEngineering.
Coordenada -1,1 inserida; confirme consistência com o restante da disciplina.


78-82: Verificar nova receita e posição em PowerGeneration.
Foi incluído PowerComputerCircuitboard e a posição -4,3. Certifique-se de que o recipe existe e a posição não causa conflito visual.


97-97: Confirmar posição de AtmosphericTech.
Coordenada -3,3 adicionada; valide sua localização no layout.


117-117: Confirmar posição de RipleyAPLU.
Posição 2,3 definida; verifique alinhamento com outros nós de mecha.


132-132: Validar posição de SpaceScanning.
Coordenada -2,1 adicionada; certifique-se de que corresponde ao design da árvore.


148-148: Validar posição de Shuttlecraft.
Posição -4,2 inserida; confira se mantém o espaçamento adequado entre níveis.


163-163: Confirmar posição de AdvancedAtmospherics.
Coordenada -2,2 adicionada; valide sua colocação em relação aos demais nós.


175-183: Verificar receitas e pré-requisito em AdvancedToolsTechnology.
Foram adicionados vários recipeUnlocks (WelderExperimental, PowerDrill, JawsOfLife, BorgModuleAdvancedTool, BorgModuleRCD), além da posição -1,2 e do pré-requisito IndustrialEngineering. Garanta que todos os recipes existem e que a dependência está corretamente declarada.


197-197: Validar posição de MassExcavation.
Coordenada -3,0 adicionada; confirme que está no local correto da árvore de tecnologia.


213-213: Confirmar posição de Ripley2.
Posição 2,4 definida; verifique o alinhamento em relação a RipleyAPLU.


236-236: Validar posição de Clarke.
Coordenada 0,4 inserida; assegure que está consistente com seu pré-requisito Ripley2.


253-255: Verificar posição e pré-requisito em BluespaceStorage.
Adicionadas posição -3,4 e dependência PortableFission. Confirme que o softCapContribution permanece correto e que o prereq existe.


271-271: Validar posição de PortableFission.
Coordenada -2,4 adicionada; confirme que reflete o posicionamento desejado e não causa conflito.

Resources/Prototypes/Research/arsenal.yml (10)

14-14: Verificar receitas e posição de BasicWeapons.
Confira se WeaponMechCombatFiredartLaser, WeaponMechCombatDisabler e MechEquipmentKineticAccelerator estão corretos e existem. Confirme também a posição 4,0 no grid do UI.

Also applies to: 23-24, 26-26


56-59: Validar posição e pré-requisito de DraconicMunitions.
Posição 4,-1 e dependência BasicWeapons adicionadas; garanta que ambos estão corretos e que o relacionamento reflete o fluxo de pesquisa.


77-77: Verificar desbloqueio, posição e pré-requisito de UraniumMunitions.
Foi adicionado SpeedLoaderRifleHeavyUranium, posição 6,0 e dependência BasicWeapons. Confirme existência do recipe e consistência do prereq.

Also applies to: 87-90


104-107: Validar posição e pré-requisito de AdvancedTacsuits.
Posição 6,1 e dependência UraniumMunitions inseridas; assegure que a ligação está correta para o tier seguinte.


125-128: Verificar ExplosiveTechnology: posição e pré-requisito.
Coordenada 5,2 e dependência AdvancedTacsuits adicionadas; confirme alinhamento no layout e exatidão do prereq.


151-153: Validar ShrapnelMunitions: posição e pré-requisito.
Posição 6,2 e dependência AdvancedTacsuits inseridas; verifique consistência com o tier e fluxo de pesquisa.


177-187: Verificar AdvancedWeapons: desbloqueio, posição e pré-requisito.
Recipe WeaponMechCombatSolarisLaser adicionado, posição 4,1 e dependência BasicWeapons. Confirme validade do recipe e diagrama de pesquisa.


205-206: Validar posição de PrototypeTacsuits.
Coordenada 7,2 adicionada; confirme se reflete o design esperado para tier 3.


224-224: Confirmar posição de LaserTurrets.
Posição 4,2 adicionada; verifique o layout de conexão com AdvancedWeapons.


241-241: Verificar PrototypeWeapons: desbloqueio e posição.
Recipe WeaponMechCombatImmolationGun adicionado e posição 7,3; assegure que o recipe exista e o nó esteja corretamente posicionado.

Also applies to: 247-248

Resources/Prototypes/_Goobstation/Research/civilianservices.yml (1)

13-13: Validar posição de HONKWeapons.
Coordenada 0,-4 atribuída; confirme que reflete o layout esperado e não entra em conflito com outras tecnologias.

Content.Client/Research/UI/MiniTechnologyCardControl.xaml (1)

22-22: Ajuste de escala de textura em MiniTechnologyCardControl.
A propriedade TextureScale foi alterada de 0.5 0.5 para 1 1. Verifique se essa mudança mantém a consistência visual em diferentes resoluções e não causa estouro de layout.

Resources/Prototypes/_Arcadis/Entities/Objects/Computers/recipes.yml (1)

13-13: Validar posição de ModularComputing.
Foi adicionada a coordenada -2,0; confirme que corresponde à exibição prevista no UI e não conflita com outros elementos do menu de pesquisa.

Resources/Prototypes/_Goobstation/Research/experimental.yml (1)

20-20: Verificar formato e unicidade da posição de ModsuitsTech
A adição de position: 7,1 define onde o ícone aparecerá na árvore de pesquisa, mas é importante garantir que:

  1. O parser YAML do jogo reconheça esse formato (string “7,1”) corretamente.
  2. Não existam outras tecnologias usando as mesmas coordenadas, evitando sobreposição na UI.
Tools/TechTreeManager/web/style.css (3)

6-10: Estilo do canvas aprovado
Uma borda leve, margem e fundo suave tornam o canvas visível e arejado.


23-25: Largura dos inputs no editor OK
#editor input { width: 100%; } garante campos responsivos.


26-28: Labels como bloco estão adequados
label { display: block; } facilita alinhamento vertical dos rótulos.

Resources/Prototypes/Nyanotrasen/Research/experimental.yml (2)

5-5: Validar caminho do sprite de PsionicCountermeasures
Foi alterado para Nyanotrasen/Clothing/Head/Helmets/insulative_skullcap.rsi.
Confirme se o arquivo existe com esse caminho e nome (sensível a maiúsculas/minúsculas) no diretório de sprites.


16-16: Verificar formato e colisão de posição
A entrada position: -3,1 define um local negativo na UI, o que é intencional, mas confirme que:

  • O parser YAML aceita valores negativos nesse formato (string).
  • Não haja outra tecnologia ocupando as mesmas coordenadas.
Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml (1)

600-602: Confirmar integração do novo BoundUserInterface
A interface foi trocada para FancyResearchConsoleBoundUserInterface. Verifique se:

  1. A enum ResearchConsoleUiKey.Key continua apontando corretamente para essa classe.
  2. O cliente já carrega/registrou FancyResearchConsoleBoundUserInterface.
  3. Não restam referências à UI antiga (ResearchConsoleBoundUserInterface) em outros protótipos.
Content.Server/Research/Systems/ResearchSystem.Console.cs (1)

73-108: Possível NRE se TechnologyPrerequisites for null
O acesso proto.TechnologyPrerequisites.All(...) assume que a lista existe. Embora os protótipos atuais preencham o campo, uma omissão futura quebrará o método. Proteja com ?. ou assegure lista vazia no protótipo por default.

Content.Client/_Goobstation/Research/UI/FancyTechnologyInfoPanel.xaml (1)

1-114: Bom trabalho na estruturação da interface da árvore tecnológica!

O layout XAML está bem organizado com uma hierarquia clara de contêineres e controles. Aprecio especialmente:

  • A separação lógica entre as seções de informação, pré-requisitos e receitas desbloqueadas
  • O uso adequado de ScrollContainer para listas potencialmente longas
  • A implementação correta de localização para textos da interface
  • A estrutura responsiva que se expande conforme necessário

Como sugestão para melhorar ainda mais a acessibilidade e usabilidade:

  • Considere adicionar ToolTips para o botão de pesquisa e ícones de tecnologia
  • Talvez incluir um indicador visual de progresso para tecnologias parcialmente pesquisadas
Content.Client/_Goobstation/Research/UI/MiniRecipeCardControl.xaml.cs (1)

1-43: Implementação limpa e bem estruturada do controle de cartão de receita!

O código está bem organizado e segue boas práticas:

  • Verificações apropriadas para valores nulos usando HasValue
  • Boa integração com os sistemas de sprites e localização
  • Implementação elegante de tooltips para descrições de receitas

Uma pequena sugestão para considerar:

  • Poderia ser útil adicionar um método para atualizar dinamicamente a receita exibida, caso precise reutilizar o mesmo controle para diferentes receitas sem criar uma nova instância.
Content.Shared/Research/Components/SharedResearchConsoleComponent.cs (1)

33-43: Boa melhoria na estrutura de dados para disponibilidade de pesquisas!

A substituição do SoftCapMultiplier por um dicionário completo de pesquisas e seus estados de disponibilidade é uma mudança significativa que oferece muito mais flexibilidade e clareza ao sistema.

Esta alteração permite:

  • Representação explícita do estado de cada tecnologia
  • Melhor sincronização entre cliente e servidor
  • Interface mais informativa com estados visuais diferenciados
Content.Client/_Goobstation/Research/UI/FancyTechnologyInfoPanel.xaml.cs (1)

97-102: Boa prática de limpeza em ExitedTree

Excelente implementação do método ExitedTree para remover o handler de evento ao sair da árvore UI. Isso evita vazamentos de memória e comportamentos inesperados que poderiam ocorrer se o controle fosse reutilizado.

Resources/Prototypes/Research/experimental.yml (2)

111-112: Excelente adição de pré-requisitos tecnológicos

A adição de pré-requisitos tecnológicos explícitos é uma melhoria significativa. Isso cria uma árvore tecnológica coerente e permite visualização adequada das dependências. Os pré-requisitos fazem sentido do ponto de vista de progressão:

  • NightVisionTech e ThermalVisionTech dependem de AdvancedParts
  • SuperParts depende de AdvancedParts
  • GravityManipulation e QuantumLeaping dependem de SuperParts

Essa estrutura cria uma progressão lógica e equilibrada no sistema de pesquisa.

Also applies to: 126-127, 144-145, 161-162, 177-178


16-16: Posições consistentes na árvore tecnológica

A adição de coordenadas de posição para cada tecnologia é essencial para visualização em uma interface gráfica de árvore tecnológica. As posições parecem ter sido cuidadosamente escolhidas para criar um layout visualmente lógico:

  • Tier 1: posições y entre -2 e -3
  • Tier 2: posições y entre -3 e -4
  • Tier 3: posição y em -5

Isso cria uma progressão visual de cima para baixo que se alinha com o aumento dos níveis de tier.

Also applies to: 33-33, 46-46, 62-62, 80-80, 94-94, 110-110, 125-125, 143-143, 160-160, 176-176

Tools/TechTreeManager/MasterIndustrial.yml (2)

197-199: Relações de pré-requisitos tecnológicos bem construídas

As relações de pré-requisitos definidas para as tecnologias industriais são lógicas e coerentes:

  • Ripley2 requer RipleyAPLU como pré-requisito
  • Clarke requer Ripley2 como pré-requisito
  • PortableFission requer AdvancedPowercells como pré-requisito

Essas relações criam um caminho de progressão lógico e coerente para o jogador seguir.

Also applies to: 219-221, 249-251


10-17: Desbloqueios de receitas bem distribuídos entre as tecnologias

Os desbloqueios de receitas são bem distribuídos entre as várias tecnologias, oferecendo recompensas relevantes para cada avanço tecnológico. As tecnologias desbloquem itens que fazem sentido temático com seus nomes e áreas, como equipamentos de salvamento, células de energia avançadas, atmosféricos, etc.

Also applies to: 29-32, 43-44, 55-60, 70-77, 88-92, 102-110, 121-124, 135-139, 150-153, 164-169, 181-183, 194-196, 210-218, 231-235, 247-248

Tools/TechTreeManager/UpdateAllYML/appUpdate.py (5)

4-5: Conjunto de arquivos a serem atualizados bem definido.

O TARGET_FILES define claramente quais arquivos de pesquisa serão processados pelo script.


7-21: Boa implementação da função de carregamento de itens.

A função carrega corretamente os itens do arquivo YAML e remove as chaves de posição (_x, _y) antes de criar um dicionário baseado nos IDs. O tratamento de erros está bem implementado.


72-89: Boa implementação da travessia de diretórios.

A função update_all_files encontra corretamente os arquivos alvo em ambos os diretórios de Research (direto e aninhado). A lógica é clara e consistente com outros scripts do projeto.


90-102: Registro de alterações implementado adequadamente.

A função write_log cria um arquivo de log claro e informativo, com tratamento adequado de erros.


104-114: Interface de usuário em linha de comando simples e funcional.

O bloco principal de execução solicita a entrada do usuário, valida o caminho do arquivo e processa as atualizações de forma clara e com mensagens informativas.

Content.Client/_Goobstation/Research/UI/FancyResearchConsoleBoundUserInterface.cs (5)

1-9: Cabeçalhos de copyright e licença adequados.

Os cabeçalhos de copyright e licença seguem o padrão do projeto.


10-18: Importações organizadas corretamente.

As importações estão organizadas de forma lógica, agrupando importações do sistema, do projeto compartilhado e do framework.


26-29: Construtor implementado corretamente.

O construtor passa corretamente os parâmetros para a classe base.


30-49: Método Open implementado corretamente com bons gerenciadores de eventos.

O método Open cria a janela da interface, define a entidade associada e configura os gerenciadores de eventos corretamente para enviar mensagens ao servidor quando o usuário interage com a interface.


51-63: Tratamento adequado de recarregamento de protótipos.

O método OnProtoReload verifica corretamente se os protótipos de tecnologia foram modificados e atualiza a interface quando necessário.

Tools/TechTreeManager/app.py (4)

6-7: Conjunto de arquivos alvo bem definido e consistente com outros scripts.

O TARGET_FILES define os mesmos arquivos alvo que são utilizados nos outros scripts do TechTreeManager.


8-27: Boa estrutura inicial da classe TechBrowser.

A interface do visualizador é bem configurada com canvas, barras de rolagem e lista de tecnologias. A estrutura é clara e funcional.


46-68: Boa implementação da análise de arquivos YAML.

A função parse_file carrega corretamente os arquivos YAML, extrai os dados relevantes e tem um tratamento de erros adequado. A conversão de posição para coordenadas é tratada de forma robusta.


77-82: Configuração da janela principal implementada corretamente.

O código principal configura adequadamente a janela, define pesos para linhas e colunas, e inicia o loop principal do Tkinter.

Tools/TechTreeManager/FetchAllResearchYML.py (3)

1-4: Importações e constantes bem definidas.

As importações são mínimas e adequadas, e o TARGET_FILES é consistente com os outros scripts.


35-48: Boa implementação da função de salvar arquivos master.

A função save_master_files é bem implementada, com capitalização apropriada do nome do arquivo, formatação consistente e bom tratamento de erros.


49-51: Bloco principal simples e eficaz.

O bloco principal executa as funções na ordem correta para coletar e salvar os dados.

Content.Client/_Goobstation/Research/UI/FancyResearchConsoleItem.xaml.cs (1)

37-58: Atualize a atribuição de cores após renomear os campos

Após o ajuste sugerido acima, troque a tupla para usar BaseColor e BaseBorderColor:

-        (Color, HoveredColor, BorderColor) = availability switch
+        (BaseColor, HoveredColor, BaseBorderColor) = availability switch

Sem esta correção, o código continuará referenciando os nomes antigos.

Tools/TechTreeManager/UpdateAllYML/updated.yml (5)

1-343: Bloco Arsenal: definições e custos coerentes
As tecnologias sob a disciplina Arsenal (linhas 1–343) apresentam estrutura consistente de tiers, cost e recipeUnlocks.
IDs, nomes e ícones estão formatados de forma uniforme e sem erros aparentes.


344-568: Bloco CivilianServices: aprovação geral
As entradas de CivilianServices (linhas 344–568) mantêm a lógica de tiers e pré-requisitos correta.
Nenhuma inconsistência encontrada nas recipeUnlocks ou custo.


603-831: Bloco Experimental: conferência de tiers e softCapContribution
As tecnologias de Experimental (linhas 603–831) corretamente aplicam softCapContribution em tiers avançados.
Verifique se os valores (1.2 vs 1.5) estão alinhados com o balanceamento desejado.


833-1118: Bloco Industrial: consistência verificada
As entradas de Industrial (linhas 833–1118) seguem o mesmo padrão de estrutura, tiers e dependências.
Sem problemas de formatação ou lógica detectados.


1-1120:

Details

✅ Verification successful

Revisão geral: consistência de IDs e dependências de pesquisa
O arquivo define mais de 100 tecnologias agrupadas por disciplina (Arsenal, CivilianServices, Experimental, Industrial).
Sugiro validar que todos os valores em technologyPrerequisites correspondam a id existentes e que a cadeia de pré-requisitos reflita a progressão desejada (sem lacunas ou ciclos).

Execute este script para verificar referências inválidas:


🏁 Script executed:

#!/bin/bash
pip install pyyaml
python3 - << 'EOF'
import yaml
data = yaml.safe_load(open("Tools/TechTreeManager/UpdateAllYML/updated.yml"))
ids = {t["id"] for t in data}
errors = False
for t in data:
    for prereq in t.get("technologyPrerequisites", []):
        if prereq not in ids:
            print(f"❌ Dependência inválida: '{prereq}' (usado em '{t['id']}')")
            errors = True
if not errors:
    print("✅ Todas as dependências referenciam IDs válidos.")
EOF

Length of output: 248


Verificação de dependências concluída com sucesso
✅ Todas as entradas em technologyPrerequisites referenciam IDs existentes no arquivo.
Não foram encontradas dependências inválidas ou ausentes.

Comment on lines +14 to +24
public int GetTierCompletionPercentage(TechnologyDatabaseComponent component, TechDisciplinePrototype techDiscipline)
{
var allTech = PrototypeManager.EnumeratePrototypes<TechnologyPrototype>()
.Where(p => p.Discipline == techDiscipline.ID && !p.Hidden).ToList();

var percentage = (float) component.UnlockedTechnologies
.Where(x => PrototypeManager.Index<TechnologyPrototype>(x).Discipline == techDiscipline.ID)
.Count() / (float) allTech.Count * 100f;

return (int) Math.Clamp(percentage, 0, 100);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implementar verificação de divisão por zero

O método GetTierCompletionPercentage calcula corretamente a porcentagem de tecnologias desbloqueadas, mas não contém proteção contra divisão por zero caso não existam tecnologias na disciplina especificada (quando allTech.Count for 0).

-        var percentage = (float) component.UnlockedTechnologies
-            .Where(x => PrototypeManager.Index<TechnologyPrototype>(x).Discipline == techDiscipline.ID)
-            .Count() / (float) allTech.Count * 100f;
-
-        return (int) Math.Clamp(percentage, 0, 100);
+        if (allTech.Count == 0)
+            return 0;
+
+        var percentage = (float) component.UnlockedTechnologies
+            .Where(x => PrototypeManager.Index<TechnologyPrototype>(x).Discipline == techDiscipline.ID)
+            .Count() / (float) allTech.Count * 100f;
+
+        return (int) Math.Clamp(percentage, 0, 100);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public int GetTierCompletionPercentage(TechnologyDatabaseComponent component, TechDisciplinePrototype techDiscipline)
{
var allTech = PrototypeManager.EnumeratePrototypes<TechnologyPrototype>()
.Where(p => p.Discipline == techDiscipline.ID && !p.Hidden).ToList();
var percentage = (float) component.UnlockedTechnologies
.Where(x => PrototypeManager.Index<TechnologyPrototype>(x).Discipline == techDiscipline.ID)
.Count() / (float) allTech.Count * 100f;
return (int) Math.Clamp(percentage, 0, 100);
}
public int GetTierCompletionPercentage(TechnologyDatabaseComponent component, TechDisciplinePrototype techDiscipline)
{
var allTech = PrototypeManager.EnumeratePrototypes<TechnologyPrototype>()
.Where(p => p.Discipline == techDiscipline.ID && !p.Hidden).ToList();
if (allTech.Count == 0)
return 0;
var percentage = (float) component.UnlockedTechnologies
.Where(x => PrototypeManager.Index<TechnologyPrototype>(x).Discipline == techDiscipline.ID)
.Count() / (float) allTech.Count * 100f;
return (int) Math.Clamp(percentage, 0, 100);
}

Comment on lines +196 to +199
- AdvancedTacsuits
softCapContribution: 1.5
position: 6,2
- type: technology
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Posição duplicada em PrototypeTacsuits
PrototypeTacsuits está em position: 6,2, mesma coordenada de PrototypeWeapons. Ajuste para evitar colisão visual.

Comment on lines +119 to +126
- ExplosivePayload
- ChemicalPayload
position: 4,2
technologyPrerequisites:
- AdvancedTacsuits
- type: technology
id: ShrapnelMunitions
name: research-technology-shrapnel-munitions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Posição duplicada em ShrapnelMunitions
Tanto ExplosiveTechnology (posição 4,2) quanto ShrapnelMunitions usam position: 4,2, o que causará sobreposição de nós na UI. Favor atribuir coordenadas únicas.

Comment on lines +235 to +239
- EnergyCutlass
- WeaponSubMachineGunBRDIR25
softCapContribution: 1.5
position: 6,2
- type: technology
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Posição duplicada em PrototypeWeapons
PrototypeWeapons também usa position: 6,2. Precisa de um novo par de coordenadas.

Comment on lines +240 to +263
id: Gygax
name: research-technology-gygax
icon:
sprite: Objects/Specific/Mech/mecha.rsi
state: gygax
discipline: Arsenal
tier: 2
cost: 12000
recipeUnlocks:
- GygaxHarness
- GygaxArmor
- GygaxHead
- GygaxLArm
- GygaxLLeg
- GygaxRArm
- GygaxRLeg
- GygaxCentralElectronics
- GygaxPeripheralsElectronics
- GygaxTargetingElectronics
- WeaponMechCombatUltraRifle
technologyPrerequisites:
- Ripley2
position: 3,0
- type: technology
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Dependência inválida: Ripley2 não existe no arsenal
O Gygax lista technologyPrerequisites: [Ripley2], mas não há protótipo Ripley2 neste arquivo. Verifique se o ID está correto ou se faltou definir esse protótipo.

Comment on lines +28 to +45
def load_data(self):
start_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "Resources", "Prototypes"))
direct_research = os.path.join(start_path, "Research")

if os.path.isdir(direct_research):
for file in os.listdir(direct_research):
if file in TARGET_FILES:
self.parse_file(os.path.join(direct_research, file))

for folder in os.listdir(start_path):
full_path = os.path.join(start_path, folder, "Research")
if os.path.isdir(full_path):
for file in os.listdir(full_path):
if file in TARGET_FILES:
self.parse_file(os.path.join(full_path, file))

self.display_grid()

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Adicione tratamento de erros ao listar diretórios.

A função load_data lida com diretórios sem nenhum tratamento de erro para operações como os.listdir(), o que pode falhar se os diretórios não existirem ou não forem acessíveis.

 def load_data(self):
     start_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "Resources", "Prototypes"))
     direct_research = os.path.join(start_path, "Research")
     
     if os.path.isdir(direct_research):
-        for file in os.listdir(direct_research):
-                if file in TARGET_FILES:
-                    self.parse_file(os.path.join(direct_research, file))
+        try:
+            for file in os.listdir(direct_research):
+                if file in TARGET_FILES:
+                    self.parse_file(os.path.join(direct_research, file))
+        except Exception as e:
+            messagebox.showerror("Erro", f"Falha ao listar diretório {direct_research}:\n{str(e)}")

-    for folder in os.listdir(start_path):
-        full_path = os.path.join(start_path, folder, "Research")
-        if os.path.isdir(full_path):
-            for file in os.listdir(full_path):
-                if file in TARGET_FILES:
-                    self.parse_file(os.path.join(full_path, file))
+    try:
+        for folder in os.listdir(start_path):
+            full_path = os.path.join(start_path, folder, "Research")
+            if os.path.isdir(full_path):
+                try:
+                    for file in os.listdir(full_path):
+                        if file in TARGET_FILES:
+                            self.parse_file(os.path.join(full_path, file))
+                except Exception as e:
+                    messagebox.showerror("Erro", f"Falha ao listar diretório {full_path}:\n{str(e)}")
+    except Exception as e:
+        messagebox.showerror("Erro", f"Falha ao listar diretório {start_path}:\n{str(e)}")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def load_data(self):
start_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "Resources", "Prototypes"))
direct_research = os.path.join(start_path, "Research")
if os.path.isdir(direct_research):
for file in os.listdir(direct_research):
if file in TARGET_FILES:
self.parse_file(os.path.join(direct_research, file))
for folder in os.listdir(start_path):
full_path = os.path.join(start_path, folder, "Research")
if os.path.isdir(full_path):
for file in os.listdir(full_path):
if file in TARGET_FILES:
self.parse_file(os.path.join(full_path, file))
self.display_grid()
def load_data(self):
start_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), "..", "..", "Resources", "Prototypes")
)
direct_research = os.path.join(start_path, "Research")
if os.path.isdir(direct_research):
try:
for file in os.listdir(direct_research):
if file in TARGET_FILES:
self.parse_file(os.path.join(direct_research, file))
except Exception as e:
messagebox.showerror(
"Erro",
f"Falha ao listar diretório {direct_research}:\n{str(e)}"
)
try:
for folder in os.listdir(start_path):
full_path = os.path.join(start_path, folder, "Research")
if os.path.isdir(full_path):
try:
for file in os.listdir(full_path):
if file in TARGET_FILES:
self.parse_file(os.path.join(full_path, file))
except Exception as e:
messagebox.showerror(
"Erro",
f"Falha ao listar diretório {full_path}:\n{str(e)}"
)
except Exception as e:
messagebox.showerror(
"Erro",
f"Falha ao listar diretório {start_path}:\n{str(e)}"
)
self.display_grid()

Comment on lines +28 to +36
// Some visuals
public static readonly Color DefaultColor = Color.FromHex("#141F2F");
public static readonly Color DefaultBorderColor = Color.FromHex("#4972A1");
public static readonly Color DefaultHoveredColor = Color.FromHex("#4972A1");

public Color Color = DefaultColor;
public Color BorderColor = DefaultBorderColor;
public Color HoveredColor = DefaultHoveredColor;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Nome do campo colide com o tipo Color, causando erro de compilação

Ao declarar public Color Color = …, o identificador Color passa a se referir ao campo, escondendo o tipo Color no restante da classe. Linhas 50-56 que usam Color.DarkOliveGreen, etc., deixam de compilar.

-    public Color Color = DefaultColor;
-    public Color BorderColor = DefaultBorderColor;
-    public Color HoveredColor = DefaultHoveredColor;
+    public Color BaseColor       = DefaultColor;
+    public Color BaseBorderColor = DefaultBorderColor;
+    public Color HoveredColor    = DefaultHoveredColor;

Altere também as demais referências (BaseColor, BaseBorderColor) dentro da classe.

Comment on lines +69 to +75
protected override void ExitedTree()
{
base.ExitedTree();

Button.OnPressed -= Selected;
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Cancelar registro do evento OnDrawModeChanged ao sair da árvore

ExitedTree() remove apenas o handler de OnPressed, mas deixa o de OnDrawModeChanged pendurado, gerando vazamento de memória e exceções quando o botão for recolorido depois do controle destruído.

-        Button.OnPressed -= Selected;
+        Button.OnPressed         -= Selected;
+        Button.OnDrawModeChanged -= UpdateColor;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
protected override void ExitedTree()
{
base.ExitedTree();
Button.OnPressed -= Selected;
}
protected override void ExitedTree()
{
base.ExitedTree();
Button.OnPressed -= Selected;
Button.OnDrawModeChanged -= UpdateColor;
}

Comment on lines +43 to +56
function handleFiles(e) {
const files = e.target.files;
for (let file of files) {
const reader = new FileReader();
reader.onload = function(evt) {
const doc = jsyaml.load(evt.target.result);
if (Array.isArray(doc)) {
techs.push(...doc.filter(t => t.type === "technology" && t.position));
draw();
}
};
reader.readAsText(file);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Evite duplicar nós quando múltiplos arquivos YAML contêm a mesma tecnologia

Atualmente, cada importação faz techs.push(...) sem verificar duplicatas, o que provoca sobreposição de retângulos e linhas duplicadas.

-        techs.push(...doc.filter(t => t.type === "technology" && t.position));
+        for (const t of doc) {
+          if (t.type !== "technology" || !t.position) continue;
+          if (!techs.some(existing => existing.id === t.id)) {
+            techs.push(t);
+          }
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function handleFiles(e) {
const files = e.target.files;
for (let file of files) {
const reader = new FileReader();
reader.onload = function(evt) {
const doc = jsyaml.load(evt.target.result);
if (Array.isArray(doc)) {
techs.push(...doc.filter(t => t.type === "technology" && t.position));
draw();
}
};
reader.readAsText(file);
}
}
function handleFiles(e) {
const files = e.target.files;
for (let file of files) {
const reader = new FileReader();
reader.onload = function(evt) {
const doc = jsyaml.load(evt.target.result);
if (Array.isArray(doc)) {
for (const t of doc) {
if (t.type !== "technology" || !t.position) continue;
if (!techs.some(existing => existing.id === t.id)) {
techs.push(t);
}
}
draw();
}
};
reader.readAsText(file);
}
}

Comment on lines +85 to +88
ServerButton.OnPressed += _ => OnServerButtonPressed?.Invoke();
DragContainer.OnKeyBindDown += OnKeybindDown;
DragContainer.OnKeyBindUp += OnKeybindUp;
RecenterButton.OnPressed += _ => Recenter();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Desregistre eventos de DragContainer no Close()

Ao fechar a window, OnKeyBindDown/Up permanecem registrados, podendo disparar em janelas futuras.

 public override void Close()
 {
     base.Close();
 
+    DragContainer.OnKeyBindDown -= OnKeybindDown;
+    DragContainer.OnKeyBindUp   -= OnKeybindUp;
     DragContainer.RemoveAllChildren();
     InfoContainer.RemoveAllChildren();
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ServerButton.OnPressed += _ => OnServerButtonPressed?.Invoke();
DragContainer.OnKeyBindDown += OnKeybindDown;
DragContainer.OnKeyBindUp += OnKeybindUp;
RecenterButton.OnPressed += _ => Recenter();
public override void Close()
{
base.Close();
DragContainer.OnKeyBindDown -= OnKeybindDown;
DragContainer.OnKeyBindUp -= OnKeybindUp;
DragContainer.RemoveAllChildren();
InfoContainer.RemoveAllChildren();
}

@Crono209ggg
Copy link

Mt foda o gui é bonitão

@github-actions
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants