🔧 PRD #2 — Developer Guide & Implementation Plan¶
GregTech Nexus Addon — Technical Implementation Document¶
Versão 1.0 | Bilíngue PT-BR / EN¶
📋 Índice¶
- Visão Técnica / Technical Overview
- Estrutura de Pastas / Folder Structure
- Padrões de Código / Coding Standards
- Ordem de Implementação / Implementation Order
- Guia de Cálculos Massivos / Large Number Calculation Guide
- Padrões de Registro / Registration Patterns
- Padrões de Multiblock / Multiblock Patterns
- Testing & Debugging
- Guia para Contribuidores / Contributor Guide
1. Visão Técnica / Technical Overview¶
Stack Tecnológica¶
| Componente | Versão | Papel |
|---|---|---|
| Minecraft | 1.20.1 | Runtime |
| Forge | 47.4.1 | Mod Loader |
| GregTech CEu Modern | 7.4.1 | API Base |
| LDLib | 1.0.40.b | GUI/Rendering |
| Registrate | MC1.20-1.3.11 | Registration DSL |
| Applied Energistics 2 | Latest 1.20.1 | Storage/Autocraft |
| ExtendedAE | Latest | AE2 Addon |
| Java | 17 | Language |
| Lombok | 1.18.24 | Boilerplate reduction |
Dependência entre Módulos¶
graph TD
API["api/"] --> Common["common/"]
Common --> Data["data/"]
Common --> Machine["machine/"]
Machine --> Multiblock["multiblock/"]
Machine --> Part["part/"]
Data --> Recipe["recipe/"]
API --> Integration["integration/"]
Integration --> AE2["ae2/"]
Integration --> Jade["jade/"]
Common --> Utils["utils/"]
2. Estrutura de Pastas / Folder Structure¶
Estrutura Atual (Problemas Identificados)¶
com.raishxn.gtna/
├── GTNACORE.java ← MOD principal
├── GTNAGTAddon.java ← GT Addon entry
├── api/ ← OK, mas precisa expandir
│ ├── data/info/
│ ├── item/tool/
│ ├── machine/
│ │ └── multiblock/
│ └── registry/
├── client/ ← OK
├── common/
│ ├── data/ ← ⚠️ Mistura materials, machines, blocks
│ │ ├── material/
│ │ ├── GTNABlocks.java
│ │ ├── GTNAElements.java
│ │ ├── GTNAItems.java
│ │ ├── GTNAMachines.java ← ⚠️ 1620 linhas! Dividir.
│ │ ├── GTNAMachines2.java ← ⚠️ Continuação, naming confuso
│ │ └── GTNAMaterials.java
│ ├── item/
│ ├── machine/
│ │ └── multiblock/
│ │ ├── electric/
│ │ ├── energy/
│ │ ├── noenergy/
│ │ ├── part/
│ │ │ └── steam/
│ │ └── steam/
│ └── recipe/ ← ⚠️ Está em common, deveria estar em data
├── config/
├── data/
│ └── recipe/ ← ⚠️ Duplicação com common/recipe
├── integration/
├── mixin/
├── network/
└── utils/
Estrutura Proposta (Refatorada)¶
com.raishxn.gtna/
├── GTNACORE.java
├── GTNAGTAddon.java
│
├── api/ ← Interfaces públicas para addons
│ ├── capability/ ← [NOVO] Capabilities customizadas
│ │ ├── IPatternBuffer.java
│ │ └── ISteamNetwork.java
│ ├── data/
│ │ ├── chemical/ ← [NOVO] Elementos e materiais API
│ │ │ ├── GTNAElements.java ← Movido de common/data
│ │ │ └── GTNAMaterialFlags.java
│ │ └── info/
│ ├── item/tool/
│ ├── machine/
│ │ ├── multiblock/
│ │ │ ├── GTNAPartAbility.java
│ │ │ └── IThreadModifierMachine.java
│ │ └── trait/ ← [NOVO]
│ │ ├── IPatternBufferProvider.java
│ │ └── ISteamOverclockable.java
│ └── registry/
│
├── client/
│ ├── ClientProxy.java
│ ├── gui/ ← [NOVO] GUIs customizadas
│ │ ├── widget/
│ │ │ ├── PatternBufferWidget.java
│ │ │ └── SteamDashboardWidget.java
│ │ └── screen/
│ └── renderer/ ← [NOVO] Custom renders
│
├── common/
│ ├── CommonProxy.java
│ ├── block/ ← [RENOMEADO] de data/GTNABlocks
│ │ ├── GTNABlocks.java
│ │ └── casing/ ← [NOVO] Specific casing logic
│ │ └── PressureCoreBlock.java
│ ├── cover/
│ │ └── GTNACovers.java
│ ├── item/
│ │ ├── GTNAItems.java
│ │ └── behavior/ ← [RENOMEADO]
│ │ ├── StructureDetectBehavior.java
│ │ └── StructureWriteBehavior.java
│ ├── machine/
│ │ ├── multiblock/
│ │ │ ├── electric/
│ │ │ │ └── WorkableElectricMultipleRecipesMachine.java
│ │ │ ├── steam/ ← [UNIFICADO] steam + noenergy
│ │ │ │ ├── ForgeOfTheIronCrown.java ← [NOVO]
│ │ │ │ ├── SteamPressureCrystallizer.java ← [NOVO]
│ │ │ │ ├── PneumaticOreWasher.java ← [NOVO]
│ │ │ │ ├── SteamDistillationColumn.java ← [NOVO]
│ │ │ │ ├── HydraulicPressComplex.java ← [NOVO]
│ │ │ │ ├── LargeSteamAlloySmelter.java
│ │ │ │ ├── LargeSteamCrusher.java
│ │ │ │ ├── LargeSteamFurnace.java
│ │ │ │ ├── MegaSolarBoilerMachine.java
│ │ │ │ ├── SteamCobbler.java
│ │ │ │ ├── SteamManufacturer.java
│ │ │ │ ├── SteamWoodcutter.java
│ │ │ │ ├── StoneSuperHeater.java
│ │ │ │ └── VoidMinerSteamGateAged.java
│ │ │ ├── energy/
│ │ │ │ ├── IndustrialSlaughterhouse.java
│ │ │ │ └── NexusReactorCore.java ← [NOVO]
│ │ │ └── part/
│ │ │ ├── AccelerateHatchPartMachine.java
│ │ │ ├── AdvancedParallelHatchPartMachine.java
│ │ │ ├── OverclockHatchPartMachine.java
│ │ │ ├── PatternBufferPartMachine.java ← [NOVO]
│ │ │ ├── ThreadPartMachine.java
│ │ │ └── steam/
│ │ └── trait/
│ │ ├── GTNAMultipleRecipesLogic.java
│ │ └── PatternBufferLogic.java ← [NOVO]
│ └── network/ ← [MOVIDO] de top-level
│ ├── GTNANetworkHandler.java
│ └── packet/
│
├── config/
│ └── ConfigHolder.java
│
├── data/ ← Registration de TUDO
│ ├── lang/
│ │ └── GTNALangProvider.java
│ ├── material/
│ │ ├── GTNAMaterials.java
│ │ ├── MaterialBuilder.java
│ │ └── MaterialAdd.java
│ ├── machine/ ← [NOVO] Dividido por era
│ │ ├── GTNAMachinesSteam.java ← Máquinas era vapor
│ │ ├── GTNAMachinesHydraulic.java ← Máquinas era hidráulica
│ │ ├── GTNAMachinesParts.java ← Hatches e parts
│ │ └── GTNAMachinesElectric.java ← Máquinas elétricas
│ ├── recipe/
│ │ ├── GTNARecipeType.java
│ │ ├── handler/ ← [NOVO] por categoria
│ │ │ ├── SteamEraRecipes.java
│ │ │ ├── HydraulicEraRecipes.java
│ │ │ ├── CraftingRecipes.java
│ │ │ └── MaterialProcessingRecipes.java
│ │ └── condition/ ← [NOVO]
│ │ └── GTNARecipeConditions.java
│ └── tag/
│ └── GTNATagPrefix.java
│
├── integration/
│ ├── ae2/ ← [NOVO] Integração AE2
│ │ ├── PatternBufferAE2Handler.java
│ │ └── MEPatternBufferPart.java
│ └── jade/
│ ├── GTNAJadePlugin.java
│ └── provider/
│
├── mixin/
│ └── gtceu/
│ ├── GTNAPlateDoubleMixin.java
│ └── GTRecipeLogicMixin.java
│
└── utils/
├── GTNARecipeHelper.java
├── GTNARecipeUtils.java
├── GTNAUtil.java
├── MachineIO.java
├── MachineUtil.java
├── NumberUtils.java
├── Registries.java
├── StructureSlicer.java
├── TextUtil.java
├── ThreadMultiplierStrategy.java
├── calc/ ← [NOVO] Cálculos
│ ├── EfficiencyCalculator.java
│ ├── SteamConversionTable.java
│ └── OverclockCalculator.java
└── datastructure/
├── CacheState.java
├── GTRecipe2IntBiMultiMap.java
└── Int128.java
[!IMPORTANT] A refatoração deve ser feita INCREMENTALMENTE: 1. Primeiro: dividir GTNAMachines.java (1620 linhas) em módulos por era 2. Segundo: mover receitas para data/recipe/handler/ 3. Terceiro: criar a pasta api/capability/ 4. Quarto: implementar novos features no novo layout
3. Padrões de Código / Coding Standards¶
3.1 Naming Conventions¶
// ✅ BOM: Classes de multiblock seguem o padrão [Nome]Machine
public class ForgeOfTheIronCrown extends SteamMultiMachineBase { }
public class SteamPressureCrystallizer extends SteamMultiMachineBase { }
// ❌ RUIM: Nomes genéricos ou abreviados
public class FoIC extends SteamMultiMachineBase { }
public class Machine1 extends SteamMultiMachineBase { }
// ✅ BOM: Constantes de registro seguem UPPER_SNAKE_CASE
public static final MultiblockMachineDefinition FORGE_OF_THE_IRON_CROWN = ...;
// ✅ BOM: Materiais seguem PascalCase
public static Material PressurizedBronze;
public static Material SteamHardenedIron;
// ✅ BOM: IDs de registro seguem snake_case
GTNACORE.id("forge_of_the_iron_crown")
GTNACORE.id("pressurized_bronze")
3.2 Organização de Imports¶
// Ordem de imports:
// 1. GTCEu/LDLib
import com.gregtechceu.gtceu.api.*;
import com.lowdragmc.lowdraglib.*;
// 2. GTNA (nosso)
import com.raishxn.gtna.*;
// 3. Minecraft/Forge
import net.minecraft.*;
import net.minecraftforge.*;
// 4. Java standard
import java.util.*;
3.3 Padrões para Recipe Modifiers¶
/**
* Padrão para recipeModifier em multiblocks GTNA.
* SEMPRE documente:
* - O que o modifier faz
* - Fórmulas usadas
* - Parâmetros que afetam o resultado
*/
public static GTRecipe recipeModifier(MetaMachine machine, GTRecipe recipe,
@NotNull OCParams params,
@NotNull OCResult result) {
// 1. Valide a máquina
if (!(machine instanceof ForgeOfTheIronCrown forgeMachine)) {
return recipe;
}
// 2. Calcule paralelos
int maxParallel = forgeMachine.getMaxParallel();
var parallelResult = GTRecipeModifiers.fastParallel(machine, recipe, maxParallel, false);
// 3. Aplique modificadores de velocidade
// Fórmula: duration = base / (1 + 0.5 * ocLevel)
recipe = parallelResult.getFirst();
int ocLevel = forgeMachine.getSteamOverclockLevel();
int newDuration = (int) (recipe.duration / (1 + 0.5 * ocLevel));
recipe = recipe.copy();
recipe.duration = Math.max(1, newDuration);
// 4. Aplique Crown Bonus se aplicável
if (forgeMachine.hasCrownBonus()) {
recipe.duration = (int) (recipe.duration * 0.9); // 10% faster
}
// 5. Ajuste consumo de steam
long steamCost = calculateSteamCost(recipe, ocLevel);
// ... apply steam cost
return recipe;
}
3.4 Lombok Usage¶
// USE Lombok para reduzir boilerplate, mas COM MODERAÇÃO:
@Getter // ✅ Em fields simples
@Setter // ✅ Em fields mutáveis
@Getter(lazy = true) // ✅ Para computações caras
// ❌ NÃO USE @Data em classes de máquina (pode causar problemas com serialização GT)
// ❌ NÃO USE @Builder em classes que estendem GT (conflito com super construtores)
3.5 Javadoc Obrigatório¶
/**
* Toda classe pública DEVE ter Javadoc com:
* - Descrição em PT-BR e EN
* - @author
* - @since (versão do GTNA)
*
* PT-BR: Forja da Coroa de Ferro — Multiblock movido a vapor que funciona
* como EBF para receitas ≤1800K.
* EN: Forge of the Iron Crown — Steam-powered multiblock functioning as
* EBF for recipes ≤1800K.
*
* @author raishxn
* @since 0.2.0
* @see SteamMultiMachineBase
*/
public class ForgeOfTheIronCrown extends SteamMultiMachineBase {
4. Ordem de Implementação / Implementation Order¶
Fase 1: Foundation (v0.2.0-alpha)¶
Prioridade: CRÍTICA | Estimativa: 2-3 semanas
1. [ ] Refatorar GTNAMachines.java → dividir em módulos por era
2. [ ] Registrar novos Elementos (Nexium, Steamforged, Crystallium)
3. [ ] Registrar novas Ligas (PressurizedBronze, SteamHardenedIron, PneumaticSteel)
4. [ ] Criar novos blocos (PressureCore, novos casings)
5. [ ] Registrar novos RecipeTypes (crystallizer, pneumatic_washer, distillation_steam)
6. [ ] Criar novos fluidos (Crystal Coolant, Hydraulic Fluid, Pressurized Water)
Fase 2: Core Multiblocks (v0.2.0-beta)¶
Prioridade: ALTA | Estimativa: 3-4 semanas
7. [ ] Implementar ForgeOfTheIronCrown (mais complexo, fazer primeiro)
8. [ ] Implementar SteamPressureCrystallizer
9. [ ] Implementar PneumaticOreWasher
10. [ ] Implementar SteamDistillationColumn
11. [ ] Implementar HydraulicPressComplex
12. [ ] Criar todas as receitas dos novos multiblocks
13. [ ] Criar texturas (programmaticamente ou via Asset Generator)
Fase 3: Pattern Buffer (v0.2.0-rc)¶
Prioridade: ALTA | Estimativa: 2-3 semanas
14. [ ] Implementar PatternBufferPartMachine (lógica core)
15. [ ] Implementar PatternBufferLogic (trait)
16. [ ] Criar GUI do Pattern Buffer (widgets LDLib)
17. [ ] Registrar 5 tiers de Pattern Buffer
18. [ ] Integração AE2 para Pattern Buffer
19. [ ] Testes de integração
Fase 4: QoL & Polish (v0.2.0-release)¶
Prioridade: MÉDIA | Estimativa: 1-2 semanas
20. [ ] Smart Tooltips em todos os multiblocks
21. [ ] Wireless Steam Dashboard GUI
22. [ ] Structure Preview Enhancement
23. [ ] JEI/EMI custom pages
24. [ ] Tradução PT-BR/EN completa
25. [ ] Debug tools e config options
Fase 5: Balanceamento & Testing (v0.2.0-final)¶
Prioridade: CRÍTICA | Estimativa: 1-2 semanas
26. [ ] Testes de performance (TPS impact)
27. [ ] Testes de gameplay (speedrun completa)
28. [ ] Balance pass em todos os custos/durações
29. [ ] Community playtest (se possível)
30. [ ] Documentação final
Dependência entre Fases¶
graph LR
F1["Fase 1<br/>Foundation"] --> F2["Fase 2<br/>Multiblocks"]
F1 --> F3["Fase 3<br/>Pattern Buffer"]
F2 --> F4["Fase 4<br/>QoL"]
F3 --> F4
F4 --> F5["Fase 5<br/>Balance"]
5. Guia de Cálculos Massivos / Large Number Calculation Guide¶
5.1 O Problema dos Números Grandes¶
No GT endgame, lidamos com valores que excedem int e às vezes long:
- Steam: até 2,147,483,647 L/t (int max) em redes grandes
- EU: até 9,223,372,036,854,775,807 (long max) em tier MAX
- Paralelos: até 262,144 (seus parallel hatches OpV)
5.2 Já Temos: Int128¶
// O projeto já possui Int128 em utils/datastructure/
// USE para cálculos que excedem long
import com.raishxn.gtna.utils.datastructure.Int128;
// Exemplo: calcular custo total de steam para 262,144 paralelos
Int128 totalSteam = Int128.of(baseSteamPerTick)
.multiply(Int128.of(parallels))
.multiply(Int128.of(durationTicks));
5.3 Estratégias de Cálculo¶
/**
* REGRA 1: Sempre use long para cálculos intermediários de EU/Steam
* REGRA 2: Use Int128 quando multiplicando 3+ valores que podem overflow
* REGRA 3: Arredonde PARA CIMA custos (Math.ceil), PARA BAIXO benefícios (Math.floor)
* REGRA 4: Nunca divida antes de multiplicar (perda de precisão)
*/
// ✅ BOM: Multiplica primeiro, divide depois
long efficiency = (baseCost * parallels * 100L) / efficiencyPercent;
// ❌ RUIM: Divide primeiro, perde precisão
long efficiency = (baseCost / efficiencyPercent) * parallels * 100;
// ✅ BOM: Usa saturação para evitar overflow
long safeSteam = Math.min(totalSteam, Integer.MAX_VALUE);
// ✅ BOM: Usa BigInteger para display (tooltip), long para lógica
BigInteger displayValue = BigInteger.valueOf(totalSteam);
String formatted = NumberFormat.getCompactNumberInstance().format(displayValue);
5.4 Tabela de Limites¶
| Tipo | Valor Máximo | Quando Usar |
|---|---|---|
int |
2.1 bilhões | Fluid em mB, durações curtas |
long |
9.2 quintilhões | EU totais, cálculos intermediários |
Int128 |
1.7×10³⁸ | Cálculos de endgame, display |
BigInteger |
Ilimitado | Apenas para display/formatting |
5.5 Funções Utilitárias Recomendadas¶
public class GTNAMathUtils {
/**
* Multiplica sem overflow, retorna Long.MAX_VALUE se exceder
*/
public static long safeMul(long a, long b) {
try {
return Math.multiplyExact(a, b);
} catch (ArithmeticException e) {
return Long.MAX_VALUE;
}
}
/**
* Calcula custo de steam com proteção de overflow
* @param baseCost custo base em L/t
* @param parallels número de paralelos ativos
* @param efficiencyMod modificador de eficiência (0.7 para Steamforged)
* @param ocLevel nível de overclock (0-3)
*/
public static long calculateSteamCost(long baseCost, int parallels,
double efficiencyMod, int ocLevel) {
long cost = baseCost;
cost = safeMul(cost, parallels);
cost = (long) (cost * efficiencyMod);
cost = safeMul(cost, (long) Math.pow(2, ocLevel));
return cost;
}
/**
* Formata números grandes para tooltips
* 1000 → "1K", 1000000 → "1M", etc.
*/
public static String formatCompact(long value) {
if (value < 1_000) return String.valueOf(value);
if (value < 1_000_000) return String.format("%.1fK", value / 1_000.0);
if (value < 1_000_000_000) return String.format("%.1fM", value / 1_000_000.0);
return String.format("%.1fB", value / 1_000_000_000.0);
}
}
6. Padrões de Registro / Registration Patterns¶
6.1 Registrar um Novo Elemento¶
// Em api/data/chemical/GTNAElements.java (ou common/data/GTNAElements.java)
public class GTNAElements {
public static Element ECHOITE;
public static Element NEXIUM;
public static Element STEAMFORGED;
public static Element CRYSTALLIUM;
// ...
public static void init() {
// Params: protons, neutrons, halfLifeSeconds (-1 = stable),
// decayTo, name, symbol, isIsotope
ECHOITE = GTElements.createAndRegister(570, 570, -1, null, "echoite", "Ec", false);
NEXIUM = GTElements.createAndRegister(571, 580, -1, null, "nexium", "Nx", false);
STEAMFORGED = GTElements.createAndRegister(573, 560, -1, null, "steamforged", "Sf", false);
CRYSTALLIUM = GTElements.createAndRegister(574, 575, -1, null, "crystallium", "Cr★", false);
}
}
6.2 Registrar um Novo Material¶
// Em data/material/MaterialBuilder.java
public static void init() {
// Liga simples
PressurizedBronze = new Material.Builder(GTNACORE.id("pressurized_bronze"))
.ingot().fluid().dust()
.color(0xCD8032) // Cor da liga
.iconSet(MaterialIconSet.SHINY) // Aparência visual
.components(Bronze, 3, CompressedSteam, 1) // Composição
.blastTemp(900, BlastProperty.GasTier.LOW) // Temperatura EBF
.flags(GENERATE_PLATE, GENERATE_ROD, GENERATE_FRAME, GENERATE_GEAR,
GENERATE_BOLT_SCREW, GENERATE_DENSE)
.fluidPipeProperties(900, 2000, true, true, true, false)
.buildAndRegister()
.setFormula("(SnCu3)3(H2O)");
// Elemento puro
Nexium = new Material.Builder(GTNACORE.id("nexium"))
.ingot().fluid().dust().plasma()
.element(GTNAElements.NEXIUM) // Vincula ao elemento
.color(0x4A7AE5)
.iconSet(MaterialIconSet.METALLIC)
.blastTemp(1600, BlastProperty.GasTier.MID)
.flags(GENERATE_PLATE, GENERATE_ROD, GENERATE_FRAME, GENERATE_GEAR,
GENERATE_BOLT_SCREW, GENERATE_FINE_WIRE, GENERATE_FOIL)
.cableProperties(GTValues.V[GTValues.MV], 32, 0, true) // Cabo MV sem perda
.buildAndRegister()
.setFormula("Nx");
}
6.3 Registrar um Novo Bloco de Casing¶
// Em common/block/GTNABlocks.java
public static final BlockEntry<Block> PRESSURE_CORE = createCasingBlock("pressure_core");
// Para blocos com lógica especial:
public static final BlockEntry<PressureCoreBlock> ADVANCED_PRESSURE_CORE = REGISTRATE
.block("advanced_pressure_core", PressureCoreBlock::new)
.initialProperties(() -> Blocks.IRON_BLOCK)
.properties(p -> p.mapColor(MapColor.METAL).strength(8.0f, 10.0f).sound(SoundType.NETHERITE_BLOCK))
.addLayer(() -> RenderType::solid)
.blockstate((ctx, prov) -> prov.simpleBlock(ctx.get(),
prov.models().cubeAll(ctx.getName(), GTNACORE.id("block/casings/pressure_core"))))
.tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE)
.item(BlockItem::new).build()
.register();
6.4 Registrar um Novo Recipe Type¶
// Em data/recipe/GTNARecipeType.java
public static final String CRYSTALLIZER = "crystallizer";
public static final GTRecipeType CRYSTALLIZER_RECIPES = register("crystallizer", CRYSTALLIZER)
.setMaxIOSize(2, 2, 2, 2) // max item in, item out, fluid in, fluid out
.setEUIO(IO.IN)
.setProgressBar(GuiTextures.PROGRESS_BAR_CRYSTALLIZE, LEFT_TO_RIGHT)
.setSound(GTSoundEntries.CHEMICAL);
public static final String PNEUMATIC_WASH = "pneumatic_wash";
public static final GTRecipeType PNEUMATIC_WASH_RECIPES = register("pneumatic_wash", PNEUMATIC_WASH)
.setMaxIOSize(1, 4, 2, 2)
.setEUIO(IO.IN)
.setProgressBar(GuiTextures.PROGRESS_BAR_BATH, LEFT_TO_RIGHT)
.setSound(GTSoundEntries.BATH);
7. Padrões de Multiblock / Multiblock Patterns¶
7.1 Template Base para Novo Multiblock GTNA¶
/**
* Template: [NomeDoMultiblock].java
*
* Copie este template e modifique para cada novo multiblock.
* Siga a ordem: fields → constructor → recipe modifier → pattern → tooltips
*/
public class TemplateMultiblock extends SteamMultiMachineBase {
// ═══ FIELDS ═══
private final int maxParallel;
private final double speedMultiplier;
// ═══ CONSTRUCTOR ═══
public TemplateMultiblock(IMachineBlockEntity holder, Object... args) {
super(holder, args);
this.maxParallel = 64;
this.speedMultiplier = 2.0;
}
// ═══ RECIPE MODIFIER ═══
@Nullable
public static GTRecipe recipeModifier(MetaMachine machine, @NotNull GTRecipe recipe,
@NotNull OCParams params, @NotNull OCResult result) {
if (!(machine instanceof TemplateMultiblock tmb)) return recipe;
// Parallel
var parallel = GTRecipeModifiers.fastParallel(machine, recipe, tmb.maxParallel, false);
recipe = parallel.getFirst();
// Speed
recipe = recipe.copy();
recipe.duration = Math.max(1, (int)(recipe.duration / tmb.speedMultiplier));
// Steam cost (se aplicável)
// ...
return recipe;
}
// ═══ PATTERN ═══
// Defina na registration class (GTNAMachinesSteam.java)
// Padrão: use GTNACORE.id() para todas as ResourceLocations
// ═══ TICK LOGIC (se necessário) ═══
@Override
public void onWorking() {
super.onWorking();
// Lógica por tick (consumo de steam, efeitos visuais, etc.)
}
}
7.2 Dicas para Definição de Patterns¶
// 1. SEMPRE use 'S' ou '~' para controller
// 2. Use letras consistentes: A=main casing, B=special, C=pipe, etc.
// 3. Espacos ' ' para any(), '#' para air()
// 4. Documente cada letra com comentário
.where('~', controller(blocks(definition.get())))
.where('A', blocks(GTNABlocks.SOME_CASING.get()) // Main casing + abilities
.or(abilities(PartAbility.STEAM_IMPORT_ITEMS).setPreviewCount(1))
.or(abilities(PartAbility.STEAM_EXPORT_ITEMS).setPreviewCount(1))
.or(abilities(PartAbility.STEAM).setExactLimit(1)))
.where('B', blocks(GTNABlocks.SPECIAL_BLOCK.get())) // Bloco especial (sem hatch)
.where('C', blocks(GTBlocks.CASING_BRONZE_PIPE.get())) // Pipe interior
.where('D', blocks(ChemicalHelper.getBlock(TagPrefix.frameGt, GTMaterials.Steel)))
.where(' ', any()) // Pode ser qualquer bloco
.where('#', air()) // Deve ser ar
8. Testing & Debugging¶
8.1 Ambiente de Desenvolvimento¶
1. IntelliJ IDEA (recomendado)
- Plugin: Minecraft Development
- Plugin: Lombok
- Configuração de Run: "runClient" via Gradle
2. Comandos úteis in-game:
/gtna debug <machine_id> → Mostra stats da máquina
/gtna steam_network → Mostra estado da rede wireless
/gtna give_materials → Dá materiais de teste
3. Estrutura de teste:
src/test/java/com/raishxn/gtna/
├── recipe/RecipeValidationTest.java
├── calc/CalculationTest.java
└── material/MaterialRegistrationTest.java
8.2 Checklist de Testes por Feature¶
Para cada novo multiblock:
[ ] Forma corretamente (structure check)
[ ] Aceita receitas corretas
[ ] Rejeita receitas incorretas
[ ] Paralelos funcionam como esperado
[ ] Consumo de steam bate com as fórmulas
[ ] Subprodutos são gerados corretamente
[ ] Wall sharing funciona
[ ] Tooltips mostram informações corretas
[ ] JEI/EMI mostra a máquina
[ ] Não causa TPS lag com 10+ instâncias
8.3 Debugging de Performance¶
// Use o MachineUtil existente para profiling:
public static void profileRecipeExecution(String machineName, Runnable execution) {
long start = System.nanoTime();
execution.run();
long elapsed = System.nanoTime() - start;
if (elapsed > 1_000_000) { // > 1ms
GTNACORE.LOGGER.warn("[PERF] {} took {}ms", machineName, elapsed / 1_000_000.0);
}
}
9. Guia para Contribuidores / Contributor Guide¶
Para quem quiser fazer addons para o GTNA:¶
// 1. Adicione GTNA como dependência no build.gradle:
modImplementation("com.raishxn.gtna:gtna-1.20.1:${gtna_version}:slim") {
transitive = false
}
// 2. Use as interfaces da API:
import com.raishxn.gtna.api.capability.IPatternBuffer;
import com.raishxn.gtna.api.machine.trait.ISteamOverclockable;
// 3. Registre receitas para nossos recipe types:
import static com.raishxn.gtna.data.recipe.GTNARecipeType.CRYSTALLIZER_RECIPES;
// 4. Estenda nossos materiais:
import com.raishxn.gtna.data.material.GTNAMaterials;
Workflow Recomendado (Git)¶
main ← production releases
├── develop ← integration branch
│ ├── feature/forge-of-iron-crown
│ ├── feature/pattern-buffer
│ ├── feature/new-materials
│ └── fix/steam-calculation-overflow
└── release/0.2.0 ← release candidate
Documento técnico do GTNA v0.2.0 — Para desenvolvedores e contribuidores