Duel allocation (#2734)

* Duels are now dynamically created and no longer statically consumes memory.
* Removed max number of duel at once.
* Updated duel modules for multi-thread and safer management.
* Remove various statically allocated tab.
* Removed duplicate code for npc_movenpc.
* Fix few warnings.
Thanks for suggestions from @anacondaqq.
This commit is contained in:
lighta 2017-12-27 19:39:45 -05:00 committed by Aleos
parent ae69e50626
commit 716f6c0f29
10 changed files with 174 additions and 124 deletions

View File

@ -5394,7 +5394,7 @@ ACMD_FUNC(skilloff)
*------------------------------------------*/
ACMD_FUNC(npcmove)
{
short x = 0, y = 0, m;
short x = 0, y = 0;
struct npc_data *nd = 0;
char npc_name[NPC_NAME_LENGTH];
@ -5412,18 +5412,12 @@ ACMD_FUNC(npcmove)
return -1;
}
if ((m=nd->bl.m) < 0 || nd->bl.prev == NULL)
{
if ( npc_movenpc( nd, x, y ) )
{ //actually failed to move
clif_displaymessage(fd, msg_txt(sd,1154)); // NPC is not on this map.
return -1; //Not on a map.
}
x = cap_value(x, 0, map[m].xs-1);
y = cap_value(y, 0, map[m].ys-1);
map_foreachinallrange(clif_outsight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl);
map_moveblock(&nd->bl, x, y, gettick());
map_foreachinallrange(clif_insight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl);
clif_displaymessage(fd, msg_txt(sd,1155)); // NPC moved.
} else
clif_displaymessage(fd, msg_txt(sd,1155)); // NPC moved
return 0;
}
@ -8307,14 +8301,12 @@ ACMD_FUNC(invite)
return -1;
}
if(did == 0) {
if(did == 0 || !duel_exist(did) ) {
clif_displaymessage(fd, msg_txt(sd,350)); // "Duel: @invite without @duel."
return 0;
}
if(duel_list[did].max_players_limit > 0 &&
duel_list[did].members_count >= duel_list[did].max_players_limit) {
if( !duel_check_player_limit( duel_get_duelid(did) ) ){
clif_displaymessage(fd, msg_txt(sd,351)); // "Duel: Limit of players is reached."
return 0;
}
@ -8426,12 +8418,12 @@ ACMD_FUNC(accept)
return 0;
}
if(sd->duel_invite <= 0) {
if(sd->duel_invite <= 0 || !duel_exist(sd->duel_invite) ) {
clif_displaymessage(fd, msg_txt(sd,360)); // "Duel: @accept without invititation."
return 0;
}
if( duel_list[sd->duel_invite].max_players_limit > 0 && duel_list[sd->duel_invite].members_count >= duel_list[sd->duel_invite].max_players_limit )
if( duel_check_player_limit( duel_get_duelid( sd->duel_invite ) ) )
{
clif_displaymessage(fd, msg_txt(sd,351)); // "Duel: Limit of players is reached."
return 0;

View File

@ -6177,19 +6177,16 @@ void clif_displaymessage(const int fd, const char* mes)
void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, enum send_target target)
{
int lp = (type&BC_COLOR_MASK) ? 4 : 0;
unsigned char *buf = (unsigned char*)aMalloc((4 + lp + len)*sizeof(unsigned char));
std::unique_ptr<unsigned char> buf(new unsigned char[4+lp+len]);
WBUFW(buf,0) = 0x9a;
WBUFW(buf,2) = 4 + lp + len;
WBUFW(buf.get(),0) = 0x9a;
WBUFW(buf.get(),2) = 4 + lp + len;
if (type&BC_BLUE)
WBUFL(buf,4) = 0x65756c62; //If there's "blue" at the beginning of the message, game client will display it in blue instead of yellow.
WBUFL(buf.get(),4) = 0x65756c62; //If there's "blue" at the beginning of the message, game client will display it in blue instead of yellow.
else if (type&BC_WOE)
WBUFL(buf,4) = 0x73737373; //If there's "ssss", game client will recognize message as 'WoE broadcast'.
memcpy(WBUFP(buf, 4 + lp), mes, len);
clif_send(buf, WBUFW(buf,2), bl, target);
if (buf)
aFree(buf);
WBUFL(buf.get(),4) = 0x73737373; //If there's "ssss", game client will recognize message as 'WoE broadcast'.
memcpy(WBUFP(buf.get(), 4 + lp), mes, len);
clif_send(buf.get(), WBUFW(buf.get(),2), bl, target);
}
/*==========================================
@ -6197,8 +6194,7 @@ void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, e
* 008d <PacketLength>.W <GID>.L <message>.?B (ZC_NOTIFY_CHAT)
*------------------------------------------*/
void clif_GlobalMessage(struct block_list* bl, const char* message, enum send_target target) {
char buf[8+CHAT_SIZE_MAX];
int len;
size_t len;
nullpo_retv(bl);
if(!message)
@ -6206,16 +6202,19 @@ void clif_GlobalMessage(struct block_list* bl, const char* message, enum send_ta
len = strlen(message)+1;
if( len > sizeof(buf)-8 ) {
static_assert(CHAT_SIZE_MAX > 8, "CHAT_SIZE_MAX too small for packet");
if( len > CHAT_SIZE_MAX ) {
ShowWarning("clif_GlobalMessage: Truncating too long message '%s' (len=%d).\n", message, len);
len = sizeof(buf)-8;
len = CHAT_SIZE_MAX;
}
std::unique_ptr<char> buf(new char[8+len]);
WBUFW(buf,0)=0x8d;
WBUFW(buf,2)=len+8;
WBUFL(buf,4)=bl->id;
safestrncpy(WBUFCP(buf,8),message,len);
clif_send((unsigned char *) buf,WBUFW(buf,2),bl,target);
WBUFW(buf.get(),0)=0x8d;
WBUFW(buf.get(),2)=static_cast<int>(len+8);
WBUFL(buf.get(),4)=bl->id;
safestrncpy(WBUFCP(buf.get(),8),message,len);
clif_send((unsigned char *)buf.get(),WBUFW(buf.get(),2),bl,target);
}
@ -6223,20 +6222,17 @@ void clif_GlobalMessage(struct block_list* bl, const char* message, enum send_ta
/// 01c3 <packet len>.W <fontColor>.L <fontType>.W <fontSize>.W <fontAlign>.W <fontY>.W <message>.?B
void clif_broadcast2(struct block_list* bl, const char* mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY, enum send_target target)
{
unsigned char *buf = (unsigned char*)aMalloc((16 + len)*sizeof(unsigned char));
std::unique_ptr<unsigned char> buf(new unsigned char[16+len]);
WBUFW(buf,0) = 0x1c3;
WBUFW(buf,2) = len + 16;
WBUFL(buf,4) = fontColor;
WBUFW(buf,8) = fontType;
WBUFW(buf,10) = fontSize;
WBUFW(buf,12) = fontAlign;
WBUFW(buf,14) = fontY;
memcpy(WBUFP(buf,16), mes, len);
clif_send(buf, WBUFW(buf,2), bl, target);
if (buf)
aFree(buf);
WBUFW(buf.get(),0) = 0x1c3;
WBUFW(buf.get(),2) = len + 16;
WBUFL(buf.get(),4) = fontColor;
WBUFW(buf.get(),8) = fontType;
WBUFW(buf.get(),10) = fontSize;
WBUFW(buf.get(),12) = fontAlign;
WBUFW(buf.get(),14) = fontY;
memcpy(WBUFP(buf.get(),16), mes, len);
clif_send(buf.get(), WBUFW(buf.get(),2), bl, target);
}
/*

View File

@ -6,6 +6,7 @@
#include <stdio.h>
#include <string.h>
#include <unordered_map>
#include "../common/cbasetypes.h"
#include "../common/timer.h"
@ -15,11 +16,34 @@
#include "pc.hpp"
#include "battle.hpp"
//global var (extern)
struct duel duel_list[MAX_DUEL]; //list of current duel
int duel_count = 0; //number of duel active
//std::recursive_mutex> duel_list_mutex; //preparation for multithread
std::unordered_map<size_t,struct duel> duel_list;
static void duel_set(const unsigned int did, struct map_session_data* sd);
std::unordered_map<size_t,struct duel> duel_get_list() { return duel_list; } //this could be exposed but not really necessarly, (hiden impl)
bool duel_exist( size_t did ) { return duel_list.find( did ) != duel_list.end(); }
duel& duel_get_duelid(size_t did) { return duel_list.at(did); }
/**
* Number of duels created
* @return duel_list size
*/
size_t duel_counttotal() {
return duel_list.size();
}
/**
* Number of active duels (player has accepted the duel)
* @return active duels
*/
size_t duel_countactives()
{
size_t count = 0;
for ( const auto& lcur : duel_list )
if ( lcur.second.members_count > 1 ) ++count;
return count;
}
static void duel_set(const size_t did, struct map_session_data* sd);
/*
* Save the current time of the duel in PC_LAST_DUEL_TIME
@ -38,7 +62,7 @@ void duel_savetime(struct map_session_data* sd)
/*
* Check if the time elapsed between last duel is enough to launch another.
*/
int duel_checktime(struct map_session_data* sd)
bool duel_checktime(struct map_session_data* sd)
{
int diff;
time_t timer;
@ -52,6 +76,18 @@ int duel_checktime(struct map_session_data* sd)
return !(diff >= 0 && diff < battle_config.duel_time_interval);
}
/*
* Check if duel respect the member limit
*/
bool duel_check_player_limit(struct duel& pDuel)
{
if(pDuel.max_players_limit > 0 &&
pDuel.members_count >= pDuel.max_players_limit) {
return false;
}
return true;
}
/*
* Display opponents name of sd
*/
@ -59,10 +95,11 @@ static int duel_showinfo_sub(struct map_session_data* sd, va_list va)
{
struct map_session_data *ssd = va_arg(va, struct map_session_data*);
int *p = va_arg(va, int*);
if (sd->duel_group != ssd->duel_group)
return 0;
char output[256];
if (sd->duel_group != ssd->duel_group) return 0;
sprintf(output, " %d. %s", ++(*p), sd->status.name);
clif_messagecolor(&ssd->bl, color_table[COLOR_LIGHT_GREEN], output, false, SELF);
return 1;
@ -72,20 +109,24 @@ static int duel_showinfo_sub(struct map_session_data* sd, va_list va)
* Display duel infos,
* Number of duely...
*/
void duel_showinfo(const unsigned int did, struct map_session_data* sd)
void duel_showinfo(const size_t did, struct map_session_data* sd)
{
//std::lock_guard<std::recursive_mutex> _(duel_list_mutex); //or shared_ptr
if ( !duel_exist( did ) )
return;
int p=0;
char output[256];
if(duel_list[did].max_players_limit > 0)
sprintf(output, msg_txt(sd,370), //" -- Duels: %d/%d, Members: %d/%d, Max players: %d --"
did, duel_count,
did, duel_counttotal(),
duel_list[did].members_count,
duel_list[did].members_count + duel_list[did].invites_count,
duel_list[did].max_players_limit);
else
sprintf(output, msg_txt(sd,371), //" -- Duels: %d/%d, Members: %d/%d --"
did, duel_count,
did, duel_counttotal(),
duel_list[did].members_count,
duel_list[did].members_count + duel_list[did].invites_count);
@ -96,7 +137,7 @@ void duel_showinfo(const unsigned int did, struct map_session_data* sd)
/*
* Moves sd to duel
*/
static void duel_set(const unsigned int did, struct map_session_data* sd) {
static void duel_set(const size_t did, struct map_session_data* sd) {
sd->state.changemap = 1;
sd->state.warping = 1;
@ -115,28 +156,27 @@ static void duel_set(const unsigned int did, struct map_session_data* sd) {
/*
* Create a new duel for sd
* return duel_id or 0 when fail
* return new duel_id or 0 when fail
*/
int duel_create(struct map_session_data* sd, const unsigned int maxpl)
size_t duel_create(struct map_session_data* sd, const unsigned int maxpl)
{
int i=1;
static size_t lastID=0;
lastID++;
{ //mutex scope
//std::lock_guard<std::recursive_mutex> _(duel_list_mutex);
duel_list[lastID].members_count++;
duel_list[lastID].invites_count = 0;
duel_list[lastID].max_players_limit = maxpl;
}
duel_set(lastID, sd);
char output[256];
while(duel_list[i].members_count > 0 && i < MAX_DUEL) i++;
if(i == MAX_DUEL) return 0;
duel_count++;
duel_set(i, sd);
duel_list[i].members_count++;
duel_list[i].invites_count = 0;
duel_list[i].max_players_limit = maxpl;
strcpy(output, msg_txt(sd,372)); // " -- Duel has been created (@invite/@leave) --"
clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], output, false, SELF);
clif_map_property(&sd->bl, MAPPROPERTY_FREEPVPZONE, SELF);
//clif_misceffect2(&sd->bl, 159);
return i;
return lastID;
}
/*
@ -145,20 +185,23 @@ int duel_create(struct map_session_data* sd, const unsigned int maxpl)
* @sd = inviting player
* @target_sd = invited player
*/
void duel_invite(const unsigned int did, struct map_session_data* sd, struct map_session_data* target_sd)
bool duel_invite(const size_t did, struct map_session_data* sd, struct map_session_data* target_sd)
{
char output[256];
// " -- Player %s invites %s to duel --"
sprintf(output, msg_txt(sd,373), sd->status.name, target_sd->status.name);
clif_disp_message(&sd->bl, output, strlen(output), DUEL_WOS);
//std::lock_guard<std::recursive_mutex> _(duel_list_mutex);
if ( !duel_exist( did ) )
return false;
target_sd->duel_invite = did;
duel_list[did].invites_count++;
char output[256];
// " -- Player %s invites %s to duel --"
sprintf(output, msg_txt(sd,373), sd->status.name, target_sd->status.name);
clif_disp_message(&sd->bl, output, strlen(output), DUEL_WOS);
// "Blue -- Player %s invites you to PVP duel (@accept/@reject) --"
sprintf(output, msg_txt(sd,374), sd->status.name);
clif_broadcast((struct block_list *)target_sd, output, strlen(output)+1, BC_BLUE, SELF);
return true;
}
/*
@ -168,7 +211,7 @@ void duel_invite(const unsigned int did, struct map_session_data* sd, struct map
*/
static int duel_leave_sub(struct map_session_data* sd, va_list va)
{
int did = va_arg(va, int);
size_t did = va_arg(va, size_t);
if (sd->duel_invite == did)
sd->duel_invite = 0;
return 0;
@ -179,24 +222,27 @@ static int duel_leave_sub(struct map_session_data* sd, va_list va)
* @did = duel id
* @sd = leaving player
*/
void duel_leave(const unsigned int did, struct map_session_data* sd)
bool duel_leave(const size_t did, struct map_session_data* sd)
{
char output[256];
// " <- Player %s has left duel --"
sprintf(output, msg_txt(sd,375), sd->status.name);
clif_disp_message(&sd->bl, output, strlen(output), DUEL_WOS);
//std::lock_guard<std::recursive_mutex> _(duel_list_mutex);
if ( !duel_exist( did ) )
return false;
duel_list[did].members_count--;
if(duel_list[did].members_count == 0) {
map_foreachpc(duel_leave_sub, did);
duel_count--;
duel_list.erase( did );
}
duel_set(0, sd);
duel_savetime(sd);
char output[256];
// " <- Player %s has left duel --"
sprintf(output, msg_txt(sd,375), sd->status.name);
clif_disp_message(&sd->bl, output, strlen(output), DUEL_WOS);
clif_map_property(&sd->bl, MAPPROPERTY_NOTHING, SELF);
return true;
}
/*
@ -204,21 +250,26 @@ void duel_leave(const unsigned int did, struct map_session_data* sd)
* @did = duel id
* @sd = player accepting duel
*/
void duel_accept(const unsigned int did, struct map_session_data* sd)
bool duel_accept(const size_t did, struct map_session_data* sd)
{
char output[256];
{ //mutex scope
//std::lock_guard<std::recursive_mutex> _(duel_list_mutex);
if ( !duel_exist( did ) )
return false;
duel_list[did].members_count++;
duel_set(sd->duel_invite, sd);
duel_list[did].invites_count--;
duel_list[did].members_count++;
duel_list[did].invites_count--;
}
duel_set( sd->duel_invite, sd );
sd->duel_invite = 0;
char output[256];
// " -> Player %s has accepted duel --"
sprintf(output, msg_txt(sd,376), sd->status.name);
clif_disp_message(&sd->bl, output, strlen(output), DUEL_WOS);
clif_map_property(&sd->bl, MAPPROPERTY_FREEPVPZONE, SELF);
//clif_misceffect2(&sd->bl, 159);
return true;
}
/*
@ -226,16 +277,22 @@ void duel_accept(const unsigned int did, struct map_session_data* sd)
* @did = duel id
* @sd = player refusing duel
*/
void duel_reject(const unsigned int did, struct map_session_data* sd)
bool duel_reject(const size_t did, struct map_session_data* sd)
{
char output[256];
{
//std::lock_guard<std::recursive_mutex> _(duel_list_mutex);
if ( !duel_exist( did ) )
return false;
duel_list[did].invites_count--;
sd->duel_invite = 0;
}
char output[256];
// " -- Player %s has rejected duel --"
sprintf(output, msg_txt(sd,377), sd->status.name);
clif_disp_message(&sd->bl, output, strlen(output), DUEL_WOS);
duel_list[did].invites_count--;
sd->duel_invite = 0;
return true;
}
/*
@ -244,11 +301,12 @@ void duel_reject(const unsigned int did, struct map_session_data* sd)
*/
void do_final_duel(void)
{
duel_list.clear();
}
/*
* Initialisator of duel module
*/
void do_init_duel(void) {
memset(&duel_list[0], 0, sizeof(duel_list));
duel_list.clear();
}

View File

@ -1,6 +1,6 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#pragma once
#ifndef _DUEL_HPP_
#define _DUEL_HPP_
@ -12,18 +12,20 @@ struct duel {
int max_players_limit;
};
#define MAX_DUEL 1024 //max number of duels on server
extern struct duel duel_list[MAX_DUEL]; //list of current duel
extern int duel_count; //current number of duel on server
duel& duel_get_duelid( size_t did );
bool duel_exist( size_t did );
size_t duel_counttotal();
size_t duel_countactives();
//Duel functions // [LuzZza]
int duel_create(struct map_session_data* sd, const unsigned int maxpl);
void duel_invite(const unsigned int did, struct map_session_data* sd, struct map_session_data* target_sd);
void duel_accept(const unsigned int did, struct map_session_data* sd);
void duel_reject(const unsigned int did, struct map_session_data* sd);
void duel_leave(const unsigned int did, struct map_session_data* sd);
void duel_showinfo(const unsigned int did, struct map_session_data* sd);
int duel_checktime(struct map_session_data* sd);
size_t duel_create(struct map_session_data* sd, const unsigned int maxpl);
bool duel_invite(const size_t did, struct map_session_data* sd, struct map_session_data* target_sd);
bool duel_accept(const size_t did, struct map_session_data* sd);
bool duel_reject(const size_t did, struct map_session_data* sd);
bool duel_leave(const size_t did, struct map_session_data* sd);
void duel_showinfo(const size_t did, struct map_session_data* sd);
bool duel_checktime(struct map_session_data* sd);
bool duel_check_player_limit( struct duel& pDuel );
void do_init_duel(void);
void do_final_duel(void);

View File

@ -2720,7 +2720,7 @@ int map_addmobtolist(unsigned short m, struct spawn_data *spawn)
if( i < MAX_MOB_LIST_PER_MAP )
{
map[m].moblist[i] = spawn;
return i;
return static_cast<int>(i);
}
return -1;
}

View File

@ -3595,10 +3595,11 @@ void npc_unsetcells(struct npc_data* nd)
map_foreachinallarea( npc_unsetcells_sub, m, x0, y0, x1, y1, BL_NPC, nd->bl.id );
}
void npc_movenpc(struct npc_data* nd, int16 x, int16 y)
bool npc_movenpc(struct npc_data* nd, int16 x, int16 y)
{
const int16 m = nd->bl.m;
if (m < 0 || nd->bl.prev == NULL) return; //Not on a map.
if (m < 0 || nd->bl.prev == NULL)
return false; //Not on a map.
x = cap_value(x, 0, map[m].xs-1);
y = cap_value(y, 0, map[m].ys-1);
@ -3606,6 +3607,7 @@ void npc_movenpc(struct npc_data* nd, int16 x, int16 y)
map_foreachinallrange(clif_outsight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl);
map_moveblock(&nd->bl, x, y, gettick());
map_foreachinallrange(clif_insight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl);
return true;
}
/// Changes the display name of the npc.

View File

@ -1138,7 +1138,7 @@ const char *npc_get_script_event_name(int npce_index);
void npc_setcells(struct npc_data* nd);
void npc_unsetcells(struct npc_data* nd);
void npc_movenpc(struct npc_data* nd, int16 x, int16 y);
bool npc_movenpc(struct npc_data* nd, int16 x, int16 y);
int npc_enable(const char* name, int flag);
void npc_setdisplayname(struct npc_data* nd, const char* newname);
void npc_setclass(struct npc_data* nd, short class_);

View File

@ -572,8 +572,8 @@ struct map_session_data {
char fakename[NAME_LENGTH]; // fake names [Valaris]
int duel_group; // duel vars [LuzZza]
int duel_invite;
size_t duel_group; // duel vars [LuzZza]
size_t duel_invite;
int killerrid, killedrid;

View File

@ -21520,8 +21520,8 @@ static void skill_readdb(void)
skill_changematerial_count = skill_spellbook_count = skill_magicmushroom_count = 0;
for(i=0; i<ARRAYLENGTH(dbsubpath); i++){
int n1 = strlen(db_path)+strlen(dbsubpath[i])+1;
int n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1;
size_t n1 = strlen(db_path)+strlen(dbsubpath[i])+1;
size_t n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1;
char* dbsubpath1 = (char*)aMalloc(n1+1);
char* dbsubpath2 = (char*)aMalloc(n2+1);

View File

@ -14521,8 +14521,8 @@ int status_readdb(void)
// read databases
// path,filename,separator,mincol,maxcol,maxrow,func_parsor
for(i=0; i<ARRAYLENGTH(dbsubpath); i++){
int n1 = strlen(db_path)+strlen(dbsubpath[i])+1;
int n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1;
size_t n1 = strlen(db_path)+strlen(dbsubpath[i])+1;
size_t n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1;
char* dbsubpath1 = (char*)aMalloc(n1+1);
char* dbsubpath2 = (char*)aMalloc(n2+1);