게임/라이브러리

flatbuffer

MAKGA 2021. 10. 23. 22:52
320x100

flatbuffer는 이기종간의 데이터 교환을 위해 구글에서 만들어진 라이브러리다.

전용 script를 작성하고 전용 compiler를 돌리면 해당 언어에 맞는 ouput을 얻을 수 있다.

raw와 비교해서 거의 속도 차이가 없고, 메모리 부분에서도 장점이 있으며 여러 언어에 구애받지 않고 작성할 수 있다는 것이다.

protobuf에 비해 3000배 빠른 속도를 가진다고 들었으나 직접 확인한 결과는 아니므로 신뢰하지는 마시라

 

C++ Benchmarks


다운로드는 다음 URL에서 진행하면 된다.

https://github.com/google/flatbuffers/releases

 

Releases · google/flatbuffers

FlatBuffers: Memory Efficient Serialization Library - google/flatbuffers

github.com

 

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 경로를 추가해 주면 되겠다.

320x100

'게임 > 라이브러리' 카테고리의 다른 글

Recast & Detour  (1) 2021.11.11
glog  (0) 2021.08.29
rapidjson  (0) 2020.07.04