EstudioVirtual — Implementação básica da simulação de Estúdios

São 01:06 da manhã quando rabisco isso no meu Obsidian. Sem Monster dessa vez, apenas o som de Riders on the Storm embalando a chuva que cai lá fora. Perfeita trilha sonora para continuar essa jornada de desenvolvimento.

Para quem não conhece, aqui está meu post anterior sobre o projeto, onde apresentei o sistema de profissionais com suas características, funções e personalidades. (Ainda em desenvolvimento, mais avançado do que esse)

Do Pensamento ao Código

Desde meu relato anterior, passei um bom tempo refletindo sobre a estrutura ideal do projeto. Acabei percebendo que talvez estivesse caindo no clássico "overengineering". Decidi então focar apenas nos "Core Systems":

  • Studio CRUD
  • Crew Auto-Generate System
  • Production CRUD
  • Contract CRUD

Mas então veio a maldita vontade de fazer algo do zero:por que não implementar estúdios controlados por IA? Afinal, a maioria dos jogos Tycoon são offline, e praticamente todas as simulações também são. E de repente, meu bd parecia tão vazio...

Posso chamar a inteligência de um jogo de IA nos dias de hoje? Ou devo abreviar para "COM"?

A Estrutura do Studio

A implementação foi relativamente simples. O modelo de Studio foi criado independente de um UserModel - este último é apenas uma referência opcional de qual usuário é o dono do estúdio, se houver algum:

public class Studio {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String description;

    // Métricas de reputação e capacidade
    private Integer audienceReputation = 0;
    private Integer criticReputation = 0;
    private Integer industryReputation = 0;
    private Integer awardsPoints = 0;
    private Integer maxSimultaneousProductions = 1;
    private Integer technologyLevel = 0;

    // Financeiro
    private BigDecimal budget = BigDecimal.valueOf(500000);       // Começam com 500k
    private BigDecimal totalRevenue = BigDecimal.ZERO;
    private BigDecimal totalExpenses = BigDecimal.ZERO;
    private BigDecimal weeklyOperationalCosts = BigDecimal.ZERO;
    private BigDecimal marketValue = BigDecimal.ZERO;

    // Timestamps
    @CreationTimestamp
    private LocalDate createdAt;
    @UpdateTimestamp
    private LocalDate updatedAt;

    // Status flags
    private Boolean isActive = true;
    private Boolean isAiControlled = false;  // ⭐ Novo campo chave

    // Relacionamentos
    @OneToMany(mappedBy = "studio", cascade = CascadeType.ALL)
    private Set<Production> productions = new HashSet<>();

    @OneToMany(mappedBy = "studio", cascade = CascadeType.ALL)
    private Set<Contract> contracts = new HashSet<>();

    @OneToOne
    @JoinColumn(name = "user_id")
    private UserModel owner;
}

O campo crucial aqui é o isAiControlled. Decidi não dar vantagens ou desvantagens especiais para estúdios controlados por IA - eles começam do zero e vão tentar crescer exatamente como um estúdio controlado por humanos faria. (Pelo menos é isso que vou tentar implemetar)

Automatizando com Spring Scheduling

Para automatizar a criação desses estúdios, ativei o @EnableScheduling do Spring:

@SpringBootApplication
@EnableScheduling  // Ativa o scheduling para tarefas automáticas
@SecurityScheme(name = "jwt_auth", scheme = "bearer", bearerFormat = "JWT", 
    type = SecuritySchemeType.HTTP, in = SecuritySchemeIn.HEADER)
public class ApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiApplication.class, args);
    }
}

O Coração: StudioAIService

Em seguida, criei um serviço dedicado para gerenciar os estúdios controlados por IA:

@Service
@RequiredArgsConstructor
public class StudioAIService {
    private final StudioRepository studioRepository;
    private final NameGenerationUtil nameGenerationUtil;
    private final CrewService crewService;
    private final Random random = new Random();

    @Transactional
    @Scheduled(fixedRate = 14400)  // Executa a cada 4 horas (14400000ms)
    public void scheduleCreateAiStudios() {
        // 5% de chance de criar um novo estúdio a cada execução
        if (random.nextDouble() < 0.05) {
            // Gera nome e descrição
            String studioName = nameGenerationUtil.generateStudioName();
            String description = nameGenerationUtil.generateStudioDescription(studioName);

            // Gera uma nova população de pessoas (ainda em desenvolvimento!)
            crewService.generateRandomCrews();
            
            // Configura o novo estúdio
            Studio studio = new Studio();
            studio.setName(studioName);
            studio.setDescription(description);
            studio.setIsAiControlled(true);

            studioRepository.save(studio);
        }
    }
}

A Arte dos Nomes: NameGenerationUtil

Para gerar nomes e descrições criativas, criei um componente separado que pode ser facilmente expandido:

Utilizei IA do ChatGPT para gerar os nomes, assim como na população de equipe.

@Component
public class NameGenerationUtil {
    private static final Random random = new Random();

    public String generateStudioDescription(String studioName) {
        String[] introductions = {
            studioName + " é um estúdio audiovisual que acredita no poder das boas histórias.",
            "No coração da criatividade, nasce o " + studioName + ", especialista em contar histórias marcantes.",
            "Mais que um estúdio, o " + studioName + " é um laboratório de ideias.",
            // ... outros 39 modelos de introdução ...
        };

        String[] specialties = {
            "Especializado em filmes que emocionam, séries que marcam e conteúdos que viralizam.",
            "Nossa especialidade são narrativas autênticas e visuais impactantes para todas as telas.",
            // ... outros 28 tipos de especialidades ...
        };

        String[] values = {
            " Cada projeto é tratado com cuidado, empatia e excelência.",
            " Aqui, criatividade, diversidade e autenticidade são prioridade.",
            // ... outros 28 tipos de valores ...
        };

        // Combina aleatoriamente uma introdução, especialidade e valor
        return introductions[random.nextInt(introductions.length)] +
               specialties[random.nextInt(specialties.length)] +
               values[random.nextInt(values.length)];
    }

    // Listas de prefixos e sufixos para nomes de estúdios
    private static final List<String> STUDIO_PREFIXES = Arrays.asList(
        "Aurora", "Brisa", "Claraboia", "Caleidoscópio", "Origem", "Radiante", 
        // ... outros 63 prefixos ...
    );

    private static final List<String> STUDIO_SUFFIXES = Arrays.asList(
        "Studios", "Filmes", "Pictures", "Produções", "Media", "Cinema", 
        // ... outros 69 sufixos ...
    );

    public String generateStudioName() {
        // Combina aleatoriamente um prefixo e um sufixo
        String prefix = STUDIO_PREFIXES.get(random.nextInt(STUDIO_PREFIXES.size()));
        String suffix = STUDIO_SUFFIXES.get(random.nextInt(STUDIO_SUFFIXES.size()));
        return prefix + " " + suffix;
    }
}

Com esta combinatória, o sistema pode gerar mais de 70 × 75 × 42 × 30 × 30 = 6.615.000 combinações com nomes e descrições diferentes! E isso não significa nada! Incrível!

Próximos Passos

Claro que isso é apenas o começo da automação. Estou planejando expandir para:

  1. Comportamento de IA: Fazer estúdios tomarem decisões baseadas em seus recursos, reputação e profissionais disponíveis.
  2. Sistema econômico dinâmico: Oferta e demanda influenciando salários, orçamentos e receitas (Comecei a fazer isso no sistema passado).
  3. Contratos e negociações: Interação entre estúdios e profissionais.
  4. Eventos aleatórios: Situações que afetam o mercado e os estúdios (Um spoiler: A inflação está chegando nesse mundo virtual)
  5. Competição: Estúdios disputando pelos melhores profissionais e visando melhores lucros.

Contribua! - Especialmente se gostar do projeto 😉

Sim, contribua até se não gostou.

Olha, pode ser até com um nome na lista de Studios ou Crew

Se você curtiu o projeto e quer contribuir, ele é open source! Visite o repositório no GitHub.

Qualquer feedback é bem-vindo! E muito obrigado pela leitura!