flatbuffer는 이기종간의 데이터 교환을 위해 구글에서 만들어진 라이브러리다.
전용 script를 작성하고 전용 compiler를 돌리면 해당 언어에 맞는 ouput을 얻을 수 있다.
raw와 비교해서 거의 속도 차이가 없고, 메모리 부분에서도 장점이 있으며 여러 언어에 구애받지 않고 작성할 수 있다는 것이다.
protobuf에 비해 3000배 빠른 속도를 가진다고 들었으나 직접 확인한 결과는 아니므로 신뢰하지는 마시라
다운로드는 다음 URL에서 진행하면 된다.
https://github.com/google/flatbuffers/releases
flatbuffer 2.0.0 버전 & Window 기준으로는 Windows.flatc.binary.zip과 Source code를 받으면 된다.
https://github.com/google/flatbuffers/releases/download/v2.0.0/Windows.flatc.binary.zip
https://github.com/google/flatbuffers/archive/refs/tags/v2.0.0.zip
압축을 풀면 flatc.exe를 얻게 되는데 이 파일을 실행시키며 argv를 인자로 주어 원하는 타입의 빌드를 실행할 수 있다.
형식 : flatc --lang -o (output_path) (input_path)
flatc --cpp -o ./output_file/Cpp ./script/FlatBuffers.fbs
flatc --csharp -o ./output_file/CSharp ./script/FlatBuffers.fbs
flatc --java -o ./output_file/Java ./script/FlatBuffers.fbs
flatc --go -o ./output_file/Go ./script/FlatBuffers.fbs
flatc --python -o ./output_file/Python ./script/FlatBuffers.fbs
flatc --javascript -o ./output_file/Javascript ./script/FlatBuffers.fbs
flatc --php -o ./output_file/PHP ./script/FlatBuffers.fbs
flatc --json -o ./output_file/Json ./script/FlatBuffers.fbs
스크립트는 다음과 같은 방식으로 작성하고나서 컴파일을 하면
namespace Server;
enum ActorType : byte
{
Character,
Monster,
NPC
}
table DropItem
{
index:int;
count:int;
}
table Monster
{
name:string;
hp:long;
type:ActorType;
dropitem:[DropItem];
}
이렇게 긴 output(C++ 버전)이 나오게 된다.
작성한 스크립트에 비해서 과하게 나오는 것 같지만 기분탓이니 넘어가자.
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_FLATBUFFERS_SERVER_H_
#define FLATBUFFERS_GENERATED_FLATBUFFERS_SERVER_H_
#include "flatbuffers/flatbuffers.h"
namespace Server {
struct DropItem;
struct DropItemBuilder;
struct Monster;
struct MonsterBuilder;
enum ActorType : int8_t {
ActorType_Character = 0,
ActorType_Monster = 1,
ActorType_NPC = 2,
ActorType_MIN = ActorType_Character,
ActorType_MAX = ActorType_NPC
};
inline const ActorType (&EnumValuesActorType())[3] {
static const ActorType values[] = {
ActorType_Character,
ActorType_Monster,
ActorType_NPC
};
return values;
}
inline const char * const *EnumNamesActorType() {
static const char * const names[4] = {
"Character",
"Monster",
"NPC",
nullptr
};
return names;
}
inline const char *EnumNameActorType(ActorType e) {
if (flatbuffers::IsOutRange(e, ActorType_Character, ActorType_NPC)) return "";
const size_t index = static_cast<size_t>(e);
return EnumNamesActorType()[index];
}
struct DropItem FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef DropItemBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_INDEX = 4,
VT_COUNT = 6
};
int32_t index() const {
return GetField<int32_t>(VT_INDEX, 0);
}
int32_t count() const {
return GetField<int32_t>(VT_COUNT, 0);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<int32_t>(verifier, VT_INDEX) &&
VerifyField<int32_t>(verifier, VT_COUNT) &&
verifier.EndTable();
}
};
struct DropItemBuilder {
typedef DropItem Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_index(int32_t index) {
fbb_.AddElement<int32_t>(DropItem::VT_INDEX, index, 0);
}
void add_count(int32_t count) {
fbb_.AddElement<int32_t>(DropItem::VT_COUNT, count, 0);
}
explicit DropItemBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<DropItem> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<DropItem>(end);
return o;
}
};
inline flatbuffers::Offset<DropItem> CreateDropItem(
flatbuffers::FlatBufferBuilder &_fbb,
int32_t index = 0,
int32_t count = 0) {
DropItemBuilder builder_(_fbb);
builder_.add_count(count);
builder_.add_index(index);
return builder_.Finish();
}
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef MonsterBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_NAME = 4,
VT_HP = 6,
VT_TYPE = 8,
VT_DROPITEM = 10
};
const flatbuffers::String *name() const {
return GetPointer<const flatbuffers::String *>(VT_NAME);
}
int64_t hp() const {
return GetField<int64_t>(VT_HP, 0);
}
Server::ActorType type() const {
return static_cast<Server::ActorType>(GetField<int8_t>(VT_TYPE, 0));
}
const flatbuffers::Vector<flatbuffers::Offset<Server::DropItem>> *dropitem() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Server::DropItem>> *>(VT_DROPITEM);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_NAME) &&
verifier.VerifyString(name()) &&
VerifyField<int64_t>(verifier, VT_HP) &&
VerifyField<int8_t>(verifier, VT_TYPE) &&
VerifyOffset(verifier, VT_DROPITEM) &&
verifier.VerifyVector(dropitem()) &&
verifier.VerifyVectorOfTables(dropitem()) &&
verifier.EndTable();
}
};
struct MonsterBuilder {
typedef Monster Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
fbb_.AddOffset(Monster::VT_NAME, name);
}
void add_hp(int64_t hp) {
fbb_.AddElement<int64_t>(Monster::VT_HP, hp, 0);
}
void add_type(Server::ActorType type) {
fbb_.AddElement<int8_t>(Monster::VT_TYPE, static_cast<int8_t>(type), 0);
}
void add_dropitem(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Server::DropItem>>> dropitem) {
fbb_.AddOffset(Monster::VT_DROPITEM, dropitem);
}
explicit MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<Monster> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Monster>(end);
return o;
}
};
inline flatbuffers::Offset<Monster> CreateMonster(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> name = 0,
int64_t hp = 0,
Server::ActorType type = Server::ActorType_Character,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Server::DropItem>>> dropitem = 0) {
MonsterBuilder builder_(_fbb);
builder_.add_hp(hp);
builder_.add_dropitem(dropitem);
builder_.add_name(name);
builder_.add_type(type);
return builder_.Finish();
}
inline flatbuffers::Offset<Monster> CreateMonsterDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const char *name = nullptr,
int64_t hp = 0,
Server::ActorType type = Server::ActorType_Character,
const std::vector<flatbuffers::Offset<Server::DropItem>> *dropitem = nullptr) {
auto name__ = name ? _fbb.CreateString(name) : 0;
auto dropitem__ = dropitem ? _fbb.CreateVector<flatbuffers::Offset<Server::DropItem>>(*dropitem) : 0;
return Server::CreateMonster(
_fbb,
name__,
hp,
type,
dropitem__);
}
} // namespace Server
#endif // FLATBUFFERS_GENERATED_FLATBUFFERS_SERVER_H_
이제 이 파일을 본인의 프로젝트 path에 복사를 한 뒤 프로젝트에 추가하고 보면
#include "flagbuffers/flatbuffers.h"
에서 Error가 발생하고 있다.
왜냐하면 내 프로젝트에 저 header파일이 존재하지 않기 때문인데 여느 library를 사용하듯이 include 폴더를 내 프로젝트에 넣어놓고 경로를 설정해주자.
위에서 받은 Source code의 압축을 풀어 include 폴더를 찾자.
요 폴더를 복사해 본인 프로젝트 library들의 폴더에 맞게 위치시키고, 프로젝트 속성에서 추가 참조할 include 경로를 추가해 주면 되겠다.
'게임 > 라이브러리' 카테고리의 다른 글
Recast & Detour (1) | 2021.11.11 |
---|---|
glog (0) | 2021.08.29 |
rapidjson (0) | 2020.07.04 |