void DoState(PointerWrap& p) { std::lock_guard<std::mutex> lk(s_ts_write_lock); p.Do(g_slice_length); p.Do(g_global_timer); p.Do(s_idled_cycles); p.Do(s_fake_dec_start_value); p.Do(s_fake_dec_start_ticks); p.Do(g_fake_TB_start_value); p.Do(g_fake_TB_start_ticks); p.Do(s_last_OC_factor); g_last_OC_factor_inverted = 1.0f / s_last_OC_factor; p.Do(s_event_fifo_id); p.DoMarker("CoreTimingData"); MoveEvents(); p.DoEachElement(s_event_queue, [](PointerWrap& pw, Event& ev) { pw.Do(ev.time); pw.Do(ev.fifo_order); // this is why we can't have (nice things) pointers as userdata pw.Do(ev.userdata); // we can't savestate ev.type directly because events might not get registered in the same // order (or at all) every time. // so, we savestate the event's type's name, and derive ev.type from that when loading. std::string name; if (pw.GetMode() != PointerWrap::MODE_READ) name = *ev.type->name; pw.Do(name); if (pw.GetMode() == PointerWrap::MODE_READ) { auto itr = s_event_types.find(name); if (itr != s_event_types.end()) { ev.type = &itr->second; } else { WARN_LOG(POWERPC, "Lost event from savestate because its type, \"%s\", has not been registered.", name.c_str()); ev.type = s_ev_lost; } } }); p.DoMarker("CoreTimingEvents"); // When loading from a save state, we must assume the Event order is random and meaningless. // The exact layout of the heap in memory is implementation defined, therefore it is platform // and library version specific. if (p.GetMode() == PointerWrap::MODE_READ) std::make_heap(s_event_queue.begin(), s_event_queue.end(), std::greater<Event>()); }