Files
SergObsidian/PERSONAL PROJECTS/PSX code - modules load and exec.md
2025-04-18 22:50:54 +05:00

6.1 KiB
Raw Blame History

Вот доработанная версия с общими переменными между основной программой и модулями. Мы создадим единую структуру GameState, которая будет передаваться в каждый модуль.


1. Общий заголовок (SHARED.H)

// Структура для общих переменных игры
typedef struct {
    int lives;          // Количество жизней
    int level;          // Текущий уровень
    bool is_paused;     // Состояние паузы
    uint32_t score;     // Счёт игрока
} GameState;

// Заголовок модуля
typedef void (*ModuleEntry)(GameState*);  // Тип функции-входа

typedef struct {
    uint32_t magic;     // 0x55AA1234
    ModuleEntry entry;  // Функция входа
    uint32_t size;      // Размер модуля
} ModuleHeader;

2. Основная программа (MAIN.C)

#include <libetc.h>
#include <libcd.h>
#include "SHARED.H"

#define MODULE_ADDR 0x80030000  // Адрес загрузки модулей

GameState game_state = {
    .lives = 3,
    .level = 1,
    .is_paused = false,
    .score = 0
};

void load_and_run_module(int sector, int size) {
    CdRead(sector, (uint32_t*)MODULE_ADDR, size);
    CdReadSync(0);

    ModuleHeader *header = (ModuleHeader*)MODULE_ADDR;
    if (header->magic == 0x55AA1234) {
        header->entry(&game_state);  // Передаём указатель на game_state
    }
}

int main() {
    ResetGraph(0);
    CdInit();
    FntLoad(960, 256);
    FntOpen(16, 16, 256, 224, 0, 512);

    while (1) {
        // Обновляем общие переменные
        game_state.score += 10;
        FntPrint("Main: Lives=%d, Score=%d\n", game_state.lives, game_state.score);

        // Загружаем и выполняем модули
        load_and_run_module(MODULE_MDEC_SECTOR, MODULE_MDEC_SIZE);
        load_and_run_module(MODULE_GPU_SECTOR, MODULE_GPU_SIZE);

        VSync(0);
    }
}

3. Модуль для MDEC (MODULE_MDEC.C)

#include <libmdec.h>
#include "SHARED.H"

void module_entry(GameState *state) {
    // Читаем и изменяем общие переменные
    if (state->lives > 0) {
        state->lives--;  // Уменьшаем жизни
        FntPrint("MDEC: Lives left=%d\n", state->lives);
    }

    // Декодируем видео только если игра не на паузе
    if (!state->is_paused) {
        uint8_t data[1024];
        uint16_t buffer[256*256];
        MDEC_DecodeFrame(data, buffer, MDEC_MODE_RGB24);
    }
}

ModuleHeader __header__ __attribute__((section(".header"))) = {
    .magic = 0x55AA1234,
    .entry = module_entry,
    .size = 0
};

4. Модуль для GPU (MODULE_GPU.C)

#include <libgpu.h>
#include "SHARED.H"

void module_entry(GameState *state) {
    // Проверяем глобальный статус
    if (state->is_paused) {
        FntPrint("GPU: Game is paused!\n");
        return;
    }

    // Рисуем HUD с общими переменными
    char hud_text[32];
    sprintf(hud_text, "LIVES: %d SCORE: %d", state->lives, state->score);
    FntPrint(hud_text);

    // Пример работы с GPU
    RECT rect = {10, 10, 100, 100};
    uint16_t color = state->lives > 1 ? 0xFF00 : 0xFF0000;  // Красный если 1 жизнь
    DrawPrim(&rect);
}

ModuleHeader __header__ __attribute__((section(".header"))) = {
    .magic = 0x55AA1234,
    .entry = module_entry,
    .size = 0
};

5. Сборка

# Компиляция модулей с их библиотеками
ccpsx MODULE_MDEC.C -o MODULE_MDEC.BIN -lpsxmdec
ccpsx MODULE_GPU.C -o MODULE_GPU.BIN -lpsxgpu

# Основная программа (без лишних библиотек)
ccpsx MAIN.C -o MAIN.EXE

6. Механика общих переменных

  1. Основная программа:

    • Создаёт глобальную структуру GameState.
    • Передаёт указатель на неё в модули через header->entry(&game_state).
  2. Модули:

    • Читают и изменяют GameState через полученный указатель.
    • Могут проверять:
      if (state->is_paused) { ... }
      
    • Могут изменять:
      state->lives--;
      
  3. Синхронизация:

    • Все изменения мгновенно видны в основном модуле и других модулях.

7. Пример работы

  1. Основная программа:
    • Устанавливает lives = 3, score = 0.
  2. Модуль MDEC:
    • Уменьшает lives до 2, если игрок ошибся.
  3. Модуль GPU:
    • Отображает текущие lives и score на экране.
  4. Основная программа:
    • Видит изменения и может реагировать (например, завершить игру при lives == 0).

8. Важные нюансы

  • Безопасность: Модули могут перезаписать любые данные в GameState. Добавьте проверки:
    if (state->lives < 0) state->lives = 0;  // Защита от отрицательных значений
    
  • Производительность: Частый доступ к общим переменным может замедлить работу. Оптимизируйте:
    int local_lives = state->lives;  // Кэширование в локальную переменную
    
  • Конфликты: Если модули работают с одними данными, добавьте флаги блокировки.

Теперь модули могут полноценно взаимодействовать с основной программой, проверяя и изменяя глобальное состояние игры! 🎮