mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
save/restore otuput values in save states
This commit is contained in:
parent
d2983c58a0
commit
ed2992101c
@ -263,6 +263,11 @@ void running_machine::start()
|
||||
save().register_presave(save_prepost_delegate(FUNC(running_machine::presave_all_devices), this));
|
||||
start_all_devices();
|
||||
save().register_postload(save_prepost_delegate(FUNC(running_machine::postload_all_devices), this));
|
||||
|
||||
// save outputs created before start time
|
||||
output().register_save();
|
||||
|
||||
// load cheat files
|
||||
manager().load_cheatfiles(*this);
|
||||
|
||||
// start recording movie if specified
|
||||
|
@ -8,8 +8,11 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "output.h"
|
||||
|
||||
#include "coreutil.h"
|
||||
#include "modules/output/output_module.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
#define OUTPUT_VERBOSE 0
|
||||
@ -67,19 +70,46 @@ void output_manager::item_proxy::resolve(device_t &device, std::string const &na
|
||||
// OUTPUT MANAGER
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// output_manager - constructor
|
||||
//-------------------------------------------------
|
||||
/*-------------------------------------------------
|
||||
output_manager - constructor
|
||||
-------------------------------------------------*/
|
||||
|
||||
output_manager::output_manager(running_machine &machine)
|
||||
: m_machine(machine),
|
||||
m_uniqueid(12345)
|
||||
: m_machine(machine)
|
||||
, m_uniqueid(12345)
|
||||
{
|
||||
/* add pause callback */
|
||||
// add callbacks
|
||||
machine.add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(&output_manager::pause, this));
|
||||
machine.add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(&output_manager::resume, this));
|
||||
machine.save().register_presave(save_prepost_delegate(FUNC(output_manager::presave), this));
|
||||
machine.save().register_postload(save_prepost_delegate(FUNC(output_manager::postload), this));
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
register_save - register for save states
|
||||
-------------------------------------------------*/
|
||||
|
||||
void output_manager::register_save()
|
||||
{
|
||||
assert(m_save_order.empty());
|
||||
assert(!m_save_data);
|
||||
|
||||
// make space for the data
|
||||
m_save_order.clear();
|
||||
m_save_order.reserve(m_itemtable.size());
|
||||
m_save_data = std::make_unique<s32 []>(m_itemtable.size());
|
||||
|
||||
// sort existing outputs by name and register for save
|
||||
for (auto &item : m_itemtable)
|
||||
m_save_order.emplace_back(item.second);
|
||||
std::sort(m_save_order.begin(), m_save_order.end(), [] (auto const &l, auto const &r) { return l.get().name() < r.get().name(); });
|
||||
|
||||
// register the reserved space for saving
|
||||
machine().save().save_pointer(nullptr, "output", nullptr, 0, NAME(m_save_data), m_itemtable.size());
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
find_item - find an item based on a string
|
||||
-------------------------------------------------*/
|
||||
@ -114,6 +144,7 @@ output_manager::output_item &output_manager::find_or_create_item(const char *out
|
||||
return item ? *item : create_new_item(outname, value);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_pause - send pause message
|
||||
-------------------------------------------------*/
|
||||
@ -129,6 +160,28 @@ void output_manager::resume()
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
presave - prepare data for save state
|
||||
-------------------------------------------------*/
|
||||
|
||||
void output_manager::presave()
|
||||
{
|
||||
for (size_t i = 0; m_save_order.size() > i; ++i)
|
||||
m_save_data[i] = m_save_order[i].get().get();
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
postload - restore loaded data
|
||||
-------------------------------------------------*/
|
||||
|
||||
void output_manager::postload()
|
||||
{
|
||||
for (size_t i = 0; m_save_order.size() > i; ++i)
|
||||
m_save_order[i].get().set(m_save_data[i]);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_set_value - set the value of an output
|
||||
-------------------------------------------------*/
|
||||
@ -145,32 +198,6 @@ void output_manager::set_value(const char *outname, s32 value)
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_set_indexed_value - set the value of an
|
||||
indexed output
|
||||
-------------------------------------------------*/
|
||||
|
||||
void output_manager::set_indexed_value(const char *basename, int index, int value)
|
||||
{
|
||||
char buffer[100];
|
||||
char *dest = buffer;
|
||||
|
||||
/* copy the string */
|
||||
while (*basename != 0)
|
||||
*dest++ = *basename++;
|
||||
|
||||
/* append the index */
|
||||
if (index >= 1000) *dest++ = '0' + ((index / 1000) % 10);
|
||||
if (index >= 100) *dest++ = '0' + ((index / 100) % 10);
|
||||
if (index >= 10) *dest++ = '0' + ((index / 10) % 10);
|
||||
*dest++ = '0' + (index % 10);
|
||||
*dest++ = 0;
|
||||
|
||||
/* set the value */
|
||||
set_value(buffer, value);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_get_value - return the value of an
|
||||
output
|
||||
@ -191,7 +218,7 @@ s32 output_manager::get_value(const char *outname)
|
||||
if nullptr is specified
|
||||
-------------------------------------------------*/
|
||||
|
||||
void output_manager::set_notifier(const char *outname, output_notifier_func callback, void *param)
|
||||
void output_manager::set_notifier(const char *outname, notifier_func callback, void *param)
|
||||
{
|
||||
// if an item is specified, find/create it
|
||||
if (outname)
|
||||
@ -206,18 +233,6 @@ void output_manager::set_notifier(const char *outname, output_notifier_func call
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_notify_all - immediately call the given
|
||||
notifier for all outputs
|
||||
-------------------------------------------------*/
|
||||
|
||||
void output_manager::notify_all(output_module *module)
|
||||
{
|
||||
for (auto &item : m_itemtable)
|
||||
module->notify(item.second.name().c_str(), item.second.get());
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_name_to_id - returns a unique ID for
|
||||
a given name
|
||||
|
@ -6,23 +6,25 @@
|
||||
|
||||
General purpose output routines.
|
||||
***************************************************************************/
|
||||
#ifndef MAME_EMU_OUTPUT_H
|
||||
#define MAME_EMU_OUTPUT_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __EMU_H__
|
||||
#error Dont include this file directly; include emu.h instead.
|
||||
#endif
|
||||
|
||||
#ifndef MAME_EMU_OUTPUT_H
|
||||
#define MAME_EMU_OUTPUT_H
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef void (*output_notifier_func)(const char *outname, s32 value, void *param);
|
||||
|
||||
// ======================> output_manager
|
||||
|
||||
class output_manager
|
||||
@ -30,10 +32,12 @@ class output_manager
|
||||
private:
|
||||
template <typename Input, std::make_unsigned_t<Input> DefaultMask> friend class devcb_write;
|
||||
|
||||
typedef void (*notifier_func)(const char *outname, s32 value, void *param);
|
||||
|
||||
class output_notify
|
||||
{
|
||||
public:
|
||||
output_notify(output_notifier_func callback, void *param)
|
||||
output_notify(notifier_func callback, void *param)
|
||||
: m_notifier(callback)
|
||||
, m_param(param)
|
||||
{
|
||||
@ -42,8 +46,8 @@ private:
|
||||
void operator()(char const *outname, s32 value) const { m_notifier(outname, value, m_param); }
|
||||
|
||||
private:
|
||||
output_notifier_func m_notifier; // callback to call
|
||||
void * m_param; // parameter to pass the callback
|
||||
notifier_func m_notifier; // callback to call
|
||||
void * m_param; // parameter to pass the callback
|
||||
};
|
||||
using notify_vector = std::vector<output_notify>;
|
||||
|
||||
@ -67,7 +71,7 @@ private:
|
||||
void set(s32 value) { if (m_value != value) { notify(value); } }
|
||||
void notify(s32 value);
|
||||
|
||||
void set_notifier(output_notifier_func callback, void *param) { m_notifylist.emplace_back(callback, param); }
|
||||
void set_notifier(notifier_func callback, void *param) { m_notifylist.emplace_back(callback, param); }
|
||||
|
||||
private:
|
||||
output_manager &m_manager; // parent output manager
|
||||
@ -158,6 +162,9 @@ public:
|
||||
// construction/destruction
|
||||
output_manager(running_machine &machine);
|
||||
|
||||
// register for save states
|
||||
void register_save() ATTR_COLD;
|
||||
|
||||
// getters
|
||||
running_machine &machine() const { return m_machine; }
|
||||
|
||||
@ -168,10 +175,14 @@ public:
|
||||
s32 get_value(const char *outname);
|
||||
|
||||
// set a notifier on a particular output, or globally if nullptr
|
||||
void set_notifier(const char *outname, output_notifier_func callback, void *param);
|
||||
void set_notifier(const char *outname, notifier_func callback, void *param);
|
||||
|
||||
// set a notifier on a particular output, or globally if nullptr
|
||||
void notify_all(output_module *module);
|
||||
// immdediately call a notifier for all outputs
|
||||
template <typename T> void notify_all(T &¬ifier) const
|
||||
{
|
||||
for (auto const &item : m_itemtable)
|
||||
notifier(item.second.name().c_str(), item.second.get());
|
||||
}
|
||||
|
||||
// map a name to a unique ID
|
||||
u32 name_to_id(const char *outname);
|
||||
@ -179,24 +190,26 @@ public:
|
||||
// map a unique ID back to a name
|
||||
const char *id_to_name(u32 id);
|
||||
|
||||
void pause();
|
||||
void resume();
|
||||
|
||||
private:
|
||||
// set an indexed value for an output (concatenates basename + index)
|
||||
void set_indexed_value(const char *basename, int index, int value);
|
||||
|
||||
output_item *find_item(const char *string);
|
||||
output_item &create_new_item(const char *outname, s32 value);
|
||||
output_item &find_or_create_item(const char *outname, s32 value);
|
||||
|
||||
// event handlers
|
||||
void pause();
|
||||
void resume();
|
||||
void presave() ATTR_COLD;
|
||||
void postload() ATTR_COLD;
|
||||
|
||||
// internal state
|
||||
running_machine &m_machine; // reference to our machine
|
||||
std::unordered_map<std::string, output_item> m_itemtable;
|
||||
notify_vector m_global_notifylist;
|
||||
std::vector<std::reference_wrapper<output_item> > m_save_order;
|
||||
std::unique_ptr<s32 []> m_save_data;
|
||||
u32 m_uniqueid;
|
||||
};
|
||||
|
||||
template <unsigned... N> using output_finder = output_manager::output_finder<void, N...>;
|
||||
|
||||
#endif // MAME_EMU_OUTPUT_H
|
||||
#endif // MAME_EMU_OUTPUT_H
|
||||
|
@ -216,9 +216,17 @@ public:
|
||||
|
||||
// global memory registration
|
||||
template <typename ItemType>
|
||||
void save_item(ItemType &value, const char *valname, int index = 0) { save_item(nullptr, "global", nullptr, index, value, valname); }
|
||||
void save_item(ItemType &value, const char *valname, int index = 0)
|
||||
{ save_item(nullptr, "global", nullptr, index, value, valname); }
|
||||
template <typename ItemType, typename StructType, typename ElementType>
|
||||
void save_item(ItemType &value, ElementType StructType::*element, const char *valname, int index = 0)
|
||||
{ save_item(nullptr, "global", nullptr, index, value, element, valname); }
|
||||
template <typename ItemType>
|
||||
void save_pointer(ItemType *value, const char *valname, u32 count, int index = 0) { save_pointer(nullptr, "global", nullptr, index, value, valname, count); }
|
||||
void save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0)
|
||||
{ save_pointer(nullptr, "global", nullptr, index, std::forward<ItemType>(value), valname, count); }
|
||||
template <typename ItemType, typename StructType, typename ElementType>
|
||||
void save_pointer(ItemType &&value, ElementType StructType::*element, const char *valname, u32 count, int index = 0)
|
||||
{ save_pointer(nullptr, "global", nullptr, index, std::forward<ItemType>(value), element, valname, count); }
|
||||
|
||||
// file processing
|
||||
static save_error check_file(running_machine &machine, emu_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...));
|
||||
|
@ -240,9 +240,9 @@ void emu_timer::register_save()
|
||||
int index = 0;
|
||||
std::string name;
|
||||
|
||||
// for non-device timers, it is an index based on the callback function name
|
||||
if (m_device == nullptr)
|
||||
{
|
||||
// for non-device timers, it is an index based on the callback function name
|
||||
name = m_callback.name() ? m_callback.name() : "unnamed";
|
||||
for (emu_timer *curtimer = machine().scheduler().first_timer(); curtimer != nullptr; curtimer = curtimer->next())
|
||||
if (!curtimer->m_temporary && curtimer->m_device == nullptr)
|
||||
@ -253,13 +253,12 @@ void emu_timer::register_save()
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// for device timers, it is an index based on the device and timer ID
|
||||
else
|
||||
{
|
||||
// for device timers, it is an index based on the device and timer ID
|
||||
name = string_format("%s/%d", m_device->tag(), m_id);
|
||||
for (emu_timer *curtimer = machine().scheduler().first_timer(); curtimer != nullptr; curtimer = curtimer->next())
|
||||
if (!curtimer->m_temporary && curtimer->m_device != nullptr && curtimer->m_device == m_device && curtimer->m_id == m_id)
|
||||
if (!curtimer->m_temporary && curtimer->m_device == m_device && curtimer->m_id == m_id)
|
||||
index++;
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ public:
|
||||
|
||||
virtual void notify(const char *outname, int32_t value) override;
|
||||
|
||||
int create_window_class(void);
|
||||
int create_window_class();
|
||||
LRESULT register_client(HWND hwnd, LPARAM id);
|
||||
LRESULT unregister_client(HWND hwnd, LPARAM id);
|
||||
LRESULT send_id_string(HWND hwnd, LPARAM id);
|
||||
@ -174,7 +174,7 @@ void output_win32::exit()
|
||||
// create_window_class
|
||||
//============================================================
|
||||
|
||||
int output_win32::create_window_class(void)
|
||||
int output_win32::create_window_class()
|
||||
{
|
||||
static bool classes_created = false;
|
||||
|
||||
@ -261,7 +261,7 @@ LRESULT output_win32::register_client(HWND hwnd, LPARAM id)
|
||||
if ((*client)->id == id)
|
||||
{
|
||||
(*client)->hwnd = hwnd;
|
||||
machine().output().notify_all(this);
|
||||
machine().output().notify_all([this] (const char *outname, int32_t value) { notify(outname, value); });
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -273,7 +273,7 @@ LRESULT output_win32::register_client(HWND hwnd, LPARAM id)
|
||||
(*client)->machine = &machine();
|
||||
|
||||
// request a notification for all outputs
|
||||
machine().output().notify_all(this);
|
||||
machine().output().notify_all([this] (const char *outname, int32_t value) { notify(outname, value); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -346,12 +346,9 @@ LRESULT output_win32::send_id_string(HWND hwnd, LPARAM id)
|
||||
|
||||
void output_win32::notify(const char *outname, int32_t value)
|
||||
{
|
||||
registered_client *client;
|
||||
// loop over clients and notify them
|
||||
for (client = m_clientlist; client != nullptr; client = client->next)
|
||||
{
|
||||
for (registered_client *client = m_clientlist; client != nullptr; client = client->next)
|
||||
PostMessage(client->hwnd, om_mame_update_state, client->machine->output().name_to_id(outname), value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user