diff --git a/db/import-tmpl/instance_db.txt b/db/import-tmpl/instance_db.txt
deleted file mode 100644
index 5672eec9e4..0000000000
--- a/db/import-tmpl/instance_db.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-// Instance Database
-//
-// Structure of Database:
-// ID,Name,LimitTime,IdleTimeOut,EnterMap,EnterX,EnterY,Map2,Map3,...,Map255
-//
-// EnterMap is considered as Map1
diff --git a/db/import-tmpl/instance_db.yml b/db/import-tmpl/instance_db.yml
new file mode 100644
index 0000000000..16dd9900e3
--- /dev/null
+++ b/db/import-tmpl/instance_db.yml
@@ -0,0 +1,38 @@
+# This file is a part of rAthena.
+# Copyright(C) 2019 rAthena Development Team
+# https://rathena.org - https://github.com/rathena
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+###########################################################################
+# Instance Database
+###########################################################################
+#
+# Instance Settings
+#
+###########################################################################
+# - Id Instance ID.
+# Name Instance Name.
+# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
+# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
+# Enter: Instance entrance coordinates.
+# Map Map Name where players start.
+# X X Coordinate where players start.
+# Y Y Coordinate where players start.
+# AdditionalMaps: List of maps that are part of an instance. (Optional)
+###########################################################################
+
+Header:
+ Type: INSTANCE_DB
+ Version: 1
diff --git a/db/instance_db.yml b/db/instance_db.yml
new file mode 100644
index 0000000000..03bcfba90c
--- /dev/null
+++ b/db/instance_db.yml
@@ -0,0 +1,46 @@
+# This file is a part of rAthena.
+# Copyright(C) 2019 rAthena Development Team
+# https://rathena.org - https://github.com/rathena
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+###########################################################################
+# Instance Database
+###########################################################################
+#
+# Instance Settings
+#
+###########################################################################
+# - Id Instance ID.
+# Name Instance Name.
+# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
+# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
+# Enter: Instance entrance coordinates.
+# Map Map Name where players start.
+# X X Coordinate where players start.
+# Y Y Coordinate where players start.
+# AdditionalMaps: List of maps that are part of an instance. (Optional)
+###########################################################################
+
+Header:
+ Type: INSTANCE_DB
+ Version: 1
+
+Footer:
+ Imports:
+ - Path: db/pre-re/instance_db.yml
+ Mode: Prerenewal
+ - Path: db/re/instance_db.yml
+ Mode: Renewal
+ - Path: db/import/instance_db.yml
diff --git a/db/pre-re/instance_db.txt b/db/pre-re/instance_db.txt
deleted file mode 100644
index e9cf668f15..0000000000
--- a/db/pre-re/instance_db.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-// Instance Database
-//
-// Structure of Database:
-// ID,Name,LimitTime,IdleTimeOut,EnterMap,EnterX,EnterY,Map2,Map3,...,Map255
-//
-// EnterMap is considered as Map1
-
-1,Endless Tower,14400,300,1@tower,50,355,2@tower,3@tower,4@tower,5@tower,6@tower
-2,Sealed Catacomb,7200,300,1@cata,100,224,2@cata
-3,Orc's Memory,3600,300,1@orcs,179,15,2@orcs
-4,Nidhoggur's Nest,14400,300,1@nyd,32,36,2@nyd
diff --git a/db/pre-re/instance_db.yml b/db/pre-re/instance_db.yml
new file mode 100644
index 0000000000..fdd82c99cc
--- /dev/null
+++ b/db/pre-re/instance_db.yml
@@ -0,0 +1,79 @@
+# This file is a part of rAthena.
+# Copyright(C) 2019 rAthena Development Team
+# https://rathena.org - https://github.com/rathena
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+###########################################################################
+# Instance Database
+###########################################################################
+#
+# Instance Settings
+#
+###########################################################################
+# - Id Instance ID.
+# Name Instance Name.
+# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
+# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
+# Enter: Instance entrance coordinates.
+# Map Map Name where players start.
+# X X Coordinate where players start.
+# Y Y Coordinate where players start.
+# AdditionalMaps: List of maps that are part of an instance. (Optional)
+###########################################################################
+
+Header:
+ Type: INSTANCE_DB
+ Version: 1
+
+Body:
+ - Id: 1
+ Name: Endless Tower
+ TimeLimit: 14400
+ Enter:
+ Map: 1@tower
+ X: 50
+ Y: 355
+ AdditionalMaps:
+ 2@tower: true
+ 3@tower: true
+ 4@tower: true
+ 5@tower: true
+ 6@tower: true
+ - Id: 2
+ Name: Sealed Catacomb
+ TimeLimit: 7200
+ Enter:
+ Map: 1@cata
+ X: 100
+ Y: 224
+ AdditionalMaps:
+ 2@cata: true
+ - Id: 3
+ Name: Orc's Memory
+ Enter:
+ Map: 1@orcs
+ X: 179
+ Y: 15
+ AdditionalMaps:
+ 2@orcs: true
+ - Id: 4
+ Name: Nidhoggur's Nest
+ TimeLimit: 14400
+ Enter:
+ Map: 1@nyd
+ X: 32
+ Y: 36
+ AdditionalMaps:
+ 2@nyd: true
diff --git a/db/re/instance_db.txt b/db/re/instance_db.txt
deleted file mode 100644
index a0443ffb8d..0000000000
--- a/db/re/instance_db.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-// Instance Database
-//
-// Structure of Database:
-// ID,Name,LimitTime,IdleTimeOut,EnterMap,EnterX,EnterY,Map2,...,Map255
-//
-// EnterMap is considered as Map1
-
-1,Endless Tower,14400,300,1@tower,50,355,2@tower,3@tower,4@tower,5@tower,6@tower
-2,Sealed Catacomb,7200,300,1@cata,100,224,2@cata
-3,Orc's Memory,3600,300,1@orcs,179,15,2@orcs
-4,Nidhoggur's Nest,14400,300,1@nyd,32,36,2@nyd
-5,Mistwood Maze,7200,300,1@mist,89,29
-6,Culvert,3600,300,1@pump,63,98,2@pump
-7,Octopus Cave,3600,300,1@cash,199,99
-8,Bangungot Hospital 2F,3600,300,1@ma_h,40,157
-9,Buwaya Cave,3600,300,1@ma_c,35,57
-10,Bakonawa Lake,7200,300,1@ma_b,64,51
-11,Wolfchev's Laboratory,14400,300,1@lhz,45,148
-12,Old Glast Heim,3600,300,1@gl_k,150,20,2@gl_k
-13,Eclage Interior,1200,300,1@ecl,60,50
-14,Sara's Memories,3600,300,1@sara,250,155
-15,Geffen Magic Tournament,7200,300,1@gef,119,209,1@gef_in,1@ge_st
-16,Horror Toy Factory,3600,300,1@xm_d,111,22
-17,Faceworm's Nest,3600,300,1@face,112,370
-18,Ghost Palace,3600,300,1@spa,42,196
-19,Devil's Tower,3600,300,1@tnm1,50,104,1@tnm2,1@tnm3
-20,Assault on the Airship,3600,300,1@air1,244,73,1@air2
-21,Fenrir and Sarah,3600,300,1@glast,367,304
-// 22,Wave Mode - Forest,3600,300,1@def01,50,21
-// 23,Wave Mode - Sky,3600,300,1@def02,29,35
-24,Nightmarish Jitterbug,3600,300,1@jtb,16,17
-25,Isle of Bios,3600,300,1@dth1,17,93,1@dth2,1@dth3
-26,Morse's Cave,3600,300,1@rev,26,181
-// 27,Temple of the Demon God,3600,300,1@eom,101,16
-28,Central Laboratory,3600,300,1@lab,120,30
-29,Last room,3600,300,1@uns,145,35
-// 30,Charleston in Distress,3600,300,1@mcd,127,282
-31,Ritual of Blessing,3600,300,2@mir,101,12
-32,Room of Consciousness,3600,300,1@mir,101,10
-// 33,Sky Fortress Invasion,3600,300,1@sthb,54,67,1@sthc,1@sthd
diff --git a/db/re/instance_db.yml b/db/re/instance_db.yml
new file mode 100644
index 0000000000..1bc5d59ef4
--- /dev/null
+++ b/db/re/instance_db.yml
@@ -0,0 +1,276 @@
+# This file is a part of rAthena.
+# Copyright(C) 2019 rAthena Development Team
+# https://rathena.org - https://github.com/rathena
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+###########################################################################
+# Instance Database
+###########################################################################
+#
+# Instance Settings
+#
+###########################################################################
+# - Id Instance ID.
+# Name Instance Name.
+# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
+# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
+# Enter: Instance entrance coordinates.
+# Map Map Name where players start.
+# X X Coordinate where players start.
+# Y Y Coordinate where players start.
+# AdditionalMaps: List of maps that are part of an instance. (Optional)
+###########################################################################
+
+Header:
+ Type: INSTANCE_DB
+ Version: 1
+
+Body:
+ - Id: 1
+ Name: Endless Tower
+ TimeLimit: 14400
+ Enter:
+ Map: 1@tower
+ X: 50
+ Y: 355
+ AdditionalMaps:
+ 2@tower: true
+ 3@tower: true
+ 4@tower: true
+ 5@tower: true
+ 6@tower: true
+ - Id: 2
+ Name: Sealed Catacomb
+ TimeLimit: 7200
+ Enter:
+ Map: 1@cata
+ X: 100
+ Y: 224
+ AdditionalMaps:
+ 2@cata: true
+ - Id: 3
+ Name: Orc's Memory
+ Enter:
+ Map: 1@orcs
+ X: 179
+ Y: 15
+ AdditionalMaps:
+ 2@orcs: true
+ - Id: 4
+ Name: Nidhoggur's Nest
+ TimeLimit: 14400
+ Enter:
+ Map: 1@nyd
+ X: 32
+ Y: 36
+ AdditionalMaps:
+ 2@nyd: true
+ - Id: 5
+ Name: Mistwood Maze
+ TimeLimit: 7200
+ Enter:
+ Map: 1@mist
+ X: 89
+ Y: 29
+ - Id: 6
+ Name: Culvert
+ Enter:
+ Map: 1@pump
+ X: 63
+ Y: 98
+ AdditionalMaps:
+ 2@pump: true
+ - Id: 7
+ Name: Octopus Cave
+ Enter:
+ Map: 1@cash
+ X: 199
+ Y: 99
+ - Id: 8
+ Name: Bangungot Hospital 2F
+ Enter:
+ Map: 1@ma_h
+ X: 40
+ Y: 157
+ - Id: 9
+ Name: Buwaya Cave
+ Enter:
+ Map: 1@ma_c
+ X: 35
+ Y: 57
+ - Id: 10
+ Name: Bakonawa Lake
+ TimeLimit: 7200
+ Enter:
+ Map: 1@ma_b
+ X: 64
+ Y: 51
+ - Id: 11
+ Name: Wolfchev's Laboratory
+ TimeLimit: 14400
+ Enter:
+ Map: 1@lhz
+ X: 45
+ Y: 148
+ - Id: 12
+ Name: Old Glast Heim
+ Enter:
+ Map: 1@gl_k
+ X: 150
+ Y: 20
+ AdditionalMaps:
+ 2@gl_k: true
+ - Id: 13
+ Name: Eclage Interior
+ TimeLimit: 1200
+ Enter:
+ Map: 1@ecl
+ X: 60
+ Y: 50
+ - Id: 14
+ Name: Sara's Memories
+ Enter:
+ Map: 1@sara
+ X: 250
+ Y: 155
+ - Id: 15
+ Name: Geffen Magic Tournament
+ TimeLimit: 7200
+ Enter:
+ Map: 1@gef
+ X: 119
+ Y: 209
+ AdditionalMaps:
+ 1@gef_in: true
+ 1@ge_st: true
+ - Id: 16
+ Name: Horror Toy Factory
+ Enter:
+ Map: 1@xm_d
+ X: 111
+ Y: 22
+ - Id: 17
+ Name: Faceworm's Nest
+ Enter:
+ Map: 1@face
+ X: 112
+ Y: 370
+ - Id: 18
+ Name: Ghost Palace
+ Enter:
+ Map: 1@spa
+ X: 42
+ Y: 196
+ - Id: 19
+ Name: Devil's Tower
+ Enter:
+ Map: 1@tnm1
+ X: 50
+ Y: 104
+ AdditionalMaps:
+ 1@tnm2: true
+ 1@tnm3: true
+ - Id: 20
+ Name: Assault on the Airship
+ Enter:
+ Map: 1@air1
+ X: 244
+ Y: 73
+ AdditionalMaps:
+ 1@air2: true
+ - Id: 21
+ Name: Fenrir and Sarah
+ Enter:
+ Map: 1@glast
+ X: 367
+ Y: 304
+# - Id: 22
+# Name: Wave Mode - Forest
+# Enter:
+# Map: 1@def01
+# X: 50
+# Y: 21
+# - Id: 23
+# Name: Wave Mode - Sky
+# Enter:
+# Map: 1@def02
+# X: 29
+# Y: 35
+ - Id: 24
+ Name: Nightmarish Jitterbug
+ Enter:
+ Map: 1@jtb
+ X: 16
+ Y: 17
+ - Id: 25
+ Name: Isle of Bios
+ Enter:
+ Map: 1@dth1
+ X: 17
+ Y: 93
+ AdditionalMaps:
+ 1@dth2: true
+ 1@dth3: true
+ - Id: 26
+ Name: Morse's Cave
+ Enter:
+ Map: 1@rev
+ X: 26
+ Y: 181
+# - Id: 27
+# Name: Temple of the Demon God
+# Enter:
+# Map: 1@eom
+# X: 101
+# Y: 16
+ - Id: 28
+ Name: Central Laboratory
+ Enter:
+ Map: 1@lab
+ X: 120
+ Y: 30
+ - Id: 29
+ Name: Last room
+ Enter:
+ Map: 1@uns
+ X: 145
+ Y: 35
+# - Id: 30
+# Name: Charleston in Distress
+# Enter:
+# Map: 1@mcd
+# X: 127
+# Y: 282
+ - Id: 31
+ Name: Ritual of Blessing
+ Enter:
+ Map: 2@mir
+ X: 101
+ Y: 12
+ - Id: 32
+ Name: Room of Consciousness
+ Enter:
+ Map: 1@mir
+ X: 101
+ Y: 10
+# - Id: 33
+# Name: Sky Fortress Invasion
+# Enter:
+# Map: 1@sthb
+# X: 54
+# Y: 67
+# AdditionalMaps:
+# 1@sthc: true
+# 1@sthd: true
diff --git a/db/readme.md b/db/readme.md
index eeddb1faed..094a296691 100644
--- a/db/readme.md
+++ b/db/readme.md
@@ -38,10 +38,18 @@ We want to add our own custom achievement that can be given to a player via an N
---
We want to add our own customized Housing Instance.
-#### /db/import/instance_db.txt
+#### /db/import/instance_db.yml
- // ID,Name,LimitTime,IdleTimeOut,EnterMap,EnterX,EnterY,Map2,Map3,...,Map255
- 35,Home,3600,900,1@home,24,6,2@home,3@home
+ - Id: 35
+ Name: Home
+ IdleTimeOut: 900
+ Enter:
+ Map: 1@home
+ X: 24
+ Y: 6
+ AdditionalMaps:
+ - Map: 2@home
+ - Map: 3@home
### Mob Alias
diff --git a/doc/script_commands.txt b/doc/script_commands.txt
index f4be22da15..d254890b9f 100644
--- a/doc/script_commands.txt
+++ b/doc/script_commands.txt
@@ -8938,7 +8938,7 @@ with the given character id.
*instance_create(""{,{,}});
Creates an instance for the of . The instance name, along with
-all other instance data, is read from 'db/(pre-)re/instance_db.txt'. Upon success,
+all other instance data, is read from 'db/(pre-)re/instance_db.yml'. Upon success,
the command generates a unique instance ID, duplicates all listed maps and NPCs,
sets the alive time, and triggers the "OnInstanceInit" label in all NPCs inside
the instance.
@@ -8971,7 +8971,7 @@ This will also trigger the "OnInstanceDestroy" label in all NPCs inside the inst
Warps the attached player to the specified . If no ID is specified,
the IM_PARTY instance the invoking player is attached to is used.
-The map and coordinates are located in 'db/(pre-)re/instance_db.txt'.
+The map and coordinates are located in 'db/(pre-)re/instance_db.yml'.
The command returns IE_OK upon success, and these values upon failure:
IE_NOMEMBER: Party/Guild/Clan not found (for party/guild/clan modes).
diff --git a/doc/yaml/db/instance_db.yml b/doc/yaml/db/instance_db.yml
new file mode 100644
index 0000000000..b7c1cf8ffe
--- /dev/null
+++ b/doc/yaml/db/instance_db.yml
@@ -0,0 +1,17 @@
+###########################################################################
+# Instance Database
+###########################################################################
+#
+# Instance Settings
+#
+###########################################################################
+# - Id Instance ID.
+# Name Instance Name.
+# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
+# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
+# Enter: Instance entrance coordinates.
+# Map Map Name where players start.
+# X X Coordinate where players start.
+# Y Y Coordinate where players start.
+# AdditionalMaps: List of maps that are part of an instance. (Optional)
+###########################################################################
diff --git a/src/common/utilities.hpp b/src/common/utilities.hpp
index e00228a378..15ba32cef6 100644
--- a/src/common/utilities.hpp
+++ b/src/common/utilities.hpp
@@ -175,6 +175,23 @@ namespace rathena {
vector.erase(vector.begin() + index);
}
+ /**
+ * Determine if a value exists in the vector and then erase it
+ * @param vector: Vector to erase value from
+ * @param value: Value to remove
+ */
+ template void vector_erase_if_exists(std::vector &vector, V value) {
+ auto it = std::find(vector.begin(), vector.end(), value);
+
+ if (it != vector.end()) {
+ if (vector.size() == 1) {
+ vector.clear();
+ vector.shrink_to_fit();
+ } else
+ vector.erase(it);
+ }
+ }
+
bool safe_addition( int64 a, int64 b, int64& result );
bool safe_substraction( int64 a, int64 b, int64& result );
bool safe_multiplication( int64 a, int64 b, int64& result );
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp
index e8a86d415a..b0f9312b18 100644
--- a/src/map/atcommand.cpp
+++ b/src/map/atcommand.cpp
@@ -4030,8 +4030,8 @@ ACMD_FUNC(reload) {
if (quest_db.reload())
clif_displaymessage(fd, msg_txt(sd,1377)); // Quest database has been reloaded.
} else if (strstr(command, "instancedb") || strncmp(message, "instancedb", 4) == 0) {
- instance_reload();
- clif_displaymessage(fd, msg_txt(sd,516)); // Instance database has been reloaded.
+ if (instance_db.reload())
+ clif_displaymessage(fd, msg_txt(sd,516)); // Instance database has been reloaded.
} else if (strstr(command, "achievementdb") || strncmp(message, "achievementdb", 4) == 0) {
achievement_db_reload();
clif_displaymessage(fd, msg_txt(sd,771)); // Achievement database has been reloaded.
diff --git a/src/map/clif.cpp b/src/map/clif.cpp
index 8b767091cc..596b1fc482 100644
--- a/src/map/clif.cpp
+++ b/src/map/clif.cpp
@@ -17793,26 +17793,25 @@ void clif_font(struct map_session_data *sd)
/// Required to start the instancing information window on Client
/// This window re-appears each "refresh" of client automatically until the keep_limit reaches 0.
/// S 0x2cb .61B .W
-void clif_instance_create(unsigned short instance_id, int num)
+void clif_instance_create(int instance_id, int num)
{
#if PACKETVER >= 20071128
- struct instance_db *db = NULL;
struct map_session_data *sd = NULL;
enum send_target target = PARTY;
unsigned char buf[65];
- instance_getsd(instance_id, &sd, &target);
+ instance_getsd(instance_id, sd, &target);
if (!sd)
return;
- db = instance_searchtype_db(instance_data[instance_id].type);
+ std::shared_ptr db = instance_db.find(util::umap_find(instances, instance_id)->id);
if (!db)
return;
WBUFW(buf,0) = 0x2cb;
- safestrncpy(WBUFCP(buf,2), StringBuf_Value(db->name), INSTANCE_NAME_LENGTH);
+ safestrncpy(WBUFCP(buf,2), db->name.c_str(), INSTANCE_NAME_LENGTH);
WBUFW(buf,63) = num;
clif_send(buf,packet_len(0x2cb),&sd->bl,target);
#endif
@@ -17822,14 +17821,14 @@ void clif_instance_create(unsigned short instance_id, int num)
/// To announce Instancing queue creation if no maps available
/// S 0x2cc .W
-void clif_instance_changewait(unsigned short instance_id, int num)
+void clif_instance_changewait(int instance_id, int num)
{
#if PACKETVER >= 20071128
struct map_session_data *sd = NULL;
enum send_target target = PARTY;
unsigned char buf[4];
- instance_getsd(instance_id, &sd, &target);
+ instance_getsd(instance_id, sd, &target);
if (!sd)
return;
@@ -17844,26 +17843,25 @@ void clif_instance_changewait(unsigned short instance_id, int num)
/// Notify the current status to members
/// S 0x2cd .61B .L .L
-void clif_instance_status(unsigned short instance_id, unsigned int limit1, unsigned int limit2)
+void clif_instance_status(int instance_id, unsigned int limit1, unsigned int limit2)
{
#if PACKETVER >= 20071128
- struct instance_db *db = NULL;
struct map_session_data *sd = NULL;
enum send_target target = PARTY;
unsigned char buf[71];
- instance_getsd(instance_id, &sd, &target);
+ instance_getsd(instance_id, sd, &target);
if (!sd)
return;
- db = instance_searchtype_db(instance_data[instance_id].type);
+ std::shared_ptr db = instance_db.find(util::umap_find(instances, instance_id)->id);
if (!db)
return;
WBUFW(buf,0) = 0x2cd;
- safestrncpy(WBUFCP(buf,2), StringBuf_Value(db->name), INSTANCE_NAME_LENGTH);
+ safestrncpy(WBUFCP(buf,2), db->name.c_str(), INSTANCE_NAME_LENGTH);
WBUFL(buf,63) = limit1;
WBUFL(buf,67) = limit2;
clif_send(buf,packet_len(0x2cd),&sd->bl,target);
@@ -17879,14 +17877,14 @@ void clif_instance_status(unsigned short instance_id, unsigned int limit1, unsig
/// 2 = The Memorial Dungeon's entry time limit expired; it has been destroyed
/// 3 = The Memorial Dungeon has been removed.
/// 4 = Create failure (removes the instance window)
-void clif_instance_changestatus(unsigned int instance_id, int type, unsigned int limit)
+void clif_instance_changestatus(int instance_id, e_instance_notify type, unsigned int limit)
{
#if PACKETVER >= 20071128
struct map_session_data *sd = NULL;
enum send_target target = PARTY;
unsigned char buf[10];
- instance_getsd(instance_id, &sd, &target);
+ instance_getsd(instance_id, sd, &target);
if (!sd)
return;
diff --git a/src/map/clif.hpp b/src/map/clif.hpp
index b52761d30b..6d8c3ed64d 100644
--- a/src/map/clif.hpp
+++ b/src/map/clif.hpp
@@ -43,6 +43,7 @@ struct achievement;
struct guild_log_entry;
enum e_guild_storage_log : uint16;
enum e_bg_queue_apply_ack : uint16;
+enum e_instance_notify : uint8;
enum e_PacketDBVersion { // packet DB
MIN_PACKET_DB = 0x064,
@@ -835,10 +836,10 @@ void clif_bg_queue_lobby_notify(const char *name, struct map_session_data *sd);
void clig_bg_queue_ack_lobby(bool result, const char *name, const char *lobbyname, struct map_session_data *sd);
// Instancing
-void clif_instance_create(unsigned short instance_id, int num);
-void clif_instance_changewait(unsigned short instance_id, int num);
-void clif_instance_status(unsigned short instance_id, unsigned int limit1, unsigned int limit2);
-void clif_instance_changestatus(unsigned int instance_id, int type, unsigned int limit);
+void clif_instance_create(int instance_id, int num);
+void clif_instance_changewait(int instance_id, int num);
+void clif_instance_status(int instance_id, unsigned int limit1, unsigned int limit2);
+void clif_instance_changestatus(int instance_id, e_instance_notify type, unsigned int limit);
// Custom Fonts
void clif_font(struct map_session_data *sd);
diff --git a/src/map/instance.cpp b/src/map/instance.cpp
index a14392eac2..f56c768bc7 100644
--- a/src/map/instance.cpp
+++ b/src/map/instance.cpp
@@ -4,6 +4,7 @@
#include "instance.hpp"
#include
+#include
#include "../common/cbasetypes.hpp"
#include "../common/db.hpp"
@@ -14,6 +15,7 @@
#include "../common/socket.hpp"
#include "../common/strlib.hpp"
#include "../common/timer.hpp"
+#include "../common/utilities.hpp"
#include "clan.hpp"
#include "clif.hpp"
@@ -23,283 +25,445 @@
#include "party.hpp"
#include "pc.hpp"
-#define INSTANCE_INTERVAL 60000 // Interval used to check when an instance is to be destroyed (ms)
+using namespace rathena;
-struct instance_data instance_data[MAX_INSTANCE_DATA];
-struct eri *instance_maps_ers = NULL; ///< Array of maps per instance
-
-int16 instance_start = 0;
-
-static DBMap *InstanceDB; /// Instance DB: struct instance_db, key: id
-static DBMap *InstanceNameDB; /// instance id, key: name
-
-static struct {
- int id[MAX_INSTANCE_DATA];
- int count;
+/// Instance Idle Queue data
+struct s_instance_wait {
+ std::deque id;
int timer;
} instance_wait;
-/*==========================================
- * Searches for an instance ID in the database
- *------------------------------------------*/
-struct instance_db *instance_searchtype_db(unsigned short instance_id) {
- return (struct instance_db *)uidb_get(InstanceDB,instance_id);
+#define INSTANCE_INTERVAL 60000 // Interval used to check when an instance is to be destroyed (ms)
+
+int16 instance_start = 0; // Instance MapID start
+int instance_count = 1; // Total created instances
+
+std::unordered_map> instances;
+
+const std::string InstanceDatabase::getDefaultLocation() {
+ return std::string(db_path) + "/instance_db.yml";
}
-static uint16 instance_name2id(const char *instance_name) {
- return (uint16)strdb_uiget(InstanceNameDB,instance_name);
+/**
+ * Reads and parses an entry from the instance_db.
+ * @param node: YAML node containing the entry.
+ * @return count of successfully parsed rows
+ */
+uint64 InstanceDatabase::parseBodyNode(const YAML::Node &node) {
+ int32 instance_id = 0;
+
+ if (!this->asInt32(node, "Id", instance_id))
+ return 0;
+
+ if (instance_id <= 0) {
+ this->invalidWarning(node, "Instance Id is invalid. Valid range 1~%d, skipping.\n", INT_MAX);
+ return 0;
+ }
+
+ std::shared_ptr instance = this->find(instance_id);
+ bool exists = instance != nullptr;
+
+ if (!exists) {
+ if (!this->nodesExist(node, { "Name", "Enter" }))
+ return 0;
+
+ instance = std::make_shared();
+ instance->id = instance_id;
+ }
+
+ if (this->nodeExists(node, "Name")) {
+ std::string name;
+
+ if (!this->asString(node, "Name", name))
+ return 0;
+
+ for (const auto &instance : instance_db) {
+ if (instance.second->name.compare(name) == 0) {
+ this->invalidWarning(node["Name"], "Instance name %s already exists, skipping.\n", name.c_str());
+ return 0;
+ }
+ }
+
+ instance->name = name;
+ }
+
+ if (this->nodeExists(node, "TimeLimit")) {
+ uint32 limit;
+
+ if (!this->asUInt32(node, "TimeLimit", limit))
+ return 0;
+
+ instance->limit = limit;
+ } else {
+ if (!exists)
+ instance->limit = 3600;
+ }
+
+ if (this->nodeExists(node, "IdleTimeOut")) {
+ uint32 idle;
+
+ if (!this->asUInt32(node, "IdleTimeOut", idle))
+ return 0;
+
+ instance->timeout = idle;
+ } else {
+ if (!exists)
+ instance->timeout = 300;
+ }
+
+ /*
+ if (this->nodeExists(node, "Destroyable")) {
+ bool destroy;
+
+ if (!this->asBool(node, "Destroyable", destroy))
+ return 0;
+
+ instance->destroyable = destroy;
+ } else {
+ if (!exists)
+ instance->destroyable = true;
+ }
+ */
+
+ if (this->nodeExists(node, "Enter")) {
+ const YAML::Node &enterNode = node["Enter"];
+
+ if (!this->nodesExist(enterNode, { "Map", "X", "Y" }))
+ return 0;
+
+ if (this->nodeExists(enterNode, "Map")) {
+ std::string map;
+
+ if (!this->asString(enterNode, "Map", map))
+ return 0;
+
+ int16 m = map_mapname2mapid(map.c_str());
+
+ if (m == -1) {
+ this->invalidWarning(enterNode["Map"], "Map %s is not a valid map, skipping.\n", map.c_str());
+ return 0;
+ }
+
+ instance->enter.map = m;
+ }
+
+ if (this->nodeExists(enterNode, "X")) {
+ int16 x;
+
+ if (!this->asInt16(enterNode, "X", x))
+ return 0;
+
+ instance->enter.x = x;
+ }
+
+ if (this->nodeExists(enterNode, "Y")) {
+ int16 y;
+
+ if (!this->asInt16(enterNode, "Y", y))
+ return 0;
+
+ instance->enter.y = y;
+ }
+ }
+
+ if (this->nodeExists(node, "AdditionalMaps")) {
+ const YAML::Node &mapNode = node["AdditionalMaps"];
+
+ for (const auto &mapIt : mapNode) {
+ std::string map = mapIt.first.as();
+ int16 m = map_mapname2mapid(map.c_str());
+
+ if (m == instance->enter.map) {
+ this->invalidWarning(mapNode, "Additional Map %s is already listed as the EnterMap.\n", map.c_str());
+ continue;
+ }
+
+ if (m == -1) {
+ this->invalidWarning(mapNode, "Additional Map %s is not a valid map, skipping.\n", map.c_str());
+ return 0;
+ }
+
+ bool active;
+
+ if (!this->asBool(mapNode, map, active))
+ return 0;
+
+ if (active)
+ instance->maplist.push_back(m);
+ else
+ util::vector_erase_if_exists(instance->maplist, m);
+ }
+ }
+
+ if (!exists)
+ this->put(instance_id, instance);
+
+ return 1;
}
-/*==========================================
+InstanceDatabase instance_db;
+
+/**
* Searches for an instance name in the database
- *------------------------------------------*/
-struct instance_db *instance_searchname_db(const char *instance_name) {
- uint16 id = instance_name2id(instance_name);
- if (id == 0)
- return NULL;
- return (struct instance_db *)uidb_get(InstanceDB,id);
+ * @param instance_name: Instance to search for
+ * @return shared_ptr of instance or nullptr on failure
+ */
+std::shared_ptr instance_search_db_name(const char *instance_name)
+{
+ for (const auto &it : instance_db) {
+ if (!strcmp(it.second->name.c_str(), instance_name))
+ return it.second;
+ }
+
+ return nullptr;
}
/**
* Search for a sd of an Instance
* @param instance_id: Instance ID
- * @param sd: Player data to attach
+ * @param sd: Pointer to player data
* @param target: Target display type
*/
-void instance_getsd(unsigned short instance_id, struct map_session_data **sd, enum send_target *target) {
- switch(instance_data[instance_id].mode) {
+void instance_getsd(int instance_id, struct map_session_data *&sd, enum send_target *target) {
+ std::shared_ptr idata = util::umap_find(instances, instance_id);
+
+ if (!idata) {
+ sd = nullptr;
+ return;
+ }
+
+ switch(idata->mode) {
case IM_NONE:
- (*sd) = NULL;
+ sd = nullptr;
(*target) = SELF;
break;
case IM_GUILD:
- (*sd) = guild_getavailablesd(guild_search(instance_data[instance_id].owner_id));
+ sd = guild_getavailablesd(guild_search(idata->owner_id));
(*target) = GUILD;
break;
case IM_PARTY:
- (*sd) = party_getavailablesd(party_search(instance_data[instance_id].owner_id));
+ sd = party_getavailablesd(party_search(idata->owner_id));
(*target) = PARTY;
break;
case IM_CHAR:
- (*sd) = map_charid2sd(instance_data[instance_id].owner_id);
+ sd = map_charid2sd(idata->owner_id);
(*target) = SELF;
break;
case IM_CLAN:
- (*sd) = clan_getavailablesd(clan_search(instance_data[instance_id].owner_id));
+ sd = clan_getavailablesd(clan_search(idata->owner_id));
(*target) = CLAN;
}
return;
}
-/*==========================================
+/**
* Deletes an instance timer (Destroys instance)
- *------------------------------------------*/
+ */
static TIMER_FUNC(instance_delete_timer){
instance_destroy(id);
return 0;
}
-/*==========================================
+/**
* Create subscription timer
- *------------------------------------------*/
+ */
static TIMER_FUNC(instance_subscription_timer){
- int i, ret;
- unsigned short instance_id = instance_wait.id[0];
- struct map_session_data *sd = NULL;
- struct party_data *pd = NULL;
- struct guild *gd = NULL;
- struct clan *cd = NULL;
- enum instance_mode mode;
+ int instance_id = instance_wait.id[0];
- if(instance_wait.count == 0 || instance_id == 0)
+ if (instance_id <= 0 || instance_wait.id.empty())
return 0;
- // Check that maps have been added
- ret = instance_addmap(instance_id);
- mode = instance_data[instance_id].mode;
+ std::shared_ptr idata = util::umap_find(instances, instance_id);
+
+ if (!idata)
+ return 0;
+
+ struct map_session_data *sd;
+ struct party_data *pd;
+ struct guild *gd;
+ struct clan *cd;
+ e_instance_mode mode = idata->mode;
+ int ret = instance_addmap(instance_id); // Check that maps have been added
switch(mode) {
case IM_NONE:
break;
case IM_CHAR:
- if (ret == 0 && (sd = map_charid2sd(instance_data[instance_id].owner_id)) != NULL) // If no maps are created, tell player to wait
+ if (ret == 0 && (sd = map_charid2sd(idata->owner_id))) // If no maps are created, tell player to wait
clif_instance_changewait(instance_id, 0xffff);
break;
case IM_PARTY:
- if (ret == 0 && (pd = party_search(instance_data[instance_id].owner_id)) != NULL) // If no maps are created, tell party to wait
+ if (ret == 0 && (pd = party_search(idata->owner_id))) // If no maps are created, tell party to wait
clif_instance_changewait(instance_id, 0xffff);
break;
case IM_GUILD:
- if (ret == 0 && (gd = guild_search(instance_data[instance_id].owner_id)) != NULL) // If no maps are created, tell guild to wait
+ if (ret == 0 && (gd = guild_search(idata->owner_id))) // If no maps are created, tell guild to wait
clif_instance_changewait(instance_id, 0xffff);
break;
case IM_CLAN:
- if (ret == 0 && (cd = clan_search(instance_data[instance_id].owner_id)) != NULL) // If no maps are created, tell clan to wait
+ if (ret == 0 && (cd = clan_search(idata->owner_id))) // If no maps are created, tell clan to wait
clif_instance_changewait(instance_id, 0xffff);
break;
default:
return 0;
}
- instance_wait.count--;
- memmove(&instance_wait.id[0],&instance_wait.id[1],sizeof(instance_wait.id[0])*instance_wait.count);
- memset(&instance_wait.id[instance_wait.count], 0, sizeof(instance_wait.id[0]));
+ instance_wait.id.pop_front();
- for(i = 0; i < instance_wait.count; i++) {
- if( instance_data[instance_wait.id[i]].state == INSTANCE_IDLE &&
- ((mode == IM_CHAR && sd != NULL) || (mode == IM_GUILD && gd != NULL) || (mode == IM_PARTY && pd != NULL) || (mode == IM_CLAN && cd != NULL))
- ){
+ for (int i = 0; i < instance_wait.id.size(); i++) {
+ if (idata->state == INSTANCE_IDLE && ((mode == IM_CHAR && sd) || (mode == IM_GUILD && gd) || (mode == IM_PARTY && pd) || (mode == IM_CLAN && cd)))
clif_instance_changewait(instance_id, i + 1);
- }
}
- if(instance_wait.count)
- instance_wait.timer = add_timer(gettick()+INSTANCE_INTERVAL, instance_subscription_timer, 0, 0);
+ if (!instance_wait.id.empty())
+ instance_wait.timer = add_timer(gettick() + INSTANCE_INTERVAL, instance_subscription_timer, 0, 0);
else
instance_wait.timer = INVALID_TIMER;
return 0;
}
-/*==========================================
+/**
* Adds timer back to members entering instance
- *------------------------------------------*/
-static int instance_startkeeptimer(struct instance_data *im, unsigned short instance_id)
+ * @param idata: Instance data
+ * @param instance_id: Instance ID to notify
+ * @return True on success or false on failure
+ */
+bool instance_startkeeptimer(std::shared_ptr idata, int instance_id)
{
- struct instance_db *db;
-
- nullpo_retr(0, im);
-
// No timer
- if(im->keep_timer != INVALID_TIMER)
- return 1;
+ if (!idata || idata->keep_timer != INVALID_TIMER)
+ return false;
- if((db = instance_searchtype_db(im->type)) == NULL)
- return 1;
+ std::shared_ptr db = instance_db.find(idata->id);
+
+ if (!db)
+ return false;
// Add timer
- im->keep_limit = (unsigned int)time(NULL) + db->limit;
- im->keep_timer = add_timer(gettick()+db->limit*1000, instance_delete_timer, instance_id, 0);
+ idata->keep_limit = static_cast(time(nullptr)) + db->limit;
+ idata->keep_timer = add_timer(gettick() + db->limit * 1000, instance_delete_timer, instance_id, 0);
- switch(im->mode) {
+ switch(idata->mode) {
case IM_NONE:
break;
case IM_CHAR:
- if (map_charid2sd(im->owner_id) != NULL) // Notify player of the added instance timer
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (map_charid2sd(idata->owner_id)) // Notify player of the added instance timer
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
case IM_PARTY:
- if (party_search(im->owner_id) != NULL) // Notify party of the added instance timer
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (party_search(idata->owner_id)) // Notify party of the added instance timer
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
case IM_GUILD:
- if (guild_search(im->owner_id) != NULL) // Notify guild of the added instance timer
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (guild_search(idata->owner_id)) // Notify guild of the added instance timer
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
case IM_CLAN:
- if (clan_search(im->owner_id) != NULL) // Notify clan of the added instance timer
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (clan_search(idata->owner_id)) // Notify clan of the added instance timer
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
default:
- return 1;
+ return false;
}
- return 0;
+ return true;
}
-/*==========================================
- * Creates idle timer
- * Default before instance destroy is 5 minutes
- *------------------------------------------*/
-static int instance_startidletimer(struct instance_data *im, unsigned short instance_id)
+/**
+ * Creates an idle timer for an instance, default is 5 minutes
+ * @param idata: Instance data
+ * @param instance_id: Instance ID to notify
+ * @param True on success or false on failure
+ */
+bool instance_startidletimer(std::shared_ptr idata, int instance_id)
{
- struct instance_db *db;
-
- nullpo_retr(1, im);
-
// No current timer
- if(im->idle_timer != INVALID_TIMER)
- return 1;
+ if (!idata || idata->idle_timer != INVALID_TIMER)
+ return false;
- if ((db = instance_searchtype_db(im->type)) == NULL)
- return 1;
+ std::shared_ptr db = instance_db.find(idata->id);
+
+ if (!db)
+ return false;
// Add the timer
- im->idle_limit = (unsigned int)time(NULL) + db->timeout;
- im->idle_timer = add_timer(gettick() + db->timeout * 1000, instance_delete_timer, instance_id, 0);
+ idata->idle_limit = static_cast(time(nullptr)) + db->timeout;
+ idata->idle_timer = add_timer(gettick() + db->timeout * 1000, instance_delete_timer, instance_id, 0);
- switch(im->mode) {
+ switch(idata->mode) {
case IM_NONE:
break;
case IM_CHAR:
- if (map_charid2sd(im->owner_id) != NULL && instance_searchtype_db(im->type) != NULL) // Notify player of added instance timer
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (map_charid2sd(idata->owner_id)) // Notify player of added instance timer
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
case IM_PARTY:
- if (party_search(im->owner_id) != NULL && instance_searchtype_db(im->type) != NULL) // Notify party of added instance timer
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (party_search(idata->owner_id)) // Notify party of added instance timer
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
case IM_GUILD:
- if (guild_search(im->owner_id) != NULL && instance_searchtype_db(im->type) != NULL) // Notify guild of added instance timer
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (guild_search(idata->owner_id)) // Notify guild of added instance timer
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
case IM_CLAN:
- if (clan_search(im->owner_id) != NULL && instance_searchtype_db(im->type) != NULL) // Notify clan of added instance timer
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (clan_search(idata->owner_id)) // Notify clan of added instance timer
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
default:
- return 1;
+ return false;
}
- return 0;
+ return true;
}
-/*==========================================
- * Delete the idle timer
- *------------------------------------------*/
-static int instance_stopidletimer(struct instance_data *im, unsigned short instance_id)
+/**
+ * Remove the idle timer from an instance
+ * @param idata: Instace data
+ * @param instance_id: Instance ID to notify
+ * @return True on success or false on failure
+ */
+bool instance_stopidletimer(std::shared_ptr idata, int instance_id)
{
- nullpo_retr(0, im);
-
// No timer
- if(im->idle_timer == INVALID_TIMER)
- return 1;
+ if (!idata || idata->idle_timer == INVALID_TIMER)
+ return false;
// Delete the timer - Party has returned or instance is destroyed
- im->idle_limit = 0;
- delete_timer(im->idle_timer, instance_delete_timer);
- im->idle_timer = INVALID_TIMER;
+ idata->idle_limit = 0;
+ delete_timer(idata->idle_timer, instance_delete_timer);
+ idata->idle_timer = INVALID_TIMER;
- switch(im->mode) {
+ switch(idata->mode) {
case IM_NONE:
break;
case IM_CHAR:
- if (map_charid2sd(im->owner_id) != NULL) // Notify the player
- clif_instance_changestatus(instance_id, 0, im->idle_limit);
+ if (map_charid2sd(idata->owner_id)) // Notify the player
+ clif_instance_changestatus(instance_id, IN_NOTIFY, idata->idle_limit);
break;
case IM_PARTY:
- if (party_search(im->owner_id) != NULL) // Notify the party
- clif_instance_changestatus(instance_id, 0, im->idle_limit);
+ if (party_search(idata->owner_id)) // Notify the party
+ clif_instance_changestatus(instance_id, IN_NOTIFY, idata->idle_limit);
break;
case IM_GUILD:
- if (guild_search(im->owner_id) != NULL) // Notify the guild
- clif_instance_changestatus(instance_id, 0, im->idle_limit);
+ if (guild_search(idata->owner_id)) // Notify the guild
+ clif_instance_changestatus(instance_id, IN_NOTIFY, idata->idle_limit);
break;
case IM_CLAN:
- if (clan_search(im->owner_id) != NULL) // Notify the clan
- clif_instance_changestatus(instance_id, 0, im->idle_limit);
+ if (clan_search(idata->owner_id)) // Notify the clan
+ clif_instance_changestatus(instance_id, IN_NOTIFY, idata->idle_limit);
break;
default:
- return 1;
+ return false;
}
- return 0;
+ return true;
}
-/*==========================================
+/**
* Run the OnInstanceInit events for duplicated NPCs
- *------------------------------------------*/
+ */
static int instance_npcinit(struct block_list *bl, va_list ap)
{
struct npc_data* nd;
@@ -311,9 +475,9 @@ static int instance_npcinit(struct block_list *bl, va_list ap)
return npc_instanceinit(nd);
}
-/*==========================================
+/**
* Run the OnInstanceDestroy events for duplicated NPCs
- *------------------------------------------*/
+ */
static int instance_npcdestroy(struct block_list *bl, va_list ap)
{
struct npc_data* nd;
@@ -325,9 +489,9 @@ static int instance_npcdestroy(struct block_list *bl, va_list ap)
return npc_instancedestroy(nd);
}
-/*==========================================
- * Add an NPC to an instance
- *------------------------------------------*/
+/**
+ * Update instance with new NPC
+ */
static int instance_addnpc_sub(struct block_list *bl, va_list ap)
{
struct npc_data* nd;
@@ -339,352 +503,324 @@ static int instance_addnpc_sub(struct block_list *bl, va_list ap)
return npc_duplicate4instance(nd, va_arg(ap, int));
}
-// Separate function used for reloading
-void instance_addnpc(struct instance_data *im)
+/**
+ * Add an NPC to an instance
+ * @param idata: Instance data
+ */
+void instance_addnpc(std::shared_ptr idata)
{
- int i;
-
// First add the NPCs
- for (i = 0; i < im->cnt_map; i++) {
- struct map_data *mapdata = map_getmapdata(im->map[i]->src_m);
+ for (const auto &it : idata->map) {
+ struct map_data *mapdata = map_getmapdata(it.m);
- map_foreachinallarea(instance_addnpc_sub, im->map[i]->src_m, 0, 0, mapdata->xs, mapdata->ys, BL_NPC, im->map[i]->m);
+ map_foreachinallarea(instance_addnpc_sub, it.src_m, 0, 0, mapdata->xs, mapdata->ys, BL_NPC, it.m);
}
// Now run their OnInstanceInit
- for (i = 0; i < im->cnt_map; i++) {
- struct map_data *mapdata = map_getmapdata(im->map[i]->m);
-
- map_foreachinallarea(instance_npcinit, im->map[i]->m, 0, 0, mapdata->xs, mapdata->ys, BL_NPC, im->map[i]->m);
- }
+ for (const auto &it : idata->map) {
+ struct map_data *mapdata = map_getmapdata(it.m);
+ map_foreachinallarea(instance_npcinit, it.m, 0, 0, mapdata->xs, mapdata->ys, BL_NPC, it.m);
+ }
}
-/*--------------------------------------
- * name : instance name
- * Return value could be
- * -4 = no free instances | -3 = already exists | -2 = character/party/guild not found | -1 = invalid type
- * On success return instance_id
- *--------------------------------------*/
-int instance_create(int owner_id, const char *name, enum instance_mode mode) {
- struct instance_db *db = instance_searchname_db(name);
- struct map_session_data *sd = NULL;
- struct party_data *pd = NULL;
- struct guild *gd = NULL;
- struct clan* cd = NULL;
- unsigned short i;
+/**
+ * Create an instance
+ * @param owner_id: Owner block ID
+ * @param name: Instance name
+ * @param mode: Instance mode
+ * @return -4 = no free instances | -3 = already exists | -2 = character/party/guild not found | -1 = invalid type | On success return instance_id
+ */
+int instance_create(int owner_id, const char *name, e_instance_mode mode) {
+ std::shared_ptr db = instance_search_db_name(name);
- nullpo_retr(-1, db);
+ if (!db) {
+ ShowError("instance_create: Unknown instance %s creation was attempted.\n", name);
+ return -1;
+ }
+
+ struct map_session_data *sd;
+ struct party_data *pd;
+ struct guild *gd;
+ struct clan* cd;
switch(mode) {
case IM_NONE:
break;
case IM_CHAR:
- if ((sd = map_charid2sd(owner_id)) == NULL) {
- ShowError("instance_create: character %d not found for instance '%s'.\n", owner_id, name);
+ if (!(sd = map_charid2sd(owner_id))) {
+ ShowError("instance_create: Character %d not found for instance '%s'.\n", owner_id, name);
return -2;
}
- if (sd->instance_id)
+ if (sd->instance_id > 0)
return -3; // Player already instancing
break;
case IM_PARTY:
- if ((pd = party_search(owner_id)) == NULL) {
- ShowError("instance_create: party %d not found for instance '%s'.\n", owner_id, name);
+ if (!(pd = party_search(owner_id))) {
+ ShowError("instance_create: Party %d not found for instance '%s'.\n", owner_id, name);
return -2;
}
- if (pd->instance_id)
+ if (pd->instance_id > 0)
return -3; // Party already instancing
break;
case IM_GUILD:
- if ((gd = guild_search(owner_id)) == NULL) {
- ShowError("instance_create: guild %d not found for instance '%s'.\n", owner_id, name);
+ if (!(gd = guild_search(owner_id))) {
+ ShowError("instance_create: Guild %d not found for instance '%s'.\n", owner_id, name);
return -2;
}
- if (gd->instance_id)
+ if (gd->instance_id > 0)
return -3; // Guild already instancing
break;
case IM_CLAN:
- if ((cd = clan_search(owner_id)) == NULL) {
- ShowError("instance_create: clan %d not found for instance '%s'.\n", owner_id, name);
+ if (!(cd = clan_search(owner_id))) {
+ ShowError("instance_create: Clan %d not found for instance '%s'.\n", owner_id, name);
return -2;
}
- if (cd->instance_id)
+ if (cd->instance_id > 0)
return -3; // Clan already instancing
break;
default:
- ShowError("instance_create: unknown mode %u for owner_id %d and name %s.\n", mode, owner_id, name);
+ ShowError("instance_create: Unknown mode %u for owner_id %d and name %s.\n", mode, owner_id, name);
return -2;
}
- // Searching a Free Instance
- // 0 is ignored as this means "no instance" on maps
- ARR_FIND(1, MAX_INSTANCE_DATA, i, instance_data[i].state == INSTANCE_FREE);
- if( i >= MAX_INSTANCE_DATA )
+ if (instance_count <= 0)
return -4;
- instance_data[i].type = db->id;
- instance_data[i].state = INSTANCE_IDLE;
- instance_data[i].owner_id = owner_id;
- instance_data[i].mode = mode;
- instance_data[i].keep_limit = 0;
- instance_data[i].keep_timer = INVALID_TIMER;
- instance_data[i].idle_limit = 0;
- instance_data[i].idle_timer = INVALID_TIMER;
- instance_data[i].regs.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
- instance_data[i].regs.arrays = NULL;
- instance_data[i].cnt_map = 0;
+ int instance_id = instance_count++;
+ std::shared_ptr entry = std::make_shared();
+
+ entry->id = db->id;
+ entry->owner_id = owner_id;
+ entry->mode = mode;
+ entry->regs.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
+ entry->regs.arrays = nullptr;
+ instances.insert({ instance_id, entry });
switch(mode) {
case IM_CHAR:
- sd->instance_id = i;
+ sd->instance_id = instance_id;
break;
case IM_PARTY:
- pd->instance_id = i;
+ pd->instance_id = instance_id;
break;
case IM_GUILD:
- gd->instance_id = i;
+ gd->instance_id = instance_id;
break;
case IM_CLAN:
- cd->instance_id = i;
+ cd->instance_id = instance_id;
break;
}
- instance_wait.id[instance_wait.count++] = i;
-
- clif_instance_create(i, instance_wait.count);
-
+ instance_wait.id.push_back(instance_id);
+ clif_instance_create(instance_id, instance_wait.id.size());
instance_subscription_timer(0,0,0,0);
- ShowInfo("[Instance] Created: %s (%hu).\n", name, i);
+ ShowInfo("[Instance] Created: %s (%d).\n", name, instance_id);
// Start the instance timer on instance creation
- instance_startkeeptimer(&instance_data[i], i);
+ instance_startkeeptimer(entry, instance_id);
- return i;
+ return instance_id;
}
-/*--------------------------------------
+/**
* Adds maps to the instance
- *--------------------------------------*/
-int instance_addmap(unsigned short instance_id) {
- int i, m;
- struct instance_data *im;
- struct instance_db *db;
- struct s_instance_map *entry;
-
- if (instance_id == 0)
+ * @param instance_id: Instance ID to add map to
+ * @return 0 on failure or map count on success
+ */
+int instance_addmap(int instance_id) {
+ if (instance_id <= 0)
return 0;
- im = &instance_data[instance_id];
+ std::shared_ptr idata = util::umap_find(instances, instance_id);
// If the instance isn't idle, we can't do anything
- if (im->state != INSTANCE_IDLE)
+ if (idata->state != INSTANCE_IDLE)
return 0;
- if ((db = instance_searchtype_db(im->type)) == NULL)
+ std::shared_ptr db = instance_db.find(idata->id);
+
+ if (!db)
return 0;
// Set to busy, update timers
- im->state = INSTANCE_BUSY;
- im->idle_limit = (unsigned int)time(NULL) + db->timeout;
- im->idle_timer = add_timer(gettick() + db->timeout * 1000, instance_delete_timer, instance_id, 0);
+ idata->state = INSTANCE_BUSY;
+ idata->idle_limit = static_cast(time(nullptr)) + db->timeout;
+ idata->idle_timer = add_timer(gettick() + db->timeout * 1000, instance_delete_timer, instance_id, 0);
- // Add the maps
- if (db->maplist_count > MAX_MAP_PER_INSTANCE) {
- ShowError("instance_addmap: Too many maps (%d) created for a single instance '%s' (%hu).\n", db->maplist_count, StringBuf_Value(db->name), instance_id);
- return 0;
- }
+ int16 m;
// Add initial map
- if ((m = map_addinstancemap(StringBuf_Value(db->enter.mapname), instance_id)) < 0) {
- ShowError("instance_addmap: Failed to create initial map for instance '%s' (%hu).\n", StringBuf_Value(db->name), instance_id);
+ if ((m = map_addinstancemap(db->enter.map, instance_id)) < 0) {
+ ShowError("instance_addmap: Failed to create initial map for instance '%s' (%d).\n", db->name.c_str(), instance_id);
return 0;
}
- entry = ers_alloc(instance_maps_ers, struct s_instance_map);
- entry->m = m;
- entry->src_m = map_mapname2mapid(StringBuf_Value(db->enter.mapname));
- RECREATE(im->map, struct s_instance_map *, im->cnt_map + 1);
- im->map[im->cnt_map++] = entry;
+
+ struct s_instance_map entry;
+
+ entry.m = m;
+ entry.src_m = db->enter.map;
+ idata->map.push_back(entry);
// Add extra maps (if any)
- for(i = 0; i < db->maplist_count; i++) {
- if(strlen(StringBuf_Value(db->maplist[i])) < 1)
- continue;
- else if( (m = map_addinstancemap(StringBuf_Value(db->maplist[i]), instance_id)) < 0) {
- // An error occured adding a map
- ShowError("instance_addmap: No maps added to instance '%s' (%hu).\n", StringBuf_Value(db->name), instance_id);
+ for (const auto &it : db->maplist) {
+ if ((m = map_addinstancemap(it, instance_id)) < 0) { // An error occured adding a map
+ ShowError("instance_addmap: No maps added to instance '%s' (%d).\n", db->name.c_str(), instance_id);
return 0;
} else {
- entry = ers_alloc(instance_maps_ers, struct s_instance_map);
- entry->m = m;
- entry->src_m = map_mapname2mapid(StringBuf_Value(db->maplist[i]));
- RECREATE(im->map, struct s_instance_map *, im->cnt_map + 1);
- im->map[im->cnt_map++] = entry;
+ entry.m = m;
+ entry.src_m = it;
+ idata->map.push_back(entry);
}
}
// Create NPCs on all maps
- instance_addnpc(im);
+ instance_addnpc(idata);
- switch(im->mode) {
+ switch(idata->mode) {
case IM_NONE:
break;
case IM_CHAR:
- if (map_charid2sd(im->owner_id) != NULL) // Inform player of the created instance
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (map_charid2sd(idata->owner_id)) // Inform player of the created instance
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
case IM_PARTY:
- if (party_search(im->owner_id) != NULL) // Inform party members of the created instance
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (party_search(idata->owner_id)) // Inform party members of the created instance
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
case IM_GUILD:
- if (guild_search(im->owner_id) != NULL) // Inform guild members of the created instance
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (guild_search(idata->owner_id)) // Inform guild members of the created instance
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
case IM_CLAN:
- if (clan_search(im->owner_id) != NULL) // Inform clan members of the created instance
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ if (clan_search(idata->owner_id)) // Inform clan members of the created instance
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
break;
default:
return 0;
}
- return im->cnt_map;
+ return idata->map.size();
}
-
-/*==========================================
- * Returns an instance map ID using a map name
- * name : source map
- * instance_id : where to search
- * result : mapid of map "name" in this instance
- *------------------------------------------*/
-int16 instance_mapname2mapid(const char *name, unsigned short instance_id)
+/**
+ * Returns an instance map ID
+ * @param m: Source map ID
+ * @param instance_id: Instance to search
+ * @return Map ID in this instance
+ */
+int16 instance_mapid(int16 m, int instance_id)
{
- struct instance_data *im;
- int16 m = map_mapname2mapid(name);
- char iname[MAP_NAME_LENGTH];
- int i;
-
if(m < 0) {
- ShowError("instance_mapname2mapid: map name %s does not exist.\n",name);
- return m;
+ ShowError("instance_mapid: Map ID %d does not exist.\n", m);
+ return -1;
}
- strcpy(iname,name);
+ std::shared_ptr idata = util::umap_find(instances, instance_id);
- if(instance_id == 0 || instance_id > MAX_INSTANCE_DATA)
- return m;
+ if(!idata || idata->state != INSTANCE_BUSY)
+ return -1;
- im = &instance_data[instance_id];
- if(im->state != INSTANCE_BUSY)
- return m;
+ const char *iname = map_mapid2mapname(m);
- for(i = 0; i < im->cnt_map; i++)
- if(im->map[i]->src_m == m) {
+ for (const auto &it : idata->map) {
+ if (it.src_m == m) {
char alt_name[MAP_NAME_LENGTH];
- if((strchr(iname,'@') == NULL) && strlen(iname) > 8) {
- memmove(iname, iname+(strlen(iname)-9), strlen(iname));
- snprintf(alt_name, sizeof(alt_name),"%hu#%s", instance_id, iname);
- } else
- snprintf(alt_name, sizeof(alt_name),"%.3hu%s", instance_id, iname);
+
+ if (!(strchr(iname, '@')) && strlen(iname) > 8) {
+ memmove((void*)iname, iname + (strlen(iname) - 9), strlen(iname));
+ snprintf(alt_name, sizeof(alt_name), "%d#%s", instance_id, iname);
+ }
+ else
+ snprintf(alt_name, sizeof(alt_name), "%.3d%s", instance_id, iname);
return map_mapname2mapid(alt_name);
}
+ }
return m;
}
-/*==========================================
- * Removes a instance, all its maps and npcs.
- *------------------------------------------*/
-int instance_destroy(unsigned short instance_id)
+/**
+ * Removes an instance, all its maps, and NPCs.
+ * @param instance_id: Instance to remove
+ * @return True on sucess or false on failure
+ */
+bool instance_destroy(int instance_id)
{
- struct instance_data *im;
- struct map_session_data *sd = NULL;
- struct party_data *pd = NULL;
- struct guild *gd = NULL;
- struct clan *cd = NULL;
- int i, type = 0;
- unsigned int now = (unsigned int)time(NULL);
- enum instance_mode mode;
+ std::shared_ptr idata = util::umap_find(instances, instance_id);
- if(instance_id == 0 || instance_id > MAX_INSTANCE_DATA)
- return 1;
+ if (!idata)
+ return false;
- im = &instance_data[instance_id];
+ struct map_session_data *sd;
+ struct party_data *pd;
+ struct guild *gd;
+ struct clan *cd;
+ e_instance_mode mode = idata->mode;
+ e_instance_notify type = IN_NOTIFY;
- if(im->state == INSTANCE_FREE)
- return 1;
-
- mode = im->mode;
switch(mode) {
case IM_NONE:
break;
case IM_CHAR:
- sd = map_charid2sd(im->owner_id);
+ sd = map_charid2sd(idata->owner_id);
break;
case IM_PARTY:
- pd = party_search(im->owner_id);
+ pd = party_search(idata->owner_id);
break;
case IM_GUILD:
- gd = guild_search(im->owner_id);
+ gd = guild_search(idata->owner_id);
break;
case IM_CLAN:
- cd = clan_search(im->owner_id);
+ cd = clan_search(idata->owner_id);
break;
}
- if(im->state == INSTANCE_IDLE) {
- for(i = 0; i < instance_wait.count; i++) {
- if(instance_wait.id[i] == instance_id) {
- instance_wait.count--;
- memmove(&instance_wait.id[i],&instance_wait.id[i+1],sizeof(instance_wait.id[0])*(instance_wait.count-i));
- memset(&instance_wait.id[instance_wait.count], 0, sizeof(instance_wait.id[0]));
+ if(idata->state == INSTANCE_IDLE) {
+ for (auto instance_it = instance_wait.id.begin(); instance_it != instance_wait.id.end(); ++instance_it) {
+ if (*instance_it == instance_id) {
+ instance_wait.id.erase(instance_it);
- for(i = 0; i < instance_wait.count; i++)
- if(instance_data[instance_wait.id[i]].state == INSTANCE_IDLE)
+ for (int i = 0; i < instance_wait.id.size(); i++) {
+ if (util::umap_find(instances, instance_wait.id[i])->state == INSTANCE_IDLE)
if ((mode == IM_CHAR && sd) || (mode == IM_PARTY && pd) || (mode == IM_GUILD && gd) || (mode == IM_CLAN && cd))
clif_instance_changewait(instance_id, i + 1);
+ }
- if(instance_wait.count)
- instance_wait.timer = add_timer(gettick()+INSTANCE_INTERVAL, instance_subscription_timer, 0, 0);
+ if (!instance_wait.id.empty())
+ instance_wait.timer = add_timer(gettick() + INSTANCE_INTERVAL, instance_subscription_timer, 0, 0);
else
instance_wait.timer = INVALID_TIMER;
- type = 0;
break;
}
}
} else {
- if(im->keep_limit && im->keep_limit <= now)
- type = 1;
- else if(im->idle_limit && im->idle_limit <= now)
- type = 2;
+ unsigned int now = static_cast(time(nullptr));
+
+ if(idata->keep_limit && idata->keep_limit <= now)
+ type = IN_DESTROY_LIVE_TIMEOUT;
+ else if(idata->idle_limit && idata->idle_limit <= now)
+ type = IN_DESTROY_ENTER_TIMEOUT;
else
- type = 3;
+ type = IN_DESTROY_USER_REQUEST;
// Run OnInstanceDestroy on all NPCs in the instance
- for(i = 0; i < im->cnt_map; i++){
- struct map_data *mapdata = map_getmapdata(im->map[i]->m);
+ for (const auto &it : idata->map) {
+ struct map_data *mapdata = map_getmapdata(it.m);
- map_foreachinallarea(instance_npcdestroy, im->map[i]->m, 0, 0, mapdata->xs, mapdata->ys, BL_NPC, im->map[i]->m);
+ map_foreachinallarea(instance_npcdestroy, it.m, 0, 0, mapdata->xs, mapdata->ys, BL_NPC, it.m);
+ map_delinstancemap(it.m);
}
-
- for(i = 0; i < im->cnt_map; i++) {
- map_delinstancemap(im->map[i]->m);
- ers_free(instance_maps_ers, im->map[i]);
- }
- im->cnt_map = 0;
- aFree(im->map);
- im->map = NULL;
}
- if(im->keep_timer != INVALID_TIMER) {
- delete_timer(im->keep_timer, instance_delete_timer);
- im->keep_timer = INVALID_TIMER;
+ if(idata->keep_timer != INVALID_TIMER) {
+ delete_timer(idata->keep_timer, instance_delete_timer);
+ idata->keep_timer = INVALID_TIMER;
}
- if(im->idle_timer != INVALID_TIMER) {
- delete_timer(im->idle_timer, instance_delete_timer);
- im->idle_timer = INVALID_TIMER;
+ if(idata->idle_timer != INVALID_TIMER) {
+ delete_timer(idata->idle_timer, instance_delete_timer);
+ idata->idle_timer = INVALID_TIMER;
}
if (mode == IM_CHAR && sd)
@@ -697,60 +833,64 @@ int instance_destroy(unsigned short instance_id)
cd->instance_id = 0;
if (mode != IM_NONE) {
- if(type)
+ if(type != IN_NOTIFY)
clif_instance_changestatus(instance_id, type, 0);
else
clif_instance_changewait(instance_id, 0xffff);
}
- if( im->regs.vars ) {
- db_destroy(im->regs.vars);
- im->regs.vars = NULL;
+ if( idata->regs.vars ) {
+ db_destroy(idata->regs.vars);
+ idata->regs.vars = NULL;
}
- if( im->regs.arrays )
- instance_data[instance_id].regs.arrays->destroy(instance_data[instance_id].regs.arrays, script_free_array_db);
+ if( idata->regs.arrays )
+ idata->regs.arrays->destroy(idata->regs.arrays, script_free_array_db);
- ShowInfo("[Instance] Destroyed %hu.\n", instance_id);
+ ShowInfo("[Instance] Destroyed %d.\n", instance_id);
- memset(&instance_data[instance_id], 0, sizeof(instance_data[instance_id]));
+ instances.erase(instance_id);
- return 0;
+ return true;
}
-/*==========================================
- * Warp a user into instance
- *------------------------------------------*/
-enum e_instance_enter instance_enter(struct map_session_data *sd, unsigned short instance_id, const char *name, short x, short y)
+/**
+ * Warp a user into an instance
+ * @param sd: Player to warp
+ * @param instance_id: Instance to warp to
+ * @param name: Map name
+ * @param x: X coordinate
+ * @param y: Y coordinate
+ * @return e_instance_enter value
+ */
+e_instance_enter instance_enter(struct map_session_data *sd, int instance_id, const char *name, short x, short y)
{
- struct instance_data *im = NULL;
- struct instance_db *db = NULL;
- struct party_data *pd = NULL;
- struct guild *gd = NULL;
- struct clan *cd = NULL;
- enum instance_mode mode;
- int16 m;
-
nullpo_retr(IE_OTHER, sd);
- if( (db = instance_searchname_db(name)) == NULL ){
- ShowError( "instance_enter: Unknown instance \"%s\".\n", name );
+ std::shared_ptr db = instance_search_db_name(name);
+
+ if (!db) {
+ ShowError("instance_enter: Unknown instance \"%s\".\n", name);
return IE_OTHER;
}
-
+
// If one of the two coordinates was not given or is below zero, we use the entry point from the database
- if( x < 0 || y < 0 ){
+ if (x < 0 || y < 0) {
x = db->enter.x;
y = db->enter.y;
}
-
- // Check if it is a valid instance
- if( instance_id == 0 ){
- // im will stay NULL and by default party checks will be used
+
+ std::shared_ptr idata = nullptr;
+ struct party_data *pd;
+ struct guild *gd;
+ struct clan *cd;
+ e_instance_mode mode;
+
+ if (instance_id <= 0) // Default party checks will be used
mode = IM_PARTY;
- }else{
- im = &instance_data[instance_id];
- mode = im->mode;
+ else {
+ idata = util::umap_find(instances, instance_id);
+ mode = idata->mode;
}
switch(mode) {
@@ -759,48 +899,50 @@ enum e_instance_enter instance_enter(struct map_session_data *sd, unsigned short
case IM_CHAR:
if (sd->instance_id == 0) // Player must have an instance
return IE_NOINSTANCE;
- if (im->owner_id != sd->status.char_id)
+ if (idata->owner_id != sd->status.char_id)
return IE_OTHER;
break;
case IM_PARTY:
if (sd->status.party_id == 0) // Character must be in instance party
return IE_NOMEMBER;
- if ((pd = party_search(sd->status.party_id)) == NULL)
+ if (!(pd = party_search(sd->status.party_id)))
return IE_NOMEMBER;
- if (pd->instance_id == 0 || im == NULL) // Party must have an instance
+ if (pd->instance_id == 0 || idata == nullptr) // Party must have an instance
return IE_NOINSTANCE;
- if (im->owner_id != pd->party.party_id)
+ if (idata->owner_id != pd->party.party_id)
return IE_OTHER;
break;
case IM_GUILD:
if (sd->status.guild_id == 0) // Character must be in instance guild
return IE_NOMEMBER;
- if ((gd = guild_search(sd->status.guild_id)) == NULL)
+ if (!(gd = guild_search(sd->status.guild_id)))
return IE_NOMEMBER;
if (gd->instance_id == 0) // Guild must have an instance
return IE_NOINSTANCE;
- if (im->owner_id != gd->guild_id)
+ if (idata->owner_id != gd->guild_id)
return IE_OTHER;
break;
case IM_CLAN:
if (sd->status.clan_id == 0) // Character must be in instance clan
return IE_NOMEMBER;
- if ((cd = clan_search(sd->status.clan_id)) == NULL)
+ if (!(cd = clan_search(sd->status.clan_id)))
return IE_NOMEMBER;
if (cd->instance_id == 0) // Clan must have an instance
return IE_NOINSTANCE;
- if (im->owner_id != cd->id)
+ if (idata->owner_id != cd->id)
return IE_OTHER;
break;
}
- if (im->state != INSTANCE_BUSY)
+ if (idata->state != INSTANCE_BUSY)
return IE_OTHER;
- if (im->type != db->id)
+ if (idata->id != db->id)
return IE_OTHER;
+ int16 m;
+
// Does the instance match?
- if ((m = instance_mapname2mapid(StringBuf_Value(db->enter.mapname), instance_id)) < 0)
+ if ((m = instance_mapid(db->enter.map, instance_id)) < 0)
return IE_OTHER;
if (pc_setpos(sd, map_id2index(m), x, y, CLR_OUTSIGHT))
@@ -809,293 +951,120 @@ enum e_instance_enter instance_enter(struct map_session_data *sd, unsigned short
return IE_OK;
}
-/*==========================================
+/**
* Request some info about the instance
- *------------------------------------------*/
-int instance_reqinfo(struct map_session_data *sd, unsigned short instance_id)
+ * @param sd: Player to display info to
+ * @param instance_id: Instance to request
+ * @return True on success or false on failure
+ */
+bool instance_reqinfo(struct map_session_data *sd, int instance_id)
{
- struct instance_data *im;
+ nullpo_retr(false, sd);
- nullpo_retr(1, sd);
+ std::shared_ptr idata = util::umap_find(instances, instance_id);
- if(instance_id == 0 || instance_id > MAX_INSTANCE_DATA)
- return 1;
-
- im = &instance_data[instance_id];
-
- if(instance_searchtype_db(im->type) == NULL)
- return 1;
+ if (!idata || !instance_db.find(idata->id))
+ return false;
// Say it's created if instance is not busy
- if(im->state == INSTANCE_IDLE) {
- int i;
-
- for(i = 0; i < instance_wait.count; i++) {
- if(instance_wait.id[i] == instance_id) {
+ if(idata->state == INSTANCE_IDLE) {
+ for (int i = 0; i < instance_wait.id.size(); i++) {
+ if (instance_wait.id[i] == instance_id) {
clif_instance_create(instance_id, i + 1);
break;
}
}
- } else if(im->state == INSTANCE_BUSY) // Give info on the instance if busy
- clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+ } else if(idata->state == INSTANCE_BUSY) // Give info on the instance if busy
+ clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
- return 0;
-}
-
-/*==========================================
- * Add players to the instance (for timers)
- *------------------------------------------*/
-int instance_addusers(unsigned short instance_id)
-{
- struct instance_data *im;
-
- if(instance_id == 0 || instance_id > MAX_INSTANCE_DATA)
- return 1;
-
- im = &instance_data[instance_id];
- if(im->state != INSTANCE_BUSY)
- return 1;
-
- // Stop the idle timer if we had one
- instance_stopidletimer(im, instance_id);
-
- // Start the instance keep timer
- instance_startkeeptimer(im, instance_id);
-
- return 0;
-}
-
-/*==========================================
- * Delete players from the instance (for timers)
- *------------------------------------------*/
-int instance_delusers(unsigned short instance_id)
-{
- struct instance_data *im;
- int i, users = 0;
-
- if(instance_id == 0 || instance_id > MAX_INSTANCE_DATA)
- return 1;
-
- im = &instance_data[instance_id];
- if(im->state != INSTANCE_BUSY)
- return 1;
-
- // If no one is in the instance, start the idle timer
- for(i = 0; i < im->cnt_map && im->map[i]->m; i++)
- users += max(map_getmapdata(im->map[i]->m)->users,0);
-
- // We check the actual map.users before being updated, hence the 1
- // The instance should be empty if users are now <= 1
- if(users <= 1)
- instance_startidletimer(im, instance_id);
-
- return 0;
-}
-
-static bool instance_db_free_sub(struct instance_db *db);
-
-/*==========================================
- * Read the instance_db.txt file
- *------------------------------------------*/
-static bool instance_readdb_sub(char* str[], int columns, int current)
-{
- uint8 i,j;
- char *ptr;
- int id = strtol(str[0], &ptr, 10);
- struct instance_db *db;
- bool isNew = false;
-
- if (!id || id > USHRT_MAX || *ptr) {
- ShowError("instance_readdb_sub: Cannot add instance with ID '%d'. Valid IDs are 1 ~ %d, skipping...\n", id, USHRT_MAX);
- return false;
- }
-
- if (mapindex_name2id(str[4]) == 0) {
- ShowError("instance_readdb_sub: Invalid map '%s' as entrance map, skipping...\n", str[4]);
- return false;
- }
-
- if (!(db = (struct instance_db *)uidb_get(InstanceDB, id))) {
- CREATE(db, struct instance_db, 1);
- db->id = id;
- db->name = StringBuf_Malloc();
- db->enter.mapname = StringBuf_Malloc();
- isNew = true;
- } else {
- StringBuf_Clear(db->name);
- StringBuf_Clear(db->enter.mapname);
- if (db->maplist_count) {
- for (i = 0; i < db->maplist_count; i++)
- StringBuf_Free(db->maplist[i]);
- aFree(db->maplist);
- db->maplist = NULL;
- }
- db->maplist_count = 0;
- }
-
- StringBuf_AppendStr(db->name, str[1]);
-
- db->limit = strtol(str[2], &ptr, 10);
- if (*ptr) {
- ShowError("instance_readdb_sub: TimeLimit must be an integer value for instance '%d', skipping...\n", id);
- instance_db_free_sub(db);
- return false;
- }
-
- db->timeout = strtol(str[3], &ptr, 10);
- if (*ptr) {
- ShowError("instance_readdb_sub: IdleTimeOut must be an integer value for instance '%d', skipping...\n", id);
- instance_db_free_sub(db);
- return false;
- }
-
- StringBuf_AppendStr(db->enter.mapname, str[4]);
-
- db->enter.x = (short)strtol(str[5], &ptr, 10);
- if (*ptr) {
- ShowError("instance_readdb_sub: EnterX must be an integer value for instance '%d', skipping...\n", id);
- instance_db_free_sub(db);
- return false;
- }
-
- db->enter.y = (short)strtol(str[6], &ptr, 10);
- if (*ptr) {
- ShowError("instance_readdb_sub: EnterY must be an integer value for instance '%d', skipping...\n", id);
- instance_db_free_sub(db);
- return false;
- }
-
- //Instance maps
- for (i = 7; i < columns; i++) {
- if (strlen(str[i])) {
- if (mapindex_name2id(str[i]) == 0) {
- ShowWarning("instance_readdb_sub: Invalid map '%s' in maplist, skipping...\n", str[i]);
- continue;
- }
-
- if (strcmpi(str[4], str[i]) == 0) {
- ShowWarning("instance_readdb_sub: '%s'(Map%d) must not be equal to EnterMap for instance id '%d', skipping...\n", str[i], i - 5, id);
- continue;
- }
-
- // Check if the map is in the list already
- for (j = 7; j < i; j++) {
- // Skip empty columns
- if (!strlen(str[j])) {
- continue;
- }
-
- if (strcmpi(str[j], str[i]) == 0) {
- break;
- }
- }
-
- // If it was already in the list
- if (j < i) {
- ShowWarning("instance_readdb_sub: '%s'(Map%d) was already added for instance id '%d', skipping...\n", str[i], i - 5, id);
- continue; // Skip it
- }
-
- RECREATE(db->maplist, StringBuf *, db->maplist_count+1);
- db->maplist[db->maplist_count] = StringBuf_Malloc();
- StringBuf_AppendStr(db->maplist[db->maplist_count], str[i]);
- db->maplist_count++;
- }
- }
-
- if (isNew) {
- uidb_put(InstanceDB, id, db);
- strdb_uiput(InstanceNameDB, StringBuf_Value(db->name), id);
- }
return true;
}
/**
- * Free InstanceDB single entry
- * @param db Instance Db entry
- **/
-static bool instance_db_free_sub(struct instance_db *db) {
- if (!db)
- return 1;
- StringBuf_Free(db->name);
- StringBuf_Free(db->enter.mapname);
- if (db->maplist_count) {
- uint8 i;
- for (i = 0; i < db->maplist_count; i++)
- StringBuf_Free(db->maplist[i]);
- aFree(db->maplist);
- }
- aFree(db);
- return 0;
+ * Add players to the instance (for timers) -- Unused?
+ * @param instance_id: Instance to add
+ * @return True on success or false on failure
+ */
+bool instance_addusers(int instance_id)
+{
+ std::shared_ptr idata = util::umap_find(instances, instance_id);
+
+ if(!idata || idata->state != INSTANCE_BUSY)
+ return false;
+
+ // Stop the idle timer if we had one
+ instance_stopidletimer(idata, instance_id);
+
+ // Start the instance keep timer
+ instance_startkeeptimer(idata, instance_id);
+
+ return true;
}
/**
- * Free InstanceDB entries
- **/
-static int instance_db_free(DBKey key, DBData *data, va_list ap) {
- struct instance_db *db = (struct instance_db *)db_data2ptr(data);
- return instance_db_free_sub(db);
+ * Delete players from the instance (for timers)
+ * @param instance_id: Instance to remove
+ * @return True on success or false on failure
+ */
+bool instance_delusers(int instance_id)
+{
+ std::shared_ptr idata = util::umap_find(instances, instance_id);
+
+ if(!idata || idata->state != INSTANCE_BUSY)
+ return false;
+
+ int users = 0;
+
+ // If no one is in the instance, start the idle timer
+ for (const auto &it : idata->map)
+ users += max(map_getmapdata(it.m)->users,0);
+
+ // We check the actual map.users before being updated, hence the 1
+ // The instance should be empty if users are now <= 1
+ if(users <= 1)
+ instance_startidletimer(idata, instance_id);
+
+ return true;
}
/**
- * Read instance_db.txt files
- **/
-void instance_readdb(void) {
- const char* filename[] = { DBPATH"instance_db.txt", "import/instance_db.txt"};
- int f;
-
- for (f = 0; f 0);
- }
-}
-
-/**
- * Reload Instance DB
- **/
-void instance_reload(void) {
- InstanceDB->clear(InstanceDB, instance_db_free);
- db_clear(InstanceNameDB);
- instance_readdb();
-}
-
-/*==========================================
* Reloads the instance in runtime (reloadscript)
- *------------------------------------------*/
+ */
void do_reload_instance(void)
{
- struct instance_data *im;
- struct instance_db *db = NULL;
- struct s_mapiterator* iter;
- struct map_session_data *sd;
- unsigned short i;
+ for (const auto &it : instances) {
+ std::shared_ptr idata = it.second;
- for( i = 1; i < MAX_INSTANCE_DATA; i++ ) {
- im = &instance_data[i];
- if(!im->cnt_map)
+ if (!idata || idata->map.empty())
continue;
else {
// First we load the NPCs again
- instance_addnpc(im);
+ instance_addnpc(idata);
// Create new keep timer
- if((db = instance_searchtype_db(im->type)) != NULL)
- im->keep_limit = (unsigned int)time(NULL) + db->limit;
+ std::shared_ptr db = instance_db.find(idata->id);
+
+ if (db)
+ idata->keep_limit = static_cast(time(nullptr)) + db->limit;
}
}
// Reset player to instance beginning
- iter = mapit_getallusers();
- for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) ) {
+ struct s_mapiterator *iter = mapit_getallusers();
+ struct map_session_data *sd;
+
+ for (sd = (TBL_PC *)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC *)mapit_next(iter)) {
struct map_data *mapdata = map_getmapdata(sd->bl.m);
- if(sd && mapdata->instance_id) {
- struct party_data *pd = NULL;
- struct guild *gd = NULL;
- struct clan *cd = NULL;
- unsigned short instance_id;
+ if (sd && mapdata->instance_id > 0) {
+ struct party_data *pd;
+ struct guild *gd;
+ struct clan *cd;
+ int instance_id;
+ std::shared_ptr idata = util::umap_find(instances, map[sd->bl.m].instance_id);
+ std::shared_ptr db = instance_db.find(idata->id);
- im = &instance_data[mapdata->instance_id];
- switch (im->mode) {
+ switch (idata->mode) {
case IM_NONE:
continue;
case IM_CHAR:
@@ -1119,42 +1088,35 @@ void do_reload_instance(void)
instance_id = cd->instance_id;
break;
default:
- ShowError("do_reload_instance: Unexpected instance mode for instance %s (id=%u, mode=%u).\n", (db) ? StringBuf_Value(db->name) : "Unknown", mapdata->instance_id, (unsigned short)im->mode);
+ ShowError("do_reload_instance: Unexpected instance mode for instance %s (id=%d, mode=%u).\n", (db) ? db->name.c_str() : "Unknown", mapdata->instance_id, (uint8)idata->mode);
continue;
}
- if((db = instance_searchtype_db(im->type)) != NULL && !instance_enter(sd, instance_id, StringBuf_Value(db->name), -1, -1)) { // All good
- clif_displaymessage(sd->fd, msg_txt(sd,515)); // Instance has been reloaded
- instance_reqinfo(sd,instance_id);
+ if (db && instance_enter(sd, instance_id, db->name.c_str(), -1, -1) == IE_OK) { // All good
+ clif_displaymessage(sd->fd, msg_txt(sd, 515)); // Instance has been reloaded
+ instance_reqinfo(sd, instance_id);
} else // Something went wrong
- ShowError("do_reload_instance: Error setting character at instance start: character_id=%d instance=%s.\n",sd->status.char_id,StringBuf_Value(db->name));
+ ShowError("do_reload_instance: Error setting character at instance start: character_id=%d instance=%s.\n", sd->status.char_id, db->name.c_str());
}
}
mapit_free(iter);
}
+/**
+ * Initializes the instance database
+ */
void do_init_instance(void) {
- InstanceDB = uidb_alloc(DB_OPT_BASE);
- InstanceNameDB = strdb_alloc((DBOptions)(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA),0);
-
instance_start = map_num;
- instance_readdb();
- memset(instance_data, 0, sizeof(instance_data));
- memset(&instance_wait, 0, sizeof(instance_wait));
- instance_wait.timer = -1;
-
- instance_maps_ers = ers_new(sizeof(struct s_instance_map),"instance.cpp::instance_maps_ers", ERS_OPT_NONE);
+ instance_db.load();
+ instance_wait.timer = INVALID_TIMER;
add_timer_func_list(instance_delete_timer,"instance_delete_timer");
add_timer_func_list(instance_subscription_timer,"instance_subscription_timer");
}
+/**
+ * Finalizes the instances and instance database
+ */
void do_final_instance(void) {
- int i;
-
- for( i = 1; i < MAX_INSTANCE_DATA; i++ )
- instance_destroy(i);
-
- InstanceDB->destroy(InstanceDB, instance_db_free);
- db_destroy(InstanceNameDB);
- ers_destroy(instance_maps_ers);
+ for (const auto &it : instances)
+ instance_destroy(it.first);
}
diff --git a/src/map/instance.hpp b/src/map/instance.hpp
index 59ac747616..54edbe2da9 100644
--- a/src/map/instance.hpp
+++ b/src/map/instance.hpp
@@ -4,29 +4,32 @@
#ifndef INSTANCE_HPP
#define INSTANCE_HPP
-#include "../common/cbasetypes.hpp"
-#include "../common/mmo.hpp" // struct point
-#include "../common/strlib.hpp"
+#include
+#include
+#include
+#include
+#include
-#include "script.hpp" // struct reg_db
+#include "../common/cbasetypes.hpp"
+#include "../common/database.hpp"
+#include "../common/mmo.hpp"
+
+#include "script.hpp"
enum send_target : uint8;
struct block_list;
extern int16 instance_start;
-
-#define MAX_INSTANCE_DATA 300 // Essentially how many instances we can create, but instance creation is primarily decided by MAX_MAP_PER_SERVER
-#define MAX_MAP_PER_INSTANCE 255 // Max number of maps per instance (Enter map is counted as one) - Supports up to 255 maps
+extern int instance_count;
#define INSTANCE_NAME_LENGTH (60+1)
-enum instance_state {
- INSTANCE_FREE,
+enum e_instance_state : uint8 {
INSTANCE_IDLE,
INSTANCE_BUSY
};
-enum instance_mode {
+enum e_instance_mode : uint8 {
IM_NONE,
IM_CHAR,
IM_PARTY,
@@ -35,69 +38,92 @@ enum instance_mode {
IM_MAX,
};
-enum e_instance_enter {
- IE_OK = 0,
+enum e_instance_enter : uint8 {
+ IE_OK,
IE_NOMEMBER,
IE_NOINSTANCE,
IE_OTHER
};
+enum e_instance_notify : uint8 {
+ IN_NOTIFY = 0,
+ IN_DESTROY_LIVE_TIMEOUT,
+ IN_DESTROY_ENTER_TIMEOUT,
+ IN_DESTROY_USER_REQUEST,
+ IN_CREATE_FAIL,
+};
+
struct s_instance_map {
int16 m, src_m;
};
-struct instance_data {
- unsigned short type; ///< Instance DB ID
- enum instance_state state; ///< State of instance
- enum instance_mode mode; ///< Mode of instance
+/// Instance data
+struct s_instance_data {
+ int id; ///< Instance DB ID
+ e_instance_state state; ///< State of instance
+ e_instance_mode mode; ///< Mode of instance
int owner_id; ///< Owner ID of instance
unsigned int keep_limit; ///< Life time of instance
- int keep_timer; ///< Remaining life time of instance
+ int keep_timer; ///< Life time ID
unsigned int idle_limit; ///< Idle time of instance
- int idle_timer; ///< Remaining idle time of instance
+ int idle_timer; ///< Idle timer ID
struct reg_db regs; ///< Instance variables for scripts
- struct s_instance_map **map; ///< Dynamic array of maps in instance
- uint8 cnt_map; ///< Number of maps in an instance
+ std::vector map; ///< Array of maps in instance
+
+ s_instance_data() :
+ id(0),
+ state(INSTANCE_IDLE),
+ mode(IM_PARTY),
+ owner_id(0),
+ keep_limit(0),
+ keep_timer(INVALID_TIMER),
+ idle_limit(0),
+ idle_timer(INVALID_TIMER),
+ regs(),
+ map() { }
};
-/// Instance DB entry struct
-struct instance_db {
- unsigned short id; ///< Instance ID
- StringBuf *name; ///< Instance name
- unsigned int limit, ///< Duration limit
+/// Instance DB entry
+struct s_instance_db {
+ int id; ///< Instance DB ID
+ std::string name; ///< Instance name
+ uint32 limit, ///< Duration limit
timeout; ///< Timeout limit
- struct s_MapInfo {
- StringBuf *mapname; ///< Mapname, the limit should be MAP_NAME_LENGTH_EXT
- short x, y; ///< Map coordinates
- } enter;
- StringBuf **maplist; ///< Used maps in instance, the limit should be MAP_NAME_LENGTH_EXT
- uint8 maplist_count; ///< Number of used maps
+ //bool destroyable; ///< Destroyable flag
+ struct point enter; ///< Instance entry point
+ std::vector maplist; ///< Maps in instance
};
-extern struct instance_data instance_data[MAX_INSTANCE_DATA];
+class InstanceDatabase : public TypesafeYamlDatabase {
+public:
+ InstanceDatabase() : TypesafeYamlDatabase("INSTANCE_DB", 1) {
-struct instance_db *instance_searchtype_db(unsigned short instance_id);
-struct instance_db *instance_searchname_db(const char* name);
-void instance_getsd(unsigned short instance_id, struct map_session_data **sd, enum send_target *target);
+ }
-int instance_create(int owner_id, const char *name, enum instance_mode mode);
-int instance_destroy(unsigned short instance_id);
-enum e_instance_enter instance_enter(struct map_session_data *sd, unsigned short instance_id, const char *name, short x, short y);
-int instance_reqinfo(struct map_session_data *sd, unsigned short instance_id);
-int instance_addusers(unsigned short instance_id);
-int instance_delusers(unsigned short instance_id);
-int16 instance_mapname2mapid(const char *name, unsigned short instance_id);
-int instance_addmap(unsigned short instance_id);
+ const std::string getDefaultLocation();
+ uint64 parseBodyNode(const YAML::Node &node);
+};
+
+extern InstanceDatabase instance_db;
+
+extern std::unordered_map> instances;
+
+std::shared_ptr instance_search_db_name(const char* name);
+void instance_getsd(int instance_id, struct map_session_data *&sd, enum send_target *target);
+
+int instance_create(int owner_id, const char *name, e_instance_mode mode);
+bool instance_destroy(int instance_id);
+e_instance_enter instance_enter(struct map_session_data *sd, int instance_id, const char *name, short x, short y);
+bool instance_reqinfo(struct map_session_data *sd, int instance_id);
+bool instance_addusers(int instance_id);
+bool instance_delusers(int instance_id);
+int16 instance_mapid(int16 m, int instance_id);
+int instance_addmap(int instance_id);
+
+void instance_addnpc(std::shared_ptr idata);
-void instance_addnpc(struct instance_data *im);
-void instance_readdb(void);
-void instance_reload(void);
void do_reload_instance(void);
void do_init_instance(void);
void do_final_instance(void);
-#if MAX_MAP_PER_INSTANCE > 255
- #error Too many maps per instance defined! Please adjust MAX_MAP_PER_INSTANCE to a lower value.
-#endif
-
#endif /* INSTANCE_HPP */
diff --git a/src/map/map-server.vcxproj b/src/map/map-server.vcxproj
index 721e354c7a..b4955a18a7 100644
--- a/src/map/map-server.vcxproj
+++ b/src/map/map-server.vcxproj
@@ -308,7 +308,7 @@
-
+
diff --git a/src/map/map.cpp b/src/map/map.cpp
index 30747e0b45..5aab4518b8 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -2171,12 +2171,12 @@ int map_quit(struct map_session_data *sd) {
struct map_data *mapdata = map_getmapdata(sd->bl.m);
- if( mapdata->instance_id )
+ if( mapdata->instance_id > 0 )
instance_delusers(mapdata->instance_id);
unit_remove_map_pc(sd,CLR_RESPAWN);
- if( mapdata->instance_id ) { // Avoid map conflicts and warnings on next login
+ if( mapdata->instance_id > 0 ) { // Avoid map conflicts and warnings on next login
int16 m;
struct point *pt;
if( mapdata->save.map )
@@ -2694,18 +2694,16 @@ bool map_addnpc(int16 m,struct npc_data *nd)
/*==========================================
* Add an instance map
*------------------------------------------*/
-int map_addinstancemap(const char *name, unsigned short instance_id)
+int map_addinstancemap(int src_m, int instance_id)
{
- int16 src_m = map_mapname2mapid(name);
- char iname[MAP_NAME_LENGTH];
- size_t num_cell, size;
-
if(src_m < 0)
return -1;
+ const char *name = map_mapid2mapname(src_m);
+
if(strlen(name) > 20) {
// against buffer overflow
- ShowError("map_addisntancemap: can't add long map name \"%s\"\n", name);
+ ShowError("map_addinstancemap: can't add long map name \"%s\"\n", name);
return -2;
}
@@ -2727,18 +2725,19 @@ int map_addinstancemap(const char *name, unsigned short instance_id)
struct map_data *src_map = map_getmapdata(src_m);
struct map_data *dst_map = map_getmapdata(dst_m);
+ char iname[MAP_NAME_LENGTH];
strcpy(iname, name);
// Alter the name
// Due to this being custom we only worry about preserving as many characters as necessary for accurate map distinguishing
// This also allows us to maintain complete independence with main map functions
- if((strchr(iname,'@') == NULL) && strlen(iname) > 8) {
- memmove(iname, iname+(strlen(iname)-9), strlen(iname));
- snprintf(dst_map->name, sizeof(dst_map->name),"%hu#%s", instance_id, iname);
+ if ((strchr(iname, '@') == NULL) && strlen(iname) > 8) {
+ memmove(iname, iname + (strlen(iname) - 9), strlen(iname));
+ snprintf(dst_map->name, sizeof(dst_map->name), "%d#%s", (instance_id % 1000), iname);
} else
- snprintf(dst_map->name, sizeof(dst_map->name),"%.3hu%s", instance_id, iname);
- dst_map->name[MAP_NAME_LENGTH-1] = '\0';
+ snprintf(dst_map->name, sizeof(dst_map->name), "%.3d%s", (instance_id % 1000), iname);
+ dst_map->name[MAP_NAME_LENGTH - 1] = '\0';
dst_map->m = dst_m;
dst_map->instance_id = instance_id;
@@ -2756,11 +2755,13 @@ int map_addinstancemap(const char *name, unsigned short instance_id)
dst_map->npc_num_warp = 0;
// Reallocate cells
- num_cell = dst_map->xs * dst_map->ys;
+ size_t num_cell = dst_map->xs * dst_map->ys;
+
CREATE( dst_map->cell, struct mapcell, num_cell );
memcpy( dst_map->cell, src_map->cell, num_cell * sizeof(struct mapcell) );
- size = dst_map->bxs * dst_map->bys * sizeof(struct block_list*);
+ size_t size = dst_map->bxs * dst_map->bys * sizeof(struct block_list*);
+
dst_map->block = (struct block_list **)aCalloc(1,size);
dst_map->block_mob = (struct block_list **)aCalloc(1,size);
@@ -2829,7 +2830,7 @@ int map_delinstancemap(int m)
{
struct map_data *mapdata = map_getmapdata(m);
- if(m < 0 || !mapdata->instance_id)
+ if(m < 0 || mapdata->instance_id <= 0)
return 0;
// Kick everyone out
@@ -2972,7 +2973,7 @@ void map_removemobs(int16 m)
return; //Mobs are already scheduled for removal
// Don't remove mobs on instance map
- if (mapdata->instance_id)
+ if (mapdata->instance_id > 0)
return;
mapdata->mob_delete_timer = add_timer(gettick()+battle_config.mob_remove_delay, map_removemobs_timer, m, 0);
@@ -2991,17 +2992,15 @@ const char* map_mapid2mapname(int m)
if (!mapdata)
return "";
- if (mapdata->instance_id) { // Instance map check
- struct instance_data *im = &instance_data[mapdata->instance_id];
+ if (mapdata->instance_id > 0) { // Instance map check
+ std::shared_ptr idata = util::umap_find(instances, map[m].instance_id);
- if (!im) // This shouldn't happen but if it does give them the map we intended to give
+ if (!idata) // This shouldn't happen but if it does give them the map we intended to give
return mapdata->name;
else {
- uint8 i;
-
- for (i = 0; i < im->cnt_map; i++) { // Loop to find the src map we want
- if (im->map[i]->m == m)
- return map[im->map[i]->src_m].name;
+ for (const auto &it : idata->map) { // Loop to find the src map we want
+ if (it.m == m)
+ return map_getmapdata(it.src_m)->name;
}
}
}
diff --git a/src/map/map.hpp b/src/map/map.hpp
index fc9bb7ee0c..7fa4a8b598 100644
--- a/src/map/map.hpp
+++ b/src/map/map.hpp
@@ -748,7 +748,7 @@ struct map_data {
int mob_delete_timer; // Timer ID for map_removemobs_timer [Skotlex]
// Instance Variables
- unsigned short instance_id;
+ int instance_id;
int instance_src_map;
/* rAthena Local Chat */
@@ -1035,7 +1035,7 @@ void map_clearflooritem(struct block_list* bl);
int map_addflooritem(struct item *item, int amount, int16 m, int16 x, int16 y, int first_charid, int second_charid, int third_charid, int flags, unsigned short mob_id, bool canShowEffect = false);
// instances
-int map_addinstancemap(const char *name, unsigned short instance_id);
+int map_addinstancemap(int src_m, int instance_id);
int map_delinstancemap(int m);
void map_data_copyall(void);
void map_data_copy(struct map_data *dst_map, struct map_data *src_map);
diff --git a/src/map/npc.cpp b/src/map/npc.cpp
index 39981bb254..d12e24df3a 100644
--- a/src/map/npc.cpp
+++ b/src/map/npc.cpp
@@ -16,6 +16,7 @@
#include "../common/showmsg.hpp"
#include "../common/strlib.hpp"
#include "../common/timer.hpp"
+#include "../common/utilities.hpp"
#include "../common/utils.hpp"
#include "battle.hpp"
@@ -33,6 +34,8 @@
#include "pet.hpp"
#include "script.hpp" // script_config
+using namespace rathena;
+
struct npc_data* fake_nd;
// linked list of npc source files
@@ -3489,7 +3492,7 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
char newname[NPC_NAME_LENGTH+1];
struct map_data *mapdata = map_getmapdata(m);
- if( mapdata->instance_id == 0 )
+ if( mapdata->instance_id <= 0 )
return 1;
snprintf(newname, ARRAYLENGTH(newname), "dup_%d_%d", mapdata->instance_id, snd->bl.id);
@@ -3500,15 +3503,17 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
if( snd->subtype == NPCTYPE_WARP ) { // Adjust destination, if instanced
struct npc_data *wnd = NULL; // New NPC
- struct instance_data *im = &instance_data[mapdata->instance_id];
- int dm = map_mapindex2mapid(snd->u.warp.mapindex), imap = 0, i;
+ std::shared_ptr idata = util::umap_find(instances, mapdata->instance_id);
+ int dm = map_mapindex2mapid(snd->u.warp.mapindex), imap = 0;
+
if( dm < 0 ) return 1;
- for(i = 0; i < im->cnt_map; i++)
- if(im->map[i]->m && map_mapname2mapid(map_getmapdata(im->map[i]->src_m)->name) == dm) {
- imap = map_mapname2mapid(map_getmapdata(im->map[i]->m)->name);
+ for (const auto &it : idata->map) {
+ if (it.m && map_mapname2mapid(map_getmapdata(it.src_m)->name) == dm) {
+ imap = map_mapname2mapid(map_getmapdata(it.m)->name);
break; // Instance map matches destination, update to instance map
}
+ }
if(!imap)
imap = map_mapname2mapid(map_getmapdata(dm)->name);
diff --git a/src/map/script.cpp b/src/map/script.cpp
index e9e10a6437..087ba7246d 100644
--- a/src/map/script.cpp
+++ b/src/map/script.cpp
@@ -385,7 +385,7 @@ static struct linkdb_node *sleep_db; // int oid -> struct script_state *
*------------------------------------------*/
const char* parse_subexpr(const char* p,int limit);
int run_func(struct script_state *st);
-unsigned short script_instancegetid(struct script_state *st, enum instance_mode mode = IM_NONE);
+int script_instancegetid(struct script_state *st, e_instance_mode mode = IM_NONE);
const char* script_op2name(int op)
{
@@ -2759,9 +2759,10 @@ struct script_data *get_val_(struct script_state* st, struct script_data* data,
if (data->ref)
n = data->ref->vars;
else {
- unsigned short instance_id = script_instancegetid(st);
- if (instance_id != 0)
- n = instance_data[instance_id].regs.vars;
+ std::shared_ptr idata = util::umap_find(instances, script_instancegetid(st));
+
+ if (idata)
+ n = idata->regs.vars;
}
if (n)
data->u.str = (char*)i64db_get(n,reference_getuid(data));
@@ -2824,9 +2825,10 @@ struct script_data *get_val_(struct script_state* st, struct script_data* data,
if (data->ref)
n = data->ref->vars;
else {
- unsigned short instance_id = script_instancegetid(st);
- if (instance_id != 0)
- n = instance_data[instance_id].regs.vars;
+ std::shared_ptr idata = util::umap_find(instances, script_instancegetid(st));
+
+ if (idata)
+ n = idata->regs.vars;
}
if (n)
data->u.num = i64db_i64get(n,reference_getuid(data));
@@ -3071,10 +3073,10 @@ struct reg_db *script_array_src(struct script_state *st, struct map_session_data
if (ref)
src = ref;
else {
- unsigned short instance_id = script_instancegetid(st);
+ std::shared_ptr idata = util::umap_find(instances, script_instancegetid(st));
- if (instance_id != 0)
- src = &instance_data[instance_id].regs;
+ if (idata)
+ src = &idata->regs;
}
break;
}
@@ -3198,11 +3200,10 @@ bool set_reg_str( struct script_state* st, struct map_session_data* sd, int64 nu
if( ref ){
src = ref;
}else{
- unsigned short instance_id = script_instancegetid( st );
+ std::shared_ptr idata = util::umap_find(instances, script_instancegetid(st));
- if( instance_id != 0 ){
- src = &instance_data[instance_id].regs;
- }
+ if (idata)
+ src = &idata->regs;
}
if( src ){
@@ -3293,11 +3294,10 @@ bool set_reg_num( struct script_state* st, struct map_session_data* sd, int64 nu
if( ref ){
src = ref;
}else{
- unsigned short instance_id = script_instancegetid( st );
+ std::shared_ptr idata = util::umap_find(instances, script_instancegetid(st));
- if( instance_id != 0 ){
- src = &instance_data[instance_id].regs;
- }
+ if (idata)
+ src = &idata->regs;
}
if( src ){
@@ -20091,9 +20091,9 @@ BUILDIN_FUNC(bg_info)
* @param mode: Instance mode
* @return instance ID on success or 0 otherwise
*/
-unsigned short script_instancegetid(struct script_state* st, enum instance_mode mode)
+int script_instancegetid(struct script_state* st, e_instance_mode mode)
{
- unsigned short instance_id = 0;
+ int instance_id = 0;
if (mode == IM_NONE) {
struct npc_data *nd = map_id2nd(st->oid);
@@ -20106,27 +20106,27 @@ unsigned short script_instancegetid(struct script_state* st, enum instance_mode
if (sd) {
switch (mode) {
case IM_CHAR:
- if (sd->instance_id)
+ if (sd->instance_id > 0)
instance_id = sd->instance_id;
break;
case IM_PARTY: {
struct party_data *pd = party_search(sd->status.party_id);
- if (pd && pd->instance_id)
+ if (pd && pd->instance_id > 0)
instance_id = pd->instance_id;
}
break;
case IM_GUILD: {
struct guild *gd = guild_search(sd->status.guild_id);
- if (gd && gd->instance_id)
+ if (gd && gd->instance_id > 0)
instance_id = gd->instance_id;
}
break;
case IM_CLAN: {
struct clan *cd = clan_search(sd->status.clan_id);
- if (cd && cd->instance_id)
+ if (cd && cd->instance_id > 0)
instance_id = cd->instance_id;
}
break;
@@ -20145,11 +20145,11 @@ unsigned short script_instancegetid(struct script_state* st, enum instance_mode
*------------------------------------------*/
BUILDIN_FUNC(instance_create)
{
- enum instance_mode mode = IM_PARTY;
+ e_instance_mode mode = IM_PARTY;
int owner_id = 0;
if (script_hasdata(st, 3)) {
- mode = static_cast(script_getnum(st, 3));
+ mode = static_cast(script_getnum(st, 3));
if (mode < IM_NONE || mode >= IM_MAX) {
ShowError("buildin_instance_create: Unknown instance mode %d for '%s'\n", mode, script_getstr(st, 2));
@@ -20200,7 +20200,7 @@ BUILDIN_FUNC(instance_create)
*------------------------------------------*/
BUILDIN_FUNC(instance_destroy)
{
- unsigned short instance_id;
+ int instance_id;
if( script_hasdata(st,2) )
instance_id = script_getnum(st,2);
@@ -20208,7 +20208,7 @@ BUILDIN_FUNC(instance_destroy)
instance_id = script_instancegetid(st);
if( instance_id == 0 ) {
- ShowError("buildin_instance_destroy: Trying to destroy invalid instance %hu.\n", instance_id);
+ ShowError("buildin_instance_destroy: Trying to destroy invalid instance %d.\n", instance_id);
return SCRIPT_CMD_FAILURE;
}
@@ -20229,7 +20229,7 @@ BUILDIN_FUNC(instance_enter)
struct map_session_data *sd = NULL;
int x = script_hasdata(st,3) ? script_getnum(st, 3) : -1;
int y = script_hasdata(st,4) ? script_getnum(st, 4) : -1;
- unsigned short instance_id;
+ int instance_id;
if (script_hasdata(st, 6))
instance_id = script_getnum(st, 6);
@@ -20253,7 +20253,7 @@ BUILDIN_FUNC(instance_enter)
BUILDIN_FUNC(instance_npcname)
{
const char *str;
- unsigned short instance_id = 0;
+ int instance_id;
struct npc_data *nd;
str = script_getstr(st,2);
@@ -20262,12 +20262,12 @@ BUILDIN_FUNC(instance_npcname)
else
instance_id = script_instancegetid(st);
- if( instance_id && (nd = npc_name2id(str)) != NULL ) {
+ if( instance_id > 0 && (nd = npc_name2id(str)) != NULL ) {
static char npcname[NAME_LENGTH];
- snprintf(npcname, sizeof(npcname), "dup_%hu_%d", instance_id, nd->bl.id);
+ snprintf(npcname, sizeof(npcname), "dup_%d_%d", instance_id, nd->bl.id);
script_pushconststr(st,npcname);
} else {
- ShowError("buildin_instance_npcname: Invalid instance NPC (instance_id: %hu, NPC name: \"%s\".)\n", instance_id, str);
+ ShowError("buildin_instance_npcname: Invalid instance NPC (instance_id: %d, NPC name: \"%s\".)\n", instance_id, str);
st->state = END;
return SCRIPT_CMD_FAILURE;
}
@@ -20284,7 +20284,7 @@ BUILDIN_FUNC(instance_mapname)
{
const char *str;
int16 m;
- unsigned short instance_id = 0;
+ int instance_id;
str = script_getstr(st,2);
@@ -20294,7 +20294,7 @@ BUILDIN_FUNC(instance_mapname)
instance_id = script_instancegetid(st);
// Check that instance mapname is a valid map
- if(!instance_id || (m = instance_mapname2mapid(str,instance_id)) < 0)
+ if(instance_id <= 0 || (m = instance_mapid(map_mapname2mapid(str), instance_id)) < 0)
script_pushconststr(st, "");
else
script_pushconststr(st, map_getmapdata(m)->name);
@@ -20319,7 +20319,7 @@ BUILDIN_FUNC(instance_id)
}
}
- script_pushint(st, script_instancegetid(st, static_cast(mode)));
+ script_pushint(st, script_instancegetid(st, static_cast(mode)));
return SCRIPT_CMD_SUCCESS;
}
@@ -20333,9 +20333,8 @@ static int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
unsigned int m = va_arg(ap,unsigned int);
int x = va_arg(ap,int);
int y = va_arg(ap,int);
- unsigned short instance_id = va_arg(ap,unsigned int);
- struct map_session_data *sd = NULL;
- int owner_id = 0;
+ int instance_id = va_arg(ap, int);
+ struct map_session_data *sd;
nullpo_retr(0, bl);
@@ -20343,8 +20342,15 @@ static int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
return 0;
sd = (TBL_PC *)bl;
- owner_id = instance_data[instance_id].owner_id;
- switch(instance_data[instance_id].mode) {
+
+ std::shared_ptr idata = util::umap_find(instances, instance_id);
+
+ if (!idata)
+ return 0;
+
+ int owner_id = idata->owner_id;
+
+ switch(idata->mode) {
case IM_NONE:
break;
case IM_CHAR:
@@ -20370,8 +20376,8 @@ static int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
BUILDIN_FUNC(instance_warpall)
{
- int16 m, i;
- unsigned short instance_id;
+ int16 m;
+ int instance_id;
const char *mapn;
int x, y;
@@ -20383,11 +20389,18 @@ BUILDIN_FUNC(instance_warpall)
else
instance_id = script_instancegetid(st, IM_PARTY);
- if( !instance_id || (m = map_mapname2mapid(mapn)) < 0 || (m = instance_mapname2mapid(map_getmapdata(m)->name,instance_id)) < 0)
+ if( instance_id <= 0 || (m = map_mapname2mapid(mapn)) < 0 || (m = instance_mapid(m, instance_id)) < 0)
return SCRIPT_CMD_FAILURE;
- for(i = 0; i < instance_data[instance_id].cnt_map; i++)
- map_foreachinmap(buildin_instance_warpall_sub, instance_data[instance_id].map[i]->m, BL_PC, map_id2index(m), x, y, instance_id);
+ std::shared_ptr idata = util::umap_find(instances, instance_id);
+
+ if (!idata) {
+ ShowError("buildin_instance_warpall: Instance is not found.\n");
+ return SCRIPT_CMD_FAILURE;
+ }
+
+ for(const auto &it : idata->map)
+ map_foreachinmap(buildin_instance_warpall_sub, it.m, BL_PC, map_id2index(m), x, y, instance_id);
return SCRIPT_CMD_SUCCESS;
}
@@ -20399,7 +20412,7 @@ BUILDIN_FUNC(instance_warpall)
* Using 0 for will auto-detect the id.
*------------------------------------------*/
BUILDIN_FUNC(instance_announce) {
- unsigned short instance_id = script_getnum(st,2);
+ int instance_id = script_getnum(st,2);
const char *mes = script_getstr(st,3);
int flag = script_getnum(st,4);
const char *fontColor = script_hasdata(st,5) ? script_getstr(st,5) : NULL;
@@ -20407,20 +20420,19 @@ BUILDIN_FUNC(instance_announce) {
int fontSize = script_hasdata(st,7) ? script_getnum(st,7) : 12; // default fontSize
int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign
int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY
- int i;
- if( instance_id == 0 ) {
+ if (instance_id <= 0)
instance_id = script_instancegetid(st);
- }
- if( !instance_id && &instance_data[instance_id] != NULL) {
- ShowError("buildin_instance_announce: Intance is not found.\n");
+ std::shared_ptr idata = util::umap_find(instances, instance_id);
+
+ if (instance_id <= 0 || !idata) {
+ ShowError("buildin_instance_announce: Instance not found.\n");
return SCRIPT_CMD_FAILURE;
}
- for( i = 0; i < instance_data[instance_id].cnt_map; i++ )
- map_foreachinmap(buildin_announce_sub, instance_data[instance_id].map[i]->m, BL_PC,
- mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
+ for (const auto &it : idata->map)
+ map_foreachinmap(buildin_announce_sub, it.m, BL_PC, mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
return SCRIPT_CMD_SUCCESS;
}
@@ -20438,7 +20450,7 @@ BUILDIN_FUNC(instance_announce) {
BUILDIN_FUNC(instance_check_party)
{
int amount, min, max, i, party_id, c = 0;
- struct party_data *p = NULL;
+ struct party_data *p;
amount = script_hasdata(st,3) ? script_getnum(st,3) : 1; // Amount of needed Partymembers for the Instance.
min = script_hasdata(st,4) ? script_getnum(st,4) : 1; // Minimum Level needed to join the Instance.
@@ -20620,9 +20632,9 @@ BUILDIN_FUNC(instance_info)
const char* name = script_getstr(st, 2);
int type = script_getnum(st, 3);
int index = 0;
- struct instance_db *db = instance_searchname_db(name);
+ std::shared_ptr db = instance_search_db_name(name);
- if( !db ){
+ if (!db) {
ShowError( "buildin_instance_info: Unknown instance name \"%s\".\n", name );
script_pushint(st, -1);
return SCRIPT_CMD_FAILURE;
@@ -20639,7 +20651,7 @@ BUILDIN_FUNC(instance_info)
script_pushint(st, db->timeout);
break;
case IIT_ENTER_MAP:
- script_pushstrcopy(st, StringBuf_Value(db->enter.mapname));
+ script_pushstrcopy(st, map_mapid2mapname(db->enter.map));
break;
case IIT_ENTER_X:
script_pushint(st, db->enter.x);
@@ -20648,7 +20660,7 @@ BUILDIN_FUNC(instance_info)
script_pushint(st, db->enter.y);
break;
case IIT_MAPCOUNT:
- script_pushint(st, db->maplist_count);
+ script_pushint(st, db->maplist.size());
break;
case IIT_MAP:
if( !script_hasdata(st, 4) || script_isstring(st, 4) ){
@@ -20671,7 +20683,7 @@ BUILDIN_FUNC(instance_info)
return SCRIPT_CMD_FAILURE;
}
- script_pushstrcopy(st, StringBuf_Value(db->maplist[index]));
+ script_pushstrcopy(st, map_mapid2mapname(db->maplist[index]));
break;
default:
@@ -20705,14 +20717,14 @@ BUILDIN_FUNC(instance_live_info)
else
id = script_getnum(st, 3);
- struct instance_db *db = nullptr;
- struct instance_data *im = nullptr;
+ std::shared_ptr db = nullptr;
+ std::shared_ptr im = nullptr;
- if (id > 0 && id < MAX_INSTANCE_DATA) {
- im = &instance_data[id];
+ if (id > 0 && id < INT_MAX) {
+ im = util::umap_find(instances, id);
if (im)
- db = instance_searchtype_db(im->type);
+ db = instance_db.find(im->id);
}
if (!im || !db) {
@@ -20725,7 +20737,7 @@ BUILDIN_FUNC(instance_live_info)
switch( type ) {
case ILI_NAME:
- script_pushstrcopy(st, StringBuf_Value(db->name));
+ script_pushstrcopy(st, db->name.c_str());
break;
case ILI_MODE:
script_pushint(st, im->mode);
@@ -24533,16 +24545,16 @@ BUILDIN_FUNC(getvariableofinstance)
return SCRIPT_CMD_FAILURE;
}
- unsigned short instance_id = script_getnum(st, 3);
+ int instance_id = script_getnum(st, 3);
- if (instance_id == 0 || instance_id > MAX_INSTANCE_DATA) {
+ if (instance_id <= 0) {
ShowError("buildin_getvariableofinstance: Invalid instance ID %d.\n", instance_id);
script_pushnil(st);
st->state = END;
return SCRIPT_CMD_FAILURE;
}
- struct instance_data *im = &instance_data[instance_id];
+ std::shared_ptr im = util::umap_find(instances, instance_id);
if (im->state != INSTANCE_BUSY) {
ShowError("buildin_getvariableofinstance: Unknown instance ID %d.\n", instance_id);
diff --git a/src/tool/csv2yaml.cpp b/src/tool/csv2yaml.cpp
index 2ed9d6c44e..1c621f5af3 100644
--- a/src/tool/csv2yaml.cpp
+++ b/src/tool/csv2yaml.cpp
@@ -51,6 +51,8 @@
using namespace rathena;
+#define MAX_MAP_PER_INSTANCE 255
+
#ifndef WIN32
int getch( void ){
struct termios oldattr, newattr;
@@ -100,6 +102,7 @@ static bool skill_parse_row_copyabledb(char* split[], int columns, int current);
static bool skill_parse_row_nonearnpcrangedb(char* split[], int columns, int current);
static bool skill_parse_row_skilldb(char* split[], int columns, int current);
static bool quest_read_db(char *split[], int columns, int current);
+static bool instance_readdb_sub(char* str[], int columns, int current);
// Constants for conversion
std::unordered_map aegis_itemnames;
@@ -360,6 +363,12 @@ int do_init( int argc, char** argv ){
return 0;
}
+ if (process("INSTANCE_DB", 1, root_paths, "instance_db", [](const std::string& path, const std::string& name_ext) -> bool {
+ return sv_readdb(path.c_str(), name_ext.c_str(), ',', 7, 7 + MAX_MAP_PER_INSTANCE, -1, &instance_readdb_sub, false);
+ })) {
+ return 0;
+ }
+
// TODO: add implementations ;-)
return 0;
@@ -2537,3 +2546,43 @@ static bool quest_read_db(char *split[], int columns, int current) {
return true;
}
+
+// Copied and adjusted from instance.cpp
+static bool instance_readdb_sub(char* str[], int columns, int current) {
+ body << YAML::BeginMap;
+ body << YAML::Key << "Id" << YAML::Value << atoi(str[0]);
+ body << YAML::Key << "Name" << YAML::Value << str[1];
+ if (atoi(str[2]) != 3600)
+ body << YAML::Key << "TimeLimit" << YAML::Value << atoi(str[2]);
+ if (atoi(str[3]) != 300)
+ body << YAML::Key << "IdleTimeOut" << YAML::Value << atoi(str[3]);
+ body << YAML::Key << "Enter";
+ body << YAML::BeginMap;
+ body << YAML::Key << "Map" << YAML::Value << str[4];
+ body << YAML::Key << "X" << YAML::Value << atoi(str[5]);
+ body << YAML::Key << "Y" << YAML::Value << atoi(str[6]);
+ body << YAML::EndMap;
+
+ if (columns > 7) {
+ body << YAML::Key << "AdditionalMaps";
+ body << YAML::BeginSeq;
+
+ for (int i = 7; i < columns; i++) {
+ if (!strlen(str[i]))
+ continue;
+
+ if (strcmpi(str[4], str[i]) == 0)
+ continue;
+
+ body << YAML::BeginMap;
+ body << YAML::Key << str[i] << YAML::Value << "true";
+ body << YAML::EndMap;
+ }
+
+ body << YAML::EndSeq;
+ }
+
+ body << YAML::EndMap;
+
+ return true;
+}