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!
This commit is contained in:
Aleos 2020-04-08 12:52:45 -04:00 committed by GitHub
parent 7507065885
commit 06c159c405
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1367 additions and 891 deletions

View File

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

View File

@ -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
db/instance_db.yml Normal file
View File

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

View File

@ -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
db/pre-re/instance_db.yml Normal file
View File

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

View File

@ -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
db/re/instance_db.yml Normal file
View File

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

View File

@ -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 #### /db/import/instance_db.yml
// ID,Name,LimitTime,IdleTimeOut,EnterMap,EnterX,EnterY,Map2,Map3,...,Map255 - Id: 35
35,Home,3600,900,1@home,24,6,2@home,3@home Name: Home
IdleTimeOut: 900
Enter:
Map: 1@home
X: 24
Y: 6
AdditionalMaps:
- Map: 2@home
- Map: 3@home
### Mob Alias ### Mob Alias

View File

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

View File

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

View File

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

View File

@ -4030,7 +4030,7 @@ 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(); if (instance_db.reload())
clif_displaymessage(fd, msg_txt(sd,516)); // Instance database has been reloaded. 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();

View File

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

View File

@ -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_create(int instance_id, int num);
void clif_instance_changewait(unsigned short instance_id, int num); void clif_instance_changewait(int instance_id, int num);
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);
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);
// Custom Fonts // Custom Fonts
void clif_font(struct map_session_data *sd); void clif_font(struct map_session_data *sd);

File diff suppressed because it is too large Load Diff

View File

@ -4,29 +4,32 @@
#ifndef INSTANCE_HPP #ifndef INSTANCE_HPP
#define INSTANCE_HPP #define INSTANCE_HPP
#include "../common/cbasetypes.hpp" #include <deque>
#include "../common/mmo.hpp" // struct point #include <memory>
#include "../common/strlib.hpp" #include <string>
#include <unordered_map>
#include <vector>
#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; enum send_target : uint8;
struct block_list; struct block_list;
extern int16 instance_start; extern int16 instance_start;
extern int instance_count;
#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
#define INSTANCE_NAME_LENGTH (60+1) #define INSTANCE_NAME_LENGTH (60+1)
enum instance_state { enum e_instance_state : uint8 {
INSTANCE_FREE,
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 { enum e_instance_enter : uint8 {
IE_OK = 0, 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 { /// Instance data
unsigned short type; ///< Instance DB ID struct s_instance_data {
enum instance_state state; ///< State of instance int id; ///< Instance DB ID
enum instance_mode mode; ///< Mode of instance 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 std::vector<s_instance_map> map; ///< Array of maps in instance
uint8 cnt_map; ///< Number of maps in an 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 /// Instance DB entry
struct instance_db { struct s_instance_db {
unsigned short id; ///< Instance ID int id; ///< Instance DB ID
StringBuf *name; ///< Instance name std::string name; ///< Instance name
unsigned int limit, ///< Duration limit uint32 limit, ///< Duration limit
timeout; ///< Timeout limit timeout; ///< Timeout limit
struct s_MapInfo { //bool destroyable; ///< Destroyable flag
StringBuf *mapname; ///< Mapname, the limit should be MAP_NAME_LENGTH_EXT struct point enter; ///< Instance entry point
short x, y; ///< Map coordinates std::vector<int16> maplist; ///< Maps in instance
} enter;
StringBuf **maplist; ///< Used maps in instance, the limit should be MAP_NAME_LENGTH_EXT
uint8 maplist_count; ///< Number of used maps
}; };
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);
int instance_create(int owner_id, const char *name, enum instance_mode mode); const std::string getDefaultLocation();
int instance_destroy(unsigned short instance_id); uint64 parseBodyNode(const YAML::Node &node);
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); extern InstanceDatabase instance_db;
int instance_delusers(unsigned short instance_id);
int16 instance_mapname2mapid(const char *name, unsigned short instance_id); extern std::unordered_map<int, std::shared_ptr<s_instance_data>> instances;
int instance_addmap(unsigned short instance_id);
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 */

View File

@ -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')" />

View File

@ -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,6 +2725,7 @@ 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);
@ -2735,9 +2734,9 @@ int map_addinstancemap(const char *name, unsigned short instance_id)
// 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) { if ((strchr(iname, '@') == NULL) && strlen(iname) > 8) {
memmove(iname, iname + (strlen(iname) - 9), strlen(iname)); memmove(iname, iname + (strlen(iname) - 9), strlen(iname));
snprintf(dst_map->name, sizeof(dst_map->name),"%hu#%s", instance_id, 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); snprintf(dst_map->name, sizeof(dst_map->name), "%.3d%s", (instance_id % 1000), iname);
dst_map->name[MAP_NAME_LENGTH - 1] = '\0'; dst_map->name[MAP_NAME_LENGTH - 1] = '\0';
dst_map->m = dst_m; dst_map->m = dst_m;
@ -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 if (mapdata->instance_id > 0) { // Instance map check
struct instance_data *im = &instance_data[mapdata->instance_id]; 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 (const auto &it : idata->map) { // Loop to find the src map we want
if (it.m == m)
for (i = 0; i < im->cnt_map; i++) { // Loop to find the src map we want return map_getmapdata(it.src_m)->name;
if (im->map[i]->m == m)
return map[im->map[i]->src_m].name;
} }
} }
} }

View File

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

View File

@ -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]; std::shared_ptr<s_instance_data> idata = util::umap_find(instances, mapdata->instance_id);
int dm = map_mapindex2mapid(snd->u.warp.mapindex), imap = 0, i; 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++) for (const auto &it : idata->map) {
if(im->map[i]->m && map_mapname2mapid(map_getmapdata(im->map[i]->src_m)->name) == dm) { if (it.m && map_mapname2mapid(map_getmapdata(it.src_m)->name) == dm) {
imap = map_mapname2mapid(map_getmapdata(im->map[i]->m)->name); 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);

View File

@ -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); std::shared_ptr<s_instance_data> idata = util::umap_find(instances, script_instancegetid(st));
if (instance_id != 0)
n = instance_data[instance_id].regs.vars; 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); std::shared_ptr<s_instance_data> idata = util::umap_find(instances, script_instancegetid(st));
if (instance_id != 0)
n = instance_data[instance_id].regs.vars; 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) if (idata)
src = &instance_data[instance_id].regs; 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 ){ if (idata)
src = &instance_data[instance_id].regs; 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 ){ if (idata)
src = &instance_data[instance_id].regs; 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); int instance_id = va_arg(ap, int);
struct map_session_data *sd = NULL; struct map_session_data *sd;
int owner_id = 0;
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; int16 m;
unsigned short instance_id; 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; return SCRIPT_CMD_FAILURE;
for(i = 0; i < instance_data[instance_id].cnt_map; i++) std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
map_foreachinmap(buildin_instance_warpall_sub, instance_data[instance_id].map[i]->m, BL_PC, map_id2index(m), x, y, 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; 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) { std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
ShowError("buildin_instance_announce: Intance is not found.\n");
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++ ) for (const auto &it : idata->map)
map_foreachinmap(buildin_announce_sub, instance_data[instance_id].map[i]->m, BL_PC, map_foreachinmap(buildin_announce_sub, it.m, BL_PC, mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
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,7 +20632,7 @@ 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 );
@ -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; std::shared_ptr<s_instance_db> db = nullptr;
struct instance_data *im = nullptr; std::shared_ptr<s_instance_data> im = nullptr;
if (id > 0 && id < MAX_INSTANCE_DATA) { if (id > 0 && id < INT_MAX) {
im = &instance_data[id]; 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);

View File

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