瀏覽代碼

Refactored Instances to utilize C++ features (#3163)

* Fixes #3087 and fixes #3095.
* Converts database file to YAML.
* Converts static array to unordered_map which frees up pre-allocated memory that may never be fully used.
* Got rid of all DBMap/ERS features.
* Removes MAX_INSTANCE_DATA in favor of INT_MAX.
* Includes TXT converter.
Thanks to @Lemongrass3110, @secretdataz, @Atemo, @lighta, @InusualZ, @Angelic234, @Normynator, @cydh, and @ecdarreola!
Aleos 5 年之前
父節點
當前提交
06c159c405

+ 0 - 6
db/import-tmpl/instance_db.txt

@@ -1,6 +0,0 @@
-// Instance Database
-//
-// Structure of Database:
-// ID,Name,LimitTime,IdleTimeOut,EnterMap,EnterX,EnterY,Map2,Map3,...,Map255
-//
-// EnterMap is considered as Map1

+ 38 - 0
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 <http://www.gnu.org/licenses/>.
+#
+###########################################################################
+# 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

+ 46 - 0
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 <http://www.gnu.org/licenses/>.
+#
+###########################################################################
+# 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

+ 0 - 11
db/pre-re/instance_db.txt

@@ -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

+ 79 - 0
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 <http://www.gnu.org/licenses/>.
+#
+###########################################################################
+# 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

+ 0 - 40
db/re/instance_db.txt

@@ -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

+ 276 - 0
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 <http://www.gnu.org/licenses/>.
+#
+###########################################################################
+# 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

+ 12 - 4
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.
 We want to add our own customized Housing Instance.
 
 
-#### /db/import/instance_db.txt
-
-    // ID,Name,LimitTime,IdleTimeOut,EnterMap,EnterX,EnterY,Map2,Map3,...,Map255
-    35,Home,3600,900,1@home,24,6,2@home,3@home
+#### /db/import/instance_db.yml
+
+	- Id: 35
+	    Name: Home
+        IdleTimeOut: 900
+        Enter:
+          Map: 1@home
+          X: 24
+          Y: 6
+        AdditionalMaps:
+          - Map: 2@home
+          - Map: 3@home
 
 
 
 
 ### Mob Alias
 ### Mob Alias

+ 2 - 2
doc/script_commands.txt

@@ -8938,7 +8938,7 @@ with the given character id.
 *instance_create("<instance name>"{,<instance mode>{,<owner id>}});
 *instance_create("<instance name>"{,<instance mode>{,<owner id>}});
 
 
 Creates an instance for the <owner id> of <mode>. The instance name, along with
 Creates an instance for the <owner id> of <mode>. 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,
 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
 sets the alive time, and triggers the "OnInstanceInit" label in all NPCs inside
 the instance.
 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 <instance id>. If no ID is specified,
 Warps the attached player to the specified <instance id>. If no ID is specified,
 the IM_PARTY instance the invoking player is attached to is used.
 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:
 The command returns IE_OK upon success, and these values upon failure:
  IE_NOMEMBER:	Party/Guild/Clan not found (for party/guild/clan modes).
  IE_NOMEMBER:	Party/Guild/Clan not found (for party/guild/clan modes).

+ 17 - 0
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)
+###########################################################################

+ 17 - 0
src/common/utilities.hpp

@@ -175,6 +175,23 @@ namespace rathena {
 				vector.erase(vector.begin() + index);
 				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 <typename K, typename V> void vector_erase_if_exists(std::vector<K> &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_addition( int64 a, int64 b, int64& result );
 		bool safe_substraction( int64 a, int64 b, int64& result );
 		bool safe_substraction( int64 a, int64 b, int64& result );
 		bool safe_multiplication( int64 a, int64 b, int64& result );
 		bool safe_multiplication( int64 a, int64 b, int64& result );

+ 2 - 2
src/map/atcommand.cpp

@@ -4030,8 +4030,8 @@ ACMD_FUNC(reload) {
 		if (quest_db.reload())
 		if (quest_db.reload())
 			clif_displaymessage(fd, msg_txt(sd,1377)); // Quest database has been reloaded.
 			clif_displaymessage(fd, msg_txt(sd,1377)); // Quest database has been reloaded.
 	} else if (strstr(command, "instancedb") || strncmp(message, "instancedb", 4) == 0) {
 	} 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) {
 	} else if (strstr(command, "achievementdb") || strncmp(message, "achievementdb", 4) == 0) {
 		achievement_db_reload();
 		achievement_db_reload();
 		clif_displaymessage(fd, msg_txt(sd,771)); // Achievement database has been reloaded.
 		clif_displaymessage(fd, msg_txt(sd,771)); // Achievement database has been reloaded.

+ 12 - 14
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
 /// Required to start the instancing information window on Client
 /// This window re-appears each "refresh" of client automatically until the keep_limit reaches 0.
 /// This window re-appears each "refresh" of client automatically until the keep_limit reaches 0.
 /// S 0x2cb <Instance name>.61B <Standby Position>.W
 /// S 0x2cb <Instance name>.61B <Standby Position>.W
-void clif_instance_create(unsigned short instance_id, int num)
+void clif_instance_create(int instance_id, int num)
 {
 {
 #if PACKETVER >= 20071128
 #if PACKETVER >= 20071128
-	struct instance_db *db = NULL;
 	struct map_session_data *sd = NULL;
 	struct map_session_data *sd = NULL;
 	enum send_target target = PARTY;
 	enum send_target target = PARTY;
 	unsigned char buf[65];
 	unsigned char buf[65];
 
 
-	instance_getsd(instance_id, &sd, &target);
+	instance_getsd(instance_id, sd, &target);
 
 
 	if (!sd)
 	if (!sd)
 		return;
 		return;
 
 
-	db = instance_searchtype_db(instance_data[instance_id].type);
+	std::shared_ptr<s_instance_db> db = instance_db.find(util::umap_find(instances, instance_id)->id);
 
 
 	if (!db)
 	if (!db)
 		return;
 		return;
 
 
 	WBUFW(buf,0) = 0x2cb;
 	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;
 	WBUFW(buf,63) = num;
 	clif_send(buf,packet_len(0x2cb),&sd->bl,target);
 	clif_send(buf,packet_len(0x2cb),&sd->bl,target);
 #endif
 #endif
@@ -17822,14 +17821,14 @@ void clif_instance_create(unsigned short instance_id, int num)
 
 
 /// To announce Instancing queue creation if no maps available
 /// To announce Instancing queue creation if no maps available
 /// S 0x2cc <Standby Position>.W
 /// S 0x2cc <Standby Position>.W
-void clif_instance_changewait(unsigned short instance_id, int num)
+void clif_instance_changewait(int instance_id, int num)
 {
 {
 #if PACKETVER >= 20071128
 #if PACKETVER >= 20071128
 	struct map_session_data *sd = NULL;
 	struct map_session_data *sd = NULL;
 	enum send_target target = PARTY;
 	enum send_target target = PARTY;
 	unsigned char buf[4];
 	unsigned char buf[4];
 
 
-	instance_getsd(instance_id, &sd, &target);
+	instance_getsd(instance_id, sd, &target);
 
 
 	if (!sd)
 	if (!sd)
 		return;
 		return;
@@ -17844,26 +17843,25 @@ void clif_instance_changewait(unsigned short instance_id, int num)
 
 
 /// Notify the current status to members
 /// Notify the current status to members
 /// S 0x2cd <Instance Name>.61B <Instance Remaining Time>.L <Instance Noplayers close time>.L
 /// S 0x2cd <Instance Name>.61B <Instance Remaining Time>.L <Instance Noplayers close time>.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
 #if PACKETVER >= 20071128
-	struct instance_db *db = NULL;
 	struct map_session_data *sd = NULL;
 	struct map_session_data *sd = NULL;
 	enum send_target target = PARTY;
 	enum send_target target = PARTY;
 	unsigned char buf[71];
 	unsigned char buf[71];
 
 
-	instance_getsd(instance_id, &sd, &target);
+	instance_getsd(instance_id, sd, &target);
 
 
 	if (!sd)
 	if (!sd)
 		return;
 		return;
 
 
-	db = instance_searchtype_db(instance_data[instance_id].type);
+	std::shared_ptr<s_instance_db> db = instance_db.find(util::umap_find(instances, instance_id)->id);
 
 
 	if (!db)
 	if (!db)
 		return;
 		return;
 
 
 	WBUFW(buf,0) = 0x2cd;
 	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,63) = limit1;
 	WBUFL(buf,67) = limit2;
 	WBUFL(buf,67) = limit2;
 	clif_send(buf,packet_len(0x2cd),&sd->bl,target);
 	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
 /// 2 = The Memorial Dungeon's entry time limit expired; it has been destroyed
 /// 3 = The Memorial Dungeon has been removed.
 /// 3 = The Memorial Dungeon has been removed.
 /// 4 = Create failure (removes the instance window)
 /// 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
 #if PACKETVER >= 20071128
 	struct map_session_data *sd = NULL;
 	struct map_session_data *sd = NULL;
 	enum send_target target = PARTY;
 	enum send_target target = PARTY;
 	unsigned char buf[10];
 	unsigned char buf[10];
 
 
-	instance_getsd(instance_id, &sd, &target);
+	instance_getsd(instance_id, sd, &target);
 
 
 	if (!sd)
 	if (!sd)
 		return;
 		return;

+ 5 - 4
src/map/clif.hpp

@@ -43,6 +43,7 @@ struct achievement;
 struct guild_log_entry;
 struct guild_log_entry;
 enum e_guild_storage_log : uint16;
 enum e_guild_storage_log : uint16;
 enum e_bg_queue_apply_ack : uint16;
 enum e_bg_queue_apply_ack : uint16;
+enum e_instance_notify : uint8;
 
 
 enum e_PacketDBVersion { // packet DB
 enum e_PacketDBVersion { // packet DB
 	MIN_PACKET_DB  = 0x064,
 	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);
 void clig_bg_queue_ack_lobby(bool result, const char *name, const char *lobbyname, struct map_session_data *sd);
 
 
 // Instancing
 // 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
 // Custom Fonts
 void clif_font(struct map_session_data *sd);
 void clif_font(struct map_session_data *sd);

文件差異過大導致無法顯示
+ 477 - 341
src/map/instance.cpp


+ 75 - 49
src/map/instance.hpp

@@ -4,29 +4,32 @@
 #ifndef INSTANCE_HPP
 #ifndef INSTANCE_HPP
 #define INSTANCE_HPP
 #define INSTANCE_HPP
 
 
+#include <deque>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
 #include "../common/cbasetypes.hpp"
 #include "../common/cbasetypes.hpp"
-#include "../common/mmo.hpp" // struct point
-#include "../common/strlib.hpp"
+#include "../common/database.hpp"
+#include "../common/mmo.hpp"
 
 
-#include "script.hpp" // struct reg_db
+#include "script.hpp"
 
 
 enum send_target : uint8;
 enum send_target : uint8;
 struct block_list;
 struct block_list;
 
 
 extern int16 instance_start;
 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)
 #define INSTANCE_NAME_LENGTH (60+1)
 
 
-enum instance_state {
-	INSTANCE_FREE,
+enum e_instance_state : uint8 {
 	INSTANCE_IDLE,
 	INSTANCE_IDLE,
 	INSTANCE_BUSY
 	INSTANCE_BUSY
 };
 };
 
 
-enum instance_mode {
+enum e_instance_mode : uint8 {
 	IM_NONE,
 	IM_NONE,
 	IM_CHAR,
 	IM_CHAR,
 	IM_PARTY,
 	IM_PARTY,
@@ -35,69 +38,92 @@ enum instance_mode {
 	IM_MAX,
 	IM_MAX,
 };
 };
 
 
-enum e_instance_enter {
-	IE_OK = 0,
+enum e_instance_enter : uint8 {
+	IE_OK,
 	IE_NOMEMBER,
 	IE_NOMEMBER,
 	IE_NOINSTANCE,
 	IE_NOINSTANCE,
 	IE_OTHER
 	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 {
 struct s_instance_map {
 	int16 m, src_m;
 	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
 	int owner_id; ///< Owner ID of instance
 	unsigned int keep_limit; ///< Life time 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
 	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 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<s_instance_map> 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
 		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<int16> maplist; ///< Maps in instance
 };
 };
 
 
-extern struct instance_data instance_data[MAX_INSTANCE_DATA];
+class InstanceDatabase : public TypesafeYamlDatabase<int32, s_instance_db> {
+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);
+	const std::string getDefaultLocation();
+	uint64 parseBodyNode(const YAML::Node &node);
+};
 
 
-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);
+extern InstanceDatabase instance_db;
+
+extern std::unordered_map<int, std::shared_ptr<s_instance_data>> instances;
+
+std::shared_ptr<s_instance_db> 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<s_instance_data> idata);
 
 
-void instance_addnpc(struct instance_data *im);
-void instance_readdb(void);
-void instance_reload(void);
 void do_reload_instance(void);
 void do_reload_instance(void);
 void do_init_instance(void);
 void do_init_instance(void);
 void do_final_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 */
 #endif /* INSTANCE_HPP */

+ 1 - 1
src/map/map-server.vcxproj

@@ -308,7 +308,7 @@
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\homun_skill_tree.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\homun_skill_tree.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\homun_skill_tree.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\homun_skill_tree.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\homunculus_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\homunculus_db.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\homunculus_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\homunculus_db.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\improvise_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\improvise_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\improvise_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\improvise_db.yml')" />
-    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\instance_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\instance_db.txt')" />
+    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\instance_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\instance_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_avail.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_avail.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_avail.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_avail.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_bluebox.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_bluebox.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_bluebox.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_bluebox.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_buyingstore.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_buyingstore.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_buyingstore.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_buyingstore.txt')" />

+ 24 - 25
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);
 	struct map_data *mapdata = map_getmapdata(sd->bl.m);
 
 
-	if( mapdata->instance_id )
+	if( mapdata->instance_id > 0 )
 		instance_delusers(mapdata->instance_id);
 		instance_delusers(mapdata->instance_id);
 
 
 	unit_remove_map_pc(sd,CLR_RESPAWN);
 	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;
 		int16 m;
 		struct point *pt;
 		struct point *pt;
 		if( mapdata->save.map )
 		if( mapdata->save.map )
@@ -2694,18 +2694,16 @@ bool map_addnpc(int16 m,struct npc_data *nd)
 /*==========================================
 /*==========================================
  * Add an instance map
  * 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)
 	if(src_m < 0)
 		return -1;
 		return -1;
 
 
+	const char *name = map_mapid2mapname(src_m);
+
 	if(strlen(name) > 20) {
 	if(strlen(name) > 20) {
 		// against buffer overflow
 		// 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;
 		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 *src_map = map_getmapdata(src_m);
 	struct map_data *dst_map = map_getmapdata(dst_m);
 	struct map_data *dst_map = map_getmapdata(dst_m);
+	char iname[MAP_NAME_LENGTH];
 
 
 	strcpy(iname, name);
 	strcpy(iname, name);
 
 
 	// Alter the name
 	// Alter the name
 	// Due to this being custom we only worry about preserving as many characters as necessary for accurate map distinguishing
 	// 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
 	// 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
 	} 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->m = dst_m;
 	dst_map->instance_id = instance_id;
 	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;
 	dst_map->npc_num_warp = 0;
 
 
 	// Reallocate cells
 	// 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 );
 	CREATE( dst_map->cell, struct mapcell, num_cell );
 	memcpy( dst_map->cell, src_map->cell, num_cell * sizeof(struct mapcell) );
 	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 = (struct block_list **)aCalloc(1,size);
 	dst_map->block_mob = (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);
 	struct map_data *mapdata = map_getmapdata(m);
 
 
-	if(m < 0 || !mapdata->instance_id)
+	if(m < 0 || mapdata->instance_id <= 0)
 		return 0;
 		return 0;
 
 
 	// Kick everyone out
 	// Kick everyone out
@@ -2972,7 +2973,7 @@ void map_removemobs(int16 m)
 		return; //Mobs are already scheduled for removal
 		return; //Mobs are already scheduled for removal
 
 
 	// Don't remove mobs on instance map
 	// Don't remove mobs on instance map
-	if (mapdata->instance_id)
+	if (mapdata->instance_id > 0)
 		return;
 		return;
 
 
 	mapdata->mob_delete_timer = add_timer(gettick()+battle_config.mob_remove_delay, map_removemobs_timer, m, 0);
 	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)
 	if (!mapdata)
 		return "";
 		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<s_instance_data> 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;
 			return mapdata->name;
 		else {
 		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;
 			}
 			}
 		}
 		}
 	}
 	}

+ 2 - 2
src/map/map.hpp

@@ -748,7 +748,7 @@ struct map_data {
 	int mob_delete_timer;	// Timer ID for map_removemobs_timer [Skotlex]
 	int mob_delete_timer;	// Timer ID for map_removemobs_timer [Skotlex]
 
 
 	// Instance Variables
 	// Instance Variables
-	unsigned short instance_id;
+	int instance_id;
 	int instance_src_map;
 	int instance_src_map;
 
 
 	/* rAthena Local Chat */
 	/* 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);
 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
 // 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);
 int map_delinstancemap(int m);
 void map_data_copyall(void);
 void map_data_copyall(void);
 void map_data_copy(struct map_data *dst_map, struct map_data *src_map);
 void map_data_copy(struct map_data *dst_map, struct map_data *src_map);

+ 11 - 6
src/map/npc.cpp

@@ -16,6 +16,7 @@
 #include "../common/showmsg.hpp"
 #include "../common/showmsg.hpp"
 #include "../common/strlib.hpp"
 #include "../common/strlib.hpp"
 #include "../common/timer.hpp"
 #include "../common/timer.hpp"
+#include "../common/utilities.hpp"
 #include "../common/utils.hpp"
 #include "../common/utils.hpp"
 
 
 #include "battle.hpp"
 #include "battle.hpp"
@@ -33,6 +34,8 @@
 #include "pet.hpp"
 #include "pet.hpp"
 #include "script.hpp" // script_config
 #include "script.hpp" // script_config
 
 
+using namespace rathena;
+
 struct npc_data* fake_nd;
 struct npc_data* fake_nd;
 
 
 // linked list of npc source files
 // 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];
 	char newname[NPC_NAME_LENGTH+1];
 	struct map_data *mapdata = map_getmapdata(m);
 	struct map_data *mapdata = map_getmapdata(m);
 
 
-	if( mapdata->instance_id == 0 )
+	if( mapdata->instance_id <= 0 )
 		return 1;
 		return 1;
 
 
 	snprintf(newname, ARRAYLENGTH(newname), "dup_%d_%d", mapdata->instance_id, snd->bl.id);
 	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
 	if( snd->subtype == NPCTYPE_WARP ) { // Adjust destination, if instanced
 		struct npc_data *wnd = NULL; // New NPC
 		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<s_instance_data> idata = util::umap_find(instances, mapdata->instance_id);
+		int dm = map_mapindex2mapid(snd->u.warp.mapindex), imap = 0;
+
 		if( dm < 0 ) return 1;
 		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
 				break; // Instance map matches destination, update to instance map
 			}
 			}
+		}
 
 
 		if(!imap)
 		if(!imap)
 			imap = map_mapname2mapid(map_getmapdata(dm)->name);
 			imap = map_mapname2mapid(map_getmapdata(dm)->name);

+ 82 - 70
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);
 const char* parse_subexpr(const char* p,int limit);
 int run_func(struct script_state *st);
 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)
 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)
 					if (data->ref)
 						n = data->ref->vars;
 						n = data->ref->vars;
 					else {
 					else {
-						unsigned short instance_id = script_instancegetid(st);
-						if (instance_id != 0)
-							n = instance_data[instance_id].regs.vars;
+						std::shared_ptr<s_instance_data> idata = util::umap_find(instances, script_instancegetid(st));
+
+						if (idata)
+							n = idata->regs.vars;
 					}
 					}
 					if (n)
 					if (n)
 						data->u.str = (char*)i64db_get(n,reference_getuid(data));
 						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)
 						if (data->ref)
 							n = data->ref->vars;
 							n = data->ref->vars;
 						else {
 						else {
-							unsigned short instance_id = script_instancegetid(st);
-							if (instance_id != 0)
-								n = instance_data[instance_id].regs.vars;
+							std::shared_ptr<s_instance_data> idata = util::umap_find(instances, script_instancegetid(st));
+
+							if (idata)
+								n = idata->regs.vars;
 						}
 						}
 						if (n)
 						if (n)
 							data->u.num = i64db_i64get(n,reference_getuid(data));
 							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)
 				if (ref)
 					src = ref;
 					src = ref;
 				else {
 				else {
-					unsigned short instance_id = script_instancegetid(st);
+					std::shared_ptr<s_instance_data> idata = util::umap_find(instances, script_instancegetid(st));
 
 
-					if (instance_id != 0)
-						src = &instance_data[instance_id].regs;
+					if (idata)
+						src = &idata->regs;
 				}
 				}
 				break;
 				break;
 			}
 			}
@@ -3198,11 +3200,10 @@ bool set_reg_str( struct script_state* st, struct map_session_data* sd, int64 nu
 				if( ref ){
 				if( ref ){
 					src = ref;
 					src = ref;
 				}else{
 				}else{
-					unsigned short instance_id = script_instancegetid( st );
+					std::shared_ptr<s_instance_data> 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 ){
 				if( src ){
@@ -3293,11 +3294,10 @@ bool set_reg_num( struct script_state* st, struct map_session_data* sd, int64 nu
 				if( ref ){
 				if( ref ){
 					src = ref;
 					src = ref;
 				}else{
 				}else{
-					unsigned short instance_id = script_instancegetid( st );
+					std::shared_ptr<s_instance_data> 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 ){
 				if( src ){
@@ -20091,9 +20091,9 @@ BUILDIN_FUNC(bg_info)
  * @param mode: Instance mode
  * @param mode: Instance mode
  * @return instance ID on success or 0 otherwise
  * @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) {
 	if (mode == IM_NONE) {
 		struct npc_data *nd = map_id2nd(st->oid);
 		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) {
 		if (sd) {
 			switch (mode) {
 			switch (mode) {
 				case IM_CHAR:
 				case IM_CHAR:
-					if (sd->instance_id)
+					if (sd->instance_id > 0)
 						instance_id = sd->instance_id;
 						instance_id = sd->instance_id;
 					break;
 					break;
 				case IM_PARTY: {
 				case IM_PARTY: {
 					struct party_data *pd = party_search(sd->status.party_id);
 					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;
 						instance_id = pd->instance_id;
 				}
 				}
 					break;
 					break;
 				case IM_GUILD: {
 				case IM_GUILD: {
 					struct guild *gd = guild_search(sd->status.guild_id);
 					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;
 						instance_id = gd->instance_id;
 				}
 				}
 					break;
 					break;
 				case IM_CLAN: {
 				case IM_CLAN: {
 					struct clan *cd = clan_search(sd->status.clan_id);
 					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;
 						instance_id = cd->instance_id;
 				}
 				}
 					break;
 					break;
@@ -20145,11 +20145,11 @@ unsigned short script_instancegetid(struct script_state* st, enum instance_mode
  *------------------------------------------*/
  *------------------------------------------*/
 BUILDIN_FUNC(instance_create)
 BUILDIN_FUNC(instance_create)
 {
 {
-	enum instance_mode mode = IM_PARTY;
+	e_instance_mode mode = IM_PARTY;
 	int owner_id = 0;
 	int owner_id = 0;
 
 
 	if (script_hasdata(st, 3)) {
 	if (script_hasdata(st, 3)) {
-		mode = static_cast<instance_mode>(script_getnum(st, 3));
+		mode = static_cast<e_instance_mode>(script_getnum(st, 3));
 
 
 		if (mode < IM_NONE || mode >= IM_MAX) {
 		if (mode < IM_NONE || mode >= IM_MAX) {
 			ShowError("buildin_instance_create: Unknown instance mode %d for '%s'\n", mode, script_getstr(st, 2));
 			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)
 BUILDIN_FUNC(instance_destroy)
 {
 {
-	unsigned short instance_id;
+	int instance_id;
 
 
 	if( script_hasdata(st,2) )
 	if( script_hasdata(st,2) )
 		instance_id = script_getnum(st,2);
 		instance_id = script_getnum(st,2);
@@ -20208,7 +20208,7 @@ BUILDIN_FUNC(instance_destroy)
 		instance_id = script_instancegetid(st);
 		instance_id = script_instancegetid(st);
 
 
 	if( instance_id == 0 ) {
 	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;
 		return SCRIPT_CMD_FAILURE;
 	}
 	}
 
 
@@ -20229,7 +20229,7 @@ BUILDIN_FUNC(instance_enter)
 	struct map_session_data *sd = NULL;
 	struct map_session_data *sd = NULL;
 	int x = script_hasdata(st,3) ? script_getnum(st, 3) : -1;
 	int x = script_hasdata(st,3) ? script_getnum(st, 3) : -1;
 	int y = script_hasdata(st,4) ? script_getnum(st, 4) : -1;
 	int y = script_hasdata(st,4) ? script_getnum(st, 4) : -1;
-	unsigned short instance_id;
+	int instance_id;
 
 
 	if (script_hasdata(st, 6))
 	if (script_hasdata(st, 6))
 		instance_id = script_getnum(st, 6);
 		instance_id = script_getnum(st, 6);
@@ -20253,7 +20253,7 @@ BUILDIN_FUNC(instance_enter)
 BUILDIN_FUNC(instance_npcname)
 BUILDIN_FUNC(instance_npcname)
 {
 {
 	const char *str;
 	const char *str;
-	unsigned short instance_id = 0;
+	int instance_id;
 	struct npc_data *nd;
 	struct npc_data *nd;
 
 
 	str = script_getstr(st,2);
 	str = script_getstr(st,2);
@@ -20262,12 +20262,12 @@ BUILDIN_FUNC(instance_npcname)
 	else
 	else
 		instance_id = script_instancegetid(st);
 		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];
 		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);
 		script_pushconststr(st,npcname);
 	} else {
 	} 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;
 		st->state = END;
 		return SCRIPT_CMD_FAILURE;
 		return SCRIPT_CMD_FAILURE;
 	}
 	}
@@ -20284,7 +20284,7 @@ BUILDIN_FUNC(instance_mapname)
 {
 {
  	const char *str;
  	const char *str;
 	int16 m;
 	int16 m;
-	unsigned short instance_id = 0;
+	int instance_id;
 
 
 	str = script_getstr(st,2);
 	str = script_getstr(st,2);
 
 
@@ -20294,7 +20294,7 @@ BUILDIN_FUNC(instance_mapname)
 		instance_id = script_instancegetid(st);
 		instance_id = script_instancegetid(st);
 
 
 	// Check that instance mapname is a valid map
 	// 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, "");
 		script_pushconststr(st, "");
 	else
 	else
 		script_pushconststr(st, map_getmapdata(m)->name);
 		script_pushconststr(st, map_getmapdata(m)->name);
@@ -20319,7 +20319,7 @@ BUILDIN_FUNC(instance_id)
 		}
 		}
 	}
 	}
 
 
-	script_pushint(st, script_instancegetid(st, static_cast<instance_mode>(mode)));
+	script_pushint(st, script_instancegetid(st, static_cast<e_instance_mode>(mode)));
 	return SCRIPT_CMD_SUCCESS;
 	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);
 	unsigned int m = va_arg(ap,unsigned int);
 	int x = va_arg(ap,int);
 	int x = va_arg(ap,int);
 	int y = 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);
 	nullpo_retr(0, bl);
 
 
@@ -20343,8 +20342,15 @@ static int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
 		return 0;
 		return 0;
 
 
 	sd = (TBL_PC *)bl;
 	sd = (TBL_PC *)bl;
-	owner_id = instance_data[instance_id].owner_id;
-	switch(instance_data[instance_id].mode) {
+
+	std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
+
+	if (!idata)
+		return 0;
+
+	int owner_id = idata->owner_id;
+
+	switch(idata->mode) {
 		case IM_NONE:
 		case IM_NONE:
 			break;
 			break;
 		case IM_CHAR:
 		case IM_CHAR:
@@ -20370,8 +20376,8 @@ static int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
 
 
 BUILDIN_FUNC(instance_warpall)
 BUILDIN_FUNC(instance_warpall)
 {
 {
-	int16 m, i;
-	unsigned short instance_id;
+	int16 m;
+	int instance_id;
 	const char *mapn;
 	const char *mapn;
 	int x, y;
 	int x, y;
 
 
@@ -20383,11 +20389,18 @@ BUILDIN_FUNC(instance_warpall)
 	else
 	else
 		instance_id = script_instancegetid(st, IM_PARTY);
 		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;
+
+	std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
+
+	if (!idata) {
+		ShowError("buildin_instance_warpall: Instance is not found.\n");
 		return SCRIPT_CMD_FAILURE;
 		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);
+	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;
 	return SCRIPT_CMD_SUCCESS;
 }
 }
@@ -20399,7 +20412,7 @@ BUILDIN_FUNC(instance_warpall)
  * Using 0 for <instance id> will auto-detect the id.
  * Using 0 for <instance id> will auto-detect the id.
  *------------------------------------------*/
  *------------------------------------------*/
 BUILDIN_FUNC(instance_announce) {
 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);
 	const char     *mes        = script_getstr(st,3);
 	int            flag        = script_getnum(st,4);
 	int            flag        = script_getnum(st,4);
 	const char     *fontColor  = script_hasdata(st,5) ? script_getstr(st,5) : NULL;
 	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            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            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            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);
 		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<s_instance_data> idata = util::umap_find(instances, instance_id);
+
+	if (instance_id <= 0 || !idata) {
+		ShowError("buildin_instance_announce: Instance not found.\n");
 		return SCRIPT_CMD_FAILURE;
 		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;
 	return SCRIPT_CMD_SUCCESS;
 }
 }
@@ -20438,7 +20450,7 @@ BUILDIN_FUNC(instance_announce) {
 BUILDIN_FUNC(instance_check_party)
 BUILDIN_FUNC(instance_check_party)
 {
 {
 	int amount, min, max, i, party_id, c = 0;
 	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.
 	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.
 	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);
 	const char* name = script_getstr(st, 2);
 	int type = script_getnum(st, 3);
 	int type = script_getnum(st, 3);
 	int index = 0;
 	int index = 0;
-	struct instance_db *db = instance_searchname_db(name);
+	std::shared_ptr<s_instance_db> db = instance_search_db_name(name);
 
 
-	if( !db ){
+	if (!db) {
 		ShowError( "buildin_instance_info: Unknown instance name \"%s\".\n", name );
 		ShowError( "buildin_instance_info: Unknown instance name \"%s\".\n", name );
 		script_pushint(st, -1);
 		script_pushint(st, -1);
 		return SCRIPT_CMD_FAILURE;
 		return SCRIPT_CMD_FAILURE;
@@ -20639,7 +20651,7 @@ BUILDIN_FUNC(instance_info)
 			script_pushint(st, db->timeout);
 			script_pushint(st, db->timeout);
 			break;
 			break;
 		case IIT_ENTER_MAP:
 		case IIT_ENTER_MAP:
-			script_pushstrcopy(st, StringBuf_Value(db->enter.mapname));
+			script_pushstrcopy(st, map_mapid2mapname(db->enter.map));
 			break;
 			break;
 		case IIT_ENTER_X:
 		case IIT_ENTER_X:
 			script_pushint(st, db->enter.x);
 			script_pushint(st, db->enter.x);
@@ -20648,7 +20660,7 @@ BUILDIN_FUNC(instance_info)
 			script_pushint(st, db->enter.y);
 			script_pushint(st, db->enter.y);
 			break;
 			break;
 		case IIT_MAPCOUNT:
 		case IIT_MAPCOUNT:
-			script_pushint(st, db->maplist_count);
+			script_pushint(st, db->maplist.size());
 			break;
 			break;
 		case IIT_MAP:
 		case IIT_MAP:
 			if( !script_hasdata(st, 4) || script_isstring(st, 4) ){
 			if( !script_hasdata(st, 4) || script_isstring(st, 4) ){
@@ -20671,7 +20683,7 @@ BUILDIN_FUNC(instance_info)
 				return SCRIPT_CMD_FAILURE;
 				return SCRIPT_CMD_FAILURE;
 			}
 			}
 
 
-			script_pushstrcopy(st, StringBuf_Value(db->maplist[index]));
+			script_pushstrcopy(st, map_mapid2mapname(db->maplist[index]));
 			break;
 			break;
 
 
 		default:
 		default:
@@ -20705,14 +20717,14 @@ BUILDIN_FUNC(instance_live_info)
 	else
 	else
 		id = script_getnum(st, 3);
 		id = script_getnum(st, 3);
 
 
-	struct instance_db *db = nullptr;
-	struct instance_data *im = nullptr;
+	std::shared_ptr<s_instance_db> db = nullptr;
+	std::shared_ptr<s_instance_data> 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)
 		if (im)
-			db = instance_searchtype_db(im->type);
+			db = instance_db.find(im->id);
 	}
 	}
 
 
 	if (!im || !db) {
 	if (!im || !db) {
@@ -20725,7 +20737,7 @@ BUILDIN_FUNC(instance_live_info)
 
 
 	switch( type ) {
 	switch( type ) {
 	case ILI_NAME:
 	case ILI_NAME:
-		script_pushstrcopy(st, StringBuf_Value(db->name));
+		script_pushstrcopy(st, db->name.c_str());
 		break;
 		break;
 	case ILI_MODE:
 	case ILI_MODE:
 		script_pushint(st, im->mode);
 		script_pushint(st, im->mode);
@@ -24533,16 +24545,16 @@ BUILDIN_FUNC(getvariableofinstance)
 		return SCRIPT_CMD_FAILURE;
 		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);
 		ShowError("buildin_getvariableofinstance: Invalid instance ID %d.\n", instance_id);
 		script_pushnil(st);
 		script_pushnil(st);
 		st->state = END;
 		st->state = END;
 		return SCRIPT_CMD_FAILURE;
 		return SCRIPT_CMD_FAILURE;
 	}
 	}
 
 
-	struct instance_data *im = &instance_data[instance_id];
+	std::shared_ptr<s_instance_data> im = util::umap_find(instances, instance_id);
 
 
 	if (im->state != INSTANCE_BUSY) {
 	if (im->state != INSTANCE_BUSY) {
 		ShowError("buildin_getvariableofinstance: Unknown instance ID %d.\n", instance_id);
 		ShowError("buildin_getvariableofinstance: Unknown instance ID %d.\n", instance_id);

+ 49 - 0
src/tool/csv2yaml.cpp

@@ -51,6 +51,8 @@
 
 
 using namespace rathena;
 using namespace rathena;
 
 
+#define MAX_MAP_PER_INSTANCE 255
+
 #ifndef WIN32
 #ifndef WIN32
 int getch( void ){
 int getch( void ){
     struct termios oldattr, newattr;
     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_nonearnpcrangedb(char* split[], int columns, int current);
 static bool skill_parse_row_skilldb(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 quest_read_db(char *split[], int columns, int current);
+static bool instance_readdb_sub(char* str[], int columns, int current);
 
 
 // Constants for conversion
 // Constants for conversion
 std::unordered_map<uint16, std::string> aegis_itemnames;
 std::unordered_map<uint16, std::string> aegis_itemnames;
@@ -360,6 +363,12 @@ int do_init( int argc, char** argv ){
 		return 0;
 		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 ;-)
 	// TODO: add implementations ;-)
 
 
 	return 0;
 	return 0;
@@ -2537,3 +2546,43 @@ static bool quest_read_db(char *split[], int columns, int current) {
 
 
 	return true;
 	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;
+}

部分文件因文件數量過多而無法顯示