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);
@ -196,19 +196,19 @@ public:
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
void SetAgreementFlag(uint32 acctid);
int GetIPExemption(std::string account_ip);
int GetInstanceID(uint32 char_id, uint32 zone_id);
/* Groups */
char* GetGroupLeaderForLogin(const char* name,char* leaderbuf);
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
uint32 GetGroupID(const char* name);
void ClearGroup(uint32 gid = 0);
void ClearGroupLeader(uint32 gid = 0);
void SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ismerc = false);

View File

@ -97,42 +97,53 @@ bool Database::CheckInstanceExists(uint16 instance_id) {
bool Database::CheckInstanceExpired(uint16 instance_id)
{
int32 start_time = 0;
int32 duration = 0;
int32 start_time = 0;
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();
start_time = atoi(row[0]);
duration = atoi(row[1]);
start_time = atoi(row[0]);
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)
@ -566,4 +609,4 @@ void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
std::string query = StringFormat("UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), "
"duration=%u WHERE id=%u", new_duration, instance_id);
auto results = QueryDatabase(query);
}
}

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

@ -1918,7 +1918,7 @@ void Client::CheckManaEndUpdate() {
else if (group) {
group->SendEndurancePacketFrom(this);
}
auto endurance_packet = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct));
EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)endurance_packet->pBuffer;
endurance_update->cur_end = GetEndurance();
@ -8756,7 +8756,7 @@ void Client::CheckRegionTypeChanges()
// still same region, do nothing
if (last_region_type == new_region)
return;
// If we got out of water clear any water aggro for water only npcs
if (last_region_type == RegionTypeWater) {
entity_list.ClearWaterAggro(this);
@ -9203,7 +9203,7 @@ void Client::SetSecondaryWeaponOrnamentation(uint32 model_id)
secondary_item->SetOrnamentationIDFile(model_id);
SendItemPacket(EQEmu::invslot::slotSecondary, secondary_item, ItemPacketTrade);
WearChange(EQEmu::textures::weaponSecondary, static_cast<uint16>(model_id), 0);
Message(Chat::Yellow, "Your secondary weapon appearance has been modified");
}
}
@ -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();
@ -691,7 +692,7 @@ public:
int GetClientMaxLevel() const { return client_max_level; }
void SetClientMaxLevel(int max_level) { client_max_level = max_level; }
void CheckManaEndUpdate();
void SendManaUpdate();
void SendEnduranceUpdate();
@ -1293,7 +1294,7 @@ public:
void SendHPUpdateMarquee();
void CheckRegionTypeChanges();
WaterRegionType GetLastRegion() { return last_region_type; }
int32 CalcATK();
@ -1635,9 +1636,9 @@ private:
bool InterrogateInventory_error(int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, int depth);
int client_max_level;
#ifdef BOTS
public:
enum BotOwnerOption : size_t {
booDeathMarquee,
@ -1654,7 +1655,7 @@ public:
bool GetBotOption(BotOwnerOption boo) const;
void SetBotOption(BotOwnerOption boo, bool flag = true);
bool GetBotPulling() { return m_bot_pulling; }
void SetBotPulling(bool flag = true) { m_bot_pulling = flag; }

View File

@ -599,7 +599,7 @@ void Client::CompleteConnect()
if (group)
group->SendHPManaEndPacketsTo(this);
}
//bulk raid send in here eventually
@ -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 (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);
}
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);
}
else if (minute) {
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);
}
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
);
}
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
);
}
else if (minute) {
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
);
}
}
SendRewards();
@ -1237,7 +1248,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */
// set to full support in case they're a gm with items in disabled expansion slots..but, have their gm flag off...
// item loss will occur when they use the 'empty' slots, if this is not done
m_inv.SetGMInventory(true);
m_inv.SetGMInventory(true);
loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */
database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */
database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */
@ -1341,7 +1352,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
client_max_level = GetCharMaxLevelFromBucket();
}
SetClientMaxLevel(client_max_level);
// we know our class now, so we might have to fix our consume timer!
if (class_ == MONK)
consume_food_timer.SetTimer(CONSUMPTION_MNK_TIMER);
@ -2840,7 +2851,7 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app)
// rogue simply won't apply at all, no skill check done.
uint16 poison_skill = GetSkill(EQEmu::skills::SkillApplyPoison);
if (ChanceRoll < (.75 + poison_skill / 1000)) {
ApplyPoisonSuccessResult = 1;
AddProcToWeapon(poison->Proc.Effect, false, (GetDEX() / 100) + 103, POISON_PROC);
@ -3917,7 +3928,7 @@ void Client::Handle_OP_Bug(const EQApplicationPacket *app)
Message(0, "Bug reporting is disabled on this server.");
return;
}
if (app->size != sizeof(BugReport_Struct)) {
printf("Wrong size of BugReport_Struct got %d expected %zu!\n", app->size, sizeof(BugReport_Struct));
}
@ -4017,7 +4028,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
//Message(Chat::Red, "You cant cast right now, you arent in control of yourself!");
return;
}
// Hack for broken RoF2 which allows casting after a zoned IVU/IVA
if (invisible_undead || invisible_animals) {
BuffFadeByEffect(SE_InvisVsAnimals);
@ -4370,9 +4381,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
sizeof(PlayerPositionUpdateClient_Struct), app->size);
return;
}
PlayerPositionUpdateClient_Struct *ppu = (PlayerPositionUpdateClient_Struct *) app->pBuffer;
/* Boat handling */
if (ppu->spawn_id != GetID()) {
/* If player is controlling boat */
@ -4382,16 +4393,16 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
controlling_boat_id = 0;
return;
}
auto boat_delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
boat->SetDelta(boat_delta);
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
PlayerPositionUpdateServer_Struct *ppus = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
boat->MakeSpawnUpdate(ppus);
entity_list.QueueCloseClients(boat, outapp, true, 300, this, false);
safe_delete(outapp);
/* Update the boat's position on the server, without sending an update */
boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading), false);
return;
@ -4406,9 +4417,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
if (cmob != nullptr) {
cmob->SetPosition(ppu->x_pos, ppu->y_pos, ppu->z_pos);
cmob->SetHeading(EQ12toFloat(ppu->heading));
mMovementManager->SendCommandToClients(cmob, 0.0, 0.0, 0.0,
mMovementManager->SendCommandToClients(cmob, 0.0, 0.0, 0.0,
0.0, 0, ClientRangeAny, nullptr, this);
cmob->CastToNPC()->SaveGuardSpot(glm::vec4(ppu->x_pos,
cmob->CastToNPC()->SaveGuardSpot(glm::vec4(ppu->x_pos,
ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading)));
}
}
@ -4426,7 +4437,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
// From this point forward, we need to use a new set of variables for client
// position. If the client is in a boat, we need to add the boat pos and
// the client offset together.
float cx = ppu->x_pos;
float cy = ppu->y_pos;
float cz = ppu->z_pos;
@ -4451,45 +4462,45 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
/* Check to see if PPU should trigger an update to the rewind position. */
float rewind_x_diff = 0;
float rewind_y_diff = 0;
rewind_x_diff = cx - m_RewindLocation.x;
rewind_x_diff *= rewind_x_diff;
rewind_y_diff = cy - m_RewindLocation.y;
rewind_y_diff *= rewind_y_diff;
/*
/*
We only need to store updated values if the player has moved.
If the player has moved more than units for x or y, then we'll store
his pre-PPU x and y for /rewind, in case he gets stuck.
*/
if ((rewind_x_diff > 750) || (rewind_y_diff > 750))
m_RewindLocation = glm::vec3(m_Position);
/*
If the PPU was a large jump, such as a cross zone gate or Call of Hero,
just update rewind coordinates to the new ppu coordinates. This will prevent exploitation.
*/
if ((rewind_x_diff > 5000) || (rewind_y_diff > 5000))
m_RewindLocation = glm::vec3(cx, cy, cz);
if (proximity_timer.Check()) {
entity_list.ProcessMove(this, glm::vec3(cx, cy, cz));
if (RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem, EnableTaskProximity))
ProcessTaskProximities(cx, cy, cz);
m_Proximity = glm::vec3(cx, cy, cz);
}
/* Update internal state */
m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
if (IsTracking() && ((m_Position.x != cx) || (m_Position.y != cy))) {
if (zone->random.Real(0, 100) < 70)//should be good
CheckIncreaseSkill(EQEmu::skills::SkillTracking, nullptr, -20);
}
/* Break Hide if moving without sneaking and set rewind timer if moved */
if (cy != m_Position.y || cx != m_Position.x) {
if ((hidden || improved_hidden) && !sneaking) {
@ -4508,7 +4519,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
}
rewind_timer.Start(30000, true);
}
/* Handle client aggro scanning timers NPCs */
is_client_moving = (cy == m_Position.y && cx == m_Position.x) ? false : true;
@ -4572,55 +4583,55 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
}
int32 new_animation = ppu->animation;
/* Update internal server position from what the client has sent */
m_Position.x = cx;
m_Position.y = cy;
m_Position.z = cz;
/* Visual Debugging */
if (RuleB(Character, OPClientUpdateVisualDebug)) {
LogDebug("ClientUpdate: ppu x: [{}] y: [{}] z: [{}] h: [{}]", cx, cy, cz, new_heading);
this->SendAppearanceEffect(78, 0, 0, 0, 0);
this->SendAppearanceEffect(41, 0, 0, 0, 0);
}
/* Only feed real time updates when client is moving */
if (is_client_moving || new_heading != m_Position.w || new_animation != animation) {
animation = ppu->animation;
m_Position.w = new_heading;
/* Broadcast update to other clients */
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
MakeSpawnUpdate(position_update);
if (gm_hide_me) {
entity_list.QueueClientsStatus(this, outapp, true, Admin(), 255);
} else {
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true);
}
/* Always send position updates to group - send when beyond normal ClientPositionUpdate range */
Group *group = this->GetGroup();
Raid *raid = this->GetRaid();
if (raid) {
raid->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
} else if (group) {
group->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
}
safe_delete(outapp);
}
if (zone->watermap) {
if (zone->watermap->InLiquid(glm::vec3(m_Position))) {
CheckIncreaseSkill(EQEmu::skills::SkillSwimming, nullptr, -17);
// Dismount horses when entering water
if (GetHorseId() && RuleB(Character, DismountWater)) {
SetHorseId(0);
@ -5757,23 +5768,23 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
printf("Error in FindPersonRequest_Struct. Expected size of: %zu, but got: %i\n", sizeof(FindPersonRequest_Struct), app->size);
else {
FindPersonRequest_Struct* t = (FindPersonRequest_Struct*)app->pBuffer;
std::vector<FindPerson_Point> points;
Mob* target = entity_list.GetMob(t->npc_id);
if (target == nullptr) {
//empty length packet == not found.
EQApplicationPacket outapp(OP_FindPersonReply, 0);
QueuePacket(&outapp);
return;
}
if (!RuleB(Pathing, Find) && RuleB(Bazaar, EnableWarpToTrader) && target->IsClient() && (target->CastToClient()->Trader ||
target->CastToClient()->Buyer)) {
Message(Chat::Yellow, "Moving you to Trader %s", target->GetName());
MovePC(zone->GetZoneID(), zone->GetInstanceID(), target->GetX(), target->GetY(), target->GetZ(), 0.0f);
}
if (!RuleB(Pathing, Find) || !zone->pathing)
{
//fill in the path array...
@ -5796,40 +5807,40 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
{
glm::vec3 Start(GetX(), GetY(), GetZ() + (GetSize() < 6.0 ? 6 : GetSize()) * HEAD_POSITION);
glm::vec3 End(target->GetX(), target->GetY(), target->GetZ() + (target->GetSize() < 6.0 ? 6 : target->GetSize()) * HEAD_POSITION);
bool partial = false;
bool stuck = false;
auto pathlist = zone->pathing->FindRoute(Start, End, partial, stuck);
if (pathlist.empty() || partial)
{
EQApplicationPacket outapp(OP_FindPersonReply, 0);
QueuePacket(&outapp);
return;
}
// Live appears to send the points in this order:
// Final destination.
// Current Position.
// rest of the points.
FindPerson_Point p;
int PointNumber = 0;
bool LeadsToTeleporter = false;
auto v = pathlist.back();
p.x = v.pos.x;
p.y = v.pos.y;
p.z = v.pos.z;
points.push_back(p);
p.x = GetX();
p.y = GetY();
p.z = GetZ();
points.push_back(p);
for (auto Iterator = pathlist.begin(); Iterator != pathlist.end(); ++Iterator)
{
if ((*Iterator).teleport) // Teleporter
@ -5837,7 +5848,7 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
LeadsToTeleporter = true;
break;
}
glm::vec3 v = (*Iterator).pos;
p.x = v.x;
p.y = v.y;
@ -5845,17 +5856,17 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
points.push_back(p);
++PointNumber;
}
if (!LeadsToTeleporter)
{
p.x = target->GetX();
p.y = target->GetY();
p.z = target->GetZ();
points.push_back(p);
}
}
SendPathPacket(points);
}
}
@ -11098,14 +11109,14 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
{
case RaidCommandInviteIntoExisting:
case RaidCommandInvite: {
Client *player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name);
if (!player_to_invite)
break;
Group *player_to_invite_group = player_to_invite->GetGroup();
if (player_to_invite->HasRaid()) {
Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName());
break;
@ -11120,7 +11131,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid.");
break;
}
/* Send out invite to the client */
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
RaidGeneral_Struct *raid_command = (RaidGeneral_Struct*)outapp->pBuffer;
@ -11132,7 +11143,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid_command->action = 20;
player_to_invite->QueuePacket(outapp);
safe_delete(outapp);
break;
@ -11228,7 +11239,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
}
if (player_invited_group->IsLeader(player_invited_group->members[x])) {
Client *c = nullptr;
if (player_invited_group->members[x]->IsClient())
c = player_invited_group->members[x]->CastToClient();
else
@ -11238,24 +11249,24 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id, true, true, true);
raid->SendBulkRaid(c);
if (raid->IsLocked()) {
raid->SendRaidLockTo(c);
}
}
else {
Client *c = nullptr;
if (player_invited_group->members[x]->IsClient())
c = player_invited_group->members[x]->CastToClient();
else
continue;
raid->SendRaidCreate(c);
raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id);
raid->SendBulkRaid(c);
if (raid->IsLocked()) {
raid->SendRaidLockTo(c);
}
@ -11289,12 +11300,12 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
c = group->members[x]->CastToClient();
else
continue;
raid->SendRaidCreate(c);
raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id, false, true);
raid->SendBulkRaid(c);
if (raid->IsLocked()) {
raid->SendRaidLockTo(c);
}
@ -11302,17 +11313,17 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
else
{
Client *c = nullptr;
if (group->members[x]->IsClient())
c = group->members[x]->CastToClient();
else
continue;
raid->SendRaidCreate(c);
raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id);
raid->SendBulkRaid(c);
if (raid->IsLocked()) {
raid->SendRaidLockTo(c);
}
@ -11329,7 +11340,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
if (player_invited_group) {
raid = new Raid(player_accepting_invite);
entity_list.AddRaid(raid);
raid->SetRaidDetails();
Client *addClientig = nullptr;
@ -11353,7 +11364,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, 0, true, true, true);
raid->SendBulkRaid(c);
if (raid->IsLocked()) {
raid->SendRaidLockTo(c);
}
@ -11478,7 +11489,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SetGroupLeader(raid_command_packet->leader_name, false);
/* We were the leader of our old group */
if (old_group < 12) {
if (old_group < 12) {
/* Assign new group leader if we can */
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
if (raid->members[x].GroupNumber == old_group) {
@ -11507,7 +11518,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
strn0cpy(raid_command_packet->playername, raid->members[x].membername, 64);
worldserver.SendPacket(pack);
safe_delete(pack);
}
break;
@ -11553,7 +11564,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SetGroupLeader(raid_command_packet->leader_name, false);
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
if (raid->members[x].GroupNumber == oldgrp && strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid_command_packet->leader_name) != 0){
raid->SetGroupLeader(raid->members[x].membername);
raid->UpdateGroupAAs(oldgrp);
@ -11576,7 +11587,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
strn0cpy(raid_command->playername, raid->members[x].membername, 64);
raid_command->zoneid = zone->GetZoneID();
raid_command->instance_id = zone->GetInstanceID();
worldserver.SendPacket(pack);
safe_delete(pack);
}
@ -11591,14 +11602,14 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
else {
auto pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct));
ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
raid_command->rid = raid->GetID();
raid_command->zoneid = zone->GetZoneID();
raid_command->instance_id = zone->GetInstanceID();
strn0cpy(raid_command->playername, raid_command_packet->leader_name, 64);
worldserver.SendPacket(pack);
safe_delete(pack);
}

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;
@ -2439,7 +2460,7 @@ XS(XS_Client_MemmedCount) {
RETVAL = THIS->MemmedCount();
XSprePUSH;
PUSHu((UV) RETVAL);
PUSHu((UV) RETVAL);
}
XSRETURN(1);
}
@ -4786,7 +4807,7 @@ XS(XS_Client_AddLevelBasedExp) {
if (items > 2)
max_level = (uint8) SvUV(ST(2));
if (items > 3)
ignore_mods = (bool) SvTRUE(ST(3));
@ -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

@ -140,7 +140,7 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) {
if(iInstanceID != 0)
{
auto pack = new ServerPacket(ServerOP_AdventureZoneData, sizeof(uint16));
*((uint16*)pack->pBuffer) = iInstanceID;
*((uint16*)pack->pBuffer) = iInstanceID;
worldserver.SendPacket(pack);
delete pack;
}
@ -491,7 +491,7 @@ void Zone::LoadNewMerchantData(uint32 merchantid) {
void Zone::GetMerchantDataForZoneLoad() {
LogInfo("Loading Merchant Lists");
std::string query = StringFormat(
std::string query = StringFormat(
"SELECT "
"DISTINCT ml.merchantid, "
"ml.slot, "
@ -816,7 +816,7 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
{
LogDebug("Graveyard ID is [{}]", graveyard_id());
bool GraveYardLoaded = database.GetZoneGraveyard(graveyard_id(), &pgraveyard_zoneid, &m_Graveyard.x, &m_Graveyard.y, &m_Graveyard.z, &m_Graveyard.w);
if (GraveYardLoaded) {
LogDebug("Loaded a graveyard for zone [{}]: graveyard zoneid is [{}] at [{}]", short_name, graveyard_zoneid(), to_string(m_Graveyard).c_str());
}
@ -907,7 +907,7 @@ Zone::~Zone() {
//Modified for timezones.
bool Zone::Init(bool iStaticZone) {
SetStaticZone(iStaticZone);
//load the zone config file.
if (!LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion())) // try loading the zone name...
LoadZoneCFG(zone->GetFileName(), zone->GetInstanceVersion()); // if that fails, try the file name, then load defaults
@ -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()));
@ -1089,7 +1093,7 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_id)
if (instance_id != 0)
{
safe_delete_array(map_name);
if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, can_combat, can_levitate,
if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, can_combat, can_levitate,
can_castoutdoor, is_city, is_hotzone, allow_mercs, max_movement_update_range, zone_type, default_ruleset, &map_name))
{
LogError("Error loading the Zone Config");
@ -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;