Sfoglia il codice sorgente

Battleground Queue fixes (#4648)

* Fixes #4644.
* Initialize all battleground queues at startup to reduce overhead of creation/deletion during live server.
* Removes lots of duplicate code between team checks.
* Adds missing checks for script commands bg_leave and bg_desert to only warp players out using the Battleground Queue System.
* Adds documentation for script commands bg_leave and bg_desert to state players will be warped out after when using the Battleground Queue System.
* Optimizes join logic to add new players to the end of the queue rather than the front.
* Cleans up the client messages so certain responses are cleared when they need to be.
Thanks to @Balferian and @Lemongrass3110!
Aleos 5 anni fa
parent
commit
1fc4b8de20

+ 6 - 0
doc/script_commands.txt

@@ -9390,6 +9390,9 @@ Note: 'bg_reserve' and 'bg_unbook' prevent the Battlegrounds queue from joining
 Same as 'bg_leave' but slaps the player with a deserter status so they can't enter another queue for the time
 defined in battleground_db (10 minutes by default).
 
+With the Battleground Queue System, it will also warp the player to their previous position when they joined or
+to their save point if the map had MF_NOSAVE.
+
 ---------------------------------------
 
 *bg_warp <Battle Group>,"<map name>",<x>,<y>;
@@ -9451,6 +9454,9 @@ OnTimer1000:
 
 Removes attached player from their Battle Group.
 
+With the Battleground Queue System, it will also warp the player to their previous position when they joined or
+to their save point if the map had MF_NOSAVE.
+
 ---------------------------------------
 
 *bg_destroy <Batte Group>;

+ 4 - 2
npc/battleground/flavius/flavius01.txt

@@ -538,7 +538,8 @@ bat_b01,10,294,3	script	Vintenar#bat_b01_aover	419,{
 		close;
 	}
 	bg_leave;
-	warp "bat_room",154,150;
+	if (!getbattleflag("feature.bgqueue"))
+		warp "bat_room",154,150;
 	end;
 
 OnInit:
@@ -562,7 +563,8 @@ bat_b01,389,14,3	script	Vintenar#bat_b01_bover	415,{
 		close;
 	}
 	bg_leave;
-	warp "bat_room",154,150;
+	if (!getbattleflag("feature.bgqueue"))
+		warp "bat_room",154,150;
 	end;
 
 OnInit:

+ 4 - 2
npc/battleground/flavius/flavius02.txt

@@ -539,7 +539,8 @@ bat_b02,10,294,3	script	Vintenar#bat_b02_aover	419,{
 		close;
 	}
 	bg_leave;
-	warp "bat_room",154,150;
+	if (!getbattleflag("feature.bgqueue"))
+		warp "bat_room",154,150;
 	end;
 
 OnInit:
@@ -563,7 +564,8 @@ bat_b02,389,14,3	script	Vintenar#bat_b02_bover	415,{
 		close;
 	}
 	bg_leave;
-	warp "bat_room",154,150;
+	if (!getbattleflag("feature.bgqueue"))
+		warp "bat_room",154,150;
 	end;
 
 OnInit:

+ 1 - 1
npc/battleground/kvm/kvm02.txt

@@ -375,8 +375,8 @@ bat_c02,51,130,5	script	KVM Officer#KVM02A	419,{
 		set Bat_Team,0;
 		if (!getbattleflag("feature.bgqueue"))
 			warp "bat_room",154,150;
-		end;
 	}
+	end;
 }
 bat_c02,148,53,1	duplicate(KVM Officer#KVM02A)	KVM Officer#KVM02B	415
 

+ 2 - 2
npc/battleground/kvm/kvm03.txt

@@ -374,8 +374,8 @@ bat_c03,51,130,5	script	KVM Officer#KVM03A	419,{
 		}
 		bg_leave;
 		set Bat_Team,0;
-	if (!getbattleflag("feature.bgqueue"))
-		warp "bat_room",154,150;
+		if (!getbattleflag("feature.bgqueue"))
+			warp "bat_room",154,150;
 	}
 	end;
 }

+ 1 - 1
npc/battleground/tierra/tierra02.txt

@@ -723,7 +723,7 @@ bat_a02,45,19,3	script	Croix Vintenar#a02_b	415,{
 			callfunc "F_BG_Badge",1,"Croix","Tierra";
 	}
 	bg_leave;
-	if (getbattleflag("feature.bgqueue"))
+	if (!getbattleflag("feature.bgqueue"))
 		warp "bat_room",154,150;
 	end;
 

+ 144 - 346
src/map/battleground.cpp

@@ -420,22 +420,26 @@ int bg_team_leave(struct map_session_data *sd, bool quit, bool deserter)
 	sd->bg_id = 0;
 
 	if (bgteam) {
-		char output[CHAT_SIZE_MAX];
-		int i;
-
-		ARR_FIND(0, bgteam->members.size(), i, bgteam->members[i].sd == sd);
-		if (i < bgteam->members.size()) { // Removes member from BG
-			if (bgteam->members[i].entry_point.map != 0) {
-				int16 map_id = map_mapindex2mapid(bgteam->members[i].entry_point.map);
-
-				if (!map_getmapflag(map_id, MF_NOSAVE))
-					pc_setpos(sd, bgteam->members[i].entry_point.map, bgteam->members[i].entry_point.x, bgteam->members[i].entry_point.y, CLR_TELEPORT);
-				else
-					pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); // Warp to save point if the entry map has no save flag.
+		// Warping members out only applies to the Battleground Queue System
+		if (battle_config.feature_bgqueue) {
+			auto member = bgteam->members.begin();
+
+			while (member != bgteam->members.end()) {
+				if (member->sd == sd && member->entry_point.map != 0) {
+					if (!map_getmapflag(map_mapindex2mapid(member->entry_point.map), MF_NOSAVE))
+						pc_setpos(sd, member->entry_point.map, member->entry_point.x, member->entry_point.y, CLR_TELEPORT);
+					else
+						pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); // Warp to save point if the entry map has no save flag.
+
+					bgteam->members.erase(member);
+					break;
+				} else
+					member++;
 			}
-			util::erase_at(bgteam->members, i);
 		}
 
+		char output[CHAT_SIZE_MAX];
+
 		if (quit)
 			sprintf(output, "Server: %s has quit the game...", sd->status.name);
 		else
@@ -681,7 +685,9 @@ static TIMER_FUNC(bg_on_ready_start)
 
 	nullpo_retr(1, queue);
 
-	bg_queue_start_battleground(std::shared_ptr<s_battleground_queue>(queue));
+	queue->tid_start = INVALID_TIMER;
+	bg_queue_start_battleground(queue);
+
 	return 0;
 }
 
@@ -794,154 +800,25 @@ bool bg_queue_reservation(const char *name, bool state)
 	return false;
 }
 
-/**
- * Initialize a Battleground queue
- * @param bg_id: Battleground ID
- * @param req_players: Required amount of players
- * @return s_battleground_queue*
- */
-std::shared_ptr<s_battleground_queue> bg_queue_create(int bg_id, int req_players)
-{
-	auto queue = std::make_shared<s_battleground_queue>();
-
-	queue->id = bg_id;
-	queue->required_players = req_players;
-	queue->accepted_players = 0;
-	queue->tid_expire = INVALID_TIMER;
-	queue->tid_start = INVALID_TIMER;
-	queue->tid_requeue = INVALID_TIMER;
-	queue->in_ready_state = false;
-
-	return queue;
-}
-
-/**
- * Allow a player to join a Battleground queue
- * @param name: Battleground name
- * @param sd: Player data
- * @return @see e_bg_queue_apply_ack
- */
-e_bg_queue_apply_ack bg_queue_join(const char *name, struct map_session_data *sd)
-{
-	if (!sd) {
-		ShowError("bg_queue_join: Tried to join non-existent player.\n.");
-		return BG_APPLY_NONE;
-	}
-
-	if (!bg_queue_check_status(sd, name))
-		return BG_APPLY_NONE;
-
-	if (bg_player_is_in_bg_map(sd)) {
-		clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You may not join a battleground queue when you're in a battleground map.
-		return BG_APPLY_NONE;
-	}
-
-	std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
-
-	if (!bg) {
-		ShowWarning("bq_queue_join: Could not find battleground \"%s\" requested by %s (AID: %d / CID: %d)\n", name, sd->status.name, sd->status.account_id, sd->status.char_id);
-		return BG_APPLY_INVALID_NAME;
-	}
-
-	if (bg->min_lvl && sd->status.base_level < bg->min_lvl)
-		return BG_APPLY_PLAYER_LEVEL; // Level too low
-
-	if (bg->max_lvl && sd->status.base_level > bg->max_lvl)
-		return BG_APPLY_PLAYER_LEVEL; // Level too high
-
-	std::shared_ptr<s_battleground_queue> queue;
-	bool r;
-
-	if (bg_queues.empty()) {
-		r = rnd() % 2 != 0;
-
-		queue = bg_queue_create(bg->id, bg->required_players);
-
-		if (!r)
-			queue->teama_members.push_back(sd);
-		else
-			queue->teamb_members.push_back(sd);
-
-		sd->bg_queue = queue;
-		bg_queues.insert(bg_queues.begin(), queue);
-		return BG_APPLY_ACCEPT;
-	} else {
-		r = rnd() % 2 != 0;
-
-		for (const auto &it : bg_queues) {
-			try {
-				queue = it;
-			} catch (std::out_of_range &) {
-				continue;
-			}
-
-			if (queue->in_ready_state)
-				continue;
-			if (!r) {
-				if (queue->teama_members.size() != queue->required_players) {
-					sd->bg_queue = queue;
-					queue->teama_members.push_back(sd);
-
-					if (queue->teama_members.size() == bg->required_players && queue->teamb_members.size() == bg->required_players) // Enough players have joined
-						bg_queue_on_ready(name, queue);
-					return BG_APPLY_ACCEPT;
-				} else if (queue->teamb_members.size() != queue->required_players) {
-					sd->bg_queue = queue;
-					queue->teamb_members.push_back(sd);
-
-					if (queue->teama_members.size() == bg->required_players && queue->teamb_members.size() == bg->required_players) // Enough players have joined
-						bg_queue_on_ready(name, queue);
-					return BG_APPLY_ACCEPT;
-				}
-			} else {
-				if (queue->teamb_members.size() != queue->required_players) {
-					sd->bg_queue = queue;
-					queue->teamb_members.push_back(sd);
-
-					if (queue->teama_members.size() == bg->required_players && queue->teamb_members.size() == bg->required_players) // Enough players have joined
-						bg_queue_on_ready(name, queue);
-					return BG_APPLY_ACCEPT;
-				} else if (queue->teama_members.size() != queue->required_players) {
-					sd->bg_queue = queue;
-					queue->teama_members.push_back(sd);
-
-					if (queue->teama_members.size() == bg->required_players && queue->teamb_members.size() == bg->required_players) // Enough players have joined
-						bg_queue_on_ready(name, queue);
-					return BG_APPLY_ACCEPT;
-				}
-			}
-		}
-	}
-
-	queue = bg_queue_create(bg->id, bg->required_players);
-	r = rnd() % 2 != 0;
-
-	if (!r)
-		queue->teama_members.push_back(sd);
-	else
-		queue->teamb_members.push_back(sd);
-
-	sd->bg_queue = queue;
-	bg_queues.insert(bg_queues.begin(), queue);
-	return BG_APPLY_ACCEPT;
-}
-
 /**
  * Join a party onto the same side of a Battleground
  * @param name: Battleground name
  * @param sd: Player who requested to join the battlegrounds
- * @return @see e_bg_queue_apply_ack
  */
-e_bg_queue_apply_ack bg_queue_join_party(const char *name, struct map_session_data *sd)
+void bg_queue_join_party(const char *name, struct map_session_data *sd)
 {
 	struct party_data *p = party_search(sd->status.party_id);
 
-	if (!p)
-		return BG_APPLY_INVALID_APP; // Someone has bypassed the client check for being in a party
+	if (!p) {
+		clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
+		return; // Someone has bypassed the client check for being in a party
+	}
 
 	for (const auto &it : p->party.member) {
-		if (it.leader && sd->status.char_id != it.char_id)
-			return BG_APPLY_PARTYGUILD_LEADER; // Not the party leader
+		if (it.leader && sd->status.char_id != it.char_id) {
+			clif_bg_queue_apply_result(BG_APPLY_PARTYGUILD_LEADER, name, sd);
+			return; // Not the party leader
+		}
 	}
 
 	std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
@@ -954,8 +831,10 @@ e_bg_queue_apply_ack bg_queue_join_party(const char *name, struct map_session_da
 				p_online++;
 		}
 
-		if (p_online > bg->max_players)
-			return BG_APPLY_PLAYER_COUNT; // Too many party members online
+		if (p_online > bg->max_players) {
+			clif_bg_queue_apply_result(BG_APPLY_PLAYER_COUNT, name, sd);
+			return; // Too many party members online
+		}
 		
 		std::vector<struct map_session_data *> list;
 
@@ -971,10 +850,11 @@ e_bg_queue_apply_ack bg_queue_join_party(const char *name, struct map_session_da
 			}
 		}
 
-		return bg_queue_join_multi(name, sd, list); // Join as party, all on the same side of the BG
+		bg_queue_join_multi(name, sd, list); // Join as party, all on the same side of the BG
 	} else {
 		ShowWarning("clif_parse_bg_queue_apply_request: Could not find Battleground: \"%s\" requested by player: %s (AID:%d CID:%d)\n", name, sd->status.name, sd->status.account_id, sd->status.char_id);
-		return BG_APPLY_INVALID_NAME; // Invalid BG name
+		clif_bg_queue_apply_result(BG_APPLY_INVALID_NAME, name, sd);
+		return; // Invalid BG name
 	}
 }
 
@@ -982,30 +862,29 @@ e_bg_queue_apply_ack bg_queue_join_party(const char *name, struct map_session_da
  * Join a guild onto the same side of a Battleground
  * @param name: Battleground name
  * @param sd: Player who requested to join the battlegrounds
- * @return @see e_bg_queue_apply_ack
  */
-e_bg_queue_apply_ack bg_queue_join_guild(const char *name, struct map_session_data *sd)
+void bg_queue_join_guild(const char *name, struct map_session_data *sd)
 {
-	if (!sd->guild)
-		return BG_APPLY_INVALID_APP; // Someone has bypassed the client check for being in a guild
+	if (!sd->guild) {
+		clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
+		return; // Someone has bypassed the client check for being in a guild
+	}
 	
-	if (strcmp(sd->status.name, sd->guild->master) != 0)
-		return BG_APPLY_PARTYGUILD_LEADER; // Not the guild leader
+	if (strcmp(sd->status.name, sd->guild->master) != 0) {
+		clif_bg_queue_apply_result(BG_APPLY_PARTYGUILD_LEADER, name, sd);
+		return; // Not the guild leader
+	}
 
 	std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
 
 	if (bg) {
-		struct guild *g = guild_search(sd->status.guild_id);
-		int g_online = 0;
+		struct guild* g = sd->guild;
 
-		for (const auto &it : g->member) {
-			if (it.online)
-				g_online++;
+		if (g->connect_member > bg->max_players) {
+			clif_bg_queue_apply_result(BG_APPLY_PLAYER_COUNT, name, sd);
+			return; // Too many guild members online
 		}
 
-		if (g_online > bg->max_players)
-			return BG_APPLY_PLAYER_COUNT; // Too many guild members online
-
 		std::vector<struct map_session_data *> list;
 
 		for (const auto &it : g->member) {
@@ -1020,10 +899,11 @@ e_bg_queue_apply_ack bg_queue_join_guild(const char *name, struct map_session_da
 			}
 		}
 
-		return bg_queue_join_multi(name, sd, list); // Join as guild, all on the same side of the BG
+		bg_queue_join_multi(name, sd, list); // Join as guild, all on the same side of the BG
 	} else {
 		ShowWarning("clif_parse_bg_queue_apply_request: Could not find Battleground: \"%s\" requested by player: %s (AID:%d CID:%d)\n", name, sd->status.name, sd->status.account_id, sd->status.char_id);
-		return BG_APPLY_INVALID_NAME; // Invalid BG name
+		clif_bg_queue_apply_result(BG_APPLY_INVALID_NAME, name, sd);
+		return; // Invalid BG name
 	}
 }
 
@@ -1032,186 +912,102 @@ e_bg_queue_apply_ack bg_queue_join_guild(const char *name, struct map_session_da
  * @param name: Battleground name
  * @param sd: Player who requested to join the battlegrounds
  * @param list: Contains all players including the player who requested to join
- * @return @see e_bg_queue_apply_ack
  */
-e_bg_queue_apply_ack bg_queue_join_multi(const char *name, struct map_session_data *sd, std::vector <map_session_data *> list)
+void bg_queue_join_multi(const char *name, struct map_session_data *sd, std::vector <map_session_data *> list)
 {
 	if (!sd) {
 		ShowError("bg_queue_join_multi: Tried to join non-existent player\n.");
-		return BG_APPLY_NONE;
-	}
-
-	if (!bg_queue_check_status(sd, name))
-		return BG_APPLY_NONE;
-
-	if (bg_player_is_in_bg_map(sd)) {
-		clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You may not join a battleground queue when you're in a battleground map.
-		return BG_APPLY_NONE;
+		return;
 	}
 
 	std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
 
 	if (!bg) {
 		ShowWarning("bq_queue_join_multi: Could not find battleground \"%s\" requested by %s (AID: %d / CID: %d)\n", name, sd->status.name, sd->status.account_id, sd->status.char_id);
-		return BG_APPLY_INVALID_NAME;
+		return;
 	}
 
-	if (bg->min_lvl && sd->status.base_level < bg->min_lvl)
-		return BG_APPLY_PLAYER_LEVEL; // Level too low
-	
-	if (bg->max_lvl && sd->status.base_level > bg->max_lvl)
-		return BG_APPLY_PLAYER_LEVEL; // Level too high
-
-	if (bg_queues.empty()) {
-		std::shared_ptr<s_battleground_queue> queue = bg_queue_create(bg->id, bg->required_players);
-		bool r = rnd() % 2 != 0;
-
-		if (!r) {
-			while (!list.empty() && queue->teama_members.size() < bg->required_players) {
-				struct map_session_data *sd2 = list.back();
-
-				list.pop_back();
-
-				if (!sd2 || sd2->bg_queue)
-					continue;
-
-				if (!bg_queue_check_joinable(bg, sd2, name))
-					continue;
-
-				sd2->bg_queue = queue;
-				clif_bg_queue_apply_result(BG_APPLY_ACCEPT, name, sd2);
-				clif_bg_queue_apply_notify(name, sd2);
-				queue->teama_members.insert(queue->teama_members.begin(), sd2);
-			}
-		} else {
-			while (!list.empty() && queue->teamb_members.size() < bg->required_players) {
-				struct map_session_data *sd2 = list.back();
+	if (!bg_queue_check_joinable(bg, sd, name)){
+		return;
+	}
 
-				list.pop_back();
+	for (const auto &queue : bg_queues) {
+		if (queue->id != bg->id)
+			continue;
+		if (queue->in_ready_state)
+			continue;
 
-				if (!sd2 || sd2->bg_queue)
-					continue;
+		// Make sure there's enough space on one side to join as a party/guild in this queue
+		if (queue->teama_members.size() + list.size() > bg->required_players && queue->teamb_members.size() + list.size() > bg->required_players) {
+			break;
+		}
 
-				if (!bg_queue_check_joinable(bg, sd2, name))
-					continue;
+		bool r = rnd() % 2 != 0;
+		std::vector<map_session_data *>* team = r ? &queue->teamb_members : &queue->teama_members;
 
-				sd2->bg_queue = queue;
-				clif_bg_queue_apply_result(BG_APPLY_ACCEPT, name, sd2);
-				clif_bg_queue_apply_notify(name, sd2);
-				queue->teamb_members.insert(queue->teamb_members.begin(), sd2);
-			}
+		// If the designated team is full, put the player into the other team
+		if (team->size() + list.size() > bg->required_players) {
+			team = r ? &queue->teama_members : &queue->teamb_members;
 		}
 
-		bg_queues.insert(bg_queues.begin(), queue);
+		while (!list.empty() && team->size() < bg->required_players) {
+			struct map_session_data *sd2 = list.back();
 
-		return BG_APPLY_ACCEPT;
-	} else {
-		std::shared_ptr<s_battleground_queue> queue;
-		bool r = rnd() % 2 != 0;
+			list.pop_back();
 
-		for (const auto &it : bg_queues) {
-			try {
-				queue = it;
-			} catch (std::out_of_range &) {
+			if (!sd2 || sd2->bg_queue)
 				continue;
-			}
 
-			if (queue->in_ready_state)
+			if (!bg_queue_check_joinable(bg, sd2, name))
 				continue;
 
-			if (queue->teama_members.size() + list.size() <= bg->required_players || queue->teamb_members.size() + list.size() <= bg->required_players) { // Make sure there's enough space on one side to join as a party/guild in this queue
-				if (!r && queue->teama_members.size() + list.size() <= bg->required_players) {
-					while (!list.empty() && queue->teama_members.size() < bg->required_players) {
-						struct map_session_data *sd2 = list.back();
-
-						list.pop_back();
-
-						if (!sd2 || sd2->bg_queue)
-							continue;
-
-						if (!bg_queue_check_joinable(bg, sd2, name))
-							continue;
-
-						sd2->bg_queue = queue;
-						clif_bg_queue_apply_result(BG_APPLY_ACCEPT, name, sd2);
-						clif_bg_queue_apply_notify(name, sd2);
-						queue->teama_members.insert(queue->teama_members.begin(), sd2);
-					}
-
-					if (queue->teama_members.size() == bg->required_players && queue->teamb_members.size() == bg->required_players) // Enough players have joined
-						bg_queue_on_ready(name, queue);
-
-					return BG_APPLY_ACCEPT;
-				} else {
-					while (!list.empty() && queue->teamb_members.size() < bg->required_players) {
-						struct map_session_data *sd2 = list.back();
-
-						list.pop_back();
-
-						if (!sd2)
-							continue;
-
-						if (!bg_queue_check_joinable(bg, sd2, name))
-							continue;
-
-						sd2->bg_queue = queue;
-						clif_bg_queue_apply_result(BG_APPLY_ACCEPT, name, sd2);
-						clif_bg_queue_apply_notify(name, sd2);
-						queue->teamb_members.insert(queue->teamb_members.begin(), sd2);
-					}
-				}
-
-				return BG_APPLY_ACCEPT;
-			}
+			sd2->bg_queue = queue;
+			team->push_back(sd2);
+			clif_bg_queue_apply_result(BG_APPLY_ACCEPT, name, sd2);
+			clif_bg_queue_apply_notify(name, sd2);
 		}
 
-		// Create a new queue if none of the existing ones are joinable for this party/guild
-		queue = nullptr;
-		queue = bg_queue_create(bg->id, bg->required_players);
-		r = rnd() % 2 != 0;
-
-		if (!r) {
-			while (!list.empty() && queue->teama_members.size() < bg->required_players) {
-				struct map_session_data *sd2 = list.back();
-
-				list.pop_back();
+		// Enough players have joined
+		if (queue->teamb_members.size() == bg->required_players && queue->teama_members.size() == bg->required_players)
+			bg_queue_on_ready(name, queue);
 
-				if (!sd2 || sd2->bg_queue)
-					continue;
-
-				if (!bg_queue_check_joinable(bg, sd2, name))
-					continue;
-
-				sd2->bg_queue = queue;
-				clif_bg_queue_apply_result(BG_APPLY_ACCEPT, name, sd2);
-				clif_bg_queue_apply_notify(name, sd2);
-				queue->teama_members.insert(queue->teama_members.begin(), sd2);
-			}
-		} else {
-			while (!list.empty() && queue->teamb_members.size() < bg->required_players) {
-				struct map_session_data *sd2 = list.back();
-
-				list.pop_back();
+		return;
+	}
 
-				if (!sd2 || sd2->bg_queue)
-					continue;
+	// Something went wrong, sends reconnect and then reapply message to client.
+	clif_bg_queue_apply_result(BG_APPLY_RECONNECT, name, sd);
+}
 
-				if (!bg_queue_check_joinable(bg, sd2, name))
-					continue;
+/**
+ * Clear Battleground queue for next one
+ * @param queue: Queue to clean up
+ */
+static void bg_queue_clear(s_battleground_queue *queue)
+{
+	if (!queue)
+		return;
 
-				sd2->bg_queue = queue;
-				clif_bg_queue_apply_result(BG_APPLY_ACCEPT, name, sd2);
-				clif_bg_queue_apply_notify(name, sd2);
-				queue->teamb_members.insert(queue->teamb_members.begin(), sd2);
-			}
-		}
+	if (queue->tid_requeue != INVALID_TIMER) {
+		delete_timer(queue->tid_requeue, bg_on_ready_loopback);
+		queue->tid_requeue = INVALID_TIMER;
+	}
 
-		bg_queues.insert(bg_queues.begin(), queue);
+	if (queue->tid_expire != INVALID_TIMER) {
+		delete_timer(queue->tid_expire, bg_on_ready_expire);
+		queue->tid_expire = INVALID_TIMER;
+	}
 
-		return BG_APPLY_ACCEPT;
+	if (queue->tid_start != INVALID_TIMER) {
+		delete_timer(queue->tid_start, bg_on_ready_start);
+		queue->tid_start = INVALID_TIMER;
 	}
 
-	return BG_APPLY_RECONNECT; // Something went wrong, sends reconnect and then reapply message to client.
+	if (queue->map != nullptr) {
+		queue->map->isReserved = false; // Remove reservation to free up for future queue
+		queue->map = nullptr;
+	}
+	queue->in_ready_state = false;
+	queue->accepted_players = 0; // Reset the queue count
 }
 
 /**
@@ -1238,22 +1034,12 @@ static bool bg_queue_leave_sub(struct map_session_data *sd, std::vector<map_sess
 				sd->bg_queue_accept_state = false;
 			}
 
-			list_it = lista.erase(list_it);
+			lista.erase(list_it);
 
 			if (lista.empty() && listb.empty()) { // If there are no players left in the queue, discard it
-				auto queue_it = bg_queues.begin();
-
-				while (queue_it != bg_queues.end()) {
-					std::shared_ptr<s_battleground_queue> q = *queue_it;
-
-					if (sd->bg_queue == q) {
-						if (q->tid_requeue != INVALID_TIMER && get_timer(q->tid_requeue)) {
-							delete_timer(q->tid_requeue, bg_on_ready_loopback);
-							q->tid_requeue = INVALID_TIMER;
-						}
-
-						queue_it = bg_queues.erase(queue_it);
-					}
+				for (auto &queue : bg_queues) {
+					if (sd->bg_queue == queue)
+						bg_queue_clear(queue.get());
 				}
 			}
 
@@ -1349,7 +1135,7 @@ void bg_queue_on_accept_invite(std::shared_ptr<s_battleground_queue> queue, stru
 	if (queue->accepted_players == queue->required_players * 2) {
 		queue->tid_start = add_timer(gettick() + battleground_db.find(queue->id)->start_delay * 1000, bg_on_ready_start, 0, (intptr_t)queue.get());
 
-		if (queue->tid_expire != INVALID_TIMER && get_timer(queue->tid_expire)) {
+		if (queue->tid_expire != INVALID_TIMER) {
 			delete_timer(queue->tid_expire, bg_on_ready_expire);
 			queue->tid_expire = INVALID_TIMER;
 		}
@@ -1360,13 +1146,8 @@ void bg_queue_on_accept_invite(std::shared_ptr<s_battleground_queue> queue, stru
  * Begin the Battleground from the given queue
  * @param queue: Battleground queue
  */
-void bg_queue_start_battleground(std::shared_ptr<s_battleground_queue> queue)
+void bg_queue_start_battleground(s_battleground_queue *queue)
 {
-	if (queue->tid_start != INVALID_TIMER && get_timer(queue->tid_start)) {
-		delete_timer(queue->tid_start, bg_on_ready_start);
-		queue->tid_start = INVALID_TIMER;
-	}
-
 	std::shared_ptr<s_battleground_type> bg = battleground_db.find(queue->id);
 
 	if (!bg) {
@@ -1401,15 +1182,28 @@ void bg_queue_start_battleground(std::shared_ptr<s_battleground_queue> queue)
 	queue->teamb_members.clear();
 	queue->teama_members.shrink_to_fit();
 	queue->teamb_members.shrink_to_fit();
+	bg_queue_clear(queue);
+}
 
-	auto queue_it = bg_queues.begin();
+/**
+ * Initialize a Battleground queue
+ * @param bg_id: Battleground ID
+ * @param req_players: Required amount of players
+ * @return s_battleground_queue*
+ */
+static void bg_queue_create(int bg_id, int req_players)
+{
+	auto queue = std::make_shared<s_battleground_queue>();
 
-	while (queue_it != bg_queues.end()) {
-		if (*queue_it == queue)
-			queue_it = bg_queues.erase(queue_it);
-	}
+	queue->id = bg_id;
+	queue->required_players = req_players;
+	queue->accepted_players = 0;
+	queue->tid_expire = INVALID_TIMER;
+	queue->tid_start = INVALID_TIMER;
+	queue->tid_requeue = INVALID_TIMER;
+	queue->in_ready_state = false;
 
-	return;
+	bg_queues.push_back(queue);
 }
 
 /**
@@ -1417,9 +1211,13 @@ void bg_queue_start_battleground(std::shared_ptr<s_battleground_queue> queue)
  */
 void do_init_battleground(void)
 {
-	if (battle_config.feature_bgqueue)
+	if (battle_config.feature_bgqueue) {
 		battleground_db.load();
 
+		for (const auto &bg : battleground_db)
+			bg_queue_create(bg.first, bg.second->required_players);
+	}
+
 	add_timer_func_list(bg_send_xy_timer, "bg_send_xy_timer");
 	add_timer_func_list(bg_on_ready_loopback, "bg_on_ready_loopback");
 	add_timer_func_list(bg_on_ready_expire, "bg_on_ready_expire");

+ 4 - 6
src/map/battleground.hpp

@@ -126,15 +126,13 @@ int bg_team_leave(struct map_session_data *sd, bool quit, bool deserter);
 bool bg_team_warp(int bg_id, unsigned short mapindex, short x, short y);
 bool bg_player_is_in_bg_map(struct map_session_data *sd);
 bool bg_queue_check_joinable(std::shared_ptr<s_battleground_type> bg, struct map_session_data *sd, const char *name);
-std::shared_ptr<s_battleground_queue> bg_queue_create(int bg_id, int req_players);
-e_bg_queue_apply_ack bg_queue_join(const char *name, struct map_session_data *sd);
-e_bg_queue_apply_ack bg_queue_join_party(const char *name, struct map_session_data *sd);
-e_bg_queue_apply_ack bg_queue_join_guild(const char *name, struct map_session_data *sd);
-e_bg_queue_apply_ack bg_queue_join_multi(const char *name, struct map_session_data *sd, std::vector<map_session_data *> list);
+void bg_queue_join_party(const char *name, struct map_session_data *sd);
+void bg_queue_join_guild(const char *name, struct map_session_data *sd);
+void bg_queue_join_multi(const char *name, struct map_session_data *sd, std::vector<map_session_data *> list);
 bool bg_queue_leave(struct map_session_data *sd);
 bool bg_queue_on_ready(const char *name, std::shared_ptr<s_battleground_queue> queue);
 void bg_queue_on_accept_invite(std::shared_ptr<s_battleground_queue> queue, struct map_session_data *sd);
-void bg_queue_start_battleground(std::shared_ptr<s_battleground_queue> queue);
+void bg_queue_start_battleground(s_battleground_queue *queue);
 bool bg_member_respawn(struct map_session_data *sd);
 void bg_send_message(struct map_session_data *sd, const char *mes, int len);
 

+ 3 - 8
src/map/clif.cpp

@@ -17482,7 +17482,6 @@ void clif_parse_bg_queue_apply_request(int fd, struct map_session_data *sd)
 
 	short type = RFIFOW(fd,2);
 	char name[NAME_LENGTH];
-	e_bg_queue_apply_ack result;
 
 	safestrncpy(name, RFIFOCP(fd, 4), NAME_LENGTH);
 
@@ -17491,20 +17490,16 @@ void clif_parse_bg_queue_apply_request(int fd, struct map_session_data *sd)
 		clif_bg_queue_apply_result(BG_APPLY_DUPLICATE, name, sd); // Duplicate application warning
 		return;
 	} else if (type == 1) // Solo
-		result = bg_queue_join(name, sd);
+		bg_queue_join_multi(name, sd, { sd });
 	else if (type == 2) // Party
-		result = bg_queue_join_party(name, sd);
+		bg_queue_join_party(name, sd);
 	else if (type == 4) // Guild
-		result = bg_queue_join_guild(name, sd);
+		bg_queue_join_guild(name, sd);
 	else {
 		ShowWarning("clif_parse_bg_queue_apply_request: Received invalid queue type: %d from player %s (AID:%d CID:%d).\n", type, sd->status.name, sd->status.account_id, sd->status.char_id);
 		clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd); // Someone sent an invalid queue type packet
 		return;
 	}
-
-	clif_bg_queue_apply_result(result, name, sd);
-	if (result == BG_APPLY_ACCEPT)
-		clif_bg_queue_apply_notify(name, sd);
 }
 
 /// Outgoing battlegrounds queue apply result.