nh_bool nhnet_view_replay_start(int fd, struct nh_window_procs *rwinprocs, struct nh_replay_info *info) { int ret; json_t *jmsg; const char *nextcmd; if (!nhnet_active()) return nh_view_replay_start(fd, rwinprocs, info); if (!api_entry()) return FALSE; alt_windowprocs = *rwinprocs; jmsg = send_receive_msg("view_start", json_pack("{si}", "gameid", fd)); if (json_unpack(jmsg, "{si,s:{ss,si,si,si,si}}", "return", &ret, "info", "nextcmd", &nextcmd, "actions", &info->actions, "max_actions", &info->max_actions, "moves", &info->moves, "max_moves", &info->max_moves) == -1) { print_error("Incorrect return object in nhnet_view_replay_step"); ret = 0; } else strncpy(info->nextcmd, nextcmd, sizeof(info->nextcmd) - 1); api_exit(); return ret; }
static void ccmd_view_start(json_t * params) { int ret, gid, fd; struct nh_replay_info info; char basename[1024], filename[1024]; json_t *jmsg; if (json_unpack(params, "{si*}", "gameid", &gid) == -1) exit_client("Bad set of parameters for view_start"); if (!db_get_game_filename(0, gid, basename, 1024)) { log_msg("Client requested nonexistent game %d for viewing", gid); jmsg = json_pack("{si}", "return", FALSE); client_msg("view_start", jmsg); return; } snprintf(filename, 1024, "%s/save/%s/%s", settings.workdir, user_info.username, basename); fd = open(filename, O_RDWR); if (fd == -1) { snprintf(filename, 1024, "%s/completed/%s", settings.workdir, basename); fd = open(filename, O_RDWR); } if (fd == -1) { log_msg("failed to open game %d (file %s) for viewing", gid, basename); jmsg = json_pack("{si}", "return", FALSE); client_msg("view_start", jmsg); return; } ret = nh_view_replay_start(fd, &server_alt_windowprocs, &info); jmsg = json_pack("{si,s:{ss,si,si,si,si}}", "return", ret, "info", "nextcmd", info.nextcmd, "actions", info.actions, "max_actions", info.max_actions, "moves", info.moves, "max_moves", info.max_moves); client_msg("view_start", jmsg); }
void replay_commandloop(int fd) { int key, move, count; char buf[BUFSZ], qbuf[BUFSZ]; nh_bool ret, firsttime = TRUE; struct nh_replay_info rinfo; struct nh_cmd_arg noarg; struct nh_cmd_desc *cmd; create_game_windows(); if (!nh_view_replay_start(fd, &curses_replay_windowprocs, &rinfo)) return; load_keymap(); while (1) { draw_msgwin(); curses_update_status(NULL); draw_sidebar(); draw_replay_info(&rinfo); if (firsttime) show_replay_help(); firsttime = FALSE; key = get_map_key(TRUE); switch (key) { /* step forward */ case KEY_RIGHT: case ' ': ret = nh_view_replay_step(&rinfo, REPLAY_FORWARD, 1); draw_replay_info(&rinfo); if (ret == FALSE) { key = curses_msgwin("You have reached the end of this game. " "Go back or press ESC to exit."); if (key == KEY_ESC) goto out; } break; /* step backward */ case KEY_LEFT: nh_view_replay_step(&rinfo, REPLAY_BACKWARD, 1); draw_replay_info(&rinfo); break; case KEY_ESC: goto out; case 'g': strncpy(qbuf, "What move do you want to jump to?", BUFSZ); if (rinfo.max_moves > 0) sprintf(qbuf + strlen(qbuf), " (Max: %d)", rinfo.max_moves); curses_getline(qbuf, buf); if (buf[0] == '\033' || !(move = atoi(buf))) break; nh_view_replay_step(&rinfo, REPLAY_GOTO, move); break; case KEY_F(12): /* timetest! */ if (allow_timetest()) timetest(fd, &rinfo); break; default: count = 0; noarg.argtype = CMD_ARG_NONE; cmd = keymap[key]; if (!cmd) break; if (cmd->flags & CMD_UI) handle_internal_cmd(&cmd, &noarg, &count); if (cmd) nh_command(cmd->name, count, &noarg); break; } } out: nh_view_replay_finish(); free_keymap(); destroy_game_windows(); cleanup_messages(); }
static void timetest(int fd, struct nh_replay_info *rinfo) { char buf[BUFSZ]; hp_time t_start, t_end; long ms; int mmax, initial, revpos; initial = rinfo->moves; nh_view_replay_step(rinfo, REPLAY_GOTO, 0); /* run forward */ gettime(&t_start); while (rinfo->actions < rinfo->max_actions) { nh_view_replay_step(rinfo, REPLAY_FORWARD, 1); curses_update_status(NULL); draw_replay_info(rinfo); doupdate(); } draw_msgwin(); gettime(&t_end); ms = clock_delta_ms(&t_start, &t_end); snprintf(buf, BUFSZ, "%d actions replayed with display in %ld ms. (%ld actions/sec)", rinfo->max_actions, ms, rinfo->max_actions * 1000 / ms); curses_msgwin(buf); /* reset the entire replay state to delete checkpoints */ mmax = rinfo->moves; /* max_moves may not be available if this is a replay of a crashed game */ nh_view_replay_finish(); nh_view_replay_start(fd, &curses_replay_windowprocs, rinfo); /* run forward without showing the map etc. */ gettime(&t_start); nh_view_replay_step(rinfo, REPLAY_GOTO, mmax); gettime(&t_end); ms = clock_delta_ms(&t_start, &t_end); snprintf(buf, BUFSZ, "%d actions replayed without display in %ld ms. (%ld actions/sec)", rinfo->actions, ms, rinfo->actions * 1000 / ms); curses_msgwin(buf); /* run backward */ revpos = rinfo->actions; gettime(&t_start); while (rinfo->actions > 0 && revpos < rinfo->actions + 1000) { nh_view_replay_step(rinfo, REPLAY_BACKWARD, 1); curses_update_status(NULL); draw_msgwin(); draw_replay_info(rinfo); doupdate(); } gettime(&t_end); ms = clock_delta_ms(&t_start, &t_end); snprintf(buf, BUFSZ, "%d actions replayed backward with display in %ld ms. (%ld actions/sec)", revpos - rinfo->actions, ms, (revpos - rinfo->actions) * 1000 / ms); curses_msgwin(buf); nh_view_replay_step(rinfo, REPLAY_GOTO, initial); }