콘텐츠 지원 Part 5: 3D 월드¶
월드 기능은 MMORPG 서버를 구현할 때 반드시 필요한 3D 공간에서 위치를 갖는 오브젝트를 다루는 기능을 제공합니다. 예를 들면 어떤 플레이어가 위치 A 에서 위치 B 로 이동하였을 때 이 정보를 전파하기 위해 특정 거리 이내의 플레이어들을 찾아내는 것 등이 될 수 있습니다.
월드 기능은 공간을 표현하는 월드와 플레이어나 몬스터 등을 표현할 수 있는 월드 오브젝트로 구성되어 있습니다.
월드 생성¶
월드는 API 함수를 이용하여 런타임에 직접 생성하거나, MANIFEST 를 이용하여 서버가 구동될 때 자동으로 생성되게 할 수 있습니다.
월드를 생성하기 위해서는 아래 값들이 필요합니다.
Name |
월드 객체를 가져오거나 검색할 때 사용할 이름입니다. |
Index Block Length |
성능을 좌우하는 값으로 월드 오브젝트 검색 시 가장 널리쓰이는 길이 값의 두배를 권장합니다. 예를 들면 플레이어 가시거리의 두 배 정도가 될 수 있습니다. |
Zone List |
월드 내의 일정 지역을 다른 지역과 구분하여 오브젝트가 들어오고 나갈 때 콜백 함수로 통지받을 수 있습니다. 자세한 설명은 Zone 를 참고 하시기 바랍니다. |
Channel Number |
같은 Name 의 월드가 2 개 이상일 때 구분하기 위한 번호입니다. |
기본적으로 월드 콤포넌트의 모든 API 함수들은 내부에서 잠금(Lock) 을 통해 Thread-Safe 하게 구현되어 있습니다. 만일, 단일 쓰레드 또는 단일 이벤트 태그에서만((예시) 이벤트 태그를 활용한 직렬화 기법) 접근하도록 구현할 경우 World::SetSingleThreadMode() 를 호출하여 내부 잠금(Lock) 을 하지 않도록 할 수 있습니다.
방법1 - API 함수¶
WorldManager 클래스의 WorldManager::Create() 와 WorldManager::CreateLocal() 함수로 월드를 생성할 수 있습니다. WorldManager::Create() 는 WorldManager::CreateLocal() 보다 느리지만 이 함수로 만들어진 월드는 다른 서버에서 이름으로 검색할 수 있습니다. 두 함수 모두 같은 이름, 같은 채널의 월드가 이미 존재하면 생성에 실패합니다.
Create() 함수 예제
// Name: "earth"
// Zone: Empty
// Index Block Length: 1000
// Channel Number: 1 (Default)
WorldManager::Create("earth", WorldManager::ZoneVector(), 1000, OnWorldCreated);
void OnWorldCreated(const Ptr<World> &world) {
if (world) {
...
} else {
LOG(ERROR) << "Failed to create the world.";
}
}
CreateLocal() 함수 예제
// Name: "moon"
// Zone: Empty
// Index Block Length: 1000
// Channel Number: 2
Ptr<World> world = WorldManager::CreateLocal("moon", WorldManager::ZoneVector(), 1000, 2);
if (world) {
...
} else {
LOG(ERROR) << "Failed to create the world.";
}
추후 지원됩니다.
방법2 - MANIFEST 설정¶
API 함수 호출없이 MANIFEST 에 월드 정보를 기술하여 서버가 구동될 때 자동으로 생성되도록 할 수 있습니다.
MANIFEST 에 WorldManager 콤포넌트를 추가하여 아래와 같이 월드를 기술합니다. 서버가 구동되면 방법1 - API 함수 와 동일하게 월드(“earth”), 로컬 월드(“moon”) 가 자동으로 생성됩니다.
...
"WorldManager": {
"world_index_block_length": 1000,
"tag_rpc_with_world_name": true,
"worlds": {
"earth": {
"channel": 0,
"local": false,
"zones": []
},
"moon": {
"channel": 2,
"local": true,
"zones": []
}
},
...
Zone¶
Zone 기능을 활용하면 월드 내의 특정 지역에 들어오고 나갈 때 콜백 함수로 통지받을 수 있습니다. Zone 정보는 월드를 생성할 때 입력받습니다.
Zone 을 생성하기 위해서는 아래 값들이 필요합니다.
Name |
Zone 을 구분하는 이름이며 Zone Handler 함수로 전달됩니다. |
Type |
Zone 의 종류를 구분하는 문자열 값이며 Zone Handler 함수로 전달됩니다. |
Sphere |
Zone 의 위치와 크기를 나타냅니다. |
Argument |
Zone Handler 로 함께 전달되는 JSON 값입니다. |
Zone 생성¶
방법1 - API 함수 를 사용할 경우 아래와 같이 Zone 을 구성할 수 있습니다. struct WorldManager::Zone 을 이용하여 하나의 Zone 을 표현합니다. struct WorldManager::Zone 의 name 과 type 값은 아래에서 설명하고 있는 Zone Handler 로 함께 전달되며 임의로 지정합니다.
WorldManager::Zone zone1;
zone1.name = "KennedySpaceCenter";
zone1.type = "portal";
zone1.sphere.coordinates.x = 1000;
zone1.sphere.coordinates.y = 1000;
zone1.sphere.coordinates.z = 1000;
zone1.sphere.radius = 30;
// zone1.argument = ...;
WorldManager::ZoneVector zones;
zones.push_back(zone1);
Ptr<World> world = WorldManager::CreateLocal("earth", zones, 1000, 2);
방법2 - MANIFEST 설정 를 사용할 경우 아래와 같이 Zone 을 구성할 수 있습니다.
...
"WorldManager": {
"world_index_block_length": 1000,
"tag_rpc_with_world_name": true,
"worlds": {
"earth": {
"channel": 2,
"local": true,
"zones": [
{"name": "KennedySpaceCenter",
"type": "portal",
"sphere": {"x": 1000, "y": 1000, "z": 10, "r": 30},
"arguments": {
"destination_world": "moon",
"coordinates": { "x": 0, "y": 0, "z": 0 }
}
}
]
}
},
...
추후 지원됩니다.
Zone 핸들러¶
Zone 에 오브젝트가 들어가고 나갈 때 통지 받을 콜백함수를 WorldManager::RegisterZoneHandler() 함수를 이용해 등록합니다.
WorldManager::RegisterZoneHandler(MyCallback);
void MyCallback(const string &world_name, const string &zone_name,
const string &type, const Json &argument, bool enter,
const Ptr<World::Object> &object) {
if (world_name == "earth" && zone_name == "KennedySpaceCenter" &&
type == "portal") {
if (enter) {
// entered
...
} else {
// left
...
}
} else {
// ...
}
}
추후 지원됩니다.
월드 찾기¶
월드 찾기 기능은 서버 내에 존재하는 월드 외에 다른 서버에 존재하는 월드까지 찾을 수 있습니다.
같은 서버 내¶
WorldManager::Get() 함수를 이용하여 월드 이름과 채널 번호로 월드를 찾을 수 있습니다. 이 함수는 서버 내에 존재하는 월드만 찾을 수 있습니다.
{
// earth#0
Ptr<World> world = WorldManager::Get("earth");
if (not world) {
LOG(ERROR) << "No world.";
}
}
{
// earth#1
Ptr<World> world = WorldManager::Get("earth", 1);
if (not world) {
LOG(ERROR) << "No world.";
}
}
추후 지원됩니다.
다른 서버¶
WorldManager::FindServer() 함수로 월드 이름으로 해당 월드가 위치한 서버를 찾을 수 있으며, 클라이언트를 다른 서버로 옮기기 에 설명된 Redirect 기능으로 클라이언트를 월드가 존재하는 서버로 이동시킬 수 있습니다.
Ptr<World> world = WorldManager::Get("earth");
if (world) {
...
} else {
WorldManager::FindServerCallback cb = [=](const Rpc::PeerId &peer) {
// AccountManager::Redirect(session, peer_id, extra_data);
};
WorldManager::FindServer("earth", cb);
}
추후 지원됩니다.
월드 삭제¶
인스턴스 던전 구현 등 필요시 WorldManager::Delete() 와 WorldManager::DeleteLocal() 함수를 이용하여 월드를 삭제할 수 있습니다. World::IsDeleted() 함수로 삭제된 월드를 구분할 수 있으며 삭제된 월드는 월드의 모든 기능이 작동하지 않습니다.
Ptr<World> earth = WorldManager::Get("earth");
WorldManager::DeleteLocal("earth");
BOOST_ASSERT(earth->IsDeleted());
추후 지원됩니다.
월드 오브젝트 생성¶
World::Object 또는 해당 오브젝트를 상속 받은 객체는 월드 오브젝트라 부르며 월드상에 존재하거나 월드에 입장할 때 사용되는 오브젝트입니다. 월드에 속한 모든 오브젝트는 위치와 크기를 가지고 있으며 월드 내에서 유일한 ID 를 할당받습니다. 모든 오브젝트는 ID 를 사용하여 언제든지 접근할 수 있습니다.
생성¶
월드 오브젝트는 아래와 같이 생성할 수 있습니다. ID 는 월드에 입장할 때 자동할당되며, 크기는 0 이 됩니다.
Ptr<World::Object> object(new World::Object());
BOOST_ASSERT(object->GetId() == World::kInvalidId);
추후 지원됩니다.
또는 ID 를 직접 부여하거나 반지름으로 표현되는 크기를 지정해줄 수 있습니다. ID 는 반드시 중복되지 않게 할당해야합니다.
int64_t id = 1234;
float radius = 5;
Ptr<World::Object> object1(new World::Object(id));
BOOST_ASSERT(object1->GetId() == id);
Ptr<World::Object> object2(new World::Object(radius));
BOOST_ASSERT(object2->GetId() == World::kInvalidId);
Ptr<World::Object> object3(new World::Object(id, radius));
BOOST_ASSERT(object3->GetId() == id);
추후 지원됩니다.
아래와 같이 상속한 클래스를 이용할 수 있습니다.
class MyObject : public World::Object {
...
};
Ptr<MyObject> object(new MyObject());
추후 지원됩니다.
이름 붙이기¶
아래와 같이 자유롭게 이름을 붙일 수 있습니다.
Ptr<World::Object> object(new World::Object());
object->SetName("Example");
string name = object->GetName();
추후 지원됩니다.
세션 붙이기¶
아래와 같이 Session 을 할당할 수 있으며 필요시 Session 을 가져와 메시지 전송 등을 할 수 있습니다. 그리고 World::Broadcast() 함수를 이용하여 메시지를 보낼 때 이용됩니다.
Ptr<Session> session = ...;
Ptr<World::Object> object(new World::Object());
object->SetSession(session);
Ptr<Session> session2 = object->GetSession();
추후 지원됩니다.
Type 지정¶
모든 오브젝트에는 Type 을 지정할 수 있으며 World::FindObject(), World::FindSession(), World::Broadcast() 에서 특정 Type 만 처리하게 할 수 있습니다. Type 은 반드시 2의 승수로 표현해야 하며 월드에 입장한 이후로는 변경할 수 없습니다.
enum WorldObjectType {
kPlayer = 1,
kClassWarrior = 2,
kClassArcher = 4,
kClassWizard = 8,
kNpc = 16,
kNpcMonster = 32,
...
};
Ptr<World::Object> object(new World::Object());
object->SetType(kPlayer | kClassWarrior);
int64_t type = object->GetType();
추후 지원됩니다.
데이터 저장¶
월드 오브젝트는 간단한 Key/Value 형태로 데이터를 저장할 수 있는 기능이 있으며 사용 방법은 다음과 같습니다.
Ptr<World::Object> object(new World::Object());
object->SetKeyValue("ExampleKey", 1234);
int64_t value = object->GetValueForKey("ExampleKey");
추후 지원됩니다.
월드 오브젝트 입장¶
월드 오브젝트는 World::InsertObject() 함수를 이용하여 월드에 입장할 수
있습니다. 오브젝트 생성 시 ID 를 할당하지 않았다면 자동으로 ID 가 할당됩니다.
World::InsertObject() 함수는 할당된 ID 를 반환하며 ID 를 생성자로 할당했다면
ID 중복 등으로 입장에 실패하면 World::kInvalidId
값을 반환합니다.
Ptr<World> world = WorldManager::Get("earth");
BOOST_ASSERT(world);
Ptr<World::Object> object(new World::Object());
int64_t id = world->InsertObject(World::Point(0, 0, 0), object);
if (id == World::kInvalidId) {
LOG(ERROR) << "Failed to insert object.";
return;
}
BOOST_ASSERT(id == object->GetId());
추후 지원됩니다.
플레이어가 월드에 입장한다면 아래와 같은 형태가 될 수 있습니다.
enum WorldObjectType {
kPlayer = 1,
kClassWarrior = 2,
kClassArcher = 4,
kClassWizard = 8,
kNpc = 16,
kNpcMonster = 32,
...
};
Ptr<World> the_world;
void OnLoginComplete(const string &char_name, const Ptr<Session> &session) {
Ptr<World::Object> object(new World::Object());
object->SetName(char_name);
object->SetSession(session);
object->SetType(kPlayer | kClassWarrior);
int64_t id = the_world->InsertObject(World::Point(0, 0, 0), object);
if (id == World::kInvalidId) {
LOG(ERROR) << "Failed to insert object.";
return;
}
BOOST_ASSERT(id == object->GetId());
session->AddToContext("world_object_id", id);
}
void OnMove(const Ptr<Session> &session, ...) {
int64_t id;
if (not session->GetFromContext("world_object_id", &id)) {
LOG(ERROR) << "Not in the world.";
return;
}
Ptr<World::Object> object = the_world->GetObject(id);
...;
}
추후 지원됩니다.
월드 오브젝트 퇴장¶
입장한 월드 오브젝트는 World::EraseObject() 함수로 월드에서 나올 수 있습니다. 이 함수는 퇴장한 오브젝트를 반환하며 오브젝트가 존재하지 않을 경우 NULL 을 반환합니다.
int64_t world_object_id = ...;
Ptr<World> world = WorldManager::Get("earth");
Ptr<World::Object> object = world->EraseObject(world_object_id);
if (object) {
...
}
추후 지원됩니다.
월드 오브젝트 이동¶
월드에 입장한 오브젝트는 World::MoveObject() 와 World::MoveObjectTo() 함수로 월드 내에서 위치를 이동할 수 있습니다. 전자는 변화량을 후자는 절대값을 이용하여 오브젝트를 이동시킬 수 있습니다.
아래는 오브젝트를 현재 위치에서 x 를 100 만큼 이동시킵니다.
int64_t world_object_id = ...;
Ptr<World> world = WorldManager::Get("earth");
world->MoveObject(world_object_id, World::Point(100, 0, 0));
// World::Point new_coordinates;
// world->MoveObject(world_object_id, World::Point(100, 0, 0),
// &new_coordinates);
추후 지원됩니다.
아래는 오브젝트를 x=500, y=500, z=0 위치로 이동시킵니다.
int64_t world_object_id = ...;
Ptr<World> world = WorldManager::Get("earth");
world->MoveObjectTo(world_object_id, World::Point(500, 500, 0));
추후 지원됩니다.
Tip
새롭게 시야에 들어온 오브젝트 찾기 의 설명을 참고하면 손쉽게 새로 시야에 들어온 오브젝트들을 찾을 수 있습니다.
월드 오브젝트 검색¶
아래는 월드 내 오브젝트들을 다양한 조건으로 검색하는 방법을 설명합니다.
오브젝트 ID 로 찾기¶
World::GetObject() 함수는 월드 오브젝트 ID 를 이용하여 월드내에 속한 오브젝트를 가져오는 기능입니다. 오브젝트 ID 는 월드에 입장할 때 자동으로 할당되거나 오브젝트를 생성할 때 직접 부여할 수 있습니다.
Ptr<World> world = WorldManager::Get("earth");
int64_t world_object_id;
{
Ptr<World::Object> object(new World::Object());
world_object_id = world->InsertObject(World::Point(0, 0, 0), object);
}
if (world_object_id != World::kInvalidId) {
Ptr<World::Object> object = world->GetObject(world_object_id);
BOOST_ASSERT(world_object_id == object->GetId());
}
추후 지원됩니다.
가까운 오브젝트들 찾기¶
World::FindObject() 함수는 어떠한 월드 오브젝트나 위치를 기준으로 일정 거리 이내에 있는 월드 오브젝트들을 찾을 수 있습니다.
위치 기준으로 찾기¶
아래는 x=1000, y=1000, z=0 위치에서 거리 500 이내에 있는 오브젝트를 가져옵니다.
마지막 인자에 World::DistanceVector
를 넘기면 거리도 함께 가져옵니다.
Ptr<World> world = WorldManager::Get("earth");
World::ObjectVector objects;
world->FindObject(World::Point(1000, 1000, 0), 500, &objects);
// World::DistanceVector distances;
// world->FindObject(World::Point(1000, 1000, 0),
// 500,
// World::kDefaultOption,
// World::kNullFilter,
// &objects,
// &distances);
for (size_t i = 0; i < objects.size(); ++i) {
Ptr<World::Object> object = objects[i];
...
}
추후 지원됩니다.
오브젝트 기준으로 찾기¶
아래는 특정 오브젝트의 위치에서 거리 500 이내에 있는 오브젝트를 가져옵니다. 이어지는 설명들에서는 모두 위치 기준으로 설명하지만 모두 동일하게 오브젝트 기준으로도 가능합니다.
Ptr<World> world = WorldManager::Get("earth");
int64_t world_object_id = ...;
World::ObjectVector objects;
world->FindObject(world_object_id, 500, &objects);
for (size_t i = 0; i < objects.size(); ++i) {
Ptr<World::Object> object = objects[i];
...
}
추후 지원됩니다.
가까운 순으로 정렬하기¶
World::FindOption 을 이용하여 반환되는 오브젝트들을 거리순으로 정렬할 수 있습니다.
Ptr<World> world = WorldManager::Get("earth");
World::FindOption option;
option.use_ascending_order = true;
World::ObjectVector objects;
world->FindObject(World::Point(1000, 1000, 0),
500,
option,
World::kNullFilter,
&objects);
for (size_t i = 0; i < objects.size(); ++i) {
Ptr<World::Object> object = objects[i];
...
}
추후 지원됩니다.
가까운 순으로 N 번째 오브젝트 찾기¶
World::FindOption 을 이용하여 N 번째 오브젝트를 찾을 수 있습니다. 아래는 x=1000, y=1000, z=0 기준으로 거리 500 이내에 있는 오브젝트 중 3 번째로 가까운 오브젝트를 가져옵니다.
Ptr<World> world = WorldManager::Get("earth");
World::FindOption option;
option.use_ascending_order = true;
option.boundary_begin = 2;
option.boundary_count = 1;
World::ObjectVector objects;
world->FindObject(World::Point(1000, 1000, 0),
500,
option,
World::kNullFilter,
&objects);
for (size_t i = 0; i < objects.size(); ++i) {
Ptr<World::Object> object = objects[i];
...
}
추후 지원됩니다.
새롭게 시야에 들어온 오브젝트 찾기¶
World::MakeMovingSightFilter() 를 이용하여 이동하는 캐릭터 등의 시야를 처리할 수 있습니다. 이 필터는 오브젝트가 위치를 이동하고 나서 새로 시야 범위에 들어온 오브젝트를 가져옵니다. 이미, 시야에 존재하던 오브젝트는 포함되지 않습니다.
Ptr<World> world = WorldManager::Get("earth");
int64_t world_object_id = ...;
Ptr<World::Object> object = world->GetObject(world_object_id);
World::Point prev_pos = object->GetCoordinates();
world->MoveObject(object, World::Point(100, 0, 0));
World::ObjectVector objects;
world->FindObject(object,
500,
World::kDefaultOption,
World::MakeMovingSightFilter(prev_pos),
&objects);
for (size_t i = 0; i < objects.size(); ++i) {
Ptr<World::Object> object = objects[i];
...
}
추후 지원됩니다.
특정 Type 의 오브젝트 찾기¶
World::MakeFilter() 를 이용하여 특정 Type 의 오브젝트만 찾을 수 있습니다.
아래는 전사와 마법사 플레이어 오브젝트만 가져오는 예입니다.
enum WorldObjectType {
kPlayer = 1,
kClassWarrior = 2,
kClassArcher = 4,
kClassWizard = 8,
kNpc = 16,
kNpcMonster = 32,
...
};
Ptr<World> world = WorldManager::Get("earth");
World::ObjectVector objects;
world->FindObject(World::Point(1000, 1000, 0),
500,
World::kDefaultOption,
World::MakeFilter(kClassWarrior | kClassWizard),
&objects);
for (size_t i = 0; i < objects.size(); ++i) {
Ptr<World::Object> object = objects[i];
...
}
추후 지원됩니다.
사각형에 포함된 오브젝트 찾기¶
World::MakeRectangleFilter() 를 이용하여 사각형 범위에 있는 오브젝트만 가져올 수 있습니다. 이 함수는 기준 위치에서의 사각형이 만들어질 거리와 방향, 사각형의 크기 정보를 입력받으며 Type 또한 지정할 수 있습니다.
아래는 x=1000, y=1000, z=0 기준위치로 하여 거리 500 이내의 오브젝트를 찾고 기준위치에서 x=1, y=0.5 방향으로 30 만큼 떨어진 위치에 길이 50 의 정사각형 안에 포함되는 플레이어 오브젝트만 가져옵니다.
높이 값이 음수이면 무한대로 처리됩니다.
enum WorldObjectType {
kPlayer = 1,
kClassWarrior = 2,
kClassArcher = 4,
kClassWizard = 8,
kNpc = 16,
kNpcMonster = 32,
...
};
Ptr<World> world = WorldManager::Get("earth");
World::FindFilter filter = World::MakeRectangleFilter(
30, World::Vector2(1, 0.5), 50, 50, 50, kPlayer);
World::ObjectVector objects;
world->FindObject(World::Point(1000, 1000, 0),
500,
World::kDefaultOption,
filter,
&objects);
for (size_t i = 0; i < objects.size(); ++i) {
Ptr<World::Object> object = objects[i];
...
}
추후 지원됩니다.
부채꼴에 포함된 오브젝트 찾기¶
World::MakeCircularSectorFilter() 를 이용하여 부채꼴 범위에 있는 오브젝트만 가져올 수 있습니다. 이 함수는 기준 위치에서의 부채꼴이 만들어질 거리와 방향, 부채꼴의 반지름 길이, 좌우 각도 정보를 입력받으며 Type 또한 지정할 수 있습니다.
아래는 x=1000, y=1000, z=0 기준위치로 하여 거리 500 이내의 오브젝트를 찾고 기준위치에서 x=1, y=1 방향으로 50 만큼 떨어진 위치에 반지름 100, 좌 45 도, 우 45 도, 높이 70 의 부채꼴에 포함되는 NPC 오브젝트만 가져옵니다.
높이 값이 음수이면 무한대로 처리됩니다.
enum WorldObjectType {
kPlayer = 1,
kClassWarrior = 2,
kClassArcher = 4,
kClassWizard = 8,
kNpc = 16,
kNpcMonster = 32,
...
};
Ptr<World> world = WorldManager::Get("earth");
World::FindFilter filter = World::MakeCircularSectorFilter(
50, World::Vector2(1, 1), 100, -45, 45, 70, kNpc);
World::ObjectVector objects;
world->FindObject(World::Point(1000, 1000, 0),
500,
World::kDefaultOption,
filter,
&objects);
for (size_t i = 0; i < objects.size(); ++i) {
Ptr<World::Object> object = objects[i];
...
}
추후 지원됩니다.
사용자 정의 필터¶
World::MakeFilter(), World::MakeRectangleFilter(),
World::MakeCircularSectorFilter() 모두 원하는 필터가 아닐 경우
World::FindFilter 형식에 맞는 함수를 만들어 원하는 필터를 만들 수 있습니다.
World::FindFilter 의 첫 번째와 두 번째 인자는 World::FindObject() 에
전달된 위치와 거리입니다. 세 번째 인자에 해당하는 오브젝트가 결과에 포함돼야하면
true
를 아니면 false
를 반환합니다.
아래는 세션이 있는 오브젝트만 찾는 필터를 만드고, 사용하는 예입니다.
bool MySessionFilter(const World::Point &, float,
const Ptr<Object> &object) {
if (object->GetSession()) {
return true;
} else {
return false;
}
}
Ptr<World> world = WorldManager::Get("earth");
World::ObjectVector objects;
world->FindObject(World::Point(1000, 1000, 0),
500,
World::kDefaultOption,
MySessionFilter,
&objects);
추후 지원됩니다.
가까운 플레이어들에게 메시지 보내기¶
아래에서 설명하는 기능은 반드시 세션 붙이기 와 함께 사용되어야 합니다.
가까운 플레이어들의 세션 찾기¶
World::FindSession() 은 World::FindObject() 에서 World::ObjectVector 대신 World::SessionVector 를 쓰는 것 외에 모두 동일합니다. 이 함수를 이용하면 월드 오브젝트 대신 월드 오브젝트에 할당된 Session 을 가져올 수 있습니다.
가까운 플레이어들에게 메시지 보내기¶
World::Broadcast() 를 이용하면 가까운 플레이어들에게 메시지를 보낼 수 있습니다.
아래는 x=1000, y=1000, z=0 기준 거리 500 이내의 플레이어들에게 이동 메시지를 전송합니다.(이동 메시지 표현은 생략)
Ptr<World> world = WorldManager::Get("earth");
string message_type = "move";
Ptr<FunMessage> message = ...; // or Json message;
world->Broadcast(World::Point(1000, 1000, 0),
500,
message_type,
message,
kDefaultEncryption,
kTcp);
추후 지원됩니다.
정적 월드 오브젝트¶
마을, 부활 위치 등 위치 이동이 없으며 거리 제약 없이 검색되어야 하는 오브젝트는 정적 오브젝트로 등록하여 다루는 것이 편리합니다. 정적 오브젝트는 비정적 오브젝트와 분리되어 처리됩니다. World::FindObject() 등으로 검색되지 않으며 아래에 설명된 함수들로만 다룰 수 있습니다.
등록¶
World::InsertStaticObject() 함수로 오브젝트를 정적 오브젝트로 등록할 수 있습니다.
아래는 “MyTownA” 마을을 x=300, y=300, z=0 위치에 정적 오브젝트로 등록합니다.
enum WorldObjectType {
kPlayer = 1,
kClassWarrior = 2,
kClassArcher = 4,
kClassWizard = 8,
kNpc = 16,
kNpcMonster = 32,
...,
kTown = 1024
};
Ptr<World> world = WorldManager::Get("earth");
BOOST_ASSERT(world);
Ptr<World::Object> object(new World::Object());
object->SetName("MyTownA");
object->SetType(kTown);
world->InsertStaticObject(World::Point(300, 300, 0), object);
추후 지원됩니다.
검색¶
World::FindStaticObject() 함수로 정적 오브젝트를 검색할 수 있습니다.
아래는 x=700, y=700, z=0 위치에서 가장 가까운 마을을 찾는 예입니다.
Ptr<World> world = WorldManager::Get("earth");
BOOST_ASSERT(world);
World::FindOption option;
option.use_ascending_order = true;
option.boundary_begin = 0;
option.boundary_count = 1;
World::ObjectVector objects;
world->FindStaticObject(World::Point(700, 700, 0), option,
World::MakeFilter(kTown), &objects);
if (not objects.empty()) {
const Ptr<World::Object> &town_object = objects[i];
World::Point rebirth_point = town_object->GetCoordinates();
...
}
추후 지원됩니다.
World::FindObject() 와 마찬가지로 기준 위치는 위치(World::Point
) 대신
월드 오브젝트 아이디로 대체 가능합니다.
월드 기타 기능¶
오브젝트 존재 유무 검사¶
World::MonitorTypeExistence() 함수를 이용하면 월드에 특정 Type 의 월드 오브젝트가 존재하는지 알 수 있습니다. 이 함수는 월드 생성 직후 어떠한 오브젝트도 월드에 입장하지 않은 상태에서만 사용해야합니다.
아래는 월드에 유저가 한 명도 없을 경우 몬스터 AI 처리를 중지시키는 예입니다.
bool Install(...) {
Ptr<World> w = WorldManager::Create(...);
w->MonitorTypeExistence(kPlayer, MyTypeExistenceCallback);
}
void MyTypeExistenceCallback(int64_t type, bool exist) {
if (type == kPlayer) {
if (exist) {
// start monster AI
} else {
// stop monster AI
}
}
}
추후 지원됩니다.
모든 오브젝트 가져오기¶
World::GetObjectCount() 함수로 월드 내의 오브젝트 개수를 가져올 수 있으며, World::GetAllObject() 함수로 월드 내의 모든 오브젝트를 가져올 수 있습니다.
모든 세션에게 메시지 보내기¶
World::Broadcast() 함수로 월드 내 모든 세션에게 메시지를 보낼 수 있습니다.
아래는 “earth” 월드 내에 모든 세션에게 “earth_notice” 메시지를 전송하는 예제입니다.
Ptr<World> world = WorldManager::Get("earth");
string message_type = "earth_notice";
Ptr<FunMessage> message = ...; // or Json message;
world->Broadcast(message_type,
message,
kDefaultEncryption,
kTcp);
추후 지원됩니다.