C++ C++;,ECS和保存/加载
我有一个采用实体组件系统框架的程序。从本质上说,这意味着我有一个实体集合,这些实体有不同的组件连接到它们。实体实际上只是整数ID号,组件通过将组件映射到实体的指定ID号而附加到它们 现在,我需要将实体集合和相关组件存储到一个文件中,以便以后可以修改,因此基本上我需要一个保存和加载功能。然而,对于C++来说,我还是有点难以理解如何精确地完成这项工作。C++ C++;,ECS和保存/加载,c++,serialization,entity,components,deserialization,C++,Serialization,Entity,Components,Deserialization,我有一个采用实体组件系统框架的程序。从本质上说,这意味着我有一个实体集合,这些实体有不同的组件连接到它们。实体实际上只是整数ID号,组件通过将组件映射到实体的指定ID号而附加到它们 现在,我需要将实体集合和相关组件存储到一个文件中,以便以后可以修改,因此基本上我需要一个保存和加载功能。然而,对于C++来说,我还是有点难以理解如何精确地完成这项工作。 来自Java和C#,我的第一个选择是将对象序列化为JSON,然后在加载JSON时反序列化它们。然而,C++没有任何反射特征。因此,问题是:如何保存和
来自Java和C#,我的第一个选择是将对象序列化为JSON,然后在加载JSON时反序列化它们。然而,C++没有任何反射特征。因此,问题是:如何保存和加载C++对象?我不是指实际的文件操作,我是指对象和结构应该如何处理,以便在程序启动之间保存它们。 < P>一种方式是在C++中创建,并存储数据。p> 查看以下链接: 类似于永恒的C++对象持久性库
C++不支持直接持久化(有一些建议,在将来添加C++和持久性)。持久性支持并不像一开始看起来那么简单。同一对象的大小和内存布局可能因平台而异。不同的字节顺序,或者称为endian,使问题更加复杂。要使对象持久化,我们必须将其状态保留在非易失性存储设备中。ie:编写一个持久对象,使其状态保持在创建它的程序范围之外
另一种方法是将对象存储到数组中,然后将数组缓冲区推送到文件中。 其优点是磁盘盘片不会浪费时间,而且可以连续执行写入 您可以通过使用线程来提高性能。将对象转储到缓冲区,一旦完成,就会触发一个线程来处理输出 示例: 以下代码尚未编译,仅用于说明目的#include <fstream>
#include <algorithm>
using std::ofstream;
using std::fill;
#define MAX_DATA_LEN 1024 // Assuming max size of data be 1024
class stream_interface
{
virtual void load_from_buffer(const unsigned char *& buf_ptr) = 0;
virtual size_t size_on_stream(void) const = 0;
virtual void store_to_buffer(unsigned char *& buf_ptr) const = 0;
};
struct Component
: public stream_interface,
data_length(MAX_DATA_LEN)
{
unsigned int entity;
std::string data;
const unsigned int data_length;
void load_from_buffer(const unsigned char *& buf_ptr)
{
entity = *((unsigned int *) buf_ptr);
buf_ptr += sizeof(unsigned int);
data = std::string((char *) buf_ptr);
buf_ptr += data_length;
return;
}
size_t size_on_stream(void) const
{
return sizeof(unsigned int) + data_length;
}
void store_to_buffer(unsigned char *& buf_ptr) const
{
*((unsigned int *) buf_ptr) = entity;
buf_ptr += sizeof(unsigned int);
std::fill(buf_ptr, 0, data_length);
strncpy((char *) buf_ptr, data.c_str(), data_length);
buf_ptr += data_length;
return;
}
};
int main(void)
{
Component c1;
c1.data = "Some Data";
c1.entity = 5;
ofstream data_file("ComponentList.bin", std::ios::binary);
// Determine size of buffer
size_t buffer_size = c1.size_on_stream();
// Allocate the buffer
unsigned char * buffer = new unsigned char [buffer_size];
unsigned char * buf_ptr = buffer;
// Write / store the object into the buffer.
c1.store_to_buffer(buf_ptr);
// Write the buffer to the file / stream.
data_file.write((char *) buffer, buffer_size);
data_file.close();
delete [] buffer;
return 0;
}
#包括
#包括
使用std::of流;
使用std::fill;
#定义MAX_DATA_LEN 1024//假设数据的最大大小为1024
类流接口
{
从缓冲区虚拟无效加载(const unsigned char*&buf_ptr)=0;
虚拟大小\u t \u流上的大小\u(void)const=0;
虚拟空存储到缓冲区(无符号字符*&buf\u ptr)常量=0;
};
结构组件
:公共流_接口,
数据长度(最大数据长度)
{
无符号整数实体;
std::字符串数据;
常量无符号整数数据长度;
从缓冲区无效加载(常量无符号字符*&buf\u ptr)
{
实体=*((无符号整数*)buf_ptr);
buf_ptr+=sizeof(无符号整数);
数据=标准::字符串((字符*)buf_ptr);
buf_ptr+=数据长度;
返回;
}
大小\u t大小\u在\u流上(无效)常数
{
返回sizeof(unsigned int)+数据长度;
}
无效存储到缓冲区(无符号字符*&buf\u ptr)常量
{
*((无符号整数*)buf_ptr)=实体;
buf_ptr+=sizeof(无符号整数);
标准:填充(buf_ptr,0,数据长度);
strncpy((char*)buf_ptr,data.c_str(),data_length);
buf_ptr+=数据长度;
返回;
}
};
内部主(空)
{
组分c1;
c1.data=“一些数据”;
c1.实体=5;
流数据_文件(“ComponentList.bin”,std::ios::binary);
//确定缓冲区的大小
size_t buffer_size=c1.size_on_stream();
//分配缓冲区
无符号字符*缓冲区=新的无符号字符[缓冲区大小];
无符号字符*buf_ptr=缓冲区;
//将对象写入/存储到缓冲区中。
c1.存储到缓冲区(buf_ptr);
//将缓冲区写入文件/流。
数据文件写入((字符*)缓冲区,缓冲区大小);
data_file.close();
删除[]缓冲区;
返回0;
}
只要稍微看一看,就会发现有很多序列化库。因为,正如您所指出的,C++没有反射,没有一个库在没有您的帮助下工作,通常以编写函数的形式来完成每个可序列化结构的数据的实际序列化/反序列化(例如,让您将成员写入流,就像写入“代码> STD::CUT”)。@JoachimPileborg我在搜索时确实找到了一些图书馆。但问题是,我不知道如何基于序列化数据构造正确的对象。假设有一个组件FooComponent
和另一个名为BarComponent
-我如何知道在没有反射数据的情况下构造哪个组件?这取决于您使用的库。有些允许您将工厂函数与标识符一起注册,序列化程序会将标识符放入流中,以便反序列化程序读取,以便调用正确的工厂函数。其他库自己处理它,这意味着您必须自己跟踪它(可能通过标识符工厂函数映射)。