Пример #1
0
/**
**  Wait for interactive input event for one frame.
**
**  Handles system events, joystick, keyboard, mouse.
**  Handles the network messages.
**  Handles the sound queue.
**
**  All events available are fetched. Sound and network only if available.
**  Returns if the time for one frame is over.
*/
void WaitEventsOneFrame()
{
	++FrameCounter;

	Uint32 ticks = SDL_GetTicks();
	if (ticks > NextFrameTicks) { // We are too slow :(
		++SlowFrameCounter;
	}

	InputMouseTimeout(*GetCallbacks(), ticks);
	InputKeyTimeout(*GetCallbacks(), ticks);
	CursorAnimate(ticks);

	int interrupts = 0;

	for (;;) {
		// Time of frame over? This makes the CPU happy. :(
		ticks = SDL_GetTicks();
		if (!interrupts && ticks < NextFrameTicks) {
			SDL_Delay(NextFrameTicks - ticks);
			ticks = SDL_GetTicks();
		}
		while (ticks >= NextFrameTicks) {
			++interrupts;
			FrameFraction += FrameRemainder;
			if (FrameFraction > 10) {
				FrameFraction -= 10;
				++NextFrameTicks;
			}
			NextFrameTicks += FrameTicks;
		}

		SDL_Event event[1];
		const int i = SDL_PollEvent(event);
		if (i) { // Handle SDL event
			SdlDoEvent(*GetCallbacks(), *event);
		}

		// Network
		int s = 0;
		if (IsNetworkGame()) {
			s = NetworkFildes.HasDataToRead(0);
			if (s > 0) {
				GetCallbacks()->NetworkEvent();
			}
		}
		// No more input and time for frame over: return
		if (!i && s <= 0 && interrupts) {
			break;
		}
	}
	handleInput(NULL);

	if (!SkipGameCycle--) {
		SkipGameCycle = SkipFrames;
	}
}
Пример #2
0
void Emulator::Run()
{
	if (!IsReady())
	{
		Load();
		if(!IsReady()) return;
	}

	if (IsRunning()) Stop();

	if (IsPaused())
	{
		Resume();
		return;
	}

	
	GetCallbacks().on_run();

	m_pause_start_time = 0;
	m_pause_amend_time = 0;
	m_state = system_state::running;

	auto on_select = [](u32, cpu_thread& cpu)
	{
		cpu.run();
	};

	idm::select<ppu_thread>(on_select);
	idm::select<ARMv7Thread>(on_select);
	idm::select<RawSPUThread>(on_select);
	idm::select<SPUThread>(on_select);
}
Пример #3
0
bool Emulator::Pause()
{
	const u64 start = get_system_time();

	// Try to pause
	if (!m_state.compare_and_swap_test(system_state::running, system_state::paused))
	{
		return m_state.compare_and_swap_test(system_state::ready, system_state::paused);
	}

	GetCallbacks().on_pause();

	// Update pause start time
	if (m_pause_start_time.exchange(start))
	{
		LOG_ERROR(GENERAL, "Emulator::Pause() error: concurrent access");
	}

	auto on_select = [](u32, cpu_thread& cpu)
	{
		cpu.state += cpu_flag::dbg_global_pause;
	};

	idm::select<ppu_thread>(on_select);
	idm::select<ARMv7Thread>(on_select);
	idm::select<RawSPUThread>(on_select);
	idm::select<SPUThread>(on_select);

	if (auto mfc = fxm::check<mfc_thread>())
	{
		on_select(0, *mfc);
	}

	return true;
}
Пример #4
0
SndSysOggSoundStream::SndSysOggSoundStream (csRef<SndSysOggSoundData> pData, 
					    OggDataStore *pDataStore, csSndSysSoundFormat *pRenderFormat, 
              int Mode3D) :
  SndSysBasicStream(pRenderFormat, Mode3D)
{
  // Initialize the stream data
  m_StreamData.datastore=pDataStore;
  m_StreamData.position=0;

  m_pSoundData=pData;

  // Allocate an advance buffer
  m_pCyclicBuffer = new SoundCyclicBuffer (
    (m_RenderFormat.Bits/8 * m_RenderFormat.Channels) * 
      (m_RenderFormat.Freq * OGG_BUFFER_LENGTH_MULTIPLIER / 
	OGG_BUFFER_LENGTH_DIVISOR));
  CS_ASSERT(m_pCyclicBuffer!=0);

  // Initialize ogg file
  memset(&m_VorbisFile,0,sizeof(OggVorbis_File));
  ov_open_callbacks (&m_StreamData,&m_VorbisFile,0,0,
    *(ov_callbacks*)GetCallbacks());

  // Set to not a valid stream
  m_CurrentOggStream=-1;
}
Пример #5
0
int TrackCount(const char* strFile)
{
  VorbisContext* ctx = new VorbisContext;
  ctx->file = XBMC->OpenFile(strFile, 4);
  if (!ctx->file)
  {
    delete ctx;
    return 1;
  }
  ctx->callbacks = GetCallbacks(strFile);

  if (ov_open_callbacks(ctx->file, &ctx->vorbisfile,
                        NULL, 0, ctx->callbacks) != 0)
  {
    delete ctx;
    return 1;
  }

  long iStreams=ov_streams(&ctx->vorbisfile);

  ov_clear(&ctx->vorbisfile);
  delete ctx;

  return iStreams;
}
bool PlayListContainer::Load(sp_playlistcontainer *container) {
    container_ = container;
    sp_playlistcontainer_callbacks callbacks;
    GetCallbacks(&callbacks);
    sp_playlistcontainer_add_callbacks(container_, &callbacks, this);
    loading_ = true;
    return true;
}
Пример #7
0
void Emulator::Stop()
{
	if (m_status.exchange(Stopped) == Stopped)
	{
		return;
	}

	LOG_NOTICE(GENERAL, "Stopping emulator...");

	rpcs3::on_stop()();
	SendDbgCommand(DID_STOP_EMU);

	{
		LV2_LOCK;

		idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
		{
			cpu.state += cpu_state::dbg_global_stop;
			cpu->lock();
			cpu->set_exception(std::make_exception_ptr(EmulationStopped()));
			cpu->unlock();
			cpu->notify();
		});
	}

	LOG_NOTICE(GENERAL, "All threads signaled...");

	while (g_thread_count)
	{
		m_cb.process_events();

		std::this_thread::sleep_for(10ms);
	}

	LOG_NOTICE(GENERAL, "All threads stopped...");

	idm::clear();
	fxm::clear();

	LOG_NOTICE(GENERAL, "Objects cleared...");

	GetCallbackManager().Clear();

	RSXIOMem.Clear();
	vm::close();

	SendDbgCommand(DID_STOPPED_EMU);

	if (g_cfg_autoexit)
	{
		GetCallbacks().exit();
	}
	else
	{
		Init();
	}
}
void PlayListContainer::Unload() {
    if (container_) {
        sp_playlistcontainer_callbacks callbacks;
        GetCallbacks(&callbacks);
        sp_playlistcontainer_remove_callbacks(container_, &callbacks, this);
        container_ = NULL;
        playlists_.clear();
        loading_ = false;
    }
}
Пример #9
0
void Emulator::Stop()
{
	if (m_status.exchange(Stopped) == Stopped)
	{
		return;
	}

	LOG_NOTICE(GENERAL, "Stopping emulator...");

	rpcs3::on_stop()();
	SendDbgCommand(DID_STOP_EMU);

	{
		LV2_LOCK;

		for (auto& thread : get_all_cpu_threads())
		{
			thread->state += cpu_state::dbg_global_stop;
			thread->safe_notify();
		}
	}

	LOG_NOTICE(GENERAL, "All threads signaled...");

	while (g_thread_count)
	{
		m_cb.process_events();

		std::this_thread::sleep_for(10ms);
	}

	LOG_NOTICE(GENERAL, "All threads stopped...");

	idm::clear();
	fxm::clear();

	LOG_NOTICE(GENERAL, "Objects cleared...");

	GetCallbackManager().Clear();

	RSXIOMem.Clear();
	vm::close();

	SendDbgCommand(DID_STOPPED_EMU);

	if (g_cfg_autoexit)
	{
		GetCallbacks().exit();
	}
	else
	{
		Init();
	}
}
Пример #10
0
/**
**  Game main loop.
**
**  Unit actions.
**  Missile actions.
**  Players (AI).
**  Cyclic events (color cycle,...)
**  Display update.
**  Input/Network/Sound.
*/
void GameMainLoop()
{
	const EventCallback *old_callbacks;

	InitGameCallbacks();

	old_callbacks = GetCallbacks();
	SetCallbacks(&GameCallbacks);

	SetVideoSync();
	GameCursor = UI.Point.Cursor;
	GameRunning = true;

	CParticleManager::init();

#ifdef REALVIDEO
	RealVideoSyncSpeed = VideoSyncSpeed;
#endif

	CclCommand("if (GameStarting ~= nil) then GameStarting() end");

	MultiPlayerReplayEachCycle();

	SingleGameLoop();

	//
	// Game over
	//
	if (GameResult == GameExit) {
		Exit(0);
		return;
	}

#ifdef REALVIDEO
	if (FastForwardCycle > GameCycle) {
		VideoSyncSpeed = RealVideoSyncSpeed;
	}
#endif
	NetworkQuitGame();
	EndReplayLog();

	GameCycle = 0;//????
	CParticleManager::exit();
	FlagRevealMap = 0;
	ReplayRevealMap = 0;
	GamePaused = false;
	GodMode = false;

	SetCallbacks(old_callbacks);
}
Пример #11
0
JSBool
Library::Open(JSContext* cx, uintN argc, jsval *vp)
{
  JSObject* ctypesObj = JS_THIS_OBJECT(cx, vp);
  if (!ctypesObj || !IsCTypesGlobal(cx, ctypesObj)) {
    JS_ReportError(cx, "not a ctypes object");
    return JS_FALSE;
  }

  if (argc != 1 || JSVAL_IS_VOID(JS_ARGV(cx, vp)[0])) {
    JS_ReportError(cx, "open requires a single argument");
    return JS_FALSE;
  }

  JSObject* library = Create(cx, JS_ARGV(cx, vp)[0], GetCallbacks(cx, ctypesObj));
  if (!library)
    return JS_FALSE;

  JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(library));
  return JS_TRUE;
}
Пример #12
0
void Emulator::Resume()
{
	// Get pause start time
	const u64 time = m_pause_start_time.exchange(0);

	// Try to increment summary pause time
	if (time)
	{
		m_pause_amend_time += get_system_time() - time;
	}

	// Try to resume
	if (!m_state.compare_and_swap_test(system_state::paused, system_state::running))
	{
		return;
	}

	if (!time)
	{
		LOG_ERROR(GENERAL, "Emulator::Resume() error: concurrent access");
	}

	auto on_select = [](u32, cpu_thread& cpu)
	{
		cpu.state -= cpu_flag::dbg_global_pause;
		cpu.notify();
	};

	idm::select<ppu_thread>(on_select);
	idm::select<ARMv7Thread>(on_select);
	idm::select<RawSPUThread>(on_select);
	idm::select<SPUThread>(on_select);

	if (auto mfc = fxm::check<mfc_thread>())
	{
		on_select(0, *mfc);
	}

	GetCallbacks().on_resume();
}
Пример #13
0
/**
**  Show a title image
*/
void TitleScreen::ShowTitleImage()
{
	const EventCallback *old_callbacks = GetCallbacks();
	EventCallback callbacks;

	WaitNoEvent = true;

	callbacks.ButtonPressed = WaitCallbackButtonPressed;
	callbacks.ButtonReleased = WaitCallbackButtonReleased;
	callbacks.MouseMoved = WaitCallbackMouse;
	callbacks.MouseExit = WaitCallbackExit;
	callbacks.KeyPressed = WaitCallbackKeyPressed;
	callbacks.KeyReleased = WaitCallbackKeyReleased;
	callbacks.KeyRepeated = WaitCallbackKeyRepeated;
	//callbacks.NetworkEvent = NetworkEvent;
	callbacks.NetworkEvent = nullptr;

	SetCallbacks(&callbacks);

	CGraphic *g = CGraphic::New(this->File);
	g->Load();
	if (this->StretchImage) {
		g->Resize(Video.Width, Video.Height);
	}

	int timeout = this->Timeout ? this->Timeout * CYCLES_PER_SECOND : -1;

	while (timeout-- && WaitNoEvent) {
		g->DrawClip((Video.Width - g->Width) / 2, (Video.Height - g->Height) / 2);
		this->ShowLabels();

		Invalidate();
		RealizeVideoMemory();
		WaitEventsOneFrame();
	}

	SetCallbacks(old_callbacks);
	CGraphic::Free(g);
}
Пример #14
0
bool
Library::Open(JSContext* cx, unsigned argc, Value* vp)
{
  CallArgs args = CallArgsFromVp(argc, vp);
  JSObject* ctypesObj = JS_THIS_OBJECT(cx, vp);
  if (!ctypesObj)
    return false;
  if (!IsCTypesGlobal(ctypesObj)) {
    JS_ReportErrorASCII(cx, "not a ctypes object");
    return false;
  }

  if (args.length() != 1 || args[0].isUndefined()) {
    JS_ReportErrorASCII(cx, "open requires a single argument");
    return false;
  }

  JSObject* library = Create(cx, args[0], GetCallbacks(ctypesObj));
  if (!library)
    return false;

  args.rval().setObject(*library);
  return true;
}
Пример #15
0
/**
**  Game main loop.
**
**  Unit actions.
**  Missile actions.
**  Players (AI).
**  Cyclic events (color cycle,...)
**  Display update.
**  Input/Network/Sound.
*/
void GameMainLoop()
{
	const EventCallback *old_callbacks;

	InitGameCallbacks();

	old_callbacks = GetCallbacks();
	SetCallbacks(&GameCallbacks);

	SetVideoSync();
	GameCursor = UI.Point.Cursor;
	//Wyrmgus start
	GameEstablishing = false;
	//Wyrmgus end
	GameRunning = true;

	CParticleManager::init();

#ifdef REALVIDEO
	RealVideoSyncSpeed = VideoSyncSpeed;
#endif

	CclCommand("if (GameStarting ~= nil) then GameStarting() end");

	MultiPlayerReplayEachCycle();
	
	//Wyrmgus start
	if (GameCycle == 0) { // so that these don't trigger when loading a saved game
		if (CurrentCampaign != NULL) {
			for (int i = 0; i < NumPlayers; ++i) {
				if (Players[i].Type != PlayerNobody && Players[i].Race != 0 && Players[i].Faction != -1) {
					if (CurrentCampaign->StartDate.year) {
						CCivilization *civilization = PlayerRaces.Civilizations[Players[i].Race];
						CFaction *faction = PlayerRaces.Factions[Players[i].Race][Players[i].Faction];
						
						for (std::map<std::string, std::map<CDate, bool>>::iterator iterator = civilization->HistoricalUpgrades.begin(); iterator != civilization->HistoricalUpgrades.end(); ++iterator) {
							int upgrade_id = UpgradeIdByIdent(iterator->first);
							if (upgrade_id == -1) {
								fprintf(stderr, "Upgrade \"%s\" doesn't exist.\n", iterator->first.c_str());
								continue;
							}
							for (std::map<CDate, bool>::reverse_iterator second_iterator = iterator->second.rbegin(); second_iterator != iterator->second.rend(); ++second_iterator) {
								if (second_iterator->first.year == 0 || CurrentCampaign->StartDate >= second_iterator->first) {
									if (second_iterator->second && UpgradeIdentAllowed(Players[i], iterator->first.c_str()) != 'R') {
										UpgradeAcquire(Players[i], AllUpgrades[upgrade_id]);
									} else if (!second_iterator->second) {
										break;
									}
								}
							}
						}
						
						for (std::map<std::string, std::map<CDate, bool>>::iterator iterator = faction->HistoricalUpgrades.begin(); iterator != faction->HistoricalUpgrades.end(); ++iterator) {
							int upgrade_id = UpgradeIdByIdent(iterator->first);
							if (upgrade_id == -1) {
								fprintf(stderr, "Upgrade \"%s\" doesn't exist.\n", iterator->first.c_str());
								continue;
							}
							for (std::map<CDate, bool>::reverse_iterator second_iterator = iterator->second.rbegin(); second_iterator != iterator->second.rend(); ++second_iterator) {
								if (second_iterator->first.year == 0 || CurrentCampaign->StartDate >= second_iterator->first) {
									if (second_iterator->second && UpgradeIdentAllowed(Players[i], iterator->first.c_str()) != 'R') {
										UpgradeAcquire(Players[i], AllUpgrades[upgrade_id]);
									} else if (!second_iterator->second) {
										break;
									}
								}
							}
						}

						for (std::map<std::pair<int, CFaction *>, int>::iterator iterator = faction->HistoricalDiplomacyStates.begin(); iterator != faction->HistoricalDiplomacyStates.end(); ++iterator) { //set the appropriate historical diplomacy states to other factions
							if (iterator->second == 0 || CurrentCampaign->StartDate.year >= iterator->first.first) {
								CPlayer *diplomacy_state_player = GetFactionPlayer(iterator->first.second);
								if (diplomacy_state_player) {
									CommandDiplomacy(i, iterator->second, diplomacy_state_player->Index);
									CommandDiplomacy(diplomacy_state_player->Index, iterator->second, i);
									if (iterator->second == DiplomacyAllied) {
										CommandSharedVision(i, true, diplomacy_state_player->Index);
										CommandSharedVision(diplomacy_state_player->Index, true, i);
									}
								}
							}
						}

						for (std::map<std::pair<CDate, int>, int>::iterator iterator = faction->HistoricalResources.begin(); iterator != faction->HistoricalResources.end(); ++iterator) { //set the appropriate historical resource quantities
							if (iterator->second == 0 || CurrentCampaign->StartDate >= iterator->first.first) {
								Players[i].SetResource(iterator->first.second, iterator->second);
							}
						}
					}
				}
			}
	
			if (CurrentCampaign->StartEffects) {
				CurrentCampaign->StartEffects->pushPreamble();
				CurrentCampaign->StartEffects->run();
			}
		}
		
		//if the person player has no faction, bring up the faction choice interface
		if (!GrandStrategy && ThisPlayer && ThisPlayer->Faction == -1) {
			char buf[256];
			snprintf(buf, sizeof(buf), "if (ChooseFaction ~= nil) then ChooseFaction(\"%s\", \"%s\") end", ThisPlayer->Race != -1 ? PlayerRaces.Name[ThisPlayer->Race].c_str() : "", "");
			CclCommand(buf);
		}
		
		if (!IsNetworkGame() && ThisPlayer && CurrentCustomHero != NULL) {
			Vec2i resPos;
			FindNearestDrop(*CurrentCustomHero->Type, ThisPlayer->StartPos, resPos, LookingW, ThisPlayer->StartMapLayer);
			CUnit *custom_hero = MakeUnitAndPlace(resPos, *CurrentCustomHero->Type, ThisPlayer, ThisPlayer->StartMapLayer);
			custom_hero->SetCharacter(CurrentCustomHero->Ident, true);	
		}
		
		if (CurrentQuest != NULL && CurrentQuest->IntroductionDialogue != NULL) {
			CurrentQuest->IntroductionDialogue->Call(ThisPlayer->Index);
		}
	}
	//Wyrmgus end

	SingleGameLoop();

	//
	// Game over
	//
	if (GameResult == GameExit) {
		Exit(0);
		return;
	}

#ifdef REALVIDEO
	if (FastForwardCycle > GameCycle) {
		VideoSyncSpeed = RealVideoSyncSpeed;
	}
#endif
	NetworkQuitGame();
	EndReplayLog();

	GameCycle = 0;//????
	CParticleManager::exit();
	FlagRevealMap = 0;
	ReplayRevealMap = 0;
	GamePaused = false;
	GodMode = false;

	SetCallbacks(old_callbacks);
}
Пример #16
0
void Emulator::Load(bool add_only)
{
	Stop();

	try
	{
		Init();

		// Load game list (maps ABCD12345 IDs to /dev_bdvd/ locations) 
		YAML::Node games = YAML::Load(fs::file{fs::get_config_dir() + "/games.yml", fs::read + fs::create}.to_string());

		if (!games.IsMap())
		{
			games.reset();
		}

		LOG_NOTICE(LOADER, "Path: %s", m_path);

		const std::string elf_dir = fs::get_parent_dir(m_path);

		// Load PARAM.SFO (TODO)
		const auto _psf = psf::load_object([&]
		{
			if (fs::file sfov{elf_dir + "/sce_sys/param.sfo"})
			{
				return sfov;
			}
			else
			{
				return fs::file(elf_dir + "/../PARAM.SFO");
			}
		}());
		m_title = psf::get_string(_psf, "TITLE", m_path);
		m_title_id = psf::get_string(_psf, "TITLE_ID");
		const auto _cat = psf::get_string(_psf, "CATEGORY");

		LOG_NOTICE(LOADER, "Title: %s", GetTitle());
		LOG_NOTICE(LOADER, "Serial: %s", GetTitleID());

		// Initialize data/cache directory
		m_cache_path = fs::get_data_dir(m_title_id, m_path);
		LOG_NOTICE(LOADER, "Cache: %s", GetCachePath());

		// Load custom config-0
		if (fs::file cfg_file{m_cache_path + "/config.yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: %s/config.yml", m_cache_path);
			g_cfg.from_string(cfg_file.to_string());
		}

		// Load custom config-1
		if (fs::file cfg_file{fs::get_config_dir() + "data/" + m_title_id + "/config.yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: data/%s/config.yml", m_title_id);
			g_cfg.from_string(cfg_file.to_string());
		}

		// Load custom config-2
		if (fs::file cfg_file{m_path + ".yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: %s.yml", m_path);
			g_cfg.from_string(cfg_file.to_string());
		}

		LOG_NOTICE(LOADER, "Used configuration:\n%s\n", g_cfg.to_string());

		// Load patches from different locations
		fxm::check_unlocked<patch_engine>()->append(fs::get_config_dir() + "data/" + m_title_id + "/patch.yml");
		fxm::check_unlocked<patch_engine>()->append(m_cache_path + "/patch.yml");

		// Mount all devices
		const std::string emu_dir_ = g_cfg.vfs.emulator_dir;
		const std::string emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
		const std::string home_dir = g_cfg.vfs.app_home;
		std::string bdvd_dir = g_cfg.vfs.dev_bdvd;

		vfs::mount("dev_hdd0", fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_hdd1", fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_flash", fmt::replace_all(g_cfg.vfs.dev_flash, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_usb", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_usb000", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
		vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir));

		// Detect boot location
		const std::string hdd0_game = vfs::get("/dev_hdd0/game/");
		const std::string hdd0_disc = vfs::get("/dev_hdd0/disc/");

		if (_cat == "DG" && m_path.find(hdd0_game + m_title_id + '/') != -1)
		{
			// Booting disc game from wrong location
			LOG_ERROR(LOADER, "Disc game found at invalid location: /dev_hdd0/game/%s/", m_title_id);

			// Move and retry from correct location
			if (fs::rename(hdd0_game + m_title_id, hdd0_disc + m_title_id))
			{
				LOG_SUCCESS(LOADER, "Disc game moved to special location: /dev_hdd0/disc/%s/", m_title_id);
				return SetPath(hdd0_disc + m_path.substr(hdd0_game.size())), Load();
			}
			else
			{
				LOG_ERROR(LOADER, "Failed to move disc game to /dev_hdd0/disc/%s/ (%s)", m_title_id, fs::g_tls_error);
				return;
			}
		}

		// Booting disc game
		if (_cat == "DG" && bdvd_dir.empty())
		{
			// Mount /dev_bdvd/ if necessary
			if (auto pos = elf_dir.rfind("/PS3_GAME") + 1)
			{
				bdvd_dir = elf_dir.substr(0, pos);
			}
		}

		// Booting patch data
		if (_cat == "GD" && bdvd_dir.empty())
		{
			// Load /dev_bdvd/ from game list if available
			if (auto node = games[m_title_id])
			{
				bdvd_dir = node.Scalar();
			}
			else
			{
				LOG_FATAL(LOADER, "Disc directory not found. Try to run the game from the actual game disc directory.");
			}
		}

		// Check /dev_bdvd/
		if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
		{
			fs::file sfb_file;

			vfs::mount("dev_bdvd", bdvd_dir);
			LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd"));

			if (!sfb_file.open(vfs::get("/dev_bdvd/PS3_DISC.SFB")) || sfb_file.size() < 4 || sfb_file.read<u32>() != ".SFB"_u32)
			{
				LOG_ERROR(LOADER, "Invalid disc directory for the disc game %s", m_title_id);
				return;
			}

			const std::string bdvd_title_id = psf::get_string(psf::load_object(fs::file{vfs::get("/dev_bdvd/PS3_GAME/PARAM.SFO")}), "TITLE_ID");

			if (bdvd_title_id != m_title_id)
			{
				LOG_ERROR(LOADER, "Unexpected disc directory for the disc game %s (found %s)", m_title_id, bdvd_title_id);
				return;
			}

			// Store /dev_bdvd/ location
			games[m_title_id] = bdvd_dir;
			YAML::Emitter out;
			out << games;
			fs::file(fs::get_config_dir() + "/games.yml", fs::rewrite).write(out.c_str(), out.size());
		}
		else if (_cat == "DG" || _cat == "GD")
		{
			LOG_ERROR(LOADER, "Failed to mount disc directory for the disc game %s", m_title_id);
			return;
		}

		if (add_only)
		{
			LOG_NOTICE(LOADER, "Finished to add data to games.yml by boot for: %s", m_path);
			return;
		}

		// Check game updates
		const std::string hdd0_boot = hdd0_game + m_title_id + "/USRDIR/EBOOT.BIN";

		if (_cat == "DG" && fs::is_file(hdd0_boot))
		{
			// Booting game update
			LOG_SUCCESS(LOADER, "Updates found at /dev_hdd0/game/%s/!", m_title_id);
			return SetPath(hdd0_boot), Load();
		}

		// Mount /host_root/ if necessary
		if (g_cfg.vfs.host_root)
		{
			vfs::mount("host_root", {});
		}

		// Open SELF or ELF
		fs::file elf_file(m_path);

		if (!elf_file)
		{
			LOG_ERROR(LOADER, "Failed to open executable: %s", m_path);
			return;
		}

		// Check SELF header
		if (elf_file.size() >= 4 && elf_file.read<u32>() == "SCE\0"_u32)
		{
			const std::string decrypted_path = m_cache_path + "boot.elf";

			fs::stat_t encrypted_stat = elf_file.stat();
			fs::stat_t decrypted_stat;

			// Check modification time and try to load decrypted ELF
			if (fs::stat(decrypted_path, decrypted_stat) && decrypted_stat.mtime == encrypted_stat.mtime)
			{
				elf_file.open(decrypted_path);
			}
			else
			{
				// Decrypt SELF
				elf_file = decrypt_self(std::move(elf_file));

				if (fs::file elf_out{decrypted_path, fs::rewrite})
				{
					elf_out.write(elf_file.to_vector<u8>());
					elf_out.close();
					fs::utime(decrypted_path, encrypted_stat.atime, encrypted_stat.mtime);
				}
				else
				{
					LOG_ERROR(LOADER, "Failed to create boot.elf");
				}
			}
		}

		ppu_exec_object ppu_exec;
		ppu_prx_object ppu_prx;
		spu_exec_object spu_exec;
		arm_exec_object arm_exec;

		if (!elf_file)
		{
			LOG_ERROR(LOADER, "Failed to decrypt SELF: %s", m_path);
			return;
		}
		else if (ppu_exec.open(elf_file) == elf_error::ok)
		{
			// PS3 executable
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();

			vm::ps3::init();

			if (m_elf_path.empty())
			{
				if (m_path.find(hdd0_game) != -1)
				{
					m_elf_path = "/dev_hdd0/game/" + m_path.substr(hdd0_game.size());
				}
				else if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
				{
					//Disc games are on /dev_bdvd/
					size_t pos = m_path.rfind("PS3_GAME");
					m_elf_path = "/dev_bdvd/" + m_path.substr(pos);
				}
				else
				{
					//For homebrew
					m_elf_path = "/host_root/" + m_path;
				}

				LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
			}

			ppu_load_exec(ppu_exec);

			fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall
		}
		else if (ppu_prx.open(elf_file) == elf_error::ok)
		{
			// PPU PRX (experimental)
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::ps3::init();
			ppu_load_prx(ppu_prx, m_path);
		}
		else if (spu_exec.open(elf_file) == elf_error::ok)
		{
			// SPU executable (experimental)
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::ps3::init();
			spu_load_exec(spu_exec);
		}
		else if (arm_exec.open(elf_file) == elf_error::ok)
		{
			// ARMv7 executable
			g_system = system_type::psv;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::psv::init();

			if (m_elf_path.empty())
			{
				m_elf_path = "host_root:" + m_path;
				LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
			}

			arm_load_exec(arm_exec);
		}
		else
		{
			LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path);

			LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error());
			LOG_WARNING(LOADER, "** ppu_prx  -> %s", ppu_prx.get_error());
			LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error());
			LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error());
			return;
		}

		if (g_cfg.misc.autostart && IsReady())
		{
			Run();
		}
		else if (IsPaused())
		{
			m_state = system_state::ready;
			GetCallbacks().on_ready();
		}
	}
	catch (const std::exception& e)
	{
		LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what());
		Stop();
	}
}
Пример #17
0
/**
**  Game main loop.
**
**  Unit actions.
**  Missile actions.
**  Players (AI).
**  Cyclic events (color cycle,...)
**  Display update.
**  Input/Network/Sound.
*/
void GameMainLoop()
{
	const EventCallback *old_callbacks;

	InitGameCallbacks();

	old_callbacks = GetCallbacks();
	SetCallbacks(&GameCallbacks);

	SetVideoSync();
	GameCursor = UI.Point.Cursor;
	GameRunning = true;

	CParticleManager::init();

#ifdef REALVIDEO
	RealVideoSyncSpeed = VideoSyncSpeed;
#endif

	CclCommand("if (GameStarting ~= nil) then GameStarting() end");

	MultiPlayerReplayEachCycle();
	
	//Wyrmgus start
	//if the person player has no faction, bring up the faction choice interface
	if (!GrandStrategy && ThisPlayer && ThisPlayer->Faction == -1) {
		char buf[256];
		snprintf(buf, sizeof(buf), "if (ChooseFaction ~= nil) then ChooseFaction(\"%s\", \"%s\") end", ThisPlayer->Race != -1 ? PlayerRaces.Name[ThisPlayer->Race].c_str() : "", "");
		CclCommand(buf);
	}
	
	if (!IsNetworkGame() && ThisPlayer && CurrentCustomHero != NULL) {
		Vec2i resPos;
		FindNearestDrop(*CurrentCustomHero->Type, ThisPlayer->StartPos, resPos, LookingW);
		CUnit *custom_hero = MakeUnitAndPlace(resPos, *CurrentCustomHero->Type, ThisPlayer);
		custom_hero->SetCharacter(CurrentCustomHero->GetFullName(), true);	
	}
	//Wyrmgus end

	SingleGameLoop();

	//
	// Game over
	//
	if (GameResult == GameExit) {
		Exit(0);
		return;
	}

#ifdef REALVIDEO
	if (FastForwardCycle > GameCycle) {
		VideoSyncSpeed = RealVideoSyncSpeed;
	}
#endif
	NetworkQuitGame();
	EndReplayLog();

	GameCycle = 0;//????
	//Wyrmgus start
	GameTimeOfDay = NoTimeOfDay;
	//Wyrmgus end
	CParticleManager::exit();
	FlagRevealMap = 0;
	ReplayRevealMap = 0;
	GamePaused = false;
	GodMode = false;

	SetCallbacks(old_callbacks);
}
Пример #18
0
/**
**  Game main loop.
**
**  Unit actions.
**  Missile actions.
**  Players (AI).
**  Cyclic events (color cycle,...)
**  Display update.
**  Input/Network/Sound.
*/
void GameMainLoop(void)
{
#ifdef DEBUG  // removes the setjmp warnings
	static bool showtip;
#else
	bool showtip;
#endif
	int player;
	int RealVideoSyncSpeed;
	const EventCallback *old_callbacks;

	InitGameCallbacks();

	old_callbacks = GetCallbacks();
	SetCallbacks(&GameCallbacks);

	SetVideoSync();
	GameCursor = UI.Point.Cursor;
	GameRunning = true;

	showtip = false;
	RealVideoSyncSpeed = VideoSyncSpeed;

	MultiPlayerReplayEachCycle();

	// StratagusAI MOD
	GamePaused = true;
	// Minimap.Update();
        
	while (GameRunning) {
		// StratagusAI MOD
		if ((GameCycle - socketInterface->lastPausedCycle) %
				socketInterface->cyclesPerTransition == 0) {
			socketInterface->handleInterface();
			if (socketInterface->warpSpeed)
				FastForwardCycle = GameCycle +
					socketInterface->cyclesPerTransition + 1;
		}

		// Can't find a better place.
		SaveGameLoading = 0;
		//
		// Game logic part
		//
		if (!GamePaused && NetworkInSync && !SkipGameCycle) {
			SinglePlayerReplayEachCycle();
			++GameCycle;
			MultiPlayerReplayEachCycle();
			NetworkCommands(); // Get network commands
			UnitActions();      // handle units
			MissileActions();   // handle missiles
			PlayersEachCycle(); // handle players
			UpdateTimer();      // update game timer

			//
			// Work todo each second.
			// Split into different frames, to reduce cpu time.
			// Increment mana of magic units.
			// Update mini-map.
			// Update map fog of war.
			// Call AI.
			// Check game goals.
			// Check rescue of units.
			//
			switch (GameCycle % CYCLES_PER_SECOND) {
				case 0: // At cycle 0, start all ai players...
					if (GameCycle == 0) {
						for (player = 0; player < NumPlayers; ++player) {
							PlayersEachSecond(player);
						}
					}
					break;
				case 1:
					break;
				case 2:
					break;
				case 3: // minimap update
					UI.Minimap.Update();
					break;
				case 4:
					break;
				case 5:
					break;
				case 6: // overtaking units
					RescueUnits();
					break;
				default:
					// FIXME: assume that NumPlayers < (CYCLES_PER_SECOND - 7)
					player = (GameCycle % CYCLES_PER_SECOND) - 7;
					Assert(player >= 0);
					if (player < NumPlayers) {
						PlayersEachSecond(player);
					}
			}
		}

		TriggersEachCycle();  // handle triggers
		UpdateMessages();     // update messages

		CheckMusicFinished(); // Check for next song

		//
		// Map scrolling
		//
		DoScrollArea(MouseScrollState | KeyScrollState, (KeyModifiers & ModifierControl) != 0);

		if (FastForwardCycle > GameCycle &&
				RealVideoSyncSpeed != VideoSyncSpeed) {
			RealVideoSyncSpeed = VideoSyncSpeed;
			VideoSyncSpeed = 3000;
		}

		// MOD
		if (socketInterface->cyclesPerVideoUpdate != -1 &&
				(GameCycle % socketInterface->cyclesPerVideoUpdate == 0 || GamePaused))
		{
			if (FastForwardCycle <= GameCycle || GameCycle <= 10 || !(GameCycle & 0x3f)) {
				//FIXME: this might be better placed somewhere at front of the
				// program, as we now still have a game on the background and
				// need to go through the game-menu or supply a map file
				UpdateDisplay();

				//
				// If double-buffered mode, we will display the contains of
				// VideoMemory. If direct mode this does nothing. In X11 it does
				// XFlush
				//
				RealizeVideoMemory();
			}
		}

		if (FastForwardCycle == GameCycle) {
			VideoSyncSpeed = RealVideoSyncSpeed;
		}
		if (FastForwardCycle <= GameCycle || !(GameCycle & 0x3f)) {
			WaitEventsOneFrame();
		}
		if (!NetworkInSync) {
			NetworkRecover(); // recover network
		}
	}

	//
	// Game over
	//
	if (FastForwardCycle > GameCycle) {
		VideoSyncSpeed = RealVideoSyncSpeed;
	}
	NetworkQuit();
	EndReplayLog();

	FlagRevealMap = 0;
	ReplayRevealMap = 0;
	GamePaused = false;
	GodMode = false;

	SetCallbacks(old_callbacks);
}
Пример #19
0
/**
**  Play a video file.
**
**  @param name   Filename of movie file.
**
**  @return       Non-zero if file isn't a supported movie.
*/
int PlayMovie(const std::string &name)
{
    OggData data;
    CFile f;
    SDL_Rect rect;
    SDL_Overlay *yuv_overlay;
    CSample *sample;
    const EventCallback *old_callbacks;
    EventCallback callbacks;
    unsigned int start_ticks;
    int need_data;
    int diff;
    char buffer[PATH_MAX];

    LibraryFileName(name.c_str(), buffer, sizeof(buffer));

    if (f.open(buffer, CL_OPEN_READ) == -1) {
        fprintf(stderr, "Can't open file `%s'\n", name.c_str());
        return -1;
    }

    memset(&data, 0, sizeof(data));
    if (OggInit(&f, &data) || !data.video) {
        OggFree(&data);
        f.close();
        return -1;
    }

    data.File = &f;

    if (data.tinfo.frame_width * 300 / 4 > data.tinfo.frame_height * 100) {
        rect.w = Video.Width;
        rect.h = Video.Width * data.tinfo.frame_height / data.tinfo.frame_width;
        rect.x = 0;
        rect.y = (Video.Height - rect.h) / 2;
    } else {
        rect.w = Video.Height * data.tinfo.frame_width / data.tinfo.frame_height;
        rect.h = Video.Height;
        rect.x = (Video.Width - rect.w) / 2;
        rect.y = 0;
    }

    yuv_overlay = SDL_CreateYUVOverlay(data.tinfo.frame_width,
                                       data.tinfo.frame_height, SDL_YV12_OVERLAY, TheScreen);

    if (yuv_overlay == NULL) {
        fprintf(stderr, "SDL_CreateYUVOverlay: %s\n", SDL_GetError());
        OggFree(&data);
        f.close();
        return 0;
    }

    StopMusic();
    if ((sample = LoadVorbis(buffer, PlayAudioStream))) {
        if ((sample->Channels != 1 && sample->Channels != 2) ||
                sample->SampleSize != 16) {
            fprintf(stderr, "Unsupported sound format in movie\n");
            delete sample;
            SDL_FreeYUVOverlay(yuv_overlay);
            OggFree(&data);
            f.close();
            return 0;
        }
        PlayMusic(sample);
    }

    callbacks.ButtonPressed = MovieCallbackButtonPressed;
    callbacks.ButtonReleased = MovieCallbackButtonReleased;
    callbacks.MouseMoved = MovieCallbackMouseMove;
    callbacks.MouseExit = MovieCallbackMouseExit;
    callbacks.KeyPressed = MovieCallbackKeyPressed;
    callbacks.KeyReleased = MovieCallbackKeyReleased;
    callbacks.KeyRepeated = MovieCallbackKeyRepeated;
    callbacks.NetworkEvent = NetworkEvent;

    old_callbacks = GetCallbacks();
    SetCallbacks(&callbacks);

    Invalidate();
    RealizeVideoMemory();

    MovieStop = false;
    start_ticks = SDL_GetTicks();
    need_data = 1;
    while (!MovieStop) {
        if (need_data) {
            if (TheoraProcessData(&data)) {
                break;
            }
            need_data = 0;
        }

        diff = SDL_GetTicks() - start_ticks - static_cast<int>(
                   theora_granule_time(&data.tstate, data.tstate.granulepos) * 1000);

        if (diff > 100) {
            // too far behind, skip some frames
            need_data = 1;
            continue;
        }
        if (diff > 0) {
            OutputTheora(&data, yuv_overlay, &rect);
            need_data = 1;
        }

        WaitEventsOneFrame();
    }

    StopMusic();
    SDL_FreeYUVOverlay(yuv_overlay);

    OggFree(&data);
    f.close();

    SetCallbacks(old_callbacks);

    return 0;
}
Пример #20
0
void* Init(const char* strFile, unsigned int filecache, int* channels,
           int* samplerate, int* bitspersample, int64_t* totaltime,
           int* bitrate, AEDataFormat* format, const AEChannel** channelinfo)
{
  VorbisContext* result = new VorbisContext;
  result->track=0;
  std::string toLoad(strFile);
  if (toLoad.find(".oggstream") != std::string::npos)
  {
    size_t iStart=toLoad.rfind('-') + 1;
    result->track = atoi(toLoad.substr(iStart, toLoad.size()-iStart-10).c_str());
    //  The directory we are in, is the file
    //  that contains the bitstream to play,
    //  so extract it
    size_t slash = toLoad.rfind('\\');
    if (slash == std::string::npos)
      slash = toLoad.rfind('/');
    toLoad = toLoad.substr(0, slash);
  }

  result->file = XBMC->OpenFile(toLoad.c_str(), 0);
  if (!result->file)
  {
    delete result;
    return NULL;
  }
  result->callbacks = GetCallbacks(strFile);

  if (ov_open_callbacks(result->file, &result->vorbisfile,
                         NULL, 0, result->callbacks) != 0)
  {
    delete result;
    return NULL;
  }

  long iStreams=ov_streams(&result->vorbisfile);
  if (iStreams>1)
  {
    if (result->track > iStreams)
    {
      DeInit(result);
      return NULL;
    }
  }

  //  Calculate the offset in secs where the bitstream starts
  result->timeoffset = 0;
  for (int i=0; i<result->track; ++i)
    result->timeoffset += ov_time_total(&result->vorbisfile, i);

  vorbis_info* pInfo=ov_info(&result->vorbisfile, result->track);
  if (!pInfo)
  {
    XBMC->Log(ADDON::LOG_ERROR, "OGGCodec: Can't get stream info from %s", toLoad.c_str());
    DeInit(result);
    return NULL;
  }

  *channels      = pInfo->channels;
  *samplerate    = pInfo->rate;
  *bitspersample = 16;
  *totaltime     = (int64_t)ov_time_total(&result->vorbisfile, result->track)*1000;
  *format        = AE_FMT_S16NE;
  static enum AEChannel map[8][9] = {
    {AE_CH_FC, AE_CH_NULL},
    {AE_CH_FL, AE_CH_FR, AE_CH_NULL},
    {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_NULL},
    {AE_CH_FL, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_NULL},
    {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_NULL},
    {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_LFE, AE_CH_NULL},
    {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_NULL},
    {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_LFE, AE_CH_NULL}
  };

  *channelinfo = NULL;
  if (*channels <= 8)
    *channelinfo = map[*channels - 1];
  *bitrate = pInfo->bitrate_nominal;

  if (*samplerate == 0 || *channels == 0 || *bitspersample == 0 || *totaltime == 0)
  {
    XBMC->Log(ADDON::LOG_ERROR, "OGGCodec: Can't get stream info, SampleRate=%i, Channels=%i, BitsPerSample=%i, TotalTime=%" PRIu64, *samplerate, *channels, *bitspersample, *totaltime);
    delete result;
    return NULL;
  }

  if (result->timeoffset > 0.0)
  {
    if (ov_time_seek(&result->vorbisfile, result->timeoffset)!=0)
    {
      XBMC->Log(ADDON::LOG_ERROR, "OGGCodec: Can't seek to the bitstream start time (%s)", toLoad.c_str());
      DeInit(result);
      return NULL;
    }
  }

  return result;
}
Пример #21
0
/**
**  Play a video file.
**
**  @param name   Filename of movie file.
**
**  @return       Non-zero if file isn't a supported movie.
*/
int PlayMovie(const std::string &name)
{
	int videoWidth, videoHeight;
#if defined(USE_OPENGL) || defined(USE_GLES)
	videoWidth  = Video.ViewportWidth;
	videoHeight = Video.ViewportHeight;
#else
	videoWidth  = Video.Width;
	videoHeight = Video.Height;
#endif

	const std::string filename = LibraryFileName(name.c_str());

	CFile f;
	if (f.open(filename.c_str(), CL_OPEN_READ) == -1) {
		fprintf(stderr, "Can't open file '%s'\n", name.c_str());
		return 0;
	}

	OggData data;
	memset(&data, 0, sizeof(data));
	if (OggInit(&f, &data) || !data.video) {
		OggFree(&data);
		f.close();
		return -1;
	}

	data.File = &f;
	SDL_Rect rect;

	if (data.tinfo.frame_width * 300 / 4 > data.tinfo.frame_height * 100) {
		rect.w = videoWidth;
		rect.h = videoWidth * data.tinfo.frame_height / data.tinfo.frame_width;
		rect.x = 0;
		rect.y = (videoHeight - rect.h) / 2;
	} else {
		rect.w = videoHeight * data.tinfo.frame_width / data.tinfo.frame_height;
		rect.h = videoHeight;
		rect.x = (videoWidth - rect.w) / 2;
		rect.y = 0;
	}

#ifdef USE_OPENGL
	// When SDL_OPENGL is used, it is not possible to call SDL_CreateYUVOverlay, so turn temporary OpenGL off
	// With GLES is all ok
	if (UseOpenGL) {
		SDL_SetVideoMode(Video.ViewportWidth, Video.ViewportHeight, Video.Depth, SDL_GetVideoSurface()->flags & ~SDL_OPENGL);
	}
#endif

	SDL_FillRect(SDL_GetVideoSurface(), NULL, 0);
	Video.ClearScreen();
	SDL_Overlay *yuv_overlay = SDL_CreateYUVOverlay(data.tinfo.frame_width, data.tinfo.frame_height, SDL_YV12_OVERLAY, TheScreen);

	if (yuv_overlay == NULL) {
		fprintf(stderr, "SDL_CreateYUVOverlay: %s\n", SDL_GetError());
		OggFree(&data);
		f.close();
		return 0;
	}

	StopMusic();
	CSample *sample = LoadVorbis(filename.c_str(), PlayAudioStream);
	if (sample) {
		if ((sample->Channels != 1 && sample->Channels != 2) || sample->SampleSize != 16) {
			fprintf(stderr, "Unsupported sound format in movie\n");
			delete sample;
			SDL_FreeYUVOverlay(yuv_overlay);
			OggFree(&data);
			f.close();
			return 0;
		}
		PlayMusic(sample);
	}

	EventCallback callbacks;

	callbacks.ButtonPressed = MovieCallbackButtonPressed;
	callbacks.ButtonReleased = MovieCallbackButtonReleased;
	callbacks.MouseMoved = MovieCallbackMouseMove;
	callbacks.MouseExit = MovieCallbackMouseExit;
	callbacks.KeyPressed = MovieCallbackKeyPressed;
	callbacks.KeyReleased = MovieCallbackKeyReleased;
	callbacks.KeyRepeated = MovieCallbackKeyRepeated;
	callbacks.NetworkEvent = NetworkEvent;

	const EventCallback *old_callbacks = GetCallbacks();
	SetCallbacks(&callbacks);

	Invalidate();
	RealizeVideoMemory();

	MovieStop = false;
	const unsigned int start_ticks = SDL_GetTicks();
	bool need_data = true;
	while (!MovieStop) {
		if (need_data) {
			if (TheoraProcessData(&data)) {
				break;
			}
			need_data = false;
		}

		const int diff = SDL_GetTicks() - start_ticks
						 - static_cast<int>(theora_granule_time(&data.tstate, data.tstate.granulepos) * 1000);

		if (diff > 100) {
			// too far behind, skip some frames
			need_data = true;
			continue;
		}
		if (diff > 0) {
			OutputTheora(&data, yuv_overlay, &rect);
			need_data = true;
		}

		WaitEventsOneFrame();
	}

	StopMusic();
	SDL_FreeYUVOverlay(yuv_overlay);

	OggFree(&data);
	f.close();

#ifdef USE_OPENGL
	if (UseOpenGL) {
		SDL_SetVideoMode(Video.ViewportWidth, Video.ViewportHeight, Video.Depth, SDL_GetVideoSurface()->flags | SDL_OPENGL);
		ReloadOpenGL();
	}
#endif

	SetCallbacks(old_callbacks);

	return 0;
}
Пример #22
0
/**
**  Game main loop.
**
**  Unit actions.
**  Missile actions.
**  Players (AI).
**  Cyclic events (color cycle,...)
**  Display update.
**  Input/Network/Sound.
*/
void GameMainLoop(void)
{
	int player;
	const EventCallback *old_callbacks;

	InitGameCallbacks();

	old_callbacks = GetCallbacks();
	SetCallbacks(&GameCallbacks);

	SetVideoSync();
	GameCursor = UI.Point.Cursor;
	GameRunning = true;

	CParticleManager::init();

	MultiPlayerReplayEachCycle();

	CclCommand("GameStarting()");

	std::ofstream output;
	std::wstring templ;
	firstClock = std::clock();
        templateClock = 0;
	int messageNumber = 1;
	std::ofstream outputEventsPerSec;
	std::ofstream outputNT;
	outputEventsPerSec.open("/tmp/boswarseventspersec.csv",std::ios::out);
   	outputNT.open("/tmp/boswarsclocksperevents.csv",std::ios::out);

	output.open("/tmp/beepbeep.fifo",std::ios::out);

	templ = templ = L"<message>\n"
				L"  <units>\n"
				    L"{% for unit in units.tabunits %}"
				    L"  <unit>\n"
				    L"    <id>{$unit.id}</id>\n"
				    L"    <type>{$unit.type}</type>\n"
				    L"    <isbuilding>{$unit.isbuilding}</isbuilding>\n"
				    L"    <player>{$unit.player}</player>\n"
				    L"    <order>\n"
				    L"      <action>{$unit.action}</action>\n"
				    L"      <goal>{$unit.goal}</goal>\n"
				    L"    </order>\n"
				    L"    <neworder>\n"
				    L"       <action>{$unit.neworder}</action>\n"
				    L"       <goal>{$unit.newgoal}</goal>\n"
				    L"    </neworder>\n"
				    L"  </unit>\n"
				    L"{% endfor %}"
             		   	L"  </units>\n"
				L"<overhead>{$overhead}</overhead>\n"
            		L"</message>\n"; 

	

	while (GameRunning) {

		// Can't find a better place.
		SaveGameLoading = false;
		//
		// Game logic part
		//
		if (!GamePaused && NetworkInSync && !SkipGameCycle) {
			SinglePlayerReplayEachCycle();
			++GameCycle;
			MultiPlayerReplayEachCycle();
			NetworkCommands();  // Get network commands
			UnitActions();      // handle units
			MissileActions();   // handle missiles
			PlayersEachCycle(); // handle players
			UpdateTimer();      // update game timer

			//
			// Work todo each second.
			// Split into different frames, to reduce cpu time.
			// Increment mana of magic units.
			// Update mini-map.
			// Update map fog of war.
			// Call AI.
			// Check game goals.
			// Check rescue of units.
			//
			switch (GameCycle % CYCLES_PER_SECOND) {
				case 0: // At cycle 0, start all ai players...
					if (GameCycle == 0) {
						for (player = 0; player < NumPlayers; ++player) {
							PlayersEachSecond(player);
						}
					}
					break;
				case 1:
					break;
				case 2:
					break;
				case 3: // minimap update
					UI.Minimap.Update();
					break;
				case 4:
					break;
				case 5:
					break;
				case 6: // overtaking units
					RescueUnits();
					break;
				default:
					// FIXME: assume that NumPlayers < (CYCLES_PER_SECOND - 7)
					player = (GameCycle % CYCLES_PER_SECOND) - 7;
					Assert(player >= 0);
					if (player < NumPlayers) {
						PlayersEachSecond(player);
					}
			}

			////////////GET INFORMATION FOR MONITORING!!!////////////////////
			
						

			if(NumUnits > 0)
			{
				std::clock_t littleClock = std::clock();
	
				cpptempl::data_list theUnits;
		    
		    		std::stringstream ss;

				for(int i = 0; i < NumUnits; i++)
				{
					cpptempl::data_map uni;

					/////////ID/////////
					ss.str("");
					ss << Units[i]->Slot;
					std::string theID = ss.str();
					std::wstring wTheID;
					wTheID.assign(theID.begin(),theID.end());
					uni[L"id"] = cpptempl::make_data(wTheID);

					//////UNITTYPE//////
					ss.str("");
					ss << Units[i]->Type->Name;
					std::string theType = ss.str();
					std::wstring wTheType;
					wTheType.assign(theType.begin(),theType.end());
					uni[L"type"] = cpptempl::make_data(wTheType);

					//////ISBUILDING//////
					ss.str("");
					if (Units[i]->Type->Building == 1)
						ss << "true";
					else
						ss << "false";
					std::string theIsBuilding = ss.str();
					std::wstring wTheIsBuilding;
					wTheIsBuilding.assign(theIsBuilding.begin(),theIsBuilding.end());
					uni[L"isbuilding"] = cpptempl::make_data(wTheIsBuilding);

					//////PLAYER//////
					ss.str("");
					ss << Units[i]->Player;
					std::string thePlayer = ss.str();
					std::wstring wThePlayer;
					wThePlayer.assign(thePlayer.begin(),thePlayer.end());
					uni[L"player"] = cpptempl::make_data(wThePlayer);

					//////UnitAction//////
					ss.str("");
					switch(Units[i]->Orders[0]->Action)
					{
					  	case UnitActionNone: ss << "UnitActionNone"; break;
						case UnitActionStill: ss << "UnitActionStill"; break;  
						case UnitActionStandGround: ss << "UnitActionStandGround"; break;
						case UnitActionFollow: ss << "UnitActionFollow"; break;    
						case UnitActionMove: ss << "UnitActionMove"; break;      
						case UnitActionAttack: ss << "UnitActionAttack"; break;   
						case UnitActionAttackGround: ss << "UnitActionAttackGround"; break;
						case UnitActionDie: ss << "UnitActionDie"; break;     

						case UnitActionSpellCast: ss << "UnitActionSpellCast"; break; 

						case UnitActionTrain: ss << "UnitActionTrain"; break;  
						case UnitActionBuilt: ss << "UnitActionBuilt"; break;   
						case UnitActionBoard: ss << "UnitActionBoard"; break;    
						case UnitActionUnload: ss << "UnitActionUnload"; break; 
						case UnitActionPatrol: ss << "UnitActionPatrol"; break; 
						case UnitActionBuild: ss << "UnitActionBuild"; break;

						case UnitActionRepair: ss << "UnitActionRepair"; break; 
						case UnitActionResource: ss << "UnitActionResource"; break;
						default: ss << "None";  
					}

					std::string theAction = ss.str();
					std::wstring wTheAction;
					wTheAction.assign(theAction.begin(),theAction.end());
					uni[L"action"] = cpptempl::make_data(wTheAction);

					//////UnitGoal//////
					ss.str("");
					if(Units[i]->Orders[0]->Goal != NULL)
						ss << Units[i]->Orders[0]->Goal->Slot;
					else
						ss << "None";
					std::string theGoal = ss.str();
					std::wstring wTheGoal;
					wTheGoal.assign(theGoal.begin(),theGoal.end());
					uni[L"goal"] = cpptempl::make_data(wTheGoal);

					///////NEW ORDER/////////
					ss.str("");
					switch(Units[i]->NewOrder.Action)
					{
					  	case UnitActionNone: ss << "UnitActionNone"; break;
						case UnitActionStill: ss << "UnitActionStill"; break;  
						case UnitActionStandGround: ss << "UnitActionStandGround"; break;
						case UnitActionFollow: ss << "UnitActionFollow"; break;    
						case UnitActionMove: ss << "UnitActionMove"; break;      
						case UnitActionAttack: ss << "UnitActionAttack"; break;   
						case UnitActionAttackGround: ss << "UnitActionAttackGround"; break;
						case UnitActionDie: ss << "UnitActionDie"; break;     

						case UnitActionSpellCast: ss << "UnitActionSpellCast"; break; 

						case UnitActionTrain: ss << "UnitActionTrain"; break;  
						case UnitActionBuilt: ss << "UnitActionBuilt"; break;   
						case UnitActionBoard: ss << "UnitActionBoard"; break;    
						case UnitActionUnload: ss << "UnitActionUnload"; break; 
						case UnitActionPatrol: ss << "UnitActionPatrol"; break; 
						case UnitActionBuild: ss << "UnitActionBuild"; break;

						case UnitActionRepair: ss << "UnitActionRepair"; break; 
						case UnitActionResource: ss << "UnitActionResource"; break;
						default: ss << "None";  
					}

					std::string theNewOrder = ss.str();
					std::wstring wTheNewOrder;
					wTheNewOrder.assign(theNewOrder.begin(),theNewOrder.end());
					uni[L"neworder"] = cpptempl::make_data(wTheNewOrder);

					//////NEW GOAL//////
					ss.str("");
					if(Units[i]->NewOrder.Goal != NULL)
						ss << Units[i]->NewOrder.Goal->Slot;
					else
						ss << "None";
					std::string theNewGoal = ss.str();
					std::wstring wTheNewGoal;
					wTheNewGoal.assign(theNewGoal.begin(),theNewGoal.end());
					uni[L"newgoal"] = cpptempl::make_data(wTheNewGoal);
			
					theUnits.push_back((cpptempl::make_data(uni)));
				}
				

				cpptempl::data_map lesUnits;
		    		lesUnits[L"tabunits"] = cpptempl::make_data(theUnits);

				// Now set this in the data map
				cpptempl::data_map data;
				data[L"units"] = cpptempl::make_data(lesUnits);

				//////////////////TIMESTAMP/////////////////////////
				std::clock_t t = std::clock() - firstClock;
				double timeStamp = ((double)t/(double)CLOCKS_PER_SEC);
				ss.str("");
				ss << std::setprecision(8) << timeStamp;
				std::string sTimeStamp = ss.str();
				std::string gnuPlotStringT = ss.str();
				std::wstring wTimeStamp;
				wTimeStamp.assign(sTimeStamp.begin(),sTimeStamp.end());
				data[L"timestamp"] = cpptempl::make_data(wTimeStamp);

				///OVERHEAD/////
				templateClock += std::clock()-littleClock;
				long double overhead = (long double)templateClock / ((long double)std::clock()-(long double)firstClock)*(long double)100.0;
				ss.str("");
				ss << std::setprecision(10) << overhead;
				std::string sOverhead = ss.str();
				std::wstring wOverhead;
				wOverhead.assign(sOverhead.begin(),sOverhead.end());
				data[L"overhead"] = cpptempl::make_data(wOverhead);
				std::cout << overhead << "% overhead\n";
				//std::cout << std::clock() << " clocl\n";

				/////////////////MESSAGENUMBER/////////////////////////<
			        ss.str("");
			        ss << messageNumber;
			        std::string gnuPlotStringN = ss.str();
			        std::string sMessageNumber = ss.str();
			        std::wstring wMessageNumber;
			        wMessageNumber.assign(sMessageNumber.begin(),sMessageNumber.end());
			        data[L"messagenumber"] = cpptempl::make_data(wMessageNumber);

				std::wstring result = cpptempl::parse(templ, data);
				
				ss.str("");
				
				double templateTime = ((double)templateClock/(double)CLOCKS_PER_SEC)*(double)1000;
				ss << std::setprecision(8) << templateTime;
				std::string templTime = ss.str();				
				
				double totalT = ((std::clock()-firstClock)/(double)CLOCKS_PER_SEC);
				std::cout << totalT << "totaltime\n";
				std::cout << CYCLES_PER_SECOND << "cycles\n";
				std::string s;
		    		s.assign(result.begin(), result.end());
				
				if (messageNumber == 1)
				{
					std::ofstream traceoutput;
					traceoutput.open("/tmp/traceout.xml",std::ios::out);
					traceoutput << s;
					traceoutput.close();
				}

				messageNumber++;

				/////STATS/////
								

				output << s;
		
				std::string out = gnuPlotStringN + "," + gnuPlotStringT + "\n";
				outputEventsPerSec << out;
		
				//OutputNT
				//std::string theT;
				out = "";
				//ss.str("");
				//ss << templTime;
				//theT = ss.str();
				out = templTime + "," + gnuPlotStringN + "\n";
				outputNT << out;
				
			}
			/////////////////////////////////////////////////////////////////
		}

		TriggersEachCycle();      // handle triggers
		UpdateMessages();         // update messages
		ParticleManager.update(); // handle particles

		CheckMusicFinished();     // Check for next song

		//
		// Map scrolling
		//
		DoScrollArea(MouseScrollState | KeyScrollState, (KeyModifiers & ModifierControl) != 0);

		if (FastForwardCycle <= GameCycle || GameCycle <= 10 || !(GameCycle & 0x3f)) {
			//FIXME: this might be better placed somewhere at front of the
			// program, as we now still have a game on the background and
			// need to go through the game-menu or supply a map file
			UpdateDisplay();

			//
			// If double-buffered mode, we will display the contains of
			// VideoMemory. If direct mode this does nothing. In X11 it does
			// XFlush
			//
			RealizeVideoMemory();
		}

		if (FastForwardCycle <= GameCycle || !(GameCycle & 0x3f)) {
			WaitEventsOneFrame();
		}
		if (!NetworkInSync) {
			NetworkRecover(); // recover network
		}

		
	}

	output.close();
	outputNT.close();
    	outputEventsPerSec.close();
	//
	// Game over
	//
	NetworkQuit();
	EndReplayLog();

	CParticleManager::exit();

	FlagRevealMap = 0;
	ReplayRevealMap = 0;
	GamePaused = false;
	GodMode = false;

	SetCallbacks(old_callbacks);
}
Пример #23
0
/**
**  Handle interactive input event.
**
**  @param callbacks  Callback structure for events.
**  @param event      SDL event structure pointer.
*/
static void SdlDoEvent(const EventCallback &callbacks, SDL_Event &event)
{
#if (defined(USE_OPENGL) || defined(USE_GLES))
	// Scale mouse-coordinates to viewport
	if (ZoomNoResize && (event.type & (SDL_MOUSEBUTTONUP | SDL_MOUSEBUTTONDOWN | SDL_MOUSEMOTION))) {
		event.button.x = (Uint16)floorf(event.button.x * float(Video.Width) / Video.ViewportWidth);
		event.button.y = (Uint16)floorf(event.button.y * float(Video.Height) / Video.ViewportHeight);
	}
#endif
	switch (event.type) {
		case SDL_MOUSEBUTTONDOWN:
			InputMouseButtonPress(callbacks, SDL_GetTicks(), event.button.button);
			break;

		case SDL_MOUSEBUTTONUP:
			InputMouseButtonRelease(callbacks, SDL_GetTicks(), event.button.button);
			break;

		// FIXME: check if this is only useful for the cursor
		// FIXME: if this is the case we don't need this.
		case SDL_MOUSEMOTION:
			InputMouseMove(callbacks, SDL_GetTicks(), event.motion.x, event.motion.y);
			// FIXME: Same bug fix from X11
			if ((UI.MouseWarpPos.x != -1 || UI.MouseWarpPos.y != -1)
				&& (event.motion.x != UI.MouseWarpPos.x || event.motion.y != UI.MouseWarpPos.y)) {
				int xw = UI.MouseWarpPos.x;
				int yw = UI.MouseWarpPos.y;
				UI.MouseWarpPos.x = -1;
				UI.MouseWarpPos.y = -1;
				SDL_WarpMouse(xw, yw);
			}
			break;

		case SDL_ACTIVEEVENT:
			if (event.active.state & SDL_APPMOUSEFOCUS) {
				static bool InMainWindow = true;

				if (InMainWindow && !event.active.gain) {
					InputMouseExit(callbacks, SDL_GetTicks());
				}
				InMainWindow = (event.active.gain != 0);
			}
			if (!IsNetworkGame() && Preference.PauseOnLeave && (event.active.state & SDL_APPACTIVE || SDL_GetAppState() & SDL_APPACTIVE)) {
				static bool DoTogglePause = false;

				if (IsSDLWindowVisible && !event.active.gain) {
					IsSDLWindowVisible = false;
					if (!GamePaused) {
						DoTogglePause = true;
						UiTogglePause();
					}
				} else if (!IsSDLWindowVisible && event.active.gain) {
					IsSDLWindowVisible = true;
					if (GamePaused && DoTogglePause) {
						DoTogglePause = false;
						UiTogglePause();
					}
				}
			}
			break;

		case SDL_KEYDOWN:
			if (GLShaderPipelineSupported
				&& event.key.keysym.sym == SDLK_SLASH
				&& event.key.keysym.mod & KMOD_ALT
				&& event.key.keysym.mod & KMOD_CTRL) {
				LoadShaders();
				break;
			}
			InputKeyButtonPress(callbacks, SDL_GetTicks(),
								event.key.keysym.sym, event.key.keysym.unicode);
			break;

		case SDL_KEYUP:
			InputKeyButtonRelease(callbacks, SDL_GetTicks(),
								  event.key.keysym.sym, event.key.keysym.unicode);
			break;

		case SDL_QUIT:
			Exit(0);
			break;
	}

	if (&callbacks == GetCallbacks()) {
		handleInput(&event);
	}
}
Пример #24
0
void Emulator::Stop()
{
	if (m_state.exchange(system_state::stopped) == system_state::stopped)
	{
		return;
	}

	LOG_NOTICE(GENERAL, "Stopping emulator...");

	GetCallbacks().on_stop();

#ifdef WITH_GDB_DEBUGGER
	//fxm for some reason doesn't call on_stop
	fxm::get<GDBDebugServer>()->on_stop();
	fxm::remove<GDBDebugServer>();
#endif

	auto e_stop = std::make_exception_ptr(cpu_flag::dbg_global_stop);

	auto on_select = [&](u32, cpu_thread& cpu)
	{
		cpu.state += cpu_flag::dbg_global_stop;
		cpu.get()->set_exception(e_stop);
	};

	idm::select<ppu_thread>(on_select);
	idm::select<ARMv7Thread>(on_select);
	idm::select<RawSPUThread>(on_select);
	idm::select<SPUThread>(on_select);

	if (auto mfc = fxm::check<mfc_thread>())
	{
		on_select(0, *mfc);
	}

	LOG_NOTICE(GENERAL, "All threads signaled...");

	while (g_thread_count)
	{
		m_cb.process_events();

		std::this_thread::sleep_for(10ms);
	}

	LOG_NOTICE(GENERAL, "All threads stopped...");

	lv2_obj::cleanup();
	idm::clear();
	fxm::clear();

	LOG_NOTICE(GENERAL, "Objects cleared...");

	RSXIOMem.Clear();
	vm::close();

	if (g_cfg.misc.autoexit)
	{
		GetCallbacks().exit();
	}
	else
	{
		Init();
	}

#ifdef LLVM_AVAILABLE
	extern void jit_finalize();
	jit_finalize();
#endif
}
Пример #25
0
/**
**  Handle interactive input event.
**
**  @param callbacks  Callback structure for events.
**  @param event      SDL event structure pointer.
*/
static void SdlDoEvent(const EventCallback *callbacks, const SDL_Event *event)
{
#ifdef DUMP_SDL_EVENTS
	DumpSdlEvent(event);
#endif

	switch (event->type) {
		case SDL_MOUSEBUTTONDOWN:
			if (event->motion.which != 0)
				return; // temporary ignore multitouch
			InputMouseButtonPress(callbacks, SDL_GetTicks(),
				event->button.button);
			break;

		case SDL_MOUSEBUTTONUP:
			if (event->motion.which != 0)
				return; // temporary ignore multitouch
			InputMouseButtonRelease(callbacks, SDL_GetTicks(),
				event->button.button);
			break;

			// FIXME: check if this is only useful for the cursor
			// FIXME: if this is the case we don't need this.
		case SDL_MOUSEMOTION:
			if (event->motion.which != 0)
				return; // temporary ignore multitouch
			InputMouseMove(callbacks, SDL_GetTicks(),
				event->motion.x, event->motion.y);
			// FIXME: Same bug fix from X11
			if ((UI.MouseWarpX != -1 || UI.MouseWarpY != -1) &&
					(event->motion.x != UI.MouseWarpX ||
						event->motion.y != UI.MouseWarpY)) {
				int xw = UI.MouseWarpX;
				int yw = UI.MouseWarpY;
				UI.MouseWarpX = -1;
				UI.MouseWarpY = -1;
				SDL_WarpMouse(xw, yw);
			}
			break;

		case SDL_ACTIVEEVENT:
			if (event->active.state & SDL_APPMOUSEFOCUS) {
				static bool InMainWindow = true;

				if (InMainWindow && !event->active.gain) {
					InputMouseExit(callbacks, SDL_GetTicks());
				}
				InMainWindow = (event->active.gain != 0);
			}
			if (event->active.state & SDL_APPACTIVE) {
				static bool IsVisible = true;
				static bool DoTogglePause = false;

				if (IsVisible && !event->active.gain) {
					IsVisible = false;
					if (!GamePaused) {
						DoTogglePause = true;
						UiTogglePause();
					}
				} else if (!IsVisible && event->active.gain) {
					IsVisible = true;
					if (GamePaused && DoTogglePause) {
						DoTogglePause = false;
						UiTogglePause();
					}
					if (UseOpenGL) {
						Video.ResizeScreen(Video.Width, Video.Height);
					}
				}
			}
			break;

		case SDL_KEYDOWN:
			InputKeyButtonPress(callbacks, SDL_GetTicks(),
				event->key.keysym.sym, event->key.keysym.unicode);
			break;

		case SDL_KEYUP:
			InputKeyButtonRelease(callbacks, SDL_GetTicks(),
				event->key.keysym.sym, event->key.keysym.unicode);
			break;

		case SDL_QUIT:
			Exit(0);
			break;
	}

	if (callbacks == GetCallbacks()) {
		handleInput(event);
	}
}
Пример #26
0
/**
**  Wait for interactive input event for one frame.
**
**  Handles system events, joystick, keyboard, mouse.
**  Handles the network messages.
**  Handles the sound queue.
**
**  All events available are fetched. Sound and network only if available.
**  Returns if the time for one frame is over.
*/
void WaitEventsOneFrame()
{
	struct timeval tv;
	fd_set rfds;
	fd_set wfds;
	Socket maxfd;
	int i;
	int s = 0;
	SDL_Event event[1];
	Uint32 ticks;
	int interrupts;

	++FrameCounter;

	ticks = SDL_GetTicks();
	if (ticks > NextFrameTicks) { // We are too slow :(
		++SlowFrameCounter;
	}

	InputMouseTimeout(GetCallbacks(), ticks);
	InputKeyTimeout(GetCallbacks(), ticks);
	CursorAnimate(ticks);

	interrupts = 0;

	for (;;) {
		//
		// Time of frame over? This makes the CPU happy. :(
		//
		ticks = SDL_GetTicks();
		if (!interrupts && ticks < NextFrameTicks) {
			SDL_Delay(NextFrameTicks - ticks);
			ticks = SDL_GetTicks();
		}
		while (ticks >= NextFrameTicks) {
			++interrupts;
			FrameFraction += FrameRemainder;
			if (FrameFraction > 10) {
				FrameFraction -= 10;
				++NextFrameTicks;
			}
			NextFrameTicks += FrameTicks;
		}

		//
		// Prepare select
		//
		maxfd = 0;
		tv.tv_sec = tv.tv_usec = 0;
		FD_ZERO(&rfds);
		FD_ZERO(&wfds);

		//
		// Network
		//
		if (IsNetworkGame()) {
			if (NetworkFildes > maxfd) {
				maxfd = NetworkFildes;
			}
			FD_SET(NetworkFildes, &rfds);
		}

#if 0
		s = select(maxfd + 1, &rfds, &wfds, NULL,
			(i = SDL_PollEvent(event)) ? &tv : NULL);
#else
		// QUICK HACK to fix the event/timer problem
		// The timer code didn't interrupt the select call.
		// Perhaps I could send a signal to the process
		// Not very nice, but this is the problem if you use other libraries
		// The event handling of SDL is wrong designed = polling only.
		// There is hope on SDL 1.3 which will have this fixed.

		//s = select(maxfd + 1, &rfds, &wfds, NULL, &tv);
		//printf("PollEvent\n");
		i = SDL_PollEvent(event);
#endif

		if (i) { // Handle SDL event
			SdlDoEvent(GetCallbacks(), event);
		}

		if (s > 0) {
			//
			// Network
			//
			if (IsNetworkGame() && FD_ISSET(NetworkFildes, &rfds) ) {
				GetCallbacks()->NetworkEvent();
			}
		}

		//
		// No more input and time for frame over: return
		//
		if (!i && s <= 0 && interrupts) {
			break;
		}
	}
	handleInput(NULL);

	if (!SkipGameCycle--) {
		SkipGameCycle = SkipFrames;
	}

	if (!UseOpenGL && (GameRunning || Editor.Running || PatchEditorRunning)) {
		Video.ClearScreen();
	}
}
Пример #27
0
void Emulator::Load()
{
	Stop();

	try
	{
		Init();

		// Open SELF or ELF
		fs::file elf_file(m_path);

		if (!elf_file)
		{
			LOG_ERROR(LOADER, "Failed to open file: %s", m_path);
			return;
		}

		LOG_NOTICE(LOADER, "Path: %s", m_path);

		const std::string elf_dir = fs::get_parent_dir(m_path);
		const fs::file sfov(elf_dir + "/sce_sys/param.sfo");
		const fs::file sfo1(elf_dir + "/../PARAM.SFO");

		// Load PARAM.SFO (TODO)
		const auto _psf = psf::load_object(sfov ? sfov : sfo1);
		m_title = psf::get_string(_psf, "TITLE", m_path);
		m_title_id = psf::get_string(_psf, "TITLE_ID");

		LOG_NOTICE(LOADER, "Title: %s", GetTitle());
		LOG_NOTICE(LOADER, "Serial: %s", GetTitleID());

		// Initialize data/cache directory
		m_cache_path = fs::get_data_dir(m_title_id, m_path);
		LOG_NOTICE(LOADER, "Cache: %s", GetCachePath());

		// Load custom config-0
		if (fs::file cfg_file{m_cache_path + "/config.yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: %s/config.yml", m_cache_path);
			g_cfg.from_string(cfg_file.to_string());
		}

		// Load custom config-1
		if (fs::file cfg_file{fs::get_config_dir() + "data/" + m_title_id + "/config.yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: data/%s/config.yml", m_title_id);
			g_cfg.from_string(cfg_file.to_string());
		}

		// Load custom config-2
		if (fs::file cfg_file{m_path + ".yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: %s.yml", m_path);
			g_cfg.from_string(cfg_file.to_string());
		}

		LOG_NOTICE(LOADER, "Used configuration:\n%s\n", g_cfg.to_string());

		// Load patches from different locations
		fxm::check_unlocked<patch_engine>()->append(fs::get_config_dir() + "data/" + m_title_id + "/patch.yml");
		fxm::check_unlocked<patch_engine>()->append(m_cache_path + "/patch.yml");

		// Mount all devices
		const std::string emu_dir_ = g_cfg.vfs.emulator_dir;
		const std::string emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
		const std::string home_dir = g_cfg.vfs.app_home;
		std::string bdvd_dir = g_cfg.vfs.dev_bdvd;

		vfs::mount("dev_hdd0", fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_hdd1", fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_flash", fmt::replace_all(g_cfg.vfs.dev_flash, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_usb", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_usb000", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
		vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir));

		// Mount /dev_bdvd/ if necessary
		if (bdvd_dir.empty()) 
		{
			size_t pos = elf_dir.rfind("PS3_GAME");
			std::string temp = elf_dir.substr(0, pos);
			if ((pos != std::string::npos) && fs::is_file(temp + "/PS3_DISC.SFB")) {
				bdvd_dir = temp;
			}
		}
		if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
		{
			vfs::mount("dev_bdvd", fmt::replace_all(bdvd_dir, "$(EmulatorDir)", emu_dir));
			LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd"));
		}

		// Mount /host_root/ if necessary
		if (g_cfg.vfs.host_root)
		{
			vfs::mount("host_root", {});
		}

		// Check SELF header
		if (elf_file.size() >= 4 && elf_file.read<u32>() == "SCE\0"_u32)
		{
			const std::string decrypted_path = m_cache_path + "boot.elf";

			fs::stat_t encrypted_stat = elf_file.stat();
			fs::stat_t decrypted_stat;

			// Check modification time and try to load decrypted ELF
			if (fs::stat(decrypted_path, decrypted_stat) && decrypted_stat.mtime == encrypted_stat.mtime)
			{
				elf_file.open(decrypted_path);
			}
			else
			{
				// Decrypt SELF
				elf_file = decrypt_self(std::move(elf_file));

				if (fs::file elf_out{decrypted_path, fs::rewrite})
				{
					elf_out.write(elf_file.to_vector<u8>());
					elf_out.close();
					fs::utime(decrypted_path, encrypted_stat.atime, encrypted_stat.mtime);
				}
				else
				{
					LOG_ERROR(LOADER, "Failed to create boot.elf");
				}
			}
		}

		ppu_exec_object ppu_exec;
		ppu_prx_object ppu_prx;
		spu_exec_object spu_exec;
		arm_exec_object arm_exec;

		if (!elf_file)
		{
			LOG_ERROR(LOADER, "Failed to decrypt SELF: %s", m_path);
			return;
		}
		else if (ppu_exec.open(elf_file) == elf_error::ok)
		{
			// PS3 executable
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();

			vm::ps3::init();

			if (m_elf_path.empty())
			{
				if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
				{
					//Disc games are on /dev_bdvd/
					size_t pos = m_path.rfind("PS3_GAME");
					m_elf_path = "/dev_bdvd/" + m_path.substr(pos);
				}
				else if (m_path.find(vfs::get("/dev_hdd0/game/")) != -1)
				{
					m_elf_path = "/dev_hdd0/game/" + m_path.substr(vfs::get("/dev_hdd0/game/").size());
				}
				else
				{
					//For homebrew
					m_elf_path = "/host_root/" + m_path;
				}

				LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
			}

			ppu_load_exec(ppu_exec);

			fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall
		}
		else if (ppu_prx.open(elf_file) == elf_error::ok)
		{
			// PPU PRX (experimental)
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::ps3::init();
			ppu_load_prx(ppu_prx, "");
		}
		else if (spu_exec.open(elf_file) == elf_error::ok)
		{
			// SPU executable (experimental)
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::ps3::init();
			spu_load_exec(spu_exec);
		}
		else if (arm_exec.open(elf_file) == elf_error::ok)
		{
			// ARMv7 executable
			g_system = system_type::psv;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::psv::init();

			if (m_elf_path.empty())
			{
				m_elf_path = "host_root:" + m_path;
				LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
			}

			arm_load_exec(arm_exec);
		}
		else
		{
			LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path);

			LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error());
			LOG_WARNING(LOADER, "** ppu_prx  -> %s", ppu_prx.get_error());
			LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error());
			LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error());
			return;
		}

		if (g_cfg.misc.autostart && IsReady())
		{
			Run();
		}
		else if (IsPaused())
		{
			m_state = system_state::ready;
			GetCallbacks().on_ready();
		}
	}
	catch (const std::exception& e)
	{
		LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what());
		Stop();
	}
}