Add client->SendToGuildHall - have instances properly cycle out IDs

This commit is contained in:
Akkadius 2020-04-10 01:43:00 -05:00
parent 1728923bbb
commit 88ff56b2f2
12 changed files with 323 additions and 174 deletions

View File

@ -159,7 +159,7 @@ public:
uint16 GetInstanceID(const char* zone, uint32 charid, int16 version);
uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version);
uint16 GetInstanceVersion(uint16 instance_id);
uint32 GetTimeRemainingInstance(uint16 instance_id, bool &is_perma);
uint32 GetTimeRemainingInstance(uint16 instance_id, bool is_perma = false);
uint32 VersionFromInstanceID(uint16 instance_id);
uint32 ZoneIDFromInstanceID(uint16 instance_id);

View File

@ -101,14 +101,20 @@ bool Database::CheckInstanceExpired(uint16 instance_id)
int32 duration = 0;
uint32 never_expires = 0;
std::string query = StringFormat("SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u", instance_id);
std::string query = StringFormat(
"SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u",
instance_id
);
auto results = QueryDatabase(query);
if (!results.Success())
if (!results.Success()) {
return true;
}
if (results.RowCount() == 0)
if (results.RowCount() == 0) {
return true;
}
auto row = results.begin();
@ -116,23 +122,28 @@ bool Database::CheckInstanceExpired(uint16 instance_id)
duration = atoi(row[1]);
never_expires = atoi(row[2]);
if (never_expires == 1)
if (never_expires == 1) {
return false;
}
timeval tv;
timeval tv{};
gettimeofday(&tv, nullptr);
if ((start_time + duration) <= tv.tv_sec)
return true;
return (start_time + duration) <= tv.tv_sec;
return false;
}
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
{
std::string query = StringFormat("INSERT INTO instance_list (id, zone, version, start_time, duration)"
" values(%lu, %lu, %lu, UNIX_TIMESTAMP(), %lu)",
(unsigned long)instance_id, (unsigned long)zone_id, (unsigned long)version, (unsigned long)duration);
std::string query = StringFormat(
"INSERT INTO instance_list (id, zone, version, start_time, duration)"
" values (%u, %u, %u, UNIX_TIMESTAMP(), %u)",
instance_id,
zone_id,
version,
duration
);
auto results = QueryDatabase(query);
return results.Success();
@ -140,66 +151,79 @@ bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version
bool Database::GetUnusedInstanceID(uint16 &instance_id)
{
uint32 count = RuleI(Zone, ReservedInstances);
uint32 max = 65535;
uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances);
uint32 max = 32000;
std::string query = StringFormat(
"SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u",
max_reserved_instance_id,
max_reserved_instance_id
);
if (RuleB(Instances, RecycleInstanceIds)) {
query = (
SQL(
SELECT i.id + 1 AS next_available
FROM instance_list i
LEFT JOIN instance_list i2 ON i2.id = i.id + 1
WHERE i2.id IS NULL
ORDER BY i.id
LIMIT 0, 1;
)
);
}
std::string query = StringFormat("SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u", count, count);
auto results = QueryDatabase(query);
if (!results.Success())
{
if (!results.Success()) {
instance_id = 0;
return false;
}
if (results.RowCount() == 0)
{
instance_id = 0;
return false;
if (results.RowCount() == 0) {
instance_id = max_reserved_instance_id;
return true;
}
auto row = results.begin();
if (atoi(row[0]) <= max)
{
if (atoi(row[0]) <= max) {
instance_id = atoi(row[0]);
return true;
}
query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", count);
query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", max_reserved_instance_id);
results = QueryDatabase(query);
if (!results.Success())
{
if (!results.Success()) {
instance_id = 0;
return false;
}
if (results.RowCount() == 0)
{
if (results.RowCount() == 0) {
instance_id = 0;
return false;
}
count++;
for (auto row = results.begin(); row != results.end(); ++row)
{
if (count < atoi(row[0]))
{
instance_id = count;
max_reserved_instance_id++;
for (auto row = results.begin(); row != results.end(); ++row) {
if (max_reserved_instance_id < atoi(row[0])) {
instance_id = max_reserved_instance_id;
return true;
}
if (count > max)
{
if (max_reserved_instance_id > max) {
instance_id = 0;
return false;
}
count++;
max_reserved_instance_id++;
}
instance_id = count;
instance_id = max_reserved_instance_id;
return true;
}
@ -357,7 +381,7 @@ uint16 Database::GetInstanceVersion(uint16 instance_id) {
return atoi(row[0]);
}
uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool is_perma)
{
uint32 start_time = 0;
uint32 duration = 0;
@ -548,17 +572,36 @@ void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &ch
void Database::PurgeExpiredInstances()
{
std::string query("SELECT id FROM instance_list where (start_time+duration) <= UNIX_TIMESTAMP() and never_expires = 0");
/**
* Delay purging by a day so that we can continue using adjacent free instance id's
* from the table without risking the chance we immediately re-allocate a zone that freshly expired but
* has not been fully de-allocated
*/
std::string query =
SQL(
SELECT
id
FROM
instance_list
where
(start_time + duration) <= (UNIX_TIMESTAMP() + 86400)
and never_expires = 0
);
auto results = QueryDatabase(query);
if (!results.Success())
if (!results.Success()) {
return;
}
if (results.RowCount() == 0)
if (results.RowCount() == 0) {
return;
}
for (auto row = results.begin(); row != results.end(); ++row)
for (auto row = results.begin(); row != results.end(); ++row) {
DeleteInstance(atoi(row[0]));
}
}
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)

View File

@ -270,7 +270,6 @@ RULE_INT(Zone, PEQZoneDebuff1, 4454, "First debuff casted by #peqzone Default is
RULE_INT(Zone, PEQZoneDebuff2, 2209, "Second debuff casted by #peqzone Default is Tendrils of Apathy")
RULE_BOOL(Zone, UsePEQZoneDebuffs, true, "Will determine if #peqzone will debuff players or not when used")
RULE_REAL(Zone, HotZoneBonus, 0.75, "")
RULE_INT(Zone, ReservedInstances, 30, "Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running")
RULE_INT(Zone, EbonCrystalItemID, 40902, "")
RULE_INT(Zone, RadiantCrystalItemID, 40903, "")
RULE_BOOL(Zone, LevelBasedEXPMods, false, "Allows you to use the level_exp_mods table in consideration to your players EXP hits")
@ -775,6 +774,12 @@ RULE_BOOL(HotReload, QuestsRepopWhenPlayersNotInCombat, true, "When a hot reload
RULE_BOOL(HotReload, QuestsResetTimersWithReload, true, "When a hot reload is triggered, quest timers will be reset")
RULE_CATEGORY_END()
RULE_CATEGORY(Instances)
RULE_INT(Instances, ReservedInstances, 30, "Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running")
RULE_BOOL(Instances, RecycleInstanceIds, true, "Will recycle free instance ids instead of gradually running out at 32k")
RULE_INT(Instances, GuildHallExpirationDays, 90, "Amount of days before a Guild Hall instance expires")
RULE_CATEGORY_END()
#undef RULE_CATEGORY
#undef RULE_INT
#undef RULE_REAL

View File

@ -129,13 +129,17 @@ void Timer::SetTimer(uint32 set_timer_time) {
}
}
uint32 Timer::GetRemainingTime() const {
uint32 Timer::GetRemainingTime() const
{
if (enabled) {
if (current_time - start_time > timer_time)
if (current_time - start_time > timer_time) {
return 0;
else
}
else {
return (start_time + timer_time) - current_time;
} else {
}
}
else {
return 0xFFFFFFFF;
}
}

View File

@ -9292,3 +9292,41 @@ void Client::SetBotOption(BotOwnerOption boo, bool flag) {
}
#endif
void Client::SendToGuildHall()
{
std::string zone_short_name = "guildhall";
uint32 zone_id = database.GetZoneID(zone_short_name.c_str());
if (zone_id == 0) {
return;
}
uint32 expiration_time = (RuleI(Instances, GuildHallExpirationDays) * 86400);
uint16 instance_id = 0;
std::string guild_hall_instance_key = fmt::format("guild-hall-instance-{}", GuildID());
std::string instance_data = DataBucket::GetData(guild_hall_instance_key);
if (!instance_data.empty() && std::stoi(instance_data) > 0) {
instance_id = std::stoi(instance_data);
}
if (instance_id <= 0) {
if (!database.GetUnusedInstanceID(instance_id)) {
Message(Chat::Red, "Server was unable to find a free instance id.");
return;
}
if (!database.CreateInstance(instance_id, zone_id, 0, expiration_time)) {
Message(Chat::Red, "Server was unable to create a new instance.");
return;
}
DataBucket::SetData(
guild_hall_instance_key,
std::to_string(instance_id),
std::to_string(expiration_time)
);
}
AssignToInstance(instance_id);
MovePC(345, instance_id, -1.00, -1.00, 3.34, 0, 1);
}

View File

@ -633,6 +633,7 @@ public:
void MovePC(uint32 zoneID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited);
void MovePC(float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited);
void MovePC(uint32 zoneID, uint32 instanceID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited);
void SendToGuildHall();
void AssignToInstance(uint16 instance_id);
void RemoveFromInstance(uint16 instance_id);
void WhoAll();

View File

@ -818,35 +818,46 @@ void Client::CompleteConnect()
database.QueryDatabase(
StringFormat(
"UPDATE `character_data` SET `last_login` = UNIX_TIMESTAMP() WHERE id = %u",
this->CharacterID()
CharacterID()
)
);
}
if (zone) {
if (zone->GetInstanceTimer()) {
uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime();
uint32 day = (ttime / 86400000);
uint32 hour = (ttime / 3600000) % 24;
uint32 minute = (ttime / 60000) % 60;
uint32 second = (ttime / 1000) % 60;
if (zone && zone->GetInstanceID() > 0) {
uint32 remaining_time_seconds = zone->GetInstanceTimeRemaining();
uint32 day = (remaining_time_seconds / 86400);
uint32 hour = (remaining_time_seconds / 3600) % 24;
uint32 minute = (remaining_time_seconds / 60) % 60;
uint32 second = (remaining_time_seconds / 1) % 60;
LogInfo("Remaining time seconds [{}]", remaining_time_seconds);
if (day) {
Message(Chat::Yellow, "%s(%u) will expire in %u days, %u hours, %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), day, hour, minute, second);
Message(
Chat::Yellow, "%s (%u) will expire in %u days, %u hours, %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), day, hour, minute, second
);
}
else if (hour) {
Message(Chat::Yellow, "%s(%u) will expire in %u hours, %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), hour, minute, second);
Message(
Chat::Yellow, "%s (%u) will expire in %u hours, %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), hour, minute, second
);
}
else if (minute) {
Message(Chat::Yellow, "%s(%u) will expire in %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), minute, second);
Message(
Chat::Yellow, "%s (%u) will expire in %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), minute, second
);
}
else {
Message(Chat::Yellow, "%s(%u) will expire in in %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), second);
}
Message(
Chat::Yellow, "%s (%u) will expire in in %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), second
);
}
}
SendRewards();

View File

@ -90,6 +90,11 @@ void Lua_Client::SetPVP(bool v) {
self->SetPVP(v);
}
void Lua_Client::SendToGuildHall() {
Lua_Safe_Call_Void();
self->SendToGuildHall();
}
bool Lua_Client::GetPVP() {
Lua_Safe_Call_Bool();
return self->GetPVP();
@ -1584,6 +1589,7 @@ luabind::scope lua_register_client() {
.def("Disconnect", (void(Lua_Client::*)(void))&Lua_Client::Disconnect)
.def("IsLD", (bool(Lua_Client::*)(void))&Lua_Client::IsLD)
.def("WorldKick", (void(Lua_Client::*)(void))&Lua_Client::WorldKick)
.def("SendToGuildHall", (void(Lua_Client::*)(void))&Lua_Client::SendToGuildHall)
.def("GetAnon", (bool(Lua_Client::*)(void))&Lua_Client::GetAnon)
.def("Duck", (void(Lua_Client::*)(void))&Lua_Client::Duck)
.def("Stand", (void(Lua_Client::*)(void))&Lua_Client::Stand)

View File

@ -39,6 +39,7 @@ public:
void Disconnect();
bool IsLD();
void WorldKick();
void SendToGuildHall();
bool GetAnon();
void Duck();
void Stand();

View File

@ -245,6 +245,27 @@ XS(XS_Client_WorldKick) {
XSRETURN_EMPTY;
}
XS(XS_Client_SendToGuildHall); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_SendToGuildHall) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Client::SendToGuildHall(THIS)");
{
Client *THIS;
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
THIS = INT2PTR(Client *, tmp);
} else
Perl_croak(aTHX_ "THIS is not of type Client");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->SendToGuildHall();
}
XSRETURN_EMPTY;
}
XS(XS_Client_GetAnon); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_GetAnon) {
dXSARGS;
@ -6564,6 +6585,7 @@ XS(boot_Client) {
newXSproto(strcpy(buf, "SendSound"), XS_Client_SendSound, file, "$");
newXSproto(strcpy(buf, "SendSpellAnim"), XS_Client_SendSpellAnim, file, "$$$");
newXSproto(strcpy(buf, "SendTargetCommand"), XS_Client_SendTargetCommand, file, "$$");
newXSproto(strcpy(buf, "SendToGuildHall"), XS_Client_SendToGuildHall, file, "$");
newXSproto(strcpy(buf, "SendWebLink"), XS_Client_SendWebLink, file, "$:$");
newXSproto(strcpy(buf, "SendZoneFlagInfo"), XS_Client_SendZoneFlagInfo, file, "$$");
newXSproto(strcpy(buf, "SetAAPoints"), XS_Client_SetAAPoints, file, "$$");

View File

@ -1018,6 +1018,10 @@ bool Zone::Init(bool iStaticZone) {
petition_list.ClearPetitions();
petition_list.ReadDatabase();
if (zone->GetInstanceID() > 0) {
zone->SetInstanceTimeRemaining(database.GetTimeRemainingInstance(zone->GetInstanceID()));
}
LogInfo("Loading timezone data");
zone->zone_time.setEQTimeZone(database.GetZoneTZ(zoneid, GetInstanceVersion()));
@ -2455,3 +2459,13 @@ void Zone::SetQuestHotReloadQueued(bool in_quest_hot_reload_queued)
{
quest_hot_reload_queued = in_quest_hot_reload_queued;
}
uint32 Zone::GetInstanceTimeRemaining() const
{
return instance_time_remaining;
}
void Zone::SetInstanceTimeRemaining(uint32 instance_time_remaining)
{
Zone::instance_time_remaining = instance_time_remaining;
}

View File

@ -278,6 +278,9 @@ public:
ZonePoint *GetClosestZonePoint(const glm::vec3 &location, uint32 to, Client *client, float max_distance = 40000.0f);
ZonePoint *GetClosestZonePointWithoutZone(float x, float y, float z, Client *client, float max_distance = 40000.0f);
uint32 GetInstanceTimeRemaining() const;
void SetInstanceTimeRemaining(uint32 instance_time_remaining);
/**
* GMSay Callback for LogSys
*
@ -361,6 +364,7 @@ private:
uint8 zone_type;
uint16 instanceversion;
uint32 instanceid;
uint32 instance_time_remaining;
uint32 pgraveyard_id, pgraveyard_zoneid;
uint32 pMaxClients;
uint32 zoneid;