首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何触发拯救程序的创建

如何触发拯救程序的创建
EN

Stack Overflow用户
提问于 2019-11-05 20:53:24
回答 1查看 129关注 0票数 0

我在试着创造一个柳条核心。这将是一个独立的游戏,所以我将RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME设置为true文档建议可以使用retro_get_memory_*保存数据,而无需显式查询RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY

如果libretro核心不能使用常规内存接口(retro_get_memory_data()),那么保存目录应该用于存储SRAM、存储卡、高分等等。

如何使用这个接口触发数据的保存?还是我误解了文档?

我希望前端调用retro_get_memory_{data,size},在停止内核时从公开缓冲区读取数据,将数据持久化到磁盘,并在下次内核启动时将其写回公开缓冲区。相反,我观察到:

  • 如果我不提供内容文件,前端就不会调用retro_get_memory_{data,size}
  • 如果我提供一个内容文件(未使用),前端将在retro_get_memory_{data,size}之后调用retro_load_game,但不会写入磁盘。

注意,这个问题是关于保存文件(自动持久化数据,通常是捕获玩家的进度),而不是保存由*serialize*方法实现的状态(用户触发的游戏状态快照)。

这里有一个简单的例子来重现这个问题(基于这个样本):

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libretro.h"

static unsigned char c = 0;

void* retro_get_memory_data(unsigned id) {
  fprintf(stderr, "retro_get_memory_data(%d)\n", id);
  return (id == RETRO_MEMORY_SAVE_RAM) ? &c : NULL;
}

size_t retro_get_memory_size(unsigned id) {
  fprintf(stderr, "retro_get_memory_size(%d)\n", id);
  return (id == RETRO_MEMORY_SAVE_RAM) ? 1 : 0;
}

#define WIDTH 320
#define HEIGHT 240

static uint32_t* frame_buf;

void retro_init(void) { frame_buf = calloc(WIDTH * HEIGHT, sizeof(uint32_t)); }

void retro_deinit(void) {
  free(frame_buf);
  frame_buf = NULL;
}

unsigned retro_api_version(void) { return RETRO_API_VERSION; }

void retro_get_system_info(struct retro_system_info* info) {
  memset(info, 0, sizeof(*info));
  info->library_name = "SaveTest";
  info->library_version = "v1";
  info->need_fullpath = false;
  info->valid_extensions = NULL;  // Anything is fine, we don't care.
}

static retro_video_refresh_t video_cb;
static retro_environment_t environ_cb;
static retro_input_poll_t input_poll_cb;
static retro_input_state_t input_state_cb;

void retro_set_input_poll(retro_input_poll_t cb) { input_poll_cb = cb; }
void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; }
void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; }
void retro_set_environment(retro_environment_t cb) {
  environ_cb = cb;
  bool no_content = true;
  cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_content);
}

void retro_get_system_av_info(struct retro_system_av_info* info) {
  float aspect = (float)WIDTH / HEIGHT;

  info->timing = (struct retro_system_timing){
      .fps = 60.0,
      .sample_rate = 0.0,
  };

  info->geometry = (struct retro_game_geometry){
      .base_width = WIDTH,
      .base_height = HEIGHT,
      .max_width = WIDTH,
      .max_height = HEIGHT,
      .aspect_ratio = aspect,
  };
}

unsigned retro_get_region(void) { return RETRO_REGION_NTSC; }

bool retro_load_game(const struct retro_game_info* info) {
  enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
  if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) {
    fprintf(stderr, "XRGB8888 is not supported.\n");
    return false;
  }
  (void)info;
  return true;
}

bool button(unsigned id) {
  return input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, id);
}

void retro_run(void) {
  input_poll_cb();
  if (button(RETRO_DEVICE_ID_JOYPAD_LEFT) && c > 0) --c;
  if (button(RETRO_DEVICE_ID_JOYPAD_RIGHT) && c < 255) ++c;
  uint32_t color = (255 - c) | (c << 8);
  uint32_t* buf = frame_buf;
  for (unsigned i = WIDTH * HEIGHT; i > 0; --i) {
    *buf = color;
    ++buf;
  }
  video_cb(frame_buf, WIDTH, HEIGHT, WIDTH * sizeof(uint32_t));
}

void retro_unload_game(void) {}

size_t retro_serialize_size(void) { return 1; }
bool retro_serialize(void* data, size_t size) {
  fprintf(stderr, "serialize(%p, %lu) <= %u\n", data, size, c);
  *(char*)data = c;
  return true;
}
bool retro_unserialize(const void* data, size_t size) {
  c = *(char*)data;
  fprintf(stderr, "unserialize(%p, %lu) => %u\n", data, size, c);
  return true;
}

void retro_set_controller_port_device(unsigned port, unsigned device) {}
void retro_set_audio_sample(retro_audio_sample_t cb) {}
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) {}
void retro_reset(void) {}
bool retro_load_game_special(unsigned type, const struct retro_game_info* info,
                             size_t num) {
  return false;
}
void retro_cheat_reset(void) {}
void retro_cheat_set(unsigned index, bool enabled, const char* code) {}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-11-19 20:39:07

它是无文档的,但意图是自动保存不会触发一个没有内容的核心。

此外,自动保存不是触发的核心,有内容,但可以不支持任何内容。这是意料之外的,最近得到了解决。

参考资料:https://github.com/libretro/RetroArch/issues/9300

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58719319

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档