Merge branch 'main' into guild_temp

This commit is contained in:
Aaron Kimbre
2023-11-27 17:39:39 -06:00
53 changed files with 757 additions and 301 deletions

View File

@@ -554,6 +554,12 @@ void Entity::Initialize() {
Loot::CacheMatrix(activityID);
}
const auto timeBeforeSmash = GetVar<float>(u"tmeSmsh");
if (timeBeforeSmash > 0) {
rebuildComponent->SetTimeBeforeSmash(timeBeforeSmash);
}
const auto compTime = GetVar<float>(u"compTime");
if (compTime > 0) {
@@ -1503,7 +1509,7 @@ void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u
destroyableComponent->Smash(source, killType, deathType);
}
void Entity::Kill(Entity* murderer) {
void Entity::Kill(Entity* murderer, const eKillType killType) {
if (!m_PlayerIsReadyForUpdates) return;
for (const auto& cb : m_DieCallbacks) {
@@ -1527,7 +1533,7 @@ void Entity::Kill(Entity* murderer) {
bool waitForDeathAnimation = false;
if (destroyableComponent) {
waitForDeathAnimation = destroyableComponent->GetDeathBehavior() == 0;
waitForDeathAnimation = destroyableComponent->GetDeathBehavior() == 0 && killType != eKillType::SILENT;
}
// Live waited a hard coded 12 seconds for death animations of type 0 before networking destruction!

View File

@@ -210,7 +210,7 @@ public:
void RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled);
void Smash(const LWOOBJID source = LWOOBJID_EMPTY, const eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"");
void Kill(Entity* murderer = nullptr);
void Kill(Entity* murderer = nullptr, const eKillType killType = eKillType::SILENT);
void AddRebuildCompleteCallback(const std::function<void(Entity* user)>& callback) const;
void AddCollisionPhantomCallback(const std::function<void(Entity* target)>& callback);
void AddDieCallback(const std::function<void()>& callback);

View File

@@ -207,7 +207,7 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
chars[i]->SaveXMLToDatabase();
chars[i]->GetEntity()->SetCharacter(nullptr);
delete chars[i];
}
@@ -275,60 +275,58 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
}
std::stringstream xml;
xml << "<obj v=\"1\"><mf hc=\"" << hairColor << "\" hs=\"" << hairStyle << "\" hd=\"0\" t=\"" << shirtColor << "\" l=\"" << pantsColor;
xml << "<obj v=\"1\">";
xml << "<mf hc=\"" << hairColor << "\" hs=\"" << hairStyle << "\" hd=\"0\" t=\"" << shirtColor << "\" l=\"" << pantsColor;
xml << "\" hdc=\"0\" cd=\"" << shirtStyle << "\" lh=\"" << lh << "\" rh=\"" << rh << "\" es=\"" << eyebrows << "\" ";
xml << "ess=\"" << eyes << "\" ms=\"" << mouth << "\"/>";
xml << "<char acct=\"" << u->GetAccountID() << "\" cc=\"0\" gm=\"0\" ft=\"0\" llog=\"" << time(NULL) << "\" ";
xml << "ls=\"0\" lzx=\"-626.5847\" lzy=\"613.3515\" lzz=\"-28.6374\" lzrx=\"0.0\" lzry=\"0.7015\" lzrz=\"0.0\" lzrw=\"0.7126\" ";
xml << "stt=\"0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;\"></char>";
xml << "<dest hm=\"4\" hc=\"4\" im=\"0\" ic=\"0\" am=\"0\" ac=\"0\" d=\"0\"/>";
xml << "<inv><bag><b t=\"0\" m=\"20\"/><b t=\"1\" m=\"40\"/><b t=\"2\" m=\"240\"/><b t=\"3\" m=\"240\"/><b t=\"14\" m=\"40\"/></bag><items><in t=\"0\">";
std::string xmlSave1 = xml.str();
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t idforshirt) {
std::stringstream xml2;
LWOOBJID lwoidforshirt = ObjectIDManager::GenerateRandomObjectID();
LWOOBJID lwoidforpants;
LWOOBJID lwoidforshirt = idforshirt;
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::CHARACTER);
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::PERSISTENT);
xml2 << xmlSave1 << "<i l=\"" << shirtLOT << "\" id=\"" << lwoidforshirt << "\" s=\"0\" c=\"1\" eq=\"1\" b=\"1\"/>";
do {
lwoidforpants = ObjectIDManager::GenerateRandomObjectID();
} while (lwoidforpants == lwoidforshirt); //Make sure we don't have the same ID for both shirt and pants
std::string xmlSave2 = xml2.str();
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::CHARACTER);
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::PERSISTENT);
GeneralUtils::SetBit(lwoidforpants, eObjectBits::CHARACTER);
GeneralUtils::SetBit(lwoidforpants, eObjectBits::PERSISTENT);
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t idforpants) {
LWOOBJID lwoidforpants = idforpants;
GeneralUtils::SetBit(lwoidforpants, eObjectBits::CHARACTER);
GeneralUtils::SetBit(lwoidforpants, eObjectBits::PERSISTENT);
xml << "<i l=\"" << shirtLOT << "\" id=\"" << lwoidforshirt << "\" s=\"0\" c=\"1\" eq=\"1\" b=\"1\"/>";
xml << "<i l=\"" << pantsLOT << "\" id=\"" << lwoidforpants << "\" s=\"1\" c=\"1\" eq=\"1\" b=\"1\"/>";
std::stringstream xml3;
xml3 << xmlSave2 << "<i l=\"" << pantsLOT << "\" id=\"" << lwoidforpants << "\" s=\"1\" c=\"1\" eq=\"1\" b=\"1\"/>";
xml << "</in></items></inv><lvl l=\"1\" cv=\"1\" sb=\"500\"/><flag></flag></obj>";
xml3 << "</in></items></inv><lvl l=\"1\" cv=\"1\" sb=\"500\"/><flag></flag></obj>";
//Check to see if our name was pre-approved:
bool nameOk = IsNamePreapproved(name);
if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
//Check to see if our name was pre-approved:
bool nameOk = IsNamePreapproved(name);
if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
std::string_view nameToAssign = !name.empty() && nameOk ? name : predefinedName;
std::string pendingName = !name.empty() && !nameOk ? name : "";
std::string_view nameToAssign = !name.empty() && nameOk ? name : predefinedName;
std::string pendingName = !name.empty() && !nameOk ? name : "";
ICharInfo::Info info;
info.name = nameToAssign;
info.pendingName = pendingName;
info.id = objectID;
info.accountId = u->GetAccountID();
ICharInfo::Info info;
info.name = nameToAssign;
info.pendingName = pendingName;
info.id = objectID;
info.accountId = u->GetAccountID();
Database::Get()->InsertNewCharacter(info);
Database::Get()->InsertNewCharacter(info);
//Now finally insert our character xml:
Database::Get()->InsertCharacterXml(objectID, xml.str());
//Now finally insert our character xml:
Database::Get()->InsertCharacterXml(objectID, xml3.str());
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::SUCCESS);
UserManager::RequestCharacterList(sysAddr);
});
});
});
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::SUCCESS);
UserManager::RequestCharacterList(sysAddr);
});
}
void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) {
@@ -466,16 +464,18 @@ void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID
uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
try {
std::string shirtQuery = "select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == \"character create shirt\" AND icc.color1 == ";
shirtQuery += std::to_string(shirtColor);
shirtQuery += " AND icc.decal == ";
shirtQuery = shirtQuery + std::to_string(shirtStyle);
auto tableData = CDClientDatabase::ExecuteQuery(shirtQuery);
auto shirtLOT = tableData.getIntField(0, -1);
auto stmt = CDClientDatabase::CreatePreppedStmt(
"select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ? AND icc.decal == ?"
);
stmt.bind(1, "character create shirt");
stmt.bind(2, static_cast<int>(shirtColor));
stmt.bind(3, static_cast<int>(shirtStyle));
auto tableData = stmt.execQuery();
auto shirtLOT = tableData.getIntField(0, 4069);
tableData.finalize();
return shirtLOT;
} catch (const std::exception&) {
LOG("Failed to execute query! Using backup...");
} catch (const std::exception& ex) {
LOG("Could not look up shirt %i %i: %s", shirtColor, shirtStyle, ex.what());
// in case of no shirt found in CDServer, return problematic red vest.
return 4069;
}
@@ -483,14 +483,17 @@ uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
uint32_t FindCharPantsID(uint32_t pantsColor) {
try {
std::string pantsQuery = "select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == \"cc pants\" AND icc.color1 == ";
pantsQuery += std::to_string(pantsColor);
auto tableData = CDClientDatabase::ExecuteQuery(pantsQuery);
auto pantsLOT = tableData.getIntField(0, -1);
auto stmt = CDClientDatabase::CreatePreppedStmt(
"select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ?"
);
stmt.bind(1, "cc pants");
stmt.bind(2, static_cast<int>(pantsColor));
auto tableData = stmt.execQuery();
auto pantsLOT = tableData.getIntField(0, 2508);
tableData.finalize();
return pantsLOT;
} catch (const std::exception&) {
LOG("Failed to execute query! Using backup...");
} catch (const std::exception& ex) {
LOG("Could not look up pants %i: %s", pantsColor, ex.what());
// in case of no pants color found in CDServer, return red pants.
return 2508;
}

View File

@@ -16,6 +16,10 @@
#include "Amf3.h"
#include "eGameMasterLevel.h"
#include "eGameActivity.h"
#include "User.h"
#include "Database.h"
#include "CDRewardCodesTable.h"
#include "Mail.h"
#include <ctime>
#include "Database.h"
#include "eObjectBits.h"
@@ -77,10 +81,14 @@ CharacterComponent::~CharacterComponent() {
void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
if (bIsInitialUpdate) {
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write(m_ClaimCodes[0] != 0);
if (m_ClaimCodes[0] != 0) outBitStream->Write(m_ClaimCodes[0]);
outBitStream->Write(m_ClaimCodes[1] != 0);
if (m_ClaimCodes[1] != 0) outBitStream->Write(m_ClaimCodes[1]);
outBitStream->Write(m_ClaimCodes[2] != 0);
if (m_ClaimCodes[2] != 0) outBitStream->Write(m_ClaimCodes[2]);
outBitStream->Write(m_ClaimCodes[3] != 0);
if (m_ClaimCodes[3] != 0) outBitStream->Write(m_ClaimCodes[3]);
outBitStream->Write(m_Character->GetHairColor());
outBitStream->Write(m_Character->GetHairStyle());
@@ -200,6 +208,13 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
SetReputation(0);
}
character->QueryUnsigned64Attribute("co", &m_ClaimCodes[0]);
character->QueryUnsigned64Attribute("co1", &m_ClaimCodes[1]);
character->QueryUnsigned64Attribute("co2", &m_ClaimCodes[2]);
character->QueryUnsigned64Attribute("co3", &m_ClaimCodes[3]);
AwardClaimCodes();
character->QueryInt64Attribute("ls", &m_Uscore);
// Load the statistics
@@ -324,6 +339,11 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
return;
}
if (m_ClaimCodes[0] != 0) character->SetAttribute("co", m_ClaimCodes[0]);
if (m_ClaimCodes[1] != 0) character->SetAttribute("co1", m_ClaimCodes[1]);
if (m_ClaimCodes[2] != 0) character->SetAttribute("co2", m_ClaimCodes[2]);
if (m_ClaimCodes[3] != 0) character->SetAttribute("co3", m_ClaimCodes[3]);
character->SetAttribute("ls", m_Uscore);
// Custom attribute to keep track of reputation.
character->SetAttribute("rpt", GetReputation());
@@ -760,4 +780,30 @@ void CharacterComponent::UpdateClientMinimap(bool showFaction, std::string ventu
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS, "SetFactionVisibility", arrayToSend);
}
void CharacterComponent::AwardClaimCodes() {
if (!m_Parent) return;
auto* user = m_Parent->GetParentUser();
if (!user) return;
auto rewardCodes = Database::Get()->GetRewardCodesByAccountID(user->GetAccountID());
if (rewardCodes.empty()) return;
auto* cdrewardCodes = CDClientManager::Instance().GetTable<CDRewardCodesTable>();
for (auto const rewardCode: rewardCodes){
LOG_DEBUG("Processing RewardCode %i", rewardCode);
const uint32_t rewardCodeIndex = rewardCode >> 6;
const uint32_t bitIndex = rewardCode % 64;
if (GeneralUtils::CheckBit(m_ClaimCodes[rewardCodeIndex], bitIndex)) continue;
m_ClaimCodes[rewardCodeIndex] = GeneralUtils::SetBit(m_ClaimCodes[rewardCodeIndex], bitIndex);
// Don't send it on this one since it's default and the mail doesn't make sense
if (rewardCode == 30) continue;
auto attachmentLOT = cdrewardCodes->GetAttachmentLOT(rewardCode);
std::ostringstream subject;
subject << "%[RewardCodes_" << rewardCode << "_subjectText]";
std::ostringstream body;
body << "%[RewardCodes_" << rewardCode << "_bodyText]";
Mail::SendMail(LWOOBJID_EMPTY, "%[MAIL_SYSTEM_NOTIFICATION]", m_Parent, subject.str(), body.str(), attachmentLOT, 1);
}
}

View File

@@ -10,6 +10,7 @@
#include "CDMissionsTable.h"
#include "tinyxml2.h"
#include "eReplicaComponentType.h"
#include <array>
enum class eGameActivity : uint32_t;
@@ -586,6 +587,10 @@ private:
LWOOBJID m_LastRocketItemID = LWOOBJID_EMPTY;
LWOOBJID m_CurrentInteracting = LWOOBJID_EMPTY;
std::array<uint64_t, 4> m_ClaimCodes{};
void AwardClaimCodes();
};
#endif // CHARACTERCOMPONENT_H

View File

@@ -796,7 +796,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
}
}
m_Parent->Kill(owner);
m_Parent->Kill(owner, killType);
}
void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) {

View File

@@ -402,10 +402,10 @@ void PhantomPhysicsComponent::SetDirection(const NiPoint3& pos) {
void PhantomPhysicsComponent::SpawnVertices() {
if (!m_dpEntity) return;
std::cout << m_Parent->GetObjectID() << std::endl;
LOG("%llu", m_Parent->GetObjectID());
auto box = static_cast<dpShapeBox*>(m_dpEntity->GetShape());
for (auto vert : box->GetVertices()) {
std::cout << vert.x << ", " << vert.y << ", " << vert.z << std::endl;
LOG("%f, %f, %f", vert.x, vert.y, vert.z);
EntityInfo info;
info.lot = 33;

View File

@@ -51,7 +51,7 @@ RacingControlComponent::RacingControlComponent(Entity* parent)
m_MainWorld = 1200;
const auto worldID = Game::server->GetZoneID();
if (Game::zoneManager->CheckIfAccessibleZone((worldID/10)*10)) m_MainWorld = (worldID/10)*10;
if (Game::zoneManager->CheckIfAccessibleZone((worldID / 10) * 10)) m_MainWorld = (worldID / 10) * 10;
m_ActivityID = 42;
CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
@@ -72,7 +72,7 @@ void RacingControlComponent::OnPlayerLoaded(Entity* player) {
// If the race has already started, send the player back to the main world.
if (m_Loaded || !vehicle) {
auto* playerInstance = dynamic_cast<Player*>(player);
if(playerInstance){
if (playerInstance) {
playerInstance->SendToZone(m_MainWorld);
}
return;
@@ -106,12 +106,12 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
if (item == nullptr) {
LOG("Failed to find item");
auto* playerInstance = dynamic_cast<Player*>(player);
if(playerInstance){
if (playerInstance) {
m_LoadedPlayers--;
playerInstance->SendToZone(m_MainWorld);
}
return;
}
// Calculate the vehicle's starting position.
@@ -213,6 +213,7 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
0,
0,
0 });
m_AllPlayersReady = false;
}
// Construct and serialize everything when done.
@@ -330,7 +331,7 @@ void RacingControlComponent::OnRequestDie(Entity* player) {
// Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live.
if (destroyableComponent) destroyableComponent->SetImagination(respawnImagination);
Game::entityManager->SerializeEntity(vehicle);
});
});
auto* characterComponent = player->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) {
@@ -384,11 +385,11 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player, int32_t bu
// Calculate the score, different loot depending on player count
auto playersRating = m_LoadedPlayers;
if(m_LoadedPlayers == 1 && m_SoloRacing) {
if (m_LoadedPlayers == 1 && m_SoloRacing) {
playersRating *= 2;
}
const auto score = playersRating * 10 + data->finished;
const auto score = playersRating * 10 + data->finished;
Loot::GiveActivityLoot(player, m_Parent, m_ActivityID, score);
// Giving rewards
@@ -436,64 +437,82 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player, int32_t bu
void RacingControlComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
// BEGIN Scripted Activity
outBitStream->Write1();
outBitStream->Write(static_cast<uint32_t>(m_RacingPlayers.size()));
for (const auto& player : m_RacingPlayers) {
outBitStream->Write(player.playerID);
for (int i = 0; i < 10; i++) {
outBitStream->Write(player.data[i]);
}
outBitStream->Write(player.data[0]);
if (player.finished != 0) outBitStream->Write<float>(player.raceTime);
else outBitStream->Write(player.data[1]);
if (player.finished != 0) outBitStream->Write<float>(player.bestLapTime);
else outBitStream->Write(player.data[2]);
if (player.finished == 1) outBitStream->Write<float>(1.0f);
else outBitStream->Write(player.data[3]);
outBitStream->Write(player.data[4]);
outBitStream->Write(player.data[5]);
outBitStream->Write(player.data[6]);
outBitStream->Write(player.data[7]);
outBitStream->Write(player.data[8]);
outBitStream->Write(player.data[9]);
}
// END Scripted Activity
outBitStream->Write1(); // Dirty?
outBitStream->Write1();
outBitStream->Write(static_cast<uint16_t>(m_RacingPlayers.size()));
outBitStream->Write(!m_RacingPlayers.empty());
if (!m_RacingPlayers.empty()) {
outBitStream->Write(!m_AllPlayersReady);
if (!m_AllPlayersReady) {
int32_t numReady = 0;
for (const auto& player : m_RacingPlayers) {
outBitStream->Write1(); // Has more date
outBitStream->Write1(); // Has more player data
outBitStream->Write(player.playerID);
outBitStream->Write(player.vehicleID);
outBitStream->Write(player.playerIndex);
outBitStream->Write(player.playerLoaded);
if (player.playerLoaded) numReady++;
}
outBitStream->Write0(); // No more data
if (numReady == m_RacingPlayers.size()) m_AllPlayersReady = true;
}
outBitStream->Write(!m_RacingPlayers.empty());
if (!m_RacingPlayers.empty()) {
for (const auto& player : m_RacingPlayers) {
if (player.finished == 0) continue;
outBitStream->Write1(); // Has more date
outBitStream->Write(player.playerID);
outBitStream->Write<uint32_t>(0);
outBitStream->Write(player.finished);
}
outBitStream->Write0(); // No more data
}
outBitStream->Write1(); // Dirty?
outBitStream->Write(m_RemainingLaps);
outBitStream->Write(static_cast<uint16_t>(m_PathName.size()));
for (const auto character : m_PathName) {
outBitStream->Write(character);
outBitStream->Write(bIsInitialUpdate);
if (bIsInitialUpdate) {
outBitStream->Write(m_RemainingLaps);
outBitStream->Write(static_cast<uint16_t>(m_PathName.size()));
for (const auto character : m_PathName) {
outBitStream->Write(character);
}
}
outBitStream->Write1(); // ???
outBitStream->Write1(); // ???
outBitStream->Write(!m_RacingPlayers.empty());
if (!m_RacingPlayers.empty()) {
for (const auto& player : m_RacingPlayers) {
if (player.finished == 0) continue;
outBitStream->Write1(); // Has more data
outBitStream->Write(player.playerID);
outBitStream->Write<float>(player.bestLapTime);
outBitStream->Write<float>(player.raceTime);
}
outBitStream->Write(m_LeadingPlayer);
outBitStream->Write(m_RaceBestLap);
outBitStream->Write(m_RaceBestTime);
outBitStream->Write0(); // No more data
}
}
RacingPlayerInfo* RacingControlComponent::GetPlayerData(LWOOBJID playerID) {
@@ -569,7 +588,7 @@ void RacingControlComponent::Update(float deltaTime) {
LoadPlayerVehicle(player, positionNumber + 1, true);
m_Loaded = true;
Game::entityManager->SerializeEntity(m_Parent);
}
m_Loaded = true;
@@ -757,6 +776,8 @@ void RacingControlComponent::Update(float deltaTime) {
continue;
}
if (m_Finished != 0) Game::entityManager->SerializeEntity(m_Parent);
// Loop through all the waypoints and see if the player has reached a
// new checkpoint
uint32_t respawnIndex = 0;
@@ -849,8 +870,6 @@ void RacingControlComponent::Update(float deltaTime) {
if (characterComponent != nullptr) {
characterComponent->TrackRaceCompleted(m_Finished == 1);
}
// TODO: Figure out how to update the GUI leaderboard.
}
}
@@ -865,28 +884,3 @@ void RacingControlComponent::Update(float deltaTime) {
}
}
}
std::string RacingControlComponent::FormatTimeString(time_t time) {
int32_t min = time / 60;
time -= min * 60;
int32_t sec = time;
std::string minText;
std::string secText;
if (min <= 0) {
minText = "0";
} else {
minText = std::to_string(min);
}
if (sec <= 0) {
secText = "00";
} else if (sec <= 9) {
secText = "0" + std::to_string(sec);
} else {
secText = std::to_string(sec);
}
return minText + ":" + secText + ".00";
}

View File

@@ -151,13 +151,6 @@ public:
*/
RacingPlayerInfo* GetPlayerData(LWOOBJID playerID);
/**
* Formats a time to a string, currently unused
* @param time the time to format
* @return the time formatted as string
*/
static std::string FormatTimeString(time_t time);
private:
/**
@@ -251,4 +244,5 @@ private:
* Value for message box response to know if we are exiting the race via the activity dialogue
*/
const int32_t m_ActivityExitConfirm = 1;
bool m_AllPlayersReady = false;
};

View File

@@ -6,6 +6,13 @@
#include "eReplicaComponentType.h"
struct RemoteInputInfo {
RemoteInputInfo() {
m_RemoteInputX = 0;
m_RemoteInputY = 0;
m_IsPowersliding = false;
m_IsModified = false;
}
void operator=(const RemoteInputInfo& other) {
m_RemoteInputX = other.m_RemoteInputX;
m_RemoteInputY = other.m_RemoteInputY;

View File

@@ -34,6 +34,8 @@
#include "eMissionTaskType.h"
#include "eReplicaComponentType.h"
#include "eConnectionType.h"
#include "ePlayerFlag.h"
#include "dConfig.h"
using namespace std;
@@ -173,6 +175,13 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
GameMessages::SendPlayerReady(entity, sysAddr);
GameMessages::SendPlayerReady(Game::zoneManager->GetZoneControlObject(), sysAddr);
if (Game::config->GetValue("allow_players_to_skip_cinematics") != "1"
|| !entity->GetCharacter()
|| !entity->GetCharacter()->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS)) return;
entity->AddCallbackTimer(0.5f, [entity, sysAddr]() {
if (!entity) return;
GameMessages::SendEndCinematic(entity->GetObjectID(), u"", sysAddr);
});
break;
}
@@ -244,13 +253,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
case eGameMessageType::REQUEST_RESURRECT: {
GameMessages::SendResurrect(entity);
/*auto* dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE));
if (dest) {
dest->SetHealth(4);
dest->SetArmor(0);
dest->SetImagination(6);
Game::entityManager->SerializeEntity(entity);
}*/
break;
}
case eGameMessageType::GET_HOT_PROPERTY_DATA: {
@@ -339,11 +341,8 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
RakNet::BitStream bitStreamLocal;
BitStreamUtils::WriteHeader(bitStreamLocal, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
bitStreamLocal.Write(entity->GetObjectID());
//bitStreamLocal.Write((unsigned short)eGameMessageType::ECHO_SYNC_SKILL);
//bitStreamLocal.Write(inStream);
SyncSkill sync = SyncSkill(inStream); // inStream replaced &bitStream
//sync.Serialize(&bitStreamLocal);
ostringstream buffer;
@@ -353,8 +352,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
buffer << setw(2) << hex << setfill('0') << (int)s << " ";
}
//cout << buffer.str() << endl;
if (usr != nullptr) {
RakNet::BitStream* bs = new RakNet::BitStream((unsigned char*)sync.sBitStream.c_str(), sync.sBitStream.size(), false);

View File

@@ -43,6 +43,7 @@
#include "eControlScheme.h"
#include "eStateChangeType.h"
#include "eConnectionType.h"
#include "ePlayerFlag.h"
#include <sstream>
#include <future>
@@ -943,14 +944,7 @@ void GameMessages::SendResurrect(Entity* entity) {
destroyableComponent->SetImagination(imaginationToRestore);
}
}
});
auto cont = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS));
if (cont && entity->GetLOT() == 1) {
cont->SetPosition(entity->GetRespawnPosition());
cont->SetRotation(entity->GetRespawnRotation());
}
});
CBITSTREAM;
CMSGHEADER;
@@ -1143,18 +1137,16 @@ void GameMessages::SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPo
bitStream.Write(position.y);
bitStream.Write(position.z);
auto con = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS));
if (con) {
auto rot = con->GetRotation();
bitStream.Write(rot.x);
bitStream.Write(rot.y);
bitStream.Write(rot.z);
bitStream.Write(rot.w);
const bool isNotIdentity = rotation != NiQuaternion::IDENTITY;
bitStream.Write(isNotIdentity);
if (isNotIdentity) {
bitStream.Write(rotation.w);
bitStream.Write(rotation.x);
bitStream.Write(rotation.y);
bitStream.Write(rotation.z);
}
//bitStream.Write(position);
//bitStream.Write(rotation);
SystemAddress sysAddr = entity->GetSystemAddress();
SEND_PACKET;
}
@@ -5027,6 +5019,14 @@ void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity)
if (emoteID == 0) return;
std::string sAnimationName = "deaded"; //Default name in case we fail to get the emote
CDEmoteTableTable* emotes = CDClientManager::Instance().GetTable<CDEmoteTableTable>();
if (emotes) {
CDEmoteTable* emote = emotes->GetEmote(emoteID);
if (emote) sAnimationName = emote->animationName;
}
RenderComponent::PlayAnimation(entity, sAnimationName);
MissionComponent* missionComponent = entity->GetComponent<MissionComponent>();
if (!missionComponent) return;
@@ -5052,14 +5052,6 @@ void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity)
missionComponent->Progress(eMissionTaskType::EMOTE, emoteID, scripted->GetObjectID());
}
}
CDEmoteTableTable* emotes = CDClientManager::Instance().GetTable<CDEmoteTableTable>();
if (emotes) {
CDEmoteTable* emote = emotes->GetEmote(emoteID);
if (emote) sAnimationName = emote->animationName;
}
RenderComponent::PlayAnimation(entity, sAnimationName);
}
void GameMessages::HandleModularBuildConvertModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
@@ -5172,6 +5164,14 @@ void GameMessages::HandleMissionDialogOK(RakNet::BitStream* inStream, Entity* en
} else if (iMissionState == eMissionState::READY_TO_COMPLETE || iMissionState == eMissionState::COMPLETE_READY_TO_COMPLETE) {
missionComponent->CompleteMission(missionID);
}
if (Game::config->GetValue("allow_players_to_skip_cinematics") != "1"
|| !player->GetCharacter()
|| !player->GetCharacter()->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS)) return;
player->AddCallbackTimer(0.5f, [player]() {
if (!player) return;
GameMessages::SendEndCinematic(player->GetObjectID(), u"", player->GetSystemAddress());
});
}
void GameMessages::HandleRequestLinkedMission(RakNet::BitStream* inStream, Entity* entity) {

View File

@@ -83,8 +83,10 @@
#include "eChatInternalMessageType.h"
#include "eMasterMessageType.h"
#include "CDRewardCodesTable.h"
#include "CDObjectsTable.h"
#include "CDZoneTableTable.h"
#include "ePlayerFlag.h"
void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr) {
auto commandCopy = command;
@@ -171,6 +173,21 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
return;
}
if (chatCommand == "toggleskipcinematics" && (Game::config->GetValue("allow_players_to_skip_cinematics") == "1" || entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER)) {
auto* character = entity->GetCharacter();
if (!character) return;
bool current = character->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS);
character->SetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS, !current);
if (!current) {
ChatPackets::SendSystemMessage(sysAddr, u"You have elected to skip cinematics. Note that not all cinematics can be skipped, but most will be skipped now.");
} else {
ChatPackets::SendSystemMessage(sysAddr, u"Cinematics will no longer be skipped.");
}
return;
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//HANDLE ALL NON GM SLASH COMMANDS RIGHT HERE!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -1372,7 +1389,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(position.x)) + u", " + (GeneralUtils::to_u16string(position.y)) + u", " + (GeneralUtils::to_u16string(position.z)) + u">");
std::cout << position.x << ", " << position.y << ", " << position.z << std::endl;
LOG("Position: %f, %f, %f", position.x, position.y, position.z);
}
if (chatCommand == "rot" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
@@ -1380,14 +1397,14 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(rotation.w)) + u", " + (GeneralUtils::to_u16string(rotation.x)) + u", " + (GeneralUtils::to_u16string(rotation.y)) + u", " + (GeneralUtils::to_u16string(rotation.z)) + u">");
std::cout << rotation.w << ", " << rotation.x << ", " << rotation.y << ", " << rotation.z << std::endl;
LOG("Rotation: %f, %f, %f, %f", rotation.w, rotation.x, rotation.y, rotation.z);
}
if (chatCommand == "locrow" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
const auto position = entity->GetPosition();
const auto rotation = entity->GetRotation();
std::cout << "<location x=\"" << position.x << "\" y=\"" << position.y << "\" z=\"" << position.z << "\" rw=\"" << rotation.w << "\" rx=\"" << rotation.x << "\" ry=\"" << rotation.y << "\" rz=\"" << rotation.z << "\" />" << std::endl;
LOG("<location x=\"%f\" y=\"%f\" z=\"%f\" rw=\"%f\" rx=\"%f\" ry=\"%f\" rz=\"%f\" />", position.x, position.y, position.z, rotation.w, rotation.x, rotation.y, rotation.z);
}
if (chatCommand == "playlvlfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
@@ -1652,7 +1669,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
auto sphere = static_cast<dpShapeSphere*>(prox.second->GetShape());
auto pos = prox.second->GetPosition();
std::cout << prox.first << ", r: " << sphere->GetRadius() << ", pos: " << pos.x << "," << pos.y << "," << pos.z << std::endl;
LOG("Proximity: %s, r: %f, pos: %f, %f, %f", prox.first.c_str(), sphere->GetRadius(), pos.x, pos.y, pos.z);
}
}
}
@@ -1895,6 +1912,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
}
}
if (chatCommand == "setrewardcode" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) {
auto* cdrewardCodes = CDClientManager::Instance().GetTable<CDRewardCodesTable>();
auto id = cdrewardCodes->GetCodeID(args[0]);
if (id != -1) Database::Get()->InsertRewardCode(user->GetAccountID(), id);
}
if (chatCommand == "inspect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) {
Entity* closest = nullptr;