Compare commits

..

10 Commits

Author SHA1 Message Date
David Markowitz
c22816bdbe fix: remove cancelOnLogout handling 2023-12-24 00:04:33 -08:00
jadebenn
6de224a2fa chore: miscellaneous code, formatting, and syntax cleanup (#1351)
* miscellaneous code, formatting, and syntax cleanup

* update

* update again

* updated to account for feedback
2023-12-23 18:11:00 -06:00
David Markowitz
5e9355b1ff fix: shooting gallery bugs (#1347)
fix: reset some more vars

Co-authored-by: Aaron Kimbre <aronwk.aaron@gmail.com>
2023-12-23 17:50:14 +00:00
David Markowitz
6b9798595e fix: leavezone command (#1345)
Players do not need access to leave Return to the Venture Explorer (rttve) via a slash command.  They can leave through the usual zone method.

Tested that you cannot leavezone in rttve
2023-12-23 11:28:32 -06:00
David Markowitz
e58218cfbc chore: Speed up and cleanup level and zone loading; Add safer asset buffer reading (#1314)
* Remove std::couts littered throughout the base

* working

End of optimizations for now

going faster

* Remove extraneous compare function

std::less<LWOSCENEID> already does this in a map.

* gaming

* Update Zone.cpp

* dlu is moving to bitbucket again

* Update Level.cpp

---------

Co-authored-by: Jettford <mrjettbradford@gmail.com>
2023-12-23 11:24:16 -06:00
jadebenn
fcf4d6c6fa feat: Improve console output to show packet enum names (magic_enum) (#1344)
* add enum stringification functionality from third party source

* squashed commit

* Macros: Add test and improve speed

Space macros out
utilize cache locality
ensure no lost functionality

* moved stringify code to dCommon

* Rename #defines in stringify enum tests

* Revert "moved stringify code to dCommon"

This reverts commit 33fa5f8d2f.

* improve macro functionality

change function handle

formatting and function definition tweaks

* typo fixes

* moved code to dCommon/dEnums and tests to dCommonTests/dEnumsTests

* initial magic_enums alternate implementation of enum stringification

* deleted unused tests

* reverted compile flag oopsy and fixed output types

* fixed testing suite

* test formatting improvement

* formatting again :(

* added gm string to "aborting gm!" message

* Push my suggestion for CI tests.

* updated magic enum test

* fix test variable type

* added gm test

* making sure magic_enum is on a release branch

* tidying up console outputs

* re-implemented enum array access for performance

* now it is bugged :(

* nvm, working

* helping out the snowflake compilers

* changed return type too

* optimization too

* formatting too I guess because why not

* being even more painfully specific

* Update WorldServer.cpp to match emo's feedback

* Update MagicEnumTests.cpp to use srand(time(NULL))

* Update eGameMessageType.h - formatting

* Trying to fix the crash but can't actually compile the code to check on my own rn

* Update WorldServer.cpp - third try at this

* Update MagicEnumTests.cpp - use better macro definitions

* Update MagicEnumTests.cpp - c string comparison fix

* addressing all but the cmake feedback

* fixed cmake to the best of my very limited ability

* added tests to verify magic enum arrays are pre-sorted

* updated

---------

Co-authored-by: David Markowitz <EmosewaMC@gmail.com>
Co-authored-by: Jettford <mrjettbradford@gmail.com>
2023-12-23 10:51:59 -06:00
David Markowitz
c1e8546d48 fix: add Nexus Tower missing scripts (#1349)
add final missing scripts for nt

also fix the turnin for the breadcrumb missions not showing the completion window.

Fix another missing script

Add another script

fix include guards

Fix dirt clouds not appearing on mission accept
2023-12-22 23:53:21 -08:00
jadebenn
c07c909a57 fix: Character access after deletion (#1348)
* assorted skill debug plus crash fix

* removed uncleaned debug
2023-12-21 22:12:52 -06:00
42ffd00478 feat: implement handling vendorStatusRequest (#1346)
this fixes the crafting menu on johny umami not being there on the initial internaction
2023-12-20 22:25:21 -06:00
jadebenn
799269c79e fix: Using 'leave-zone' in Return to the Venture Explorer allows players to return to the original Venture Explorer map (#1341)
* fixed VE zone bug and added config option to renable it

* add zero back to LWOMAPID initialization

* typo

* removed config option to enable bug
2023-12-20 15:12:01 -06:00
79 changed files with 2562 additions and 2245 deletions

View File

@@ -269,6 +269,7 @@ set(INCLUDED_DIRECTORIES
"dScripts/ai/GENERAL"
"dScripts/ai/GF"
"dScripts/ai/MINIGAME"
"dScripts/ai/MINIGAME/Objects"
"dScripts/ai/NP"
"dScripts/ai/NS"
"dScripts/ai/PETS"
@@ -292,12 +293,12 @@ set(INCLUDED_DIRECTORIES
"dScripts/zone/PROPERTY/GF"
"dScripts/zone/PROPERTY/NS"
"thirdparty/magic_enum/include/magic_enum"
"thirdparty/raknet/Source"
"thirdparty/tinyxml2"
"thirdparty/recastnavigation"
"thirdparty/SQLite"
"thirdparty/cpplinq"
"thirdparty/magic_enum/include"
"tests"
"tests/dCommonTests"
@@ -374,7 +375,7 @@ add_subdirectory(dNavigation)
add_subdirectory(dPhysics)
# Create a list of common libraries shared between all binaries
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp")
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp" "magic_enum")
# Add platform specific common libraries
if (UNIX)

View File

@@ -1,14 +1,6 @@
#include "BinaryIO.h"
#include <string>
void BinaryIO::WriteString(const std::string& stringToWrite, std::ofstream& outstream) {
//BinaryWrite(outstream, uint32_t(stringToWrite.length()));
for (size_t i = 0; i < size_t(stringToWrite.length()); ++i) {
BinaryIO::BinaryWrite(outstream, stringToWrite[i]);
}
}
//For reading null-terminated strings
std::string BinaryIO::ReadString(std::istream& instream) {
std::string toReturn;
@@ -23,36 +15,3 @@ std::string BinaryIO::ReadString(std::istream& instream) {
return toReturn;
}
//For reading strings of a specific size
std::string BinaryIO::ReadString(std::istream& instream, size_t size) {
std::string toReturn;
char buffer;
for (size_t i = 0; i < size; ++i) {
BinaryIO::BinaryRead(instream, buffer);
toReturn += buffer;
}
return toReturn;
}
std::string BinaryIO::ReadWString(std::istream& instream) {
size_t size;
BinaryRead(instream, size);
//toReturn.resize(size);
std::string test;
unsigned char buf;
for (size_t i = 0; i < size; ++i) {
//instream.ignore(1);
BinaryRead(instream, buf);
test += buf;
}
//printf("%s\n", test.c_str());
//instream.read((char*)&toReturn[0], size * 2);
//std::string str(toReturn.begin(), toReturn.end());
return test;
}

View File

@@ -1,8 +1,17 @@
#pragma once
#ifndef __BINARYIO__H__
#define __BINARYIO__H__
#include <iostream>
#include <fstream>
#include <string>
#include "Game.h"
#include "Logger.h"
namespace BinaryIO {
template<typename T>
std::ostream& BinaryWrite(std::ostream& stream, const T& value) {
return stream.write(reinterpret_cast<const char*>(&value), sizeof(T));
@@ -15,13 +24,51 @@ namespace BinaryIO {
return stream.read(reinterpret_cast<char*>(&value), sizeof(T));
}
void WriteString(const std::string& stringToWrite, std::ofstream& outstream);
enum class ReadType : int8_t {
WideString = 0,
String = 1,
};
template<typename SizeType>
inline void ReadString(std::istream& stream, std::u16string& value) {
static_assert(std::is_integral<SizeType>::value, "SizeType must be an integral type.");
SizeType size;
BinaryRead(stream, size);
if (!stream.good()) throw std::runtime_error("Failed to read from istream.");
value.resize(size);
stream.read(reinterpret_cast<char*>(value.data()), size * sizeof(uint16_t));
}
template<typename SizeType>
inline void ReadString(std::istream& stream, std::string& value, ReadType readType) {
static_assert(std::is_integral<SizeType>::value, "SizeType must be an integral type.");
SizeType size;
BinaryRead(stream, size);
if (!stream.good()) throw std::runtime_error("Failed to read from istream.");
value.resize(size);
if (readType == ReadType::WideString) {
uint16_t wideChar;
// Faster to do this than to read a u16string and convert it to a string since we only go through allocator once
for (SizeType i = 0; i < size; ++i) {
BinaryRead(stream, wideChar);
value[i] = static_cast<char>(wideChar);
}
} else {
stream.read(value.data(), size);
}
}
std::string ReadString(std::istream& instream);
std::string ReadString(std::istream& instream, size_t size);
std::string ReadWString(std::istream& instream);
inline bool DoesFileExist(const std::string& name) {
std::ifstream f(name.c_str());
return f.good();
}
}
#endif //!__BINARYIO__H__

View File

@@ -28,19 +28,17 @@ FdbToSqlite::Convert::Convert(std::string binaryOutPath) {
this->m_BinaryOutPath = binaryOutPath;
}
bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) {
bool FdbToSqlite::Convert::ConvertDatabase(AssetStream& buffer) {
if (m_ConversionStarted) return false;
std::istream cdClientBuffer(&buffer);
this->m_ConversionStarted = true;
try {
CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite");
CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;");
int32_t numberOfTables = ReadInt32(cdClientBuffer);
ReadTables(numberOfTables, cdClientBuffer);
int32_t numberOfTables = ReadInt32(buffer);
ReadTables(numberOfTables, buffer);
CDClientDatabase::ExecuteQuery("COMMIT;");
} catch (CppSQLite3Exception& e) {

View File

@@ -7,7 +7,7 @@
#include <iosfwd>
#include <map>
class AssetMemoryBuffer;
#include "AssetManager.h"
enum class eSqliteDataType : int32_t;
@@ -27,7 +27,7 @@ namespace FdbToSqlite {
*
* @return true if the database was converted properly, false otherwise.
*/
bool ConvertDatabase(AssetMemoryBuffer& buffer);
bool ConvertDatabase(AssetStream& buffer);
/**
* @brief Reads a 32 bit int from the fdb file.

View File

@@ -234,18 +234,30 @@ namespace GeneralUtils {
return T();
}
// on Windows we need to undef these or else they conflict with our numeric limits calls
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
#ifdef _WIN32
#undef min
#undef max
#endif
/**
* Casts the value of an enum entry to its underlying type
* @param entry Enum entry to cast
* @returns The enum entry's value in its underlying type
*/
template <typename eType>
inline constexpr typename std::underlying_type_t<eType> CastUnderlyingType(const eType entry) {
static_assert(std::is_enum_v<eType>, "Not an enum");
return static_cast<typename std::underlying_type_t<eType>>(entry);
}
// on Windows we need to undef these or else they conflict with our numeric limits calls
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
#ifdef _WIN32
#undef min
#undef max
#endif
template <typename T>
inline T GenerateRandomNumber() {
// Make sure it is a numeric type
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
return GenerateRandomNumber<T>(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
}
}

View File

@@ -152,13 +152,12 @@ bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) {
return success;
}
AssetMemoryBuffer AssetManager::GetFileAsBuffer(const char* name) {
char* buf;
uint32_t len;
AssetStream AssetManager::GetFile(const char* name) {
char* buf; uint32_t len;
bool success = this->GetFile(name, &buf, &len);
return AssetMemoryBuffer(buf, len, success);
return AssetStream(buf, len, success);
}
uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) {

View File

@@ -25,6 +25,10 @@ struct AssetMemoryBuffer : std::streambuf {
this->setg(base, base, base + n);
}
~AssetMemoryBuffer() {
free(m_Base);
}
pos_type seekpos(pos_type sp, std::ios_base::openmode which) override {
return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which);
}
@@ -40,9 +44,17 @@ struct AssetMemoryBuffer : std::streambuf {
setg(eback(), eback() + off, egptr());
return gptr() - eback();
}
};
void close() {
free(m_Base);
struct AssetStream : std::istream {
AssetStream(char* base, std::ptrdiff_t n, bool success) : std::istream(new AssetMemoryBuffer(base, n, success)) {}
~AssetStream() {
delete rdbuf();
}
operator bool() {
return reinterpret_cast<AssetMemoryBuffer*>(rdbuf())->m_Success;
}
};
@@ -56,7 +68,7 @@ public:
bool HasFile(const char* name);
bool GetFile(const char* name, char** data, uint32_t* len);
AssetMemoryBuffer GetFileAsBuffer(const char* name);
AssetStream GetFile(const char* name);
private:
void LoadPackIndex();

View File

@@ -8,21 +8,10 @@ PackIndex::PackIndex(const std::filesystem::path& filePath) {
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_Version);
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackPathCount);
for (int i = 0; i < m_PackPathCount; i++) {
uint32_t stringLen = 0;
BinaryIO::BinaryRead<uint32_t>(m_FileStream, stringLen);
std::string path;
for (int j = 0; j < stringLen; j++) {
char inChar;
BinaryIO::BinaryRead<char>(m_FileStream, inChar);
path += inChar;
}
m_PackPaths.push_back(path);
m_PackPaths.resize(m_PackPathCount);
for (auto& item : m_PackPaths) {
BinaryIO::ReadString<uint32_t>(m_FileStream, item, BinaryIO::ReadType::String);
}
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackFileIndexCount);

View File

@@ -0,0 +1,29 @@
#ifndef __STRINGIFIEDENUM_H__
#define __STRINGIFIEDENUM_H__
#include <string>
#include "magic_enum.hpp"
namespace StringifiedEnum {
template<typename T>
const std::string_view ToString(const T e) {
static_assert(std::is_enum_v<T>, "Not an enum"); // Check type
constexpr auto sv = &magic_enum::enum_entries<T>();
std::string_view output;
const auto it = std::lower_bound(
sv->begin(), sv->end(), e,
[&](const std::pair<T, std::string_view>& lhs, const T rhs) { return lhs.first < rhs; }
);
if (it != sv->end() && it->first == e) {
output = it->second;
} else {
output = "UNKNOWN";
}
return output;
}
}
#endif // !__STRINGIFIEDENUM_H__

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,8 @@
#include <cstdint>
#include "magic_enum.hpp"
enum class eWorldMessageType : uint32_t {
VALIDATION = 1, // Session info
CHARACTER_LIST_REQUEST,
@@ -40,4 +42,10 @@ enum class eWorldMessageType : uint32_t {
UI_HELP_TOP_5 = 91
};
template <>
struct magic_enum::customize::enum_range<eWorldMessageType> {
static constexpr int min = 0;
static constexpr int max = 91;
};
#endif //!__EWORLDMESSAGETYPE__H__

View File

@@ -166,7 +166,9 @@ void Entity::Initialize() {
if (!groupIDs.empty()) {
m_Groups = GeneralUtils::SplitString(groupIDs, ';');
m_Groups.erase(m_Groups.end() - 1);
if (!m_Groups.empty()) {
if (m_Groups.back().empty()) m_Groups.erase(m_Groups.end() - 1);
}
}
/**
@@ -334,7 +336,7 @@ void Entity::Initialize() {
CDDestructibleComponentTable* destCompTable = CDClientManager::Instance().GetTable<CDDestructibleComponentTable>();
std::vector<CDDestructibleComponent> destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); });
bool isSmashable = GetVarAs<int32_t>(u"is_smashable") != 0;
if (buffComponentID > 0 || collectibleComponentID > 0 || isSmashable) {
DestroyableComponent* comp = AddComponent<DestroyableComponent>();
@@ -541,8 +543,7 @@ void Entity::Initialize() {
// Known bug with moving platform in FV that casues it to build at the end instead of the start.
// This extends the smash time so players can ride up the lift.
if (m_TemplateID == 9483)
{
if (m_TemplateID == 9483) {
rebuildComponent->SetResetTime(rebuildComponent->GetResetTime() + 25);
}
}

View File

@@ -47,10 +47,6 @@ std::vector<LWOMAPID> EntityManager::m_GhostingExcludedZones = {
// Configure some exceptions for ghosting, nessesary for some special objects.
std::vector<LOT> EntityManager::m_GhostingExcludedLOTs = {
// NT - Pipes
9524,
12408,
// AG - Footrace
4967
};

View File

@@ -60,6 +60,8 @@ void Player::SetSystemAddress(const SystemAddress& value) {
}
void Player::SetRespawnPos(const NiPoint3 position) {
if (!m_Character) return;
m_respawnPos = position;
m_Character->SetRespawnPoint(Game::zoneManager->GetZone()->GetWorldID(), position);

View File

@@ -44,57 +44,53 @@ inline void StripCR(std::string& str) {
void UserManager::Initialize() {
std::string line;
AssetMemoryBuffer fnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_first.txt");
if (!fnBuff.m_Success) {
auto fnStream = Game::assetManager->GetFile("names/minifigname_first.txt");
if (!fnStream) {
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_first.txt").string().c_str());
throw std::runtime_error("Aborting initialization due to missing minifigure name file.");
}
std::istream fnStream = std::istream(&fnBuff);
while (std::getline(fnStream, line, '\n')) {
std::string name = line;
StripCR(name);
m_FirstNames.push_back(name);
}
fnBuff.close();
AssetMemoryBuffer mnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_middle.txt");
if (!mnBuff.m_Success) {
auto mnStream = Game::assetManager->GetFile("names/minifigname_middle.txt");
if (!mnStream) {
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_middle.txt").string().c_str());
throw std::runtime_error("Aborting initialization due to missing minifigure name file.");
}
std::istream mnStream = std::istream(&mnBuff);
while (std::getline(mnStream, line, '\n')) {
std::string name = line;
StripCR(name);
m_MiddleNames.push_back(name);
}
mnBuff.close();
AssetMemoryBuffer lnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_last.txt");
if (!lnBuff.m_Success) {
auto lnStream = Game::assetManager->GetFile("names/minifigname_last.txt");
if (!lnStream) {
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_last.txt").string().c_str());
throw std::runtime_error("Aborting initialization due to missing minifigure name file.");
}
std::istream lnStream = std::istream(&lnBuff);
while (std::getline(lnStream, line, '\n')) {
std::string name = line;
StripCR(name);
m_LastNames.push_back(name);
}
lnBuff.close();
//Load our pre-approved names:
AssetMemoryBuffer chatListBuff = Game::assetManager->GetFileAsBuffer("chatplus_en_us.txt");
if (!chatListBuff.m_Success) {
// Load our pre-approved names:
auto chatListStream = Game::assetManager->GetFile("chatplus_en_us.txt");
if (!chatListStream) {
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "chatplus_en_us.txt").string().c_str());
throw std::runtime_error("Aborting initialization due to missing chat whitelist file.");
}
std::istream chatListStream = std::istream(&chatListBuff);
while (std::getline(chatListStream, line, '\n')) {
StripCR(line);
m_PreapprovedNames.push_back(line);
}
chatListBuff.close();
}
UserManager::~UserManager() {

View File

@@ -22,7 +22,6 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
if (entity->IsPlayer() && !this->m_DontApplyImmune) {
const float immunityTime = Game::zoneManager->GetWorldConfig()->globalImmunityTime;
destroyableComponent->SetDamageCooldownTimer(immunityTime);
LOG_DEBUG("Target targetEntity %llu took damage, setting damage cooldown timer to %f s", branch.target, immunityTime);
}
}
@@ -188,11 +187,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
return;
}
const float immunityTime = Game::zoneManager->GetWorldConfig()->globalImmunityTime;
LOG_DEBUG("Damage cooldown timer currently %f s", destroyableComponent->GetDamageCooldownTimer());
const bool isImmune = (destroyableComponent->IsImmune()) || (destroyableComponent->IsCooldownImmune());
const bool isImmune = destroyableComponent->IsImmune() || destroyableComponent->IsCooldownImmune();
bitStream->Write(isImmune);
if (isImmune) {
@@ -219,8 +214,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
//Handle player damage cooldown
if (isSuccess && targetEntity->IsPlayer() && !this->m_DontApplyImmune) {
destroyableComponent->SetDamageCooldownTimer(immunityTime);
LOG_DEBUG("Target targetEntity %llu took damage, setting damage cooldown timer to %f s", branch.target, immunityTime);
destroyableComponent->SetDamageCooldownTimer(Game::zoneManager->GetWorldConfig()->globalImmunityTime);
}
eBasicAttackSuccessTypes successState = eBasicAttackSuccessTypes::FAILIMMUNE;

View File

@@ -398,7 +398,8 @@ void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
for (const auto& [id, buff] : m_Buffs) {
auto* buffEntry = doc->NewElement("b");
if (buff.cancelOnZone || buff.cancelOnLogout) continue;
// TODO: change this if to if (buff.cancelOnZone || buff.cancelOnLogout) handling at some point. No current way to differentiate between zone transfer and logout.
if (buff.cancelOnZone) continue;
buffEntry->SetAttribute("id", id);
buffEntry->SetAttribute("t", buff.time);

View File

@@ -557,7 +557,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
}
if (IsImmune() || IsCooldownImmune()) {
LOG_DEBUG("Target targetEntity %llu is immune!", m_Parent->GetObjectID()); //Immune is succesfully proc'd
LOG_DEBUG("Target targetEntity %llu is immune!", m_Parent->GetObjectID());
return;
}

View File

@@ -621,3 +621,12 @@ bool MissionComponent::HasCollectible(int32_t collectibleID) {
bool MissionComponent::HasMission(uint32_t missionId) {
return GetMission(missionId) != nullptr;
}
void MissionComponent::ResetMission(const int32_t missionId) {
auto* mission = GetMission(missionId);
if (!mission) return;
m_Missions.erase(missionId);
GameMessages::SendResetMissions(m_Parent, m_Parent->GetSystemAddress(), missionId);
}

View File

@@ -170,6 +170,7 @@ public:
*/
bool HasMission(uint32_t missionId);
void ResetMission(const int32_t missionId);
private:
/**
* All the missions owned by this entity, mapped by mission ID

View File

@@ -29,11 +29,11 @@ uint32_t OfferedMission::GetMissionId() const {
return this->missionId;
}
bool OfferedMission::GetOfferMission() const {
bool OfferedMission::GetOffersMission() const {
return this->offersMission;
}
bool OfferedMission::GetAcceptMission() const {
bool OfferedMission::GetAcceptsMission() const {
return this->acceptsMission;
}
@@ -203,7 +203,10 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi
const auto selected = canAcceptPool[GeneralUtils::GenerateRandomNumber<int>(0, canAcceptPool.size() - 1)];
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), selected, m_Parent->GetObjectID());
} else if (std::find(offered.begin(), offered.end(), missionId) == offered.end() && offeredMission->GetOfferMission()) {
} else if (
std::find(offered.begin(), offered.end(), missionId) == offered.end()
&&
(offeredMission->GetOffersMission() || offeredMission->GetAcceptsMission())) {
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), missionId, m_Parent->GetObjectID());
}
}

View File

@@ -30,13 +30,13 @@ struct OfferedMission {
* Returns if this mission is offered by the entity
* @return true if this mission is offered by the entity, false otherwise
*/
bool GetOfferMission() const;
bool GetOffersMission() const;
/**
* Returns if this mission may be accepted by the entity (currently unused)
* @return true if this mission may be accepted by the entity, false otherwise
*/
bool GetAcceptMission() const;
bool GetAcceptsMission() const;
private:

View File

@@ -24,6 +24,7 @@ void ShootingGalleryComponent::Serialize(RakNet::BitStream* outBitStream, bool i
outBitStream->Write<uint32_t>(0);
} else {
outBitStream->Write<uint32_t>(1);
outBitStream->Write<LWOOBJID>(m_CurrentPlayerID);
for (size_t i = 0; i < 10; i++) {
outBitStream->Write<float_t>(0.0f);
}
@@ -60,6 +61,7 @@ void ShootingGalleryComponent::Serialize(RakNet::BitStream* outBitStream, bool i
outBitStream->Write<LWOOBJID>(m_CurrentPlayerID);
outBitStream->Write<float_t>(m_DynamicParams.cannonTimeout);
outBitStream->Write<float_t>(m_DynamicParams.cannonFOV);
if (!isInitialUpdate) m_Dirty = false;
}
}

View File

@@ -34,8 +34,10 @@
#include "eMissionTaskType.h"
#include "eReplicaComponentType.h"
#include "eConnectionType.h"
#include "eGameMessageType.h"
#include "ePlayerFlag.h"
#include "dConfig.h"
#include "StringifiedEnum.h"
void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const SystemAddress& sysAddr, LWOOBJID objectID, eGameMessageType messageID) {
@@ -47,11 +49,11 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
User* usr = UserManager::Instance()->GetUser(sysAddr);
if (!entity) {
LOG("Failed to find associated entity (%llu), aborting GM (%4i) %s!", objectID, messageID, magic_enum::enum_name(messageID).data());
LOG("Failed to find associated entity (%llu), aborting GM: %4i, %s!", objectID, messageID, StringifiedEnum::ToString(messageID).data());
return;
}
if (messageID != eGameMessageType::READY_FOR_UPDATES) LOG_DEBUG("Received GM with ID and name: %4i, %s", messageID, magic_enum::enum_name(messageID).data());
if (messageID != eGameMessageType::READY_FOR_UPDATES) LOG_DEBUG("Received GM with ID and name: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data());
switch (messageID) {
@@ -347,7 +349,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
for (unsigned int k = 0; k < sync.sBitStream.size(); k++) {
char s;
s = sync.sBitStream.at(k);
buffer << std::setw(2) << std::hex << std::setfill('0') << (int)s << " ";
buffer << std::setw(2) << std::hex << std::setfill('0') << static_cast<int>(s) << " ";
}
if (usr != nullptr) {
@@ -688,8 +690,11 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
case eGameMessageType::CANCEL_DONATION_ON_PLAYER:
GameMessages::HandleCancelDonationOnPlayer(inStream, entity);
break;
case eGameMessageType::REQUEST_VENDOR_STATUS_UPDATE:
GameMessages::SendVendorStatusUpdate(entity, sysAddr, true);
break;
default:
LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, magic_enum::enum_name(messageID).data());
LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data());
break;
}
}

View File

@@ -19,8 +19,7 @@
#include "Logger.h"
#include "GameMessages.h"
#include "CDClientDatabase.h"
enum class eGameMessageType : uint16_t;
#include "eGameMessageType.h"
namespace GameMessageHandler {
void HandleMessage(RakNet::BitStream* inStream, const SystemAddress& sysAddr, LWOOBJID objectID, eGameMessageType messageID);

View File

@@ -111,7 +111,7 @@ void GameMessages::SendFireEventClientSide(const LWOOBJID& objectID, const Syste
uint32_t argSize = args.size();
bitStream.Write(argSize);
for (uint32_t k = 0; k < argSize; k++) {
bitStream.Write(static_cast<uint16_t>(args[k]));
bitStream.Write<uint16_t>(args[k]);
}
bitStream.Write(object);
bitStream.Write0();
@@ -221,13 +221,13 @@ void GameMessages::SendInvalidZoneTransferList(Entity* entity, const SystemAddre
uint32_t CustomerFeedbackURLLength = feedbackURL.size();
bitStream.Write(CustomerFeedbackURLLength);
for (uint32_t k = 0; k < CustomerFeedbackURLLength; k++) {
bitStream.Write(static_cast<uint16_t>(feedbackURL[k]));
bitStream.Write<uint16_t>(feedbackURL[k]);
}
uint32_t InvalidMapTransferListLength = invalidMapTransferList.size();
bitStream.Write(InvalidMapTransferListLength);
for (uint32_t k = 0; k < InvalidMapTransferListLength; k++) {
bitStream.Write(static_cast<uint16_t>(invalidMapTransferList[k]));
bitStream.Write<uint16_t>(invalidMapTransferList[k]);
}
bitStream.Write(feedbackOnExit);
@@ -318,17 +318,17 @@ void GameMessages::SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& s
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::PLAY_ND_AUDIO_EMITTER);
bitStream.Write(eGameMessageType::PLAY_ND_AUDIO_EMITTER);
bitStream.Write0();
bitStream.Write0();
uint32_t length = audioGUID.size();
bitStream.Write(length);
for (uint32_t k = 0; k < length; k++) {
bitStream.Write(static_cast<char>(audioGUID[k]));
bitStream.Write<char>(audioGUID[k]);
}
bitStream.Write(uint32_t(0));
bitStream.Write<uint32_t>(0);
bitStream.Write0();
bitStream.Write0();
@@ -345,6 +345,19 @@ void GameMessages::SendStartPathing(Entity* entity) {
SEND_PACKET_BROADCAST;
}
void GameMessages::SendResetMissions(Entity* entity, const SystemAddress& sysAddr, const int32_t missionid) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write(eGameMessageType::RESET_MISSIONS);
bitStream.Write(missionid != -1);
if (missionid != -1) bitStream.Write(missionid);
SEND_PACKET;
}
void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint,
int iIndex, int iDesiredWaypointIndex, int nextIndex,
eMovementPlatformState movementState) {
@@ -362,7 +375,7 @@ void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAd
}
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::PLATFORM_RESYNC);
bitStream.Write(eGameMessageType::PLATFORM_RESYNC);
bool bReverse = false;
int eCommand = 0;
@@ -419,7 +432,7 @@ void GameMessages::SendChatModeUpdate(const LWOOBJID& objectID, eGameMasterLevel
CBITSTREAM;
CMSGHEADER;
bitStream.Write(objectID);
bitStream.Write((uint16_t)eGameMessageType::UPDATE_CHAT_MODE);
bitStream.Write(eGameMessageType::UPDATE_CHAT_MODE);
bitStream.Write(level);
SEND_PACKET_BROADCAST;
}
@@ -428,7 +441,7 @@ void GameMessages::SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLev
CBITSTREAM;
CMSGHEADER;
bitStream.Write(objectID);
bitStream.Write((uint16_t)eGameMessageType::SET_GM_LEVEL);
bitStream.Write(eGameMessageType::SET_GM_LEVEL);
bitStream.Write1();
bitStream.Write(level);
SEND_PACKET_BROADCAST;
@@ -459,9 +472,9 @@ void GameMessages::SendAddItemToInventoryClientSync(Entity* entity, const System
bitStream.Write<uint32_t>(extraInfo.name.size());
if (extraInfo.name.size() > 0) {
for (uint32_t i = 0; i < extraInfo.name.size(); ++i) {
bitStream.Write(static_cast<uint16_t>(extraInfo.name[i]));
bitStream.Write<uint16_t>(extraInfo.name[i]);
}
bitStream.Write(static_cast<uint16_t>(0x00));
bitStream.Write<uint16_t>(0x00);
}
bitStream.Write(item->GetLot());
@@ -498,7 +511,7 @@ void GameMessages::SendNotifyClientFlagChange(const LWOOBJID& objectID, uint32_t
CMSGHEADER;
bitStream.Write(objectID);
bitStream.Write((uint16_t)eGameMessageType::NOTIFY_CLIENT_FLAG_CHANGE);
bitStream.Write(eGameMessageType::NOTIFY_CLIENT_FLAG_CHANGE);
bitStream.Write(bFlag);
bitStream.Write(iFlagID);
@@ -510,7 +523,7 @@ void GameMessages::SendChangeObjectWorldState(const LWOOBJID& objectID, eObjectW
CMSGHEADER;
bitStream.Write(objectID);
bitStream.Write((uint16_t)eGameMessageType::CHANGE_OBJECT_WORLD_STATE);
bitStream.Write(eGameMessageType::CHANGE_OBJECT_WORLD_STATE);
bitStream.Write(state);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST
@@ -565,7 +578,7 @@ void GameMessages::SendNotifyMissionTask(Entity* entity, const SystemAddress& sy
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::NOTIFY_MISSION_TASK);
bitStream.Write(eGameMessageType::NOTIFY_MISSION_TASK);
bitStream.Write(missionID);
bitStream.Write(taskMask);
@@ -583,7 +596,7 @@ void GameMessages::SendModifyLEGOScore(Entity* entity, const SystemAddress& sysA
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::MODIFY_LEGO_SCORE);
bitStream.Write(eGameMessageType::MODIFY_LEGO_SCORE);
bitStream.Write(score);
bitStream.Write(sourceType != eLootSourceType::NONE);
@@ -597,14 +610,14 @@ void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const Syste
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT);
bitStream.Write(eGameMessageType::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT);
bitStream.Write<AMFBaseValue&>(args);
uint32_t strMessageNameLength = message.size();
bitStream.Write(strMessageNameLength);
for (uint32_t k = 0; k < strMessageNameLength; k++) {
bitStream.Write(static_cast<char>(message[k]));
bitStream.Write<char>(message[k]);
}
SEND_PACKET;
@@ -616,14 +629,14 @@ void GameMessages::SendUIMessageServerToAllClients(const std::string& message, A
LWOOBJID empty = 0;
bitStream.Write(empty);
bitStream.Write((uint16_t)eGameMessageType::UI_MESSAGE_SERVER_TO_ALL_CLIENTS);
bitStream.Write(eGameMessageType::UI_MESSAGE_SERVER_TO_ALL_CLIENTS);
bitStream.Write<AMFBaseValue&>(args);
uint32_t strMessageNameLength = message.size();
bitStream.Write(strMessageNameLength);
for (uint32_t k = 0; k < strMessageNameLength; k++) {
bitStream.Write(static_cast<char>(message[k]));
bitStream.Write<char>(message[k]);
}
SEND_PACKET_BROADCAST;
@@ -634,11 +647,11 @@ void GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity,
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT);
bitStream.Write(eGameMessageType::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT);
bitStream.Write(static_cast<uint32_t>(effectName.length()));
bitStream.Write<uint32_t>(effectName.length());
for (uint32_t k = 0; k < effectName.length(); k++) {
bitStream.Write(static_cast<uint16_t>(effectName[k]));
bitStream.Write<uint16_t>(effectName[k]);
}
bitStream.Write(fromObjectID);
bitStream.Write(radius);
@@ -655,7 +668,7 @@ void GameMessages::SendPlayFXEffect(const LWOOBJID& entity, int32_t effectID, co
CMSGHEADER;
bitStream.Write(entity);
bitStream.Write((uint16_t)eGameMessageType::PLAY_FX_EFFECT);
bitStream.Write(eGameMessageType::PLAY_FX_EFFECT);
bitStream.Write(effectID != -1);
if (effectID != -1) bitStream.Write(effectID);
@@ -703,22 +716,22 @@ void GameMessages::SendBroadcastTextToChatbox(Entity* entity, const SystemAddres
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::BROADCAST_TEXT_TO_CHATBOX);
bitStream.Write(eGameMessageType::BROADCAST_TEXT_TO_CHATBOX);
LWONameValue attribs;
attribs.name = attrs;
attribs.length = attrs.size();
bitStream.Write(static_cast<uint32_t>(attribs.length));
bitStream.Write<uint32_t>(attribs.length);
for (uint32_t i = 0; i < attribs.length; ++i) {
bitStream.Write(static_cast<uint16_t>(attribs.name[i]));
bitStream.Write<uint16_t>(attribs.name[i]);
}
bitStream.Write(static_cast<uint16_t>(0x00)); // Null Terminator
bitStream.Write<uint16_t>(0x00); // Null Terminator
uint32_t wsTextLength = wsText.size();
bitStream.Write(wsTextLength);
for (uint32_t k = 0; k < wsTextLength; k++) {
bitStream.Write(static_cast<uint16_t>(wsText[k]));
bitStream.Write<uint16_t>(wsText[k]);
}
SEND_PACKET_BROADCAST;
@@ -759,7 +772,7 @@ void GameMessages::SendRebuildNotifyState(Entity* entity, eRebuildState prevStat
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::REBUILD_NOTIFY_STATE);
bitStream.Write(eGameMessageType::REBUILD_NOTIFY_STATE);
bitStream.Write(prevState);
bitStream.Write(state);
@@ -773,7 +786,7 @@ void GameMessages::SendEnableRebuild(Entity* entity, bool enable, bool fail, boo
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::ENABLE_REBUILD);
bitStream.Write(eGameMessageType::ENABLE_REBUILD);
bitStream.Write(enable);
bitStream.Write(fail);
@@ -793,7 +806,7 @@ void GameMessages::SendTerminateInteraction(const LWOOBJID& objectID, eTerminate
CMSGHEADER;
bitStream.Write(objectID);
bitStream.Write((uint16_t)eGameMessageType::TERMINATE_INTERACTION);
bitStream.Write(eGameMessageType::TERMINATE_INTERACTION);
bitStream.Write(terminator);
bitStream.Write(type);
@@ -829,7 +842,7 @@ void GameMessages::SendDie(Entity* entity, const LWOOBJID& killerID, const LWOOB
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::DIE);
bitStream.Write(eGameMessageType::DIE);
bitStream.Write(bClientDeath);
bitStream.Write(bSpawnLoot);
@@ -840,7 +853,7 @@ void GameMessages::SendDie(Entity* entity, const LWOOBJID& killerID, const LWOOB
uint32_t deathTypeLength = deathType.size();
bitStream.Write(deathTypeLength);
for (uint32_t k = 0; k < deathTypeLength; k++) {
bitStream.Write(static_cast<uint16_t>(deathType[k]));
bitStream.Write<uint16_t>(deathType[k]);
}
bitStream.Write(directionRelative_AngleXZ);
@@ -963,7 +976,7 @@ void GameMessages::SendStop2DAmbientSound(Entity* entity, bool force, std::strin
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::STOP2_D_AMBIENT_SOUND);
bitStream.Write(eGameMessageType::STOP2_D_AMBIENT_SOUND);
uint32_t audioGUIDSize = audioGUID.size();
@@ -971,7 +984,7 @@ void GameMessages::SendStop2DAmbientSound(Entity* entity, bool force, std::strin
bitStream.Write(audioGUIDSize);
for (uint32_t k = 0; k < audioGUIDSize; k++) {
bitStream.Write(static_cast<char>(audioGUID[k]));
bitStream.Write<char>(audioGUID[k]);
}
bitStream.Write(result);
@@ -986,13 +999,12 @@ void GameMessages::SendPlay2DAmbientSound(Entity* entity, std::string audioGUID,
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::PLAY2_D_AMBIENT_SOUND);
bitStream.Write(eGameMessageType::PLAY2_D_AMBIENT_SOUND);
uint32_t audioGUIDSize = audioGUID.size();
bitStream.Write(audioGUIDSize);
for (uint32_t k = 0; k < audioGUIDSize; k++) {
bitStream.Write(static_cast<char>(audioGUID[k]));
bitStream.Write<char>(audioGUID[k]);
}
bitStream.Write(result);
@@ -1005,7 +1017,7 @@ void GameMessages::SendSetNetworkScriptVar(Entity* entity, const SystemAddress&
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::SCRIPT_NETWORK_VAR_UPDATE);
bitStream.Write(eGameMessageType::SCRIPT_NETWORK_VAR_UPDATE);
// FIXME: this is a bad place to need to do a conversion because we have no clue whether data is utf8 or plain ascii
// an this has performance implications
@@ -1014,9 +1026,9 @@ void GameMessages::SendSetNetworkScriptVar(Entity* entity, const SystemAddress&
bitStream.Write(dataSize);
for (auto value : u16Data) {
bitStream.Write(uint16_t(value));
bitStream.Write<uint16_t>(value);
}
if (dataSize > 0) bitStream.Write(uint16_t(0));
if (dataSize > 0) bitStream.Write<uint16_t>(0);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
SEND_PACKET;
@@ -1131,16 +1143,16 @@ void GameMessages::SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPo
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::PLAYER_REACHED_RESPAWN_CHECKPOINT);
bitStream.Write(eGameMessageType::PLAYER_REACHED_RESPAWN_CHECKPOINT);
bitStream.Write(position.x);
bitStream.Write(position.y);
bitStream.Write(position.z);
const bool isNotIdentity = rotation != NiQuaternion::IDENTITY;
bitStream.Write(isNotIdentity);
if (isNotIdentity) {
const bool bIsNotIdentity = rotation != NiQuaternion::IDENTITY;
bitStream.Write(bIsNotIdentity);
if (bIsNotIdentity) {
bitStream.Write(rotation.w);
bitStream.Write(rotation.x);
bitStream.Write(rotation.y);
@@ -1163,7 +1175,7 @@ void GameMessages::SendAddSkill(Entity* entity, TSkillID skillID, BehaviorSlot s
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write((uint16_t)eGameMessageType::ADD_SKILL);
bitStream.Write(eGameMessageType::ADD_SKILL);
bitStream.Write(AICombatWeight != 0);
if (AICombatWeight != 0) bitStream.Write(AICombatWeight);
@@ -1332,8 +1344,8 @@ void GameMessages::SendRemoveItemFromInventory(Entity* entity, const SystemAddre
bitStream.Write(eInvType);
bitStream.Write1();
bitStream.Write(eLootTypeSource);
bitStream.Write(static_cast<uint32_t>(0)); //extra info
//bitStream.Write(static_cast<uint16_t>(0)); //extra info
bitStream.Write<uint32_t>(0); //extra info
//bitStream.Write<uint16_t>(0); //extra info
bitStream.Write(forceDeletion);
bitStream.Write0();
bitStream.Write1();
@@ -1456,11 +1468,11 @@ void GameMessages::SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr,
bitStream.Write(entity->GetObjectID());
bitStream.Write(eGameMessageType::MATCH_UPDATE);
bitStream.Write(uint32_t(data.size()));
bitStream.Write<uint32_t>(data.size());
for (char character : data) {
bitStream.Write(uint16_t(character));
bitStream.Write<uint16_t>(character);
}
if (data.size() > 0) bitStream.Write(uint16_t(0));
if (data.size() > 0) bitStream.Write<uint16_t>(0);
bitStream.Write(type);
SEND_PACKET;
@@ -1544,7 +1556,7 @@ void GameMessages::NotifyLevelRewards(LWOOBJID objectID, const SystemAddress& sy
CMSGHEADER;
bitStream.Write(objectID);
bitStream.Write((uint16_t)eGameMessageType::NOTIFY_LEVEL_REWARDS);
bitStream.Write(eGameMessageType::NOTIFY_LEVEL_REWARDS);
bitStream.Write(level);
bitStream.Write(sending_rewards);
@@ -1730,7 +1742,7 @@ void GameMessages::SendSetRailMovement(const LWOOBJID& objectID, bool pathGoForw
bitStream.Write(pathGoForward);
bitStream.Write(uint32_t(pathName.size()));
bitStream.Write<uint32_t>(pathName.size());
for (auto character : pathName) {
bitStream.Write<uint16_t>(character);
}
@@ -1769,14 +1781,14 @@ void GameMessages::SendStartRailMovement(const LWOOBJID& objectID, std::u16strin
bitStream.Write(cameraLocked);
bitStream.Write(collisionEnabled);
bitStream.Write(uint32_t(loopSound.size()));
bitStream.Write<uint32_t>(loopSound.size());
for (auto character : loopSound) {
bitStream.Write<uint16_t>(character);
}
bitStream.Write(goForward);
bitStream.Write(uint32_t(pathName.size()));
bitStream.Write<uint32_t>(pathName.size());
for (auto character : pathName) {
bitStream.Write<uint16_t>(character);
}
@@ -1799,12 +1811,12 @@ void GameMessages::SendStartRailMovement(const LWOOBJID& objectID, std::u16strin
bitStream.Write<LWOOBJID>(railActivatorObjectID);
}
bitStream.Write(uint32_t(startSound.size()));
bitStream.Write<uint32_t>(startSound.size());
for (auto character : startSound) {
bitStream.Write<uint16_t>(character);
}
bitStream.Write(uint32_t(stopSound.size()));
bitStream.Write<uint32_t>(stopSound.size());
for (auto character : stopSound) {
bitStream.Write<uint16_t>(character);
}
@@ -1822,7 +1834,7 @@ void GameMessages::SendNotifyClientObject(const LWOOBJID& objectID, std::u16stri
bitStream.Write(objectID);
bitStream.Write(eGameMessageType::NOTIFY_CLIENT_OBJECT);
bitStream.Write(uint32_t(name.size()));
bitStream.Write<uint32_t>(name.size());
for (auto character : name) {
bitStream.Write<uint16_t>(character);
}
@@ -1833,7 +1845,7 @@ void GameMessages::SendNotifyClientObject(const LWOOBJID& objectID, std::u16stri
bitStream.Write(paramObj);
bitStream.Write(uint32_t(paramStr.size()));
bitStream.Write<uint32_t>(paramStr.size());
for (auto character : paramStr) {
bitStream.Write(character);
}
@@ -1851,7 +1863,7 @@ void GameMessages::SendNotifyClientZoneObject(const LWOOBJID& objectID, const st
bitStream.Write(objectID);
bitStream.Write(eGameMessageType::NOTIFY_CLIENT_ZONE_OBJECT);
bitStream.Write(uint32_t(name.size()));
bitStream.Write<uint32_t>(name.size());
for (const auto& character : name) {
bitStream.Write<uint16_t>(character);
}
@@ -1860,7 +1872,7 @@ void GameMessages::SendNotifyClientZoneObject(const LWOOBJID& objectID, const st
bitStream.Write(param2);
bitStream.Write(paramObj);
bitStream.Write(uint32_t(paramStr.size()));
bitStream.Write<uint32_t>(paramStr.size());
for (const auto& character : paramStr) {
bitStream.Write(character);
}
@@ -1877,9 +1889,9 @@ void GameMessages::SendNotifyClientFailedPrecondition(LWOOBJID objectId, const S
bitStream.Write(objectId);
bitStream.Write(eGameMessageType::NOTIFY_CLIENT_FAILED_PRECONDITION);
bitStream.Write(uint32_t(failedReason.size()));
bitStream.Write<uint32_t>(failedReason.size());
for (uint16_t character : failedReason) {
bitStream.Write(uint16_t(character));
bitStream.Write<uint16_t>(character);
}
bitStream.Write(preconditionID);
@@ -2003,7 +2015,7 @@ void GameMessages::SendLockNodeRotation(Entity* entity, std::string nodeName) {
bitStream.Write(entity->GetObjectID());
bitStream.Write(eGameMessageType::LOCK_NODE_ROTATION);
bitStream.Write(uint32_t(nodeName.size()));
bitStream.Write<uint32_t>(nodeName.size());
for (char character : nodeName) {
bitStream.Write(character);
}
@@ -2038,7 +2050,7 @@ void GameMessages::SendGetModelsOnProperty(LWOOBJID objectId, std::map<LWOOBJID,
bitStream.Write(objectId);
bitStream.Write(eGameMessageType::GET_MODELS_ON_PROPERTY);
bitStream.Write(static_cast<uint32_t>(models.size()));
bitStream.Write<uint32_t>(models.size());
for (const auto& pair : models) {
bitStream.Write(pair.first);
@@ -2420,7 +2432,7 @@ void GameMessages::HandleBBBLoadItemRequest(RakNet::BitStream* inStream, Entity*
void GameMessages::SendBlueprintLoadItemResponse(const SystemAddress& sysAddr, bool success, LWOOBJID oldItemId, LWOOBJID newItemId) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_LOAD_RESPONSE_ITEMID);
bitStream.Write(static_cast<uint8_t>(success));
bitStream.Write<uint8_t>(success);
bitStream.Write<LWOOBJID>(oldItemId);
bitStream.Write<LWOOBJID>(newItemId);
SEND_PACKET;
@@ -3045,7 +3057,7 @@ void GameMessages::SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std
bitStream.Write(eGameMessageType::NOTIFY_OBJECT);
bitStream.Write(objIDSender);
bitStream.Write(static_cast<uint32_t>(name.size()));
bitStream.Write<uint32_t>(name.size());
for (const auto character : name) {
bitStream.Write(character);
}
@@ -3102,7 +3114,7 @@ void GameMessages::SendServerTradeInvite(LWOOBJID objectId, bool bNeedInvitePopU
bitStream.Write(bNeedInvitePopUp);
bitStream.Write(i64Requestor);
bitStream.Write(static_cast<uint32_t>(wsName.size()));
bitStream.Write<uint32_t>(wsName.size());
for (const auto character : wsName) {
bitStream.Write(character);
}
@@ -3120,7 +3132,7 @@ void GameMessages::SendServerTradeInitialReply(LWOOBJID objectId, LWOOBJID i64In
bitStream.Write(i64Invitee);
bitStream.Write(resultType);
bitStream.Write(static_cast<uint32_t>(wsName.size()));
bitStream.Write<uint32_t>(wsName.size());
for (const auto character : wsName) {
bitStream.Write(character);
}
@@ -3138,7 +3150,7 @@ void GameMessages::SendServerTradeFinalReply(LWOOBJID objectId, bool bResult, LW
bitStream.Write(bResult);
bitStream.Write(i64Invitee);
bitStream.Write(static_cast<uint32_t>(wsName.size()));
bitStream.Write<uint32_t>(wsName.size());
for (const auto character : wsName) {
bitStream.Write(character);
}
@@ -3180,7 +3192,7 @@ void GameMessages::SendServerTradeUpdate(LWOOBJID objectId, uint64_t coins, cons
bitStream.Write(false);
bitStream.Write(coins);
bitStream.Write(static_cast<uint32_t>(items.size()));
bitStream.Write<uint32_t>(items.size());
for (const auto& item : items) {
bitStream.Write(item.itemId);
@@ -3389,7 +3401,7 @@ void GameMessages::SendNotifyPetTamingPuzzleSelected(LWOOBJID objectId, const st
bitStream.Write(objectId);
bitStream.Write(eGameMessageType::NOTIFY_TAMING_PUZZLE_SELECTED);
bitStream.Write(static_cast<uint32_t>(bricks.size()));
bitStream.Write<uint32_t>(bricks.size());
for (const auto& brick : bricks) {
bitStream.Write(brick.designerID);
bitStream.Write(brick.materialID);
@@ -3438,7 +3450,7 @@ void GameMessages::SendAddPetToPlayer(LWOOBJID objectId, int32_t iElementalType,
bitStream.Write(eGameMessageType::ADD_PET_TO_PLAYER);
bitStream.Write(iElementalType);
bitStream.Write(static_cast<uint32_t>(name.size()));
bitStream.Write<uint32_t>(name.size());
for (const auto character : name) {
bitStream.Write(character);
}
@@ -3572,7 +3584,7 @@ void GameMessages::SendSetPetName(LWOOBJID objectId, std::u16string name, LWOOBJ
bitStream.Write(objectId);
bitStream.Write(eGameMessageType::SET_PET_NAME);
bitStream.Write(static_cast<uint32_t>(name.size()));
bitStream.Write<uint32_t>(name.size());
for (const auto character : name) {
bitStream.Write(character);
}
@@ -3611,12 +3623,12 @@ void GameMessages::SendPetNameChanged(LWOOBJID objectId, int32_t moderationStatu
bitStream.Write(moderationStatus);
bitStream.Write(static_cast<uint32_t>(name.size()));
bitStream.Write<uint32_t>(name.size());
for (const auto character : name) {
bitStream.Write(character);
}
bitStream.Write(static_cast<uint32_t>(ownerName.size()));
bitStream.Write<uint32_t>(ownerName.size());
for (const auto character : ownerName) {
bitStream.Write(character);
}
@@ -3894,19 +3906,19 @@ void GameMessages::SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID
bitStream.Write(bShow);
bitStream.Write(callbackClient);
bitStream.Write(static_cast<uint32_t>(identifier.size()));
bitStream.Write<uint32_t>(identifier.size());
for (const auto character : identifier) {
bitStream.Write(character);
}
bitStream.Write(imageID);
bitStream.Write(static_cast<uint32_t>(text.size()));
bitStream.Write<uint32_t>(text.size());
for (const auto character : text) {
bitStream.Write(character);
}
bitStream.Write(static_cast<uint32_t>(userData.size()));
bitStream.Write<uint32_t>(userData.size());
for (const auto character : userData) {
bitStream.Write(character);
}
@@ -3923,7 +3935,7 @@ void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string
bitStream.Write(objectId);
bitStream.Write(eGameMessageType::DISPLAY_CHAT_BUBBLE);
bitStream.Write(static_cast<uint32_t>(text.size()));
bitStream.Write<uint32_t>(text.size());
for (const auto character : text) {
bitStream.Write(character);
}
@@ -4114,8 +4126,7 @@ void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity,
}
racingControlComponent->OnRequestDie(entity);
}
else {
} else {
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
if (!destroyableComponent) return;
@@ -4232,7 +4243,7 @@ void GameMessages::SendModuleAssemblyDBDataForClient(LWOOBJID objectId, LWOOBJID
bitStream.Write(assemblyID);
bitStream.Write(static_cast<uint32_t>(data.size()));
bitStream.Write<uint32_t>(data.size());
for (auto character : data) {
bitStream.Write(character);
}
@@ -4377,7 +4388,7 @@ void GameMessages::SendNotifyRacingClient(LWOOBJID objectId, int32_t eventType,
bitStream.Write(paramObj);
bitStream.Write(static_cast<uint32_t>(paramStr.size()));
bitStream.Write<uint32_t>(paramStr.size());
for (auto character : paramStr) {
bitStream.Write(character);
}
@@ -4572,7 +4583,7 @@ void GameMessages::SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditi
bitStream.Write(bPlayCountdownSound);
bitStream.Write(static_cast<uint32_t>(sndName.size()));
bitStream.Write<uint32_t>(sndName.size());
for (auto character : sndName) {
bitStream.Write(character);
}
@@ -5588,7 +5599,7 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity*
if (entity->GetLOT() != 9980 || Game::server->GetZoneID() != 1200) {
if (missionComponent != nullptr) {
missionComponent->Progress(eMissionTaskType::SCRIPT, entity->GetLOT(), entity->GetObjectID());
if (count >= 7 && everyPieceSwapped) missionComponent->Progress(eMissionTaskType::RACING, LWOOBJID_EMPTY, (LWOOBJID)eRacingTaskParam::MODULAR_BUILDING);
if (count >= 7 && everyPieceSwapped) missionComponent->Progress(eMissionTaskType::RACING, LWOOBJID_EMPTY, static_cast<LWOOBJID>(eRacingTaskParam::MODULAR_BUILDING));
}
}

View File

@@ -74,6 +74,7 @@ namespace GameMessages {
int iIndex = 0, int iDesiredWaypointIndex = 1, int nextIndex = 1,
eMovementPlatformState movementState = eMovementPlatformState::Moving);
void SendResetMissions(Entity* entity, const SystemAddress& sysAddr, const int32_t missionid = -1);
void SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr);
void SendServerDoneLoadingAllObjects(Entity* entity, const SystemAddress& sysAddr);
void SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLevel level);

View File

@@ -423,25 +423,16 @@ void Item::DisassembleModel(uint32_t numToDismantle) {
if (renderAssetSplit.empty()) return;
std::string lxfmlPath = "BrickModels" + lxfmlFolderName + "/" + GeneralUtils::SplitString(renderAssetSplit.back(), '.').at(0) + ".lxfml";
auto buffer = Game::assetManager->GetFileAsBuffer(lxfmlPath.c_str());
auto file = Game::assetManager->GetFile(lxfmlPath.c_str());
if (!buffer.m_Success) {
if (!file) {
LOG("Failed to load %s to disassemble model into bricks, check that this file exists", lxfmlPath.c_str());
return;
}
std::istream file(&buffer);
if (!file.good()) {
buffer.close();
return;
}
std::stringstream data;
data << file.rdbuf();
buffer.close();
uint32_t fileSize;
file.seekg(0, std::ios::end);
fileSize = static_cast<uint32_t>(file.tellg());

View File

@@ -324,14 +324,9 @@ void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress&
}
ControlBehaviors::ControlBehaviors() {
auto blocksDefStreamBuffer = Game::assetManager->GetFileAsBuffer("ui\\ingame\\blocksdef.xml");
if (!blocksDefStreamBuffer.m_Success) {
LOG("failed to open blocksdef");
return;
}
std::istream blocksBuffer(&blocksDefStreamBuffer);
if (!blocksBuffer.good()) {
LOG("Blocks buffer is not good!");
auto blocksBuffer = Game::assetManager->GetFile("ui\\ingame\\blocksdef.xml");
if (!blocksBuffer) {
LOG("Failed to open blocksdef.xml");
return;
}
@@ -342,7 +337,7 @@ ControlBehaviors::ControlBehaviors() {
std::string buffer{};
bool commentBlockStart = false;
while (std::getline(blocksBuffer, read)) {
// tinyxml2 should handle comment blocks but the client has one that fails the processing.
// tinyxml2 should handle comment blocks but the client has one that fails the processing.
// This preprocessing just removes all comments from the read file out of an abundance of caution.
if (read.find("<!--") != std::string::npos) {
commentBlockStart = true;

View File

@@ -17,26 +17,18 @@ const BrickList& BrickDatabase::GetBricks(const LxfmlPath& lxfmlPath) {
return cached->second;
}
AssetMemoryBuffer buffer = Game::assetManager->GetFileAsBuffer((lxfmlPath).c_str());
auto file = Game::assetManager->GetFile((lxfmlPath).c_str());
if (!buffer.m_Success) {
return emptyCache;
}
std::istream file(&buffer);
if (!file.good()) {
if (!file) {
return emptyCache;
}
std::stringstream data;
data << file.rdbuf();
if (data.str().empty()) {
buffer.close();
return emptyCache;
}
buffer.close();
auto* doc = new tinyxml2::XMLDocument();
if (doc->Parse(data.str().c_str(), data.str().size()) != 0) {
delete doc;

View File

@@ -288,11 +288,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
return;
}
if (chatCommand == "leave-zone") {
if (chatCommand == "leave-zone" || chatCommand == "leavezone") {
const auto currentZone = Game::zoneManager->GetZone()->GetZoneID().GetMapID();
LWOMAPID newZone = 0;
if (currentZone % 100 == 0) {
if (currentZone == 1001 || currentZone % 100 == 0) {
ChatPackets::SendSystemMessage(sysAddr, u"You are not in an instanced zone.");
return;
} else {
@@ -347,6 +347,17 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
});
}
if (chatCommand == "resetmission") {
uint32_t missionId;
if (!GeneralUtils::TryParse(args[0], missionId)) {
ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission ID.");
return;
}
auto* missionComponent = entity->GetComponent<MissionComponent>();
if (!missionComponent) return;
missionComponent->ResetMission(missionId);
}
if (user->GetMaxGMLevel() == eGameMasterLevel::CIVILIAN || entity->GetGMLevel() >= eGameMasterLevel::CIVILIAN) {
if (chatCommand == "die") {
entity->Smash(entity->GetObjectID());
@@ -608,15 +619,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (args[0].find("/") != std::string::npos) return;
if (args[0].find("\\") != std::string::npos) return;
auto buf = Game::assetManager->GetFileAsBuffer(("macros/" + args[0] + ".scm").c_str());
auto infile = Game::assetManager->GetFile(("macros/" + args[0] + ".scm").c_str());
if (!buf.m_Success) {
if (!infile) {
ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?");
return;
}
std::istream infile(&buf);
if (infile.good()) {
std::string line;
while (std::getline(infile, line)) {
@@ -626,8 +635,6 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?");
}
buf.close();
return;
}

View File

@@ -169,8 +169,8 @@ int main(int argc, char** argv) {
(BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").c_str(),
(Game::assetManager->GetResPath() / "cdclient.fdb").c_str());
AssetMemoryBuffer cdClientBuffer = Game::assetManager->GetFileAsBuffer("cdclient.fdb");
if (!cdClientBuffer.m_Success) {
auto cdclientStream = Game::assetManager->GetFile("cdclient.fdb");
if (!cdclientStream) {
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "cdclient.fdb").c_str());
throw std::runtime_error("Aborting initialization due to missing cdclient.fdb.");
}
@@ -178,11 +178,10 @@ int main(int argc, char** argv) {
LOG("Found %s. Converting to SQLite", (Game::assetManager->GetResPath() / "cdclient.fdb").c_str());
Game::logger->Flush();
if (FdbToSqlite::Convert((BinaryPathFinder::GetBinaryDir() / "resServer").string()).ConvertDatabase(cdClientBuffer) == false) {
if (FdbToSqlite::Convert((BinaryPathFinder::GetBinaryDir() / "resServer").string()).ConvertDatabase(cdclientStream) == false) {
LOG("Failed to convert fdb to sqlite.");
return EXIT_FAILURE;
}
cdClientBuffer.close();
}
}

View File

@@ -223,7 +223,7 @@ void AuthPackets::SendLoginResponse(dServer* server, const SystemAddress& sysAdd
server->Send(&packet, sysAddr, false);
//Inform the master server that we've created a session for this user:
{
if (responseCode == eLoginResponse::SUCCESS) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SET_SESSION_KEY);
bitStream.Write(sessionKey);

View File

@@ -31,7 +31,7 @@ void MasterPackets::SendZoneTransferRequest(dServer* server, uint64_t requestID,
BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_ZONE_TRANSFER);
bitStream.Write(requestID);
bitStream.Write(static_cast<uint8_t>(mythranShift));
bitStream.Write<uint8_t>(mythranShift);
bitStream.Write(zoneID);
bitStream.Write(cloneID);
@@ -58,7 +58,7 @@ void MasterPackets::SendZoneRequestPrivate(dServer* server, uint64_t requestID,
BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_PRIVATE_ZONE);
bitStream.Write(requestID);
bitStream.Write(static_cast<uint8_t>(mythranShift));
bitStream.Write<uint8_t>(mythranShift);
bitStream.Write<uint32_t>(password.size());
for (auto character : password) {
@@ -83,11 +83,11 @@ void MasterPackets::SendZoneTransferResponse(dServer* server, const SystemAddres
BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_ZONE_TRANSFER_RESPONSE);
bitStream.Write(requestID);
bitStream.Write(static_cast<uint8_t>(mythranShift));
bitStream.Write<uint8_t>(mythranShift);
bitStream.Write(zoneID);
bitStream.Write(zoneInstance);
bitStream.Write(zoneClone);
bitStream.Write(static_cast<uint16_t>(serverPort));
bitStream.Write<uint16_t>(serverPort);
bitStream.Write(LUString(serverIP, static_cast<uint32_t>(serverIP.size() + 1)));
server->Send(&bitStream, sysAddr, false);

View File

@@ -21,19 +21,19 @@ void WorldPackets::SendLoadStaticZone(const SystemAddress& sysAddr, float x, flo
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::LOAD_STATIC_ZONE);
auto zone = Game::zoneManager->GetZone()->GetZoneID();
bitStream.Write(static_cast<uint16_t>(zone.GetMapID()));
bitStream.Write(static_cast<uint16_t>(zone.GetInstanceID()));
//bitStream.Write(static_cast<uint32_t>(zone.GetCloneID()));
bitStream.Write<uint16_t>(zone.GetMapID());
bitStream.Write<uint16_t>(zone.GetInstanceID());
//bitStream.Write<uint32_t>(zone.GetCloneID());
bitStream.Write(0);
bitStream.Write(checksum);
bitStream.Write(static_cast<uint16_t>(0)); // ??
bitStream.Write<uint16_t>(0); // ??
bitStream.Write(x);
bitStream.Write(y);
bitStream.Write(z);
bitStream.Write(static_cast<uint32_t>(0)); // Change this to eventually use 4 on activity worlds
bitStream.Write<uint32_t>(0); // Change this to eventually use 4 on activity worlds
SEND_PACKET;
}
@@ -45,18 +45,18 @@ void WorldPackets::SendCharacterList(const SystemAddress& sysAddr, User* user) {
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHARACTER_LIST_RESPONSE);
std::vector<Character*> characters = user->GetCharacters();
bitStream.Write(static_cast<uint8_t>(characters.size()));
bitStream.Write(static_cast<uint8_t>(0)); //character index in front, just picking 0
bitStream.Write<uint8_t>(characters.size());
bitStream.Write<uint8_t>(0); //character index in front, just picking 0
for (uint32_t i = 0; i < characters.size(); ++i) {
bitStream.Write(characters[i]->GetObjectID());
bitStream.Write(static_cast<uint32_t>(0));
bitStream.Write<uint32_t>(0);
bitStream.Write(LUWString(characters[i]->GetName()));
bitStream.Write(LUWString(characters[i]->GetUnapprovedName()));
bitStream.Write(static_cast<uint8_t>(characters[i]->GetNameRejected()));
bitStream.Write(static_cast<uint8_t>(false));
bitStream.Write<uint8_t>(characters[i]->GetNameRejected());
bitStream.Write<uint8_t>(false);
bitStream.Write(LUString("", 10));
@@ -70,16 +70,16 @@ void WorldPackets::SendCharacterList(const SystemAddress& sysAddr, User* user) {
bitStream.Write(characters[i]->GetEyebrows());
bitStream.Write(characters[i]->GetEyes());
bitStream.Write(characters[i]->GetMouth());
bitStream.Write(static_cast<uint32_t>(0));
bitStream.Write<uint32_t>(0);
bitStream.Write(static_cast<uint16_t>(characters[i]->GetZoneID()));
bitStream.Write(static_cast<uint16_t>(characters[i]->GetZoneInstance()));
bitStream.Write<uint16_t>(characters[i]->GetZoneID());
bitStream.Write<uint16_t>(characters[i]->GetZoneInstance());
bitStream.Write(characters[i]->GetZoneClone());
bitStream.Write(characters[i]->GetLastLogin());
const auto& equippedItems = characters[i]->GetEquippedItems();
bitStream.Write(static_cast<uint16_t>(equippedItems.size()));
bitStream.Write<uint16_t>(equippedItems.size());
for (uint32_t j = 0; j < equippedItems.size(); ++j) {
bitStream.Write(equippedItems[j]);
@@ -106,7 +106,7 @@ void WorldPackets::SendCharacterRenameResponse(const SystemAddress& sysAddr, eRe
void WorldPackets::SendCharacterDeleteResponse(const SystemAddress& sysAddr, bool response) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::DELETE_CHARACTER_RESPONSE);
bitStream.Write(static_cast<uint8_t>(response));
bitStream.Write<uint8_t>(response);
SEND_PACKET;
}
@@ -115,8 +115,8 @@ void WorldPackets::SendTransferToWorld(const SystemAddress& sysAddr, const std::
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TRANSFER_TO_WORLD);
bitStream.Write(LUString(serverIP));
bitStream.Write(static_cast<uint16_t>(serverPort));
bitStream.Write(static_cast<uint8_t>(mythranShift));
bitStream.Write<uint16_t>(serverPort);
bitStream.Write<uint8_t>(mythranShift);
SEND_PACKET;
}
@@ -124,7 +124,7 @@ void WorldPackets::SendTransferToWorld(const SystemAddress& sysAddr, const std::
void WorldPackets::SendServerState(const SystemAddress& sysAddr) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::SERVER_STATES);
bitStream.Write(static_cast<uint8_t>(1)); //If the server is receiving this request, it probably is ready anyway.
bitStream.Write<uint8_t>(1); //If the server is receiving this request, it probably is ready anyway.
SEND_PACKET;
}
@@ -204,8 +204,8 @@ void WorldPackets::SendChatModerationResponse(const SystemAddress& sysAddr, bool
bitStream.Write<uint8_t>(unacceptedItems.empty()); // Is sentence ok?
bitStream.Write<uint16_t>(0x16); // Source ID, unknown
bitStream.Write(static_cast<uint8_t>(requestID)); // request ID
bitStream.Write(static_cast<char>(0)); // chat mode
bitStream.Write<uint8_t>(requestID); // request ID
bitStream.Write<char>(0); // chat mode
bitStream.Write(LUWString(receiver, 42)); // receiver name

View File

@@ -3,6 +3,7 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL
"BaseInteractDropLootServer.cpp"
"Binoculars.cpp"
"ExplodingAsset.cpp"
"FrictionVolumeServer.cpp"
"ForceVolumeServer.cpp"
"GrowingFlower.cpp"
"ImaginationBackpackHealServer.cpp"
@@ -17,6 +18,8 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL
"StoryBoxInteractServer.cpp"
"TokenConsoleServer.cpp"
"TouchMissionUpdateServer.cpp"
"VisToggleNotifierServer.cpp"
"NTNaomiDirtServer.cpp"
"WishingWellServer.cpp")
add_subdirectory(Ninjago)

View File

@@ -0,0 +1,19 @@
#include "FrictionVolumeServer.h"
#include "PhantomPhysicsComponent.h"
#include "ePhysicsEffectType.h"
#include "Game.h"
#include "EntityManager.h"
void FrictionVolumeServer::OnStartup(Entity* self) {
auto frictionAmount = self->GetVar<float>(u"FrictionAmt");
if (frictionAmount == 0.0f) frictionAmount = DefaultFrictionAmount;
auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>();
if (!phantomPhysicsComponent) return;
phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::FRICTION);
phantomPhysicsComponent->SetDirectionalMultiplier(frictionAmount);
phantomPhysicsComponent->SetPhysicsEffectActive(true);
Game::entityManager->SerializeEntity(self);
}

View File

@@ -0,0 +1,13 @@
#ifndef __FRICTIONVOLUMESERVER__H__
#define __FRICTIONVOLUMESERVER__H__
#include "CppScripts.h"
class FrictionVolumeServer : public CppScripts::Script {
public:
void OnStartup(Entity* self) override;
private:
const float DefaultFrictionAmount = 1.5f;
};
#endif //!__FRICTIONVOLUMESERVER__H__

View File

@@ -0,0 +1,14 @@
#include "NTNaomiDirtServer.h"
namespace {
std::map<int32_t, std::string> VisibilityMissionTable = {
{1253, std::string("Dirt_Clouds_Sent")},
{1276, std::string("Dirt_Clouds_Assem")},
{1277, std::string("Dirt_Clouds_Para")},
{1283, std::string("Dirt_Clouds_Halls")}
};
};
void NTNaomiDirtServer::OnStartup(Entity* self) {
SetGameVariables(VisibilityMissionTable);
}

View File

@@ -0,0 +1,11 @@
#ifndef __NTNAOMIDIRTSERVER__H__
#define __NTNAOMIDIRTSERVER__H__
#include "VisToggleNotifierServer.h"
class NTNaomiDirtServer : public VisToggleNotifierServer {
public:
void OnStartup(Entity* self) override;
};
#endif //!__NTNAOMIDIRTSERVER__H__

View File

@@ -0,0 +1,23 @@
#include "VisToggleNotifierServer.h"
#include "eMissionState.h"
#include "Game.h"
#include "dZoneManager.h"
void VisToggleNotifierServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionId, eMissionState missionState) {
auto itr = m_GameVariables.find(missionId);
if (itr != m_GameVariables.end()) {
bool visible = true;
if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) {
visible = false;
}
auto spawners = Game::zoneManager->GetSpawnersByName(itr->second);
if (spawners.empty()) return;
for (const auto spawner : spawners) {
auto spawnedObjIds = spawner->GetSpawnedObjectIDs();
for (const auto& objId : spawnedObjIds) {
GameMessages::SendNotifyClientObject(objId, u"SetVisibility", visible);
}
}
}
}

View File

@@ -0,0 +1,15 @@
#ifndef __VISTOGGLENOTIFIERSERVER__H__
#define __VISTOGGLENOTIFIERSERVER__H__
#include "CppScripts.h"
class VisToggleNotifierServer : public CppScripts::Script {
public:
void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override;
protected:
void SetGameVariables(std::map<int32_t, std::string>& gameVariables) { m_GameVariables = gameVariables; }
private:
std::map<int32_t, std::string> m_GameVariables;
};
#endif //!__VISTOGGLENOTIFIERSERVER__H__

View File

@@ -18,9 +18,12 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_NT
"NtXRayServer.cpp"
"NtSleepingGuard.cpp"
"NtImagimeterVisibility.cpp"
"NTPipeVisibilityServer.cpp"
"NtSentinelWalkwayServer.cpp"
"NtDarkitectRevealServer.cpp"
"NtParadoxTeleServer.cpp"
"NtVentureSpeedPadServer.cpp"
"NtVentureCannonServer.cpp"
"NtBcSubmitServer.cpp"
"NtNaomiBreadcrumbServer.cpp"
PARENT_SCOPE)

View File

@@ -0,0 +1,15 @@
#include "NTPipeVisibilityServer.h"
#include "Entity.h"
#include "Character.h"
void NTPipeVisibilityServer::OnRebuildComplete(Entity* self, Entity* target) {
const auto flag = self->GetVar<int32_t>(u"flag");
if (flag == 0) return;
auto* character = target->GetCharacter();
if (!character) return;
character->SetPlayerFlag(flag, true);
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PipeBuilt");
}

View File

@@ -0,0 +1,11 @@
#ifndef __NTPIPEVISIBILITYSERVER__H__
#define __NTPIPEVISIBILITYSERVER__H__
#include "CppScripts.h"
class NTPipeVisibilityServer : public CppScripts::Script {
public:
void OnRebuildComplete(Entity* self, Entity* target) override;
};
#endif //!__NTPIPEVISIBILITYSERVER__H__

View File

@@ -0,0 +1,34 @@
#include "NtBcSubmitServer.h"
#include <cstdint>
#include <map>
#include "Entity.h"
#include "MissionComponent.h"
// https://explorer.lu/missions/
// Key is the main mission, value is the breadcrumb mission to reset upon Mission Dialogue Ok.
// To see the actual missions, just append the number to the end of the URL.
namespace {
std::map<uint32_t, uint32_t> ResetMissionsTable = {
{999, 1335},
{1002, 1355},
{1006, 1349},
{1009, 1348},
{1379, 1335},
{1380, 1355},
{1378, 1349},
{1377, 1348},
};
}
void NtBcSubmitServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) {
auto* missionComponent = target->GetComponent<MissionComponent>();
if (!missionComponent) return;
auto it = ResetMissionsTable.find(missionID);
if (it == ResetMissionsTable.end()) return;
const auto missionToReset = it->second;
missionComponent->ResetMission(missionToReset);
}

View File

@@ -0,0 +1,11 @@
#ifndef __NTBCSUBMITSERVER__H__
#define __NTBCSUBMITSERVER__H__
#include "CppScripts.h"
class NtBcSubmitServer : public virtual CppScripts::Script {
public:
void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override;
};
#endif //!__NTBCSUBMITSERVER__H__

View File

@@ -37,4 +37,5 @@ void NtDukeServer::OnMissionDialogueOK(Entity* self, Entity* target, int mission
inventoryComponent->RemoveItem(m_SwordLot, lotCount);
}
}
NtBcSubmitServer::OnMissionDialogueOK(self, target, missionID, missionState);
}

View File

@@ -1,7 +1,8 @@
#pragma once
#include "NtFactionSpyServer.h"
#include "NtBcSubmitServer.h"
class NtDukeServer : public NtFactionSpyServer {
class NtDukeServer : public NtFactionSpyServer, public NtBcSubmitServer {
void SetVariables(Entity* self) override;
void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override;
const uint32_t m_SwordMissionID = 1448;

View File

@@ -1,6 +1,7 @@
#pragma once
#include "NtFactionSpyServer.h"
#include "NtBcSubmitServer.h"
class NtHaelServer : public NtFactionSpyServer {
class NtHaelServer : public NtFactionSpyServer, public NtBcSubmitServer {
void SetVariables(Entity* self) override;
};

View File

@@ -0,0 +1,43 @@
#include "NtNaomiBreadcrumbServer.h"
#include <map>
#include "eMissionState.h"
#include "MissionComponent.h"
// https://explorer.lu/missions/
// Key is the main mission, value is the breadcrumb mission to reset upon Mission Dialogue Ok.
// To see the actual missions, just append the number to the end of the URL.
namespace {
std::map<int32_t, std::vector<int32_t>> CompleteBcMissionTable = {
{1377, {1378, 1379, 1380, 1349, 1335, 1355}},
{1378, {1377, 1379, 1380, 1348, 1335, 1355}},
{1379, {1377, 1378, 1380, 1348, 1349, 1355}},
{1380, {1377, 1378, 1379, 1348, 1349, 1335}},
};
std::map<int32_t, int32_t> MatchingBCTable = {
{1377, 1348},
{1378, 1349},
{1379, 1335},
{1380, 1355}
};
}
void NtNaomiBreadcrumbServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) {
auto* missionComponent = target->GetComponent<MissionComponent>();
if (!missionComponent) return;
auto itr = MatchingBCTable.find(missionID);
if (itr == MatchingBCTable.end()) return;
missionComponent->AcceptMission(itr->second);
auto it = CompleteBcMissionTable.find(missionID);
if (it == CompleteBcMissionTable.end()) return;
if (missionState == eMissionState::AVAILABLE || missionState == eMissionState::COMPLETE_AVAILABLE) {
for (const auto& bcMission : it->second) {
missionComponent->ResetMission(bcMission);
}
}
}

View File

@@ -0,0 +1,11 @@
#ifndef __NTNAOMIBREADCRUMBSERVER__H__
#define __NTNAOMIBREADCRUMBSERVER__H__
#include "CppScripts.h"
class NtNaomiBreadcrumbServer : public CppScripts::Script {
public:
void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override;
};
#endif //!__NTNAOMIBREADCRUMBSERVER__H__

View File

@@ -1,7 +1,8 @@
#pragma once
#include "NtFactionSpyServer.h"
#include "NtBcSubmitServer.h"
class NtOverbuildServer : public NtFactionSpyServer {
class NtOverbuildServer : public NtFactionSpyServer, public NtBcSubmitServer {
void SetVariables(Entity* self) override;
const std::u16string m_OtherEntitiesGroupVariable = u"SpyConvo2Group";
};

View File

@@ -11,4 +11,5 @@ void NtVandaServer::OnMissionDialogueOK(Entity* self, Entity* target, int missio
inventoryComponent->RemoveItem(alienPartLot, 1);
}
}
NtBcSubmitServer::OnMissionDialogueOK(self, target, missionID, missionState);
}

View File

@@ -1,7 +1,8 @@
#pragma once
#include "CppScripts.h"
#include "NtBcSubmitServer.h"
class NtVandaServer : public CppScripts::Script {
class NtVandaServer : public NtBcSubmitServer {
void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override;
const uint32_t m_AlienPartMissionID = 1183;
const std::vector<LOT> m_AlienPartLots = { 12479, 12480, 12481 };

View File

@@ -209,6 +209,11 @@
#include "NtXRayServer.h"
#include "NtSleepingGuard.h"
#include "NtImagimeterVisibility.h"
#include "FrictionVolumeServer.h"
#include "NTPipeVisibilityServer.h"
#include "NTNaomiDirtServer.h"
#include "MinigameBlueMark.h"
#include "NtNaomiBreadcrumbServer.h"
// DLU Scripts
#include "DLUVanityNPC.h"
@@ -311,6 +316,7 @@
#include "WildNinjaStudent.h"
#include "WildNinjaSensei.h"
#include "WildNinjaBricks.h"
#include "VisToggleNotifierServer.h"
namespace {
InvalidScript* invalidToReturn = new InvalidScript();
@@ -694,19 +700,30 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr
script = new NtDukeServer();
else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_HAEL_SERVER.lua")
script = new NtHaelServer();
else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_FACTION_SPY_SERVER.lua")
script = new NtFactionSpyServer();
else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_OVERBUILD_SERVER.lua")
script = new NtOverbuildServer();
else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_VANDA_SERVER.lua")
script = new NtVandaServer();
else if (scriptName == "scripts\\02_server\\Map\\General\\L_FORCE_VOLUME_SERVER.lua")
script = new ForceVolumeServer();
else if (scriptName == "scripts\\02_server\\Map\\General\\L_FRICTION_VOLUME_SERVER.lua")
script = new FrictionVolumeServer();
else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_XRAY_SERVER.lua")
script = new NtXRayServer();
else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_SLEEPING_GUARD.lua")
script = new NtSleepingGuard();
else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_IMAGIMETER_VISIBILITY_SERVER.lua") {
else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_IMAGIMETER_VISIBILITY_SERVER.lua")
script = new NTImagimeterVisibility();
}
else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_PIPE_VISIBILITY_SERVER.lua")
script = new NTPipeVisibilityServer();
else if (scriptName == "scripts\\ai\\MINIGAME\\Objects\\MINIGAME_BLUE_MARK.lua")
script = new MinigameBlueMark();
else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_NAOMI_BREADCRUMB_SERVER.lua")
script = new NtNaomiBreadcrumbServer();
else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_NAOMI_DIRT_SERVER.lua")
script = new NTNaomiDirtServer();
//AM:
else if (scriptName == "scripts\\02_server\\Map\\AM\\L_AM_CONSOLE_TELEPORT_SERVER.lua")

View File

@@ -12,7 +12,7 @@ struct SpyData {
uint32_t missionID;
};
class NtFactionSpyServer : public CppScripts::Script {
class NtFactionSpyServer : public virtual CppScripts::Script {
void OnStartup(Entity* self) override;
void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override;
void OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, const std::u16string& pathName, float_t pathTime, float_t totalTime, int32_t waypoint) override;

View File

@@ -6,4 +6,10 @@ foreach(file ${DSCRIPTS_SOURCES_AI_MINIGAME_SG_GF})
set(DSCRIPTS_SOURCES_AI_MINIGAME ${DSCRIPTS_SOURCES_AI_MINIGAME} "SG_GF/${file}")
endforeach()
add_subdirectory(Objects)
foreach(file ${DSCRIPTS_SOURCES_AI_MINIGAME_OBJECTS})
set(DSCRIPTS_SOURCES_AI_MINIGAME ${DSCRIPTS_SOURCES_AI_MINIGAME} "Objects/${file}")
endforeach()
set(DSCRIPTS_SOURCES_AI_MINIGAME ${DSCRIPTS_SOURCES_AI_MINIGAME} PARENT_SCOPE)

View File

@@ -0,0 +1,4 @@
SET(DSCRIPTS_SOURCES_AI_MINIGAME_OBJECTS
"MinigameBlueMark.cpp"
PARENT_SCOPE
)

View File

@@ -0,0 +1,7 @@
#include "MinigameBlueMark.h"
#include "Game.h"
#include "dZoneManager.h"
void MinigameBlueMark::OnStartup(Entity* self) {
Game::zoneManager->GetZoneControlObject()->NotifyObject(self, "Blue_Mark");
}

View File

@@ -0,0 +1,6 @@
#include "CppScripts.h"
class MinigameBlueMark : public CppScripts::Script {
public:
void OnStartup(Entity* self) override;
};

View File

@@ -1040,6 +1040,13 @@ void SGCannon::ResetVars(Entity* self) {
self->SetVar<std::vector<LOT>>(RewardsVariable, {});
self->SetVar<uint32_t>(TotalScoreVariable, 0);
self->SetVar<uint32_t>(u"m_curStreak", 0);
self->SetNetworkVar<float>(u"SuperChargeBar", 0);
self->SetVar<uint32_t>(u"LastSuperTotal", 0);
self->SetNetworkVar<float>(u"SuperChargeBar", 0.0f);
self->SetNetworkVar<bool>(u"ShowStreak", 0);
self->SetNetworkVar<bool>(u"UnMarkAll", true);
const_cast<std::vector<SGEnemy>&>(self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable)).clear();
self->SetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable, {});

View File

@@ -76,6 +76,7 @@
#include "EntityManager.h"
#include "CheatDetection.h"
#include "eGameMasterLevel.h"
#include "StringifiedEnum.h"
namespace Game {
Logger* logger = nullptr;
@@ -216,7 +217,7 @@ int main(int argc, char** argv) {
uint32_t chatPort = 1501;
if (Game::config->GetValue("chat_server_port") != "") chatPort = std::atoi(Game::config->GetValue("chat_server_port").c_str());
auto chatSock = SocketDescriptor(uint16_t(ourPort + 2), 0);
auto chatSock = SocketDescriptor(static_cast<uint16_t>(ourPort + 2), 0);
Game::chatServer = RakNetworkFactory::GetRakPeerInterface();
Game::chatServer->Startup(1, 30, &chatSock, 1);
Game::chatServer->Connect(masterIP.c_str(), chatPort, "3.25 ND1", 8);
@@ -1244,11 +1245,9 @@ void HandlePacket(Packet* packet) {
}
default:
if (packet->bitSize < (16 + sizeof(uint32_t) * 8)) break;
uint32_t messageId = *reinterpret_cast<uint32_t*>(&packet->data[3]);
const char* messageIdString = magic_enum::enum_name(static_cast<eWorldMessageType>(messageId)).data();
LOG("Unknown world packet received: (%4i) %s", messageId, messageIdString);
const auto messageId = *reinterpret_cast<eWorldMessageType*>(&packet->data[3]);
const std::string_view messageIdString = StringifiedEnum::ToString(messageId);
LOG("Unknown world packet received: %4i, %s", messageId, messageIdString.data());
}
}

View File

@@ -16,36 +16,20 @@
#include "AssetManager.h"
#include "dConfig.h"
void Level::SceneObjectDataChunk::PrintAllObjects() const {
for (const auto& [id, sceneObj] : objects) {
LOG("ID: %d LOT: %d", id, sceneObj.lot);
}
}
Level::Level(Zone* parentZone, const std::string& filepath) {
m_ParentZone = parentZone;
auto buffer = Game::assetManager->GetFileAsBuffer(filepath.c_str());
auto stream = Game::assetManager->GetFile(filepath.c_str());
if (!buffer.m_Success) {
if (!stream) {
LOG("Failed to load %s", filepath.c_str());
return;
}
std::istream file(&buffer);
ReadChunks(file);
buffer.close();
ReadChunks(stream);
}
Level::~Level() {
for (auto& [id, header] : m_ChunkHeaders) {
if (header.id == Level::ChunkTypeID::FileInfo) delete header.fileInfo;
if (header.id == Level::ChunkTypeID::SceneObjectData) delete header.sceneObjects;
}
}
void Level::MakeSpawner(SceneObject obj){
void Level::MakeSpawner(SceneObject obj) {
SpawnerInfo spawnInfo = SpawnerInfo();
SpawnerNode* node = new SpawnerNode();
spawnInfo.templateID = obj.lot;
@@ -56,7 +40,7 @@ void Level::MakeSpawner(SceneObject obj){
node->config = obj.settings;
spawnInfo.nodes.push_back(node);
for (LDFBaseData* data : obj.settings) {
if (data) {
if (!data) continue;
if (data->GetKey() == u"spawntemplate") {
spawnInfo.templateID = std::stoi(data->GetValueAsString());
}
@@ -99,7 +83,7 @@ void Level::MakeSpawner(SceneObject obj){
if (data->GetKey() == u"groupID") { // Load object groups
std::string groupStr = data->GetValueAsString();
spawnInfo.groups = GeneralUtils::SplitString(groupStr, ';');
spawnInfo.groups.erase(spawnInfo.groups.end() - 1);
if (spawnInfo.groups.back().empty()) spawnInfo.groups.erase(spawnInfo.groups.end() - 1);
}
if (data->GetKey() == u"no_auto_spawn") {
spawnInfo.noAutoSpawn = static_cast<LDFData<bool>*>(data)->GetValue();
@@ -111,16 +95,8 @@ void Level::MakeSpawner(SceneObject obj){
spawnInfo.spawnActivator = static_cast<LDFData<bool>*>(data)->GetValue();
}
}
}
Game::zoneManager->MakeSpawner(spawnInfo);
}
const void Level::PrintAllObjects() {
for (std::map<uint32_t, Header>::iterator it = m_ChunkHeaders.begin(); it != m_ChunkHeaders.end(); ++it) {
if (it->second.id == Level::ChunkTypeID::SceneObjectData) {
it->second.sceneObjects->PrintAllObjects();
}
}
Game::zoneManager->MakeSpawner(spawnInfo);
}
void Level::ReadChunks(std::istream& file) {
@@ -155,11 +131,10 @@ void Level::ReadChunks(std::istream& file) {
file.seekg(0);
Header header;
header.id = ChunkTypeID::FileInfo; //I guess?
FileInfoChunk* fileInfo = new FileInfoChunk();
BinaryIO::BinaryRead(file, header.chunkVersion);
BinaryIO::BinaryRead(file, header.chunkType);
file.ignore(1);
BinaryIO::BinaryRead(file, fileInfo->revision);
BinaryIO::BinaryRead(file, header.fileInfo.revision);
if (header.chunkVersion >= 45) file.ignore(4);
file.ignore(4 * (4 * 3));
@@ -172,9 +147,7 @@ void Level::ReadChunks(std::istream& file) {
uint32_t s = 0;
BinaryIO::BinaryRead(file, s);
for (uint32_t i = 0; i < s; ++i) {
file.ignore(4); //a uint
file.ignore(4); //two floats
file.ignore(4);
file.ignore(4 * 3); //a uint and two floats
}
}
} else {
@@ -208,7 +181,6 @@ void Level::ReadChunks(std::istream& file) {
BinaryIO::BinaryRead(file, count);
file.ignore(count * 12);
header.fileInfo = fileInfo;
m_ChunkHeaders.insert(std::make_pair(header.id, header));
//Now pretend to be a normal file and read Objects chunk:
@@ -222,20 +194,17 @@ void Level::ReadChunks(std::istream& file) {
}
void Level::ReadFileInfoChunk(std::istream& file, Header& header) {
FileInfoChunk* fi = new FileInfoChunk;
BinaryIO::BinaryRead(file, fi->version);
BinaryIO::BinaryRead(file, fi->revision);
BinaryIO::BinaryRead(file, fi->enviromentChunkStart);
BinaryIO::BinaryRead(file, fi->objectChunkStart);
BinaryIO::BinaryRead(file, fi->particleChunkStart);
header.fileInfo = fi;
BinaryIO::BinaryRead(file, header.fileInfo.version);
BinaryIO::BinaryRead(file, header.fileInfo.revision);
BinaryIO::BinaryRead(file, header.fileInfo.enviromentChunkStart);
BinaryIO::BinaryRead(file, header.fileInfo.objectChunkStart);
BinaryIO::BinaryRead(file, header.fileInfo.particleChunkStart);
//PATCH FOR AG: (messed up file?)
if (header.fileInfo->revision == 3452816845 && m_ParentZone->GetZoneID().GetMapID() == 1100) header.fileInfo->revision = 26;
if (header.fileInfo.revision == 0xCDCDCDCD && m_ParentZone->GetZoneID().GetMapID() == 1100) header.fileInfo.revision = 26;
}
void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) {
SceneObjectDataChunk* chunk = new SceneObjectDataChunk;
uint32_t objectsCount = 0;
BinaryIO::BinaryRead(file, objectsCount);
@@ -249,7 +218,10 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) {
GeneralUtils::TryParse<int32_t>(Game::config->GetValue("version_current"), gating.current);
GeneralUtils::TryParse<int32_t>(Game::config->GetValue("version_minor"), gating.minor);
const auto zoneControlObject = Game::zoneManager->GetZoneControlObject();
DluAssert(zoneControlObject != nullptr);
for (uint32_t i = 0; i < objectsCount; ++i) {
std::u16string ldfString;
SceneObject obj;
BinaryIO::BinaryRead(file, obj.id);
BinaryIO::BinaryRead(file, obj.lot);
@@ -260,6 +232,8 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) {
BinaryIO::BinaryRead(file, obj.position);
BinaryIO::BinaryRead(file, obj.rotation);
BinaryIO::BinaryRead(file, obj.scale);
BinaryIO::ReadString<uint32_t>(file, ldfString);
BinaryIO::BinaryRead(file, obj.value3);
//This is a little bit of a bodge, but because the alpha client (HF) doesn't store the
//spawn position / rotation like the later versions do, we need to check the LOT for the spawn pos & set it.
@@ -268,16 +242,6 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) {
Game::zoneManager->GetZone()->SetSpawnRot(obj.rotation);
}
std::u16string ldfString = u"";
uint32_t length = 0;
BinaryIO::BinaryRead(file, length);
for (uint32_t i = 0; i < length; ++i) {
uint16_t data;
BinaryIO::BinaryRead(file, data);
ldfString.push_back(data);
}
std::string sData = GeneralUtils::UTF16ToWTF8(ldfString);
std::stringstream ssData(sData);
std::string token;
@@ -288,35 +252,40 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) {
obj.settings.push_back(ldfData);
}
BinaryIO::BinaryRead(file, obj.value3);
// Feature gating
bool gated = false;
// We should never have more than 1 zone control object
bool skipLoadingObject = obj.lot == zoneControlObject->GetLOT();
for (LDFBaseData* data : obj.settings) {
if (!data) continue;
if (data->GetKey() == u"gatingOnFeature") {
gating.featureName = data->GetValueAsString();
if (gating.featureName == Game::config->GetValue("event_1")) break;
else if (gating.featureName == Game::config->GetValue("event_2")) break;
else if (gating.featureName == Game::config->GetValue("event_3")) break;
else if (gating.featureName == Game::config->GetValue("event_4")) break;
else if (gating.featureName == Game::config->GetValue("event_5")) break;
else if (gating.featureName == Game::config->GetValue("event_6")) break;
else if (gating.featureName == Game::config->GetValue("event_7")) break;
else if (gating.featureName == Game::config->GetValue("event_8")) break;
if (gating.featureName == Game::config->GetValue("event_1")) continue;
else if (gating.featureName == Game::config->GetValue("event_2")) continue;
else if (gating.featureName == Game::config->GetValue("event_3")) continue;
else if (gating.featureName == Game::config->GetValue("event_4")) continue;
else if (gating.featureName == Game::config->GetValue("event_5")) continue;
else if (gating.featureName == Game::config->GetValue("event_6")) continue;
else if (gating.featureName == Game::config->GetValue("event_7")) continue;
else if (gating.featureName == Game::config->GetValue("event_8")) continue;
else if (!featureGatingTable->FeatureUnlocked(gating)) {
gated = true;
// The feature is not unlocked, so we can skip loading this object
skipLoadingObject = true;
break;
}
}
// If this is a client only object, we can skip loading it
if (data->GetKey() == u"loadOnClientOnly") {
skipLoadingObject = static_cast<bool>(std::stoi(data->GetValueAsString()));
break;
}
}
if (gated) {
if (skipLoadingObject) {
for (auto* setting : obj.settings) {
delete setting;
setting = nullptr;
}
obj.settings.clear();
continue;
}
@@ -331,45 +300,7 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) {
info.rot = obj.rotation;
info.settings = obj.settings;
info.scale = obj.scale;
//Check to see if we shouldn't be loading this:
bool clientOnly = false;
bool serverOnly = false;
std::string featureGate = "";
for (LDFBaseData* data : obj.settings) {
if (data) {
if (data->GetKey() == u"loadOnClientOnly") {
clientOnly = (bool)std::stoi(data->GetValueAsString());
break;
}
if (data->GetKey() == u"loadSrvrOnly") {
serverOnly = (bool)std::stoi(data->GetValueAsString());
break;
}
}
}
if (!clientOnly) {
// We should never have more than 1 zone control object
const auto zoneControlObject = Game::zoneManager->GetZoneControlObject();
if (zoneControlObject != nullptr && info.lot == zoneControlObject->GetLOT())
goto deleteSettings;
Game::entityManager->CreateEntity(info, nullptr);
} else {
deleteSettings:
for (auto* setting : info.settings) {
delete setting;
setting = nullptr;
}
info.settings.clear();
obj.settings.clear();
}
Game::entityManager->CreateEntity(info);
}
}
header.sceneObjects = chunk;
}

View File

@@ -27,33 +27,21 @@ public:
uint32_t particleChunkStart;
};
struct SceneObjectDataChunk {
std::map<LWOOBJID, SceneObject> objects;
void PrintAllObjects() const;
uint32_t GetObjectCount() { return objects.size(); }
};
struct Header {
uint32_t id;
uint16_t chunkVersion;
ChunkTypeID chunkType;
uint32_t size;
uint32_t startPosition;
FileInfoChunk* fileInfo;
SceneObjectDataChunk* sceneObjects;
FileInfoChunk fileInfo;
LWOSCENEID lwoSceneID;
};
public:
Level(Zone* parentZone, const std::string& filepath);
~Level();
static void MakeSpawner(SceneObject obj);
const void PrintAllObjects();
std::map<uint32_t, Header> m_ChunkHeaders;
private:
Zone* m_ParentZone;

View File

@@ -205,6 +205,15 @@ void Spawner::Update(const float deltaTime) {
}
}
std::vector<LWOOBJID> Spawner::GetSpawnedObjectIDs() const {
std::vector<LWOOBJID> ids;
ids.reserve(m_Entities.size());
for (const auto& [objId, spawnerNode] : m_Entities) {
ids.push_back(objId);
}
return ids;
}
void Spawner::NotifyOfEntityDeath(const LWOOBJID& objectID) {
for (std::function<void()> cb : m_SpawnedEntityDieCallbacks) {
cb();

View File

@@ -66,6 +66,7 @@ public:
void SetRespawnTime(float time);
void SetNumToMaintain(int32_t value);
bool GetIsSpawnSmashGroup() const { return m_SpawnSmashFoundGroup; };
std::vector<LWOOBJID> GetSpawnedObjectIDs() const;
SpawnerInfo m_Info;
bool m_Active = true;

View File

@@ -20,7 +20,6 @@
Zone::Zone(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) :
m_ZoneID(mapID, instanceID, cloneID) {
m_NumberOfScenesLoaded = 0;
m_NumberOfObjectsLoaded = 0;
m_NumberOfSceneTransitionsLoaded = 0;
m_CheckSum = 0;
@@ -46,14 +45,13 @@ void Zone::LoadZoneIntoMemory() {
m_ZonePath = m_ZoneFilePath.substr(0, m_ZoneFilePath.rfind('/') + 1);
if (m_ZoneFilePath == "ERR") return;
AssetMemoryBuffer buffer = Game::assetManager->GetFileAsBuffer(m_ZoneFilePath.c_str());
auto file = Game::assetManager->GetFile(m_ZoneFilePath.c_str());
if (!buffer.m_Success) {
if (!file) {
LOG("Failed to load %s", m_ZoneFilePath.c_str());
throw std::runtime_error("Aborting Zone loading due to no Zone File.");
}
std::istream file(&buffer);
if (file) {
BinaryIO::BinaryRead(file, m_FileFormatVersion);
@@ -81,18 +79,10 @@ void Zone::LoadZoneIntoMemory() {
}
//Read generic zone info:
uint8_t stringLength;
BinaryIO::BinaryRead(file, stringLength);
m_ZonePath = BinaryIO::ReadString(file, stringLength);
BinaryIO::BinaryRead(file, stringLength);
m_ZoneRawPath = BinaryIO::ReadString(file, stringLength);
BinaryIO::BinaryRead(file, stringLength);
m_ZoneName = BinaryIO::ReadString(file, stringLength);
BinaryIO::BinaryRead(file, stringLength);
m_ZoneDesc = BinaryIO::ReadString(file, stringLength);
BinaryIO::ReadString<uint8_t>(file, m_ZonePath, BinaryIO::ReadType::String);
BinaryIO::ReadString<uint8_t>(file, m_ZoneRawPath, BinaryIO::ReadType::String);
BinaryIO::ReadString<uint8_t>(file, m_ZoneName, BinaryIO::ReadType::String);
BinaryIO::ReadString<uint8_t>(file, m_ZoneDesc, BinaryIO::ReadType::String);
if (m_FileFormatVersion >= Zone::FileFormatVersion::PreAlpha) {
BinaryIO::BinaryRead(file, m_NumberOfSceneTransitionsLoaded);
@@ -108,59 +98,57 @@ void Zone::LoadZoneIntoMemory() {
uint32_t pathCount;
BinaryIO::BinaryRead(file, pathCount);
m_Paths.reserve(pathCount);
for (uint32_t i = 0; i < pathCount; ++i) LoadPath(file);
for (Path path : m_Paths) {
if (path.pathType == PathType::Spawner) {
SpawnerInfo info = SpawnerInfo();
for (PathWaypoint waypoint : path.pathWaypoints) {
SpawnerNode* node = new SpawnerNode();
node->position = waypoint.position;
node->rotation = waypoint.rotation;
node->nodeID = 0;
node->config = waypoint.config;
if (path.pathType != PathType::Spawner) continue;
SpawnerInfo info = SpawnerInfo();
for (PathWaypoint waypoint : path.pathWaypoints) {
SpawnerNode* node = new SpawnerNode();
node->position = waypoint.position;
node->rotation = waypoint.rotation;
node->nodeID = 0;
node->config = waypoint.config;
for (LDFBaseData* data : waypoint.config) {
if (data) {
if (data->GetKey() == u"spawner_node_id") {
node->nodeID = std::stoi(data->GetValueAsString());
} else if (data->GetKey() == u"spawner_max_per_node") {
node->nodeMax = std::stoi(data->GetValueAsString());
} else if (data->GetKey() == u"groupID") { // Load object group
std::string groupStr = data->GetValueAsString();
info.groups = GeneralUtils::SplitString(groupStr, ';');
info.groups.erase(info.groups.end() - 1);
} else if (data->GetKey() == u"grpNameQBShowBricks") {
if (data->GetValueAsString() == "") continue;
/*std::string groupStr = data->GetValueAsString();
info.groups.push_back(groupStr);*/
info.grpNameQBShowBricks = data->GetValueAsString();
} else if (data->GetKey() == u"spawner_name") {
info.name = data->GetValueAsString();
}
}
for (LDFBaseData* data : waypoint.config) {
if (!data) continue;
if (data->GetKey() == u"spawner_node_id") {
node->nodeID = std::stoi(data->GetValueAsString());
} else if (data->GetKey() == u"spawner_max_per_node") {
node->nodeMax = std::stoi(data->GetValueAsString());
} else if (data->GetKey() == u"groupID") { // Load object group
std::string groupStr = data->GetValueAsString();
info.groups = GeneralUtils::SplitString(groupStr, ';');
if (info.groups.back().empty()) info.groups.erase(info.groups.end() - 1);
} else if (data->GetKey() == u"grpNameQBShowBricks") {
if (data->GetValueAsString().empty()) continue;
/*std::string groupStr = data->GetValueAsString();
info.groups.push_back(groupStr);*/
info.grpNameQBShowBricks = data->GetValueAsString();
} else if (data->GetKey() == u"spawner_name") {
info.name = data->GetValueAsString();
}
info.nodes.push_back(node);
}
info.templateID = path.spawner.spawnedLOT;
info.spawnerID = path.spawner.spawnerObjID;
info.respawnTime = path.spawner.respawnTime;
info.amountMaintained = path.spawner.amountMaintained;
info.maxToSpawn = path.spawner.maxToSpawn;
info.activeOnLoad = path.spawner.spawnerNetActive;
info.isNetwork = true;
Spawner* spawner = new Spawner(info);
Game::zoneManager->AddSpawner(info.spawnerID, spawner);
info.nodes.push_back(node);
}
info.templateID = path.spawner.spawnedLOT;
info.spawnerID = path.spawner.spawnerObjID;
info.respawnTime = path.spawner.respawnTime;
info.amountMaintained = path.spawner.amountMaintained;
info.maxToSpawn = path.spawner.maxToSpawn;
info.activeOnLoad = path.spawner.spawnerNetActive;
info.isNetwork = true;
Spawner* spawner = new Spawner(info);
Game::zoneManager->AddSpawner(info.spawnerID, spawner);
}
}
} else {
LOG("Failed to open: %s", m_ZoneFilePath.c_str());
}
m_ZonePath = m_ZoneFilePath.substr(0, m_ZoneFilePath.rfind('/') + 1);
buffer.close();
}
std::string Zone::GetFilePathForZoneID() {
@@ -180,16 +168,16 @@ std::string Zone::GetFilePathForZoneID() {
uint32_t Zone::CalculateChecksum() {
uint32_t sum1 = 0xffff, sum2 = 0xffff;
for (std::map<LWOSCENEID, uint32_t>::const_iterator it = m_MapRevisions.cbegin(); it != m_MapRevisions.cend(); ++it) {
uint32_t sceneID = it->first.GetSceneID();
for (const auto& [scene, sceneRevision] : m_MapRevisions) {
uint32_t sceneID = scene.GetSceneID();
sum2 += sum1 += (sceneID >> 16);
sum2 += sum1 += (sceneID & 0xffff);
uint32_t layerID = it->first.GetLayerID();
uint32_t layerID = scene.GetLayerID();
sum2 += sum1 += (layerID >> 16);
sum2 += sum1 += (layerID & 0xffff);
uint32_t revision = it->second;
uint32_t revision = sceneRevision;
sum2 += sum1 += (revision >> 16);
sum2 += sum1 += (revision & 0xffff);
}
@@ -201,30 +189,20 @@ uint32_t Zone::CalculateChecksum() {
}
void Zone::LoadLevelsIntoMemory() {
for (std::map<LWOSCENEID, SceneRef>::iterator it = m_Scenes.begin(); it != m_Scenes.end(); ++it) {
if (it->second.level == nullptr) {
it->second.level = new Level(this, m_ZonePath + it->second.filename);
for (auto& [sceneID, scene] : m_Scenes) {
if (scene.level) continue;
scene.level = new Level(this, m_ZonePath + scene.filename);
if (it->second.level->m_ChunkHeaders.size() > 0) {
it->second.level->m_ChunkHeaders.begin()->second.lwoSceneID = it->first;
AddRevision(it->second.level->m_ChunkHeaders.begin()->second.lwoSceneID, it->second.level->m_ChunkHeaders.begin()->second.fileInfo->revision);
}
}
if (scene.level->m_ChunkHeaders.empty()) continue;
scene.level->m_ChunkHeaders.begin()->second.lwoSceneID = sceneID;
AddRevision(scene.level->m_ChunkHeaders.begin()->second.lwoSceneID, scene.level->m_ChunkHeaders.begin()->second.fileInfo.revision);
}
}
void Zone::AddRevision(LWOSCENEID sceneID, uint32_t revision) {
for (std::pair<LWOSCENEID, uint32_t> item : m_MapRevisions) {
if (item.first == sceneID) return;
}
m_MapRevisions[LWOSCENEID(sceneID)] = revision;
}
const void Zone::PrintAllGameObjects() {
for (std::pair<LWOSCENEID, SceneRef> scene : m_Scenes) {
LOG("In sceneID: %i", scene.first.GetSceneID());
scene.second.level->PrintAllObjects();
if (m_MapRevisions.find(sceneID) == m_MapRevisions.end()) {
m_MapRevisions.insert(std::make_pair(sceneID, revision));
}
}
@@ -233,17 +211,10 @@ void Zone::LoadScene(std::istream& file) {
scene.level = nullptr;
LWOSCENEID lwoSceneID(LWOZONEID_INVALID, 0);
uint8_t sceneFilenameLength;
BinaryIO::BinaryRead(file, sceneFilenameLength);
scene.filename = BinaryIO::ReadString(file, sceneFilenameLength);
BinaryIO::ReadString<uint8_t>(file, scene.filename, BinaryIO::ReadType::String);
std::string luTriggersPath = scene.filename.substr(0, scene.filename.size() - 4) + ".lutriggers";
std::vector<LUTriggers::Trigger*> triggers;
if(Game::assetManager->HasFile((m_ZonePath + luTriggersPath).c_str())) triggers = LoadLUTriggers(luTriggersPath, scene.id);
for (LUTriggers::Trigger* trigger : triggers) {
scene.triggers.insert({ trigger->id, trigger });
}
if (Game::assetManager->HasFile((m_ZonePath + luTriggersPath).c_str())) LoadLUTriggers(luTriggersPath, scene);
if (m_FileFormatVersion >= Zone::FileFormatVersion::LatePreAlpha || m_FileFormatVersion < Zone::FileFormatVersion::PrePreAlpha) {
BinaryIO::BinaryRead(file, scene.id);
@@ -253,12 +224,10 @@ void Zone::LoadScene(std::istream& file) {
BinaryIO::BinaryRead(file, scene.sceneType);
lwoSceneID.SetLayerID(scene.sceneType);
uint8_t sceneNameLength;
BinaryIO::BinaryRead(file, sceneNameLength);
scene.name = BinaryIO::ReadString(file, sceneNameLength);
BinaryIO::ReadString<uint8_t>(file, scene.name, BinaryIO::ReadType::String);
}
if (m_FileFormatVersion == Zone::FileFormatVersion::LatePreAlpha){
if (m_FileFormatVersion == Zone::FileFormatVersion::LatePreAlpha) {
BinaryIO::BinaryRead(file, scene.unknown1);
BinaryIO::BinaryRead(file, scene.unknown2);
}
@@ -270,61 +239,51 @@ void Zone::LoadScene(std::istream& file) {
}
m_Scenes.insert(std::make_pair(lwoSceneID, scene));
m_NumberOfScenesLoaded++;
}
std::vector<LUTriggers::Trigger*> Zone::LoadLUTriggers(std::string triggerFile, LWOSCENEID sceneID) {
std::vector<LUTriggers::Trigger*> lvlTriggers;
auto buffer = Game::assetManager->GetFileAsBuffer((m_ZonePath + triggerFile).c_str());
if (!buffer.m_Success) {
LOG("Failed to load %s from disk. Skipping loading triggers", (m_ZonePath + triggerFile).c_str());
return lvlTriggers;
}
std::istream file(&buffer);
void Zone::LoadLUTriggers(std::string triggerFile, SceneRef& scene) {
auto file = Game::assetManager->GetFile((m_ZonePath + triggerFile).c_str());
std::stringstream data;
data << file.rdbuf();
buffer.close();
data.seekg(0, std::ios::end);
int32_t size = data.tellg();
data.seekg(0, std::ios::beg);
if (data.str().size() == 0) return lvlTriggers;
if (size == 0) return;
tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
if (!doc) return lvlTriggers;
tinyxml2::XMLDocument doc;
if (doc->Parse(data.str().c_str(), data.str().size()) == 0) {
//LOG("Loaded LUTriggers from file %s!", triggerFile.c_str());
} else {
if (doc.Parse(data.str().c_str(), size) != tinyxml2::XML_SUCCESS) {
LOG("Failed to load LUTriggers from file %s", triggerFile.c_str());
return lvlTriggers;
return;
}
tinyxml2::XMLElement* triggers = doc->FirstChildElement("triggers");
if (!triggers) return lvlTriggers;
auto* triggers = doc.FirstChildElement("triggers");
if (!triggers) return;
auto currentTrigger = triggers->FirstChildElement("trigger");
auto* currentTrigger = triggers->FirstChildElement("trigger");
while (currentTrigger) {
LUTriggers::Trigger* newTrigger = new LUTriggers::Trigger();
currentTrigger->QueryAttribute("enabled", &newTrigger->enabled);
currentTrigger->QueryAttribute("id", &newTrigger->id);
auto currentEvent = currentTrigger->FirstChildElement("event");
auto* currentEvent = currentTrigger->FirstChildElement("event");
while (currentEvent) {
LUTriggers::Event* newEvent = new LUTriggers::Event();
newEvent->id = TriggerEventType::StringToTriggerEventType(currentEvent->Attribute("id"));
auto currentCommand = currentEvent->FirstChildElement("command");
auto* currentCommand = currentEvent->FirstChildElement("command");
while (currentCommand) {
LUTriggers::Command* newCommand = new LUTriggers::Command();
newCommand->id = TriggerCommandType::StringToTriggerCommandType(currentCommand->Attribute("id"));
newCommand->target = currentCommand->Attribute("target");
if (currentCommand->Attribute("targetName") != NULL) {
if (currentCommand->Attribute("targetName")) {
newCommand->targetName = currentCommand->Attribute("targetName");
}
if (currentCommand->Attribute("args") != NULL) {
} else if (currentCommand->Attribute("args")) {
newCommand->args = currentCommand->Attribute("args");
}
newEvent->commands.push_back(newCommand);
currentCommand = currentCommand->NextSiblingElement("command");
}
@@ -332,19 +291,18 @@ std::vector<LUTriggers::Trigger*> Zone::LoadLUTriggers(std::string triggerFile,
currentEvent = currentEvent->NextSiblingElement("event");
}
currentTrigger = currentTrigger->NextSiblingElement("trigger");
lvlTriggers.push_back(newTrigger);
scene.triggers.insert(std::make_pair(newTrigger->id, newTrigger));
}
delete doc;
return lvlTriggers;
}
LUTriggers::Trigger* Zone::GetTrigger(uint32_t sceneID, uint32_t triggerID) {
if (m_Scenes.find(sceneID) == m_Scenes.end()) return nullptr;
if (m_Scenes[sceneID].triggers.find(triggerID) == m_Scenes[sceneID].triggers.end()) return nullptr;
auto scene = m_Scenes.find(sceneID);
if (scene == m_Scenes.end()) return nullptr;
return m_Scenes[sceneID].triggers[triggerID];
auto trigger = scene->second.triggers.find(triggerID);
if (trigger == scene->second.triggers.end()) return nullptr;
return trigger->second;
}
const Path* Zone::GetPath(std::string name) const {
@@ -360,15 +318,14 @@ const Path* Zone::GetPath(std::string name) const {
void Zone::LoadSceneTransition(std::istream& file) {
SceneTransition sceneTrans;
if (m_FileFormatVersion < Zone::FileFormatVersion::Auramar) {
uint8_t length;
BinaryIO::BinaryRead(file, length);
sceneTrans.name = BinaryIO::ReadString(file, length);
BinaryIO::ReadString<uint8_t>(file, sceneTrans.name, BinaryIO::ReadType::String);
BinaryIO::BinaryRead(file, sceneTrans.width);
}
//BR<42>THER MAY I HAVE SOME L<><4C>PS?
uint8_t loops = (m_FileFormatVersion <= Zone::FileFormatVersion::LatePreAlpha || m_FileFormatVersion >= Zone::FileFormatVersion::Launch) ? 2 : 5;
sceneTrans.points.reserve(loops);
for (uint8_t i = 0; i < loops; ++i) {
sceneTrans.points.push_back(LoadSceneTransitionInfo(file));
}
@@ -388,13 +345,7 @@ void Zone::LoadPath(std::istream& file) {
BinaryIO::BinaryRead(file, path.pathVersion);
uint8_t stringLength;
BinaryIO::BinaryRead(file, stringLength);
for (uint8_t i = 0; i < stringLength; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
path.pathName.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, path.pathName, BinaryIO::ReadType::WideString);
BinaryIO::BinaryRead(file, path.pathType);
BinaryIO::BinaryRead(file, path.flags);
@@ -404,13 +355,7 @@ void Zone::LoadPath(std::istream& file) {
if (path.pathVersion >= 18) {
BinaryIO::BinaryRead(file, path.movingPlatform.timeBasedMovement);
} else if (path.pathVersion >= 13) {
uint8_t count;
BinaryIO::BinaryRead(file, count);
for (uint8_t i = 0; i < count; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
path.movingPlatform.platformTravelSound.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, path.movingPlatform.platformTravelSound, BinaryIO::ReadType::WideString);
}
} else if (path.pathType == PathType::Property) {
BinaryIO::BinaryRead(file, path.property.pathType);
@@ -419,20 +364,8 @@ void Zone::LoadPath(std::istream& file) {
BinaryIO::BinaryRead(file, path.property.associatedZone);
if (path.pathVersion >= 5) {
uint8_t count1;
BinaryIO::BinaryRead(file, count1);
for (uint8_t i = 0; i < count1; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
path.property.displayName.push_back(character);
}
uint32_t count2;
BinaryIO::BinaryRead(file, count2);
for (uint8_t i = 0; i < count2; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
path.property.displayDesc.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, path.property.displayName, BinaryIO::ReadType::WideString);
BinaryIO::ReadString<uint32_t>(file, path.property.displayDesc, BinaryIO::ReadType::WideString);
}
if (path.pathVersion >= 6) BinaryIO::BinaryRead(file, path.property.type);
@@ -449,13 +382,7 @@ void Zone::LoadPath(std::istream& file) {
BinaryIO::BinaryRead(file, path.property.maxBuildHeight);
}
} else if (path.pathType == PathType::Camera) {
uint8_t count;
BinaryIO::BinaryRead(file, count);
for (uint8_t i = 0; i < count; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
path.camera.nextPath.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, path.camera.nextPath, BinaryIO::ReadType::WideString);
if (path.pathVersion >= 14) {
BinaryIO::BinaryRead(file, path.camera.rotatePlayer);
@@ -472,7 +399,7 @@ void Zone::LoadPath(std::istream& file) {
// Read waypoints
BinaryIO::BinaryRead(file, path.waypointCount);
path.pathWaypoints.reserve(path.waypointCount);
for (uint32_t i = 0; i < path.waypointCount; ++i) {
PathWaypoint waypoint = PathWaypoint();
@@ -493,20 +420,8 @@ void Zone::LoadPath(std::istream& file) {
BinaryIO::BinaryRead(file, waypoint.movingPlatform.speed);
BinaryIO::BinaryRead(file, waypoint.movingPlatform.wait);
if (path.pathVersion >= 13) {
uint8_t count1;
BinaryIO::BinaryRead(file, count1);
for (uint8_t i = 0; i < count1; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
waypoint.movingPlatform.departSound.push_back(character);
}
uint8_t count2;
BinaryIO::BinaryRead(file, count2);
for (uint8_t i = 0; i < count2; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
waypoint.movingPlatform.arriveSound.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, waypoint.movingPlatform.departSound, BinaryIO::ReadType::WideString);
BinaryIO::ReadString<uint8_t>(file, waypoint.movingPlatform.arriveSound, BinaryIO::ReadType::WideString);
}
} else if (path.pathType == PathType::Camera) {
BinaryIO::BinaryRead(file, waypoint.camera.time);
@@ -529,22 +444,11 @@ void Zone::LoadPath(std::istream& file) {
uint32_t count;
BinaryIO::BinaryRead(file, count);
for (uint32_t i = 0; i < count; ++i) {
uint8_t count1;
std::string parameter;
BinaryIO::ReadString<uint8_t>(file, parameter, BinaryIO::ReadType::WideString);
std::string value;
BinaryIO::BinaryRead(file, count1);
for (uint8_t i = 0; i < count1; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
parameter.push_back(character);
}
uint8_t count2;
BinaryIO::BinaryRead(file, count2);
for (uint8_t i = 0; i < count2; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
value.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, value, BinaryIO::ReadType::WideString);
LDFBaseData* ldfConfig = nullptr;
if (path.pathType == PathType::Movement || path.pathType == PathType::Rail) {

View File

@@ -210,7 +210,6 @@ public:
void AddRevision(LWOSCENEID sceneID, uint32_t revision);
const LWOZONEID& GetZoneID() const { return m_ZoneID; }
const uint32_t GetChecksum() const { return m_CheckSum; }
const void PrintAllGameObjects();
LUTriggers::Trigger* GetTrigger(uint32_t sceneID, uint32_t triggerID);
const Path* GetPath(std::string name) const;
@@ -228,7 +227,6 @@ public:
private:
LWOZONEID m_ZoneID;
std::string m_ZoneFilePath;
uint32_t m_NumberOfScenesLoaded;
uint32_t m_NumberOfObjectsLoaded;
uint32_t m_NumberOfSceneTransitionsLoaded;
FileFormatVersion m_FileFormatVersion;
@@ -243,18 +241,17 @@ private:
std::string m_ZoneDesc; //Description of the zone by a level designer
std::string m_ZoneRawPath; //Path to the .raw file of this zone.
std::map<LWOSCENEID, SceneRef, mapCompareLwoSceneIDs> m_Scenes;
std::map<LWOSCENEID, SceneRef> m_Scenes;
std::vector<SceneTransition> m_SceneTransitions;
uint32_t m_PathDataLength;
uint32_t m_PathChunkVersion;
std::vector<Path> m_Paths;
std::map<LWOSCENEID, uint32_t, mapCompareLwoSceneIDs> m_MapRevisions; //rhs is the revision!
std::map<LWOSCENEID, uint32_t> m_MapRevisions; //rhs is the revision!
//private ("helper") functions:
void LoadScene(std::istream& file);
std::vector<LUTriggers::Trigger*> LoadLUTriggers(std::string triggerFile, LWOSCENEID sceneID);
void LoadLUTriggers(std::string triggerFile, SceneRef& scene);
void LoadSceneTransition(std::istream& file);
SceneTransitionInfo LoadSceneTransitionInfo(std::istream& file);
void LoadPath(std::istream& file);

View File

@@ -5,10 +5,6 @@
#include "LDFFormat.h"
#include <vector>
struct mapCompareLwoSceneIDs {
bool operator()(const LWOSCENEID& lhs, const LWOSCENEID& rhs) const { return lhs < rhs; }
};
struct SceneObject {
LWOOBJID id;
LOT lot;

View File

@@ -94,33 +94,6 @@ void dZoneManager::LoadZone(const LWOZONEID& zoneID) {
m_pZone = new Zone(zoneID.GetMapID(), zoneID.GetInstanceID(), zoneID.GetCloneID());
}
void dZoneManager::NotifyZone(const dZoneNotifier& notifier, const LWOOBJID& objectID) {
switch (notifier) {
case dZoneNotifier::SpawnedObjectDestroyed:
break;
case dZoneNotifier::SpawnedChildObjectDestroyed:
break;
case dZoneNotifier::ReloadZone:
LOG("Forcing reload of zone %i", m_ZoneID.GetMapID());
LoadZone(m_ZoneID);
m_pZone->Initalize();
break;
case dZoneNotifier::UserJoined:
break;
case dZoneNotifier::UserMoved:
break;
case dZoneNotifier::PrintAllGameObjects:
m_pZone->PrintAllGameObjects();
break;
case dZoneNotifier::InvalidNotifier:
LOG("Got an invalid zone notifier.");
break;
default:
LOG("Unknown zone notifier: %i", int(notifier));
}
}
void dZoneManager::AddSpawner(LWOOBJID id, Spawner* spawner) {
m_Spawners.insert_or_assign(id, spawner);
}

View File

@@ -14,7 +14,6 @@ public:
ReloadZone, //Forces the server and all connects clients to reload the map
UserJoined,
UserMoved,
PrintAllGameObjects, //Using this is a BAD idea in production
InvalidNotifier
};
@@ -30,7 +29,6 @@ public:
Zone* GetZone(); //Gets a pointer to the currently loaded zone.
void LoadZone(const LWOZONEID& zoneID); //Discard the current zone (if any) and loads a new zone.
void NotifyZone(const dZoneNotifier& notifier, const LWOOBJID& objectID); //Notifies the zone of a certain event or command.
void AddSpawner(LWOOBJID id, Spawner* spawner);
LWOZONEID GetZoneID() const;
LWOOBJID MakeSpawner(SpawnerInfo info);

View File

@@ -1,6 +1,7 @@
set(DCOMMONTEST_SOURCES
"AMFDeserializeTests.cpp"
"Amf3Tests.cpp"
"CastUnderlyingTypeTests.cpp"
"HeaderSkipTest.cpp"
"TestCDFeatureGatingTable.cpp"
"TestLDFFormat.cpp"
@@ -11,6 +12,9 @@ set(DCOMMONTEST_SOURCES
"dCommonDependencies.cpp"
)
add_subdirectory(dEnumsTests)
list(APPEND DCOMMONTEST_SOURCES ${DENUMS_TESTS})
# Set our executable
add_executable(dCommonTests ${DCOMMONTEST_SOURCES})

View File

@@ -0,0 +1,24 @@
#include <gtest/gtest.h>
#include "GeneralUtils.h"
#include "eGameMasterLevel.h"
#include "eGameMessageType.h"
#include "eWorldMessageType.h"
#define ASSERT_TYPE_EQ(TYPE, ENUM)\
ASSERT_TRUE(typeid(TYPE) == typeid(GeneralUtils::CastUnderlyingType(static_cast<ENUM>(0))));
#define ASSERT_TYPE_NE(TYPE, ENUM)\
ASSERT_FALSE(typeid(TYPE) == typeid(GeneralUtils::CastUnderlyingType(static_cast<ENUM>(0))));
// Verify that the underlying enum types are being cast correctly
TEST(CastUnderlyingTypeTests, VerifyCastUnderlyingType) {
ASSERT_TYPE_EQ(uint8_t, eGameMasterLevel);
ASSERT_TYPE_EQ(uint16_t, eGameMessageType);
ASSERT_TYPE_EQ(uint32_t, eWorldMessageType)
ASSERT_TYPE_NE(void, eGameMasterLevel);
ASSERT_TYPE_NE(void, eGameMessageType);
ASSERT_TYPE_NE(void, eWorldMessageType)
}

View File

@@ -0,0 +1,10 @@
set(DENUMS_TESTS
"MagicEnumTests.cpp"
)
# Get the folder name and prepend it to the files above
get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
list(TRANSFORM DENUMS_TESTS PREPEND "${thisFolderName}/")
# Export to parent scope
set(DENUMS_TESTS ${DENUMS_TESTS} PARENT_SCOPE)

View File

@@ -0,0 +1,142 @@
#include <chrono>
#include <string>
#include <gtest/gtest.h>
#include "StringifiedEnum.h"
#include "Logger.h"
#include "Game.h"
#include "eGameMessageType.h"
#include "eWorldMessageType.h"
#include "magic_enum.hpp"
#define ENUM_EQ(e, y, z)\
LOG("%s %s", StringifiedEnum::ToString(static_cast<e>(y)).data(), #z);\
ASSERT_STREQ(StringifiedEnum::ToString(static_cast<e>(y)).data(), #z);
#define ENUM_NE(e, y)\
ENUM_EQ(e, y, UNKNOWN);
// Test World Message Enum Reflection
TEST(MagicEnumTest, eWorldMessageTypeTest) {
Game::logger = new Logger("./MagicEnumTest_eWorldMessageTypeTest.log", true, true);
ENUM_EQ(eWorldMessageType, 1, VALIDATION);
ENUM_EQ(eWorldMessageType, 2, CHARACTER_LIST_REQUEST);
ENUM_EQ(eWorldMessageType, 3, CHARACTER_CREATE_REQUEST);
ENUM_EQ(eWorldMessageType, 4, LOGIN_REQUEST);
ENUM_EQ(eWorldMessageType, 5, GAME_MSG);
ENUM_EQ(eWorldMessageType, 6, CHARACTER_DELETE_REQUEST);
ENUM_EQ(eWorldMessageType, 7, CHARACTER_RENAME_REQUEST);
ENUM_EQ(eWorldMessageType, 8, HAPPY_FLOWER_MODE_NOTIFY);
ENUM_EQ(eWorldMessageType, 9, SLASH_RELOAD_MAP);
ENUM_EQ(eWorldMessageType, 10, SLASH_PUSH_MAP_REQUEST);
ENUM_EQ(eWorldMessageType, 11, SLASH_PUSH_MAP);
ENUM_EQ(eWorldMessageType, 12, SLASH_PULL_MAP);
ENUM_EQ(eWorldMessageType, 13, LOCK_MAP_REQUEST);
ENUM_EQ(eWorldMessageType, 14, GENERAL_CHAT_MESSAGE);
ENUM_EQ(eWorldMessageType, 15, HTTP_MONITOR_INFO_REQUEST);
ENUM_EQ(eWorldMessageType, 16, SLASH_DEBUG_SCRIPTS);
ENUM_EQ(eWorldMessageType, 17, MODELS_CLEAR);
ENUM_EQ(eWorldMessageType, 18, EXHIBIT_INSERT_MODEL);
ENUM_EQ(eWorldMessageType, 19, LEVEL_LOAD_COMPLETE);
ENUM_EQ(eWorldMessageType, 20, TMP_GUILD_CREATE);
ENUM_EQ(eWorldMessageType, 21, ROUTE_PACKET);
ENUM_EQ(eWorldMessageType, 22, POSITION_UPDATE);
ENUM_EQ(eWorldMessageType, 23, MAIL);
ENUM_EQ(eWorldMessageType, 24, WORD_CHECK);
ENUM_EQ(eWorldMessageType, 25, STRING_CHECK);
ENUM_EQ(eWorldMessageType, 26, GET_PLAYERS_IN_ZONE);
ENUM_EQ(eWorldMessageType, 27, REQUEST_UGC_MANIFEST_INFO);
ENUM_EQ(eWorldMessageType, 28, BLUEPRINT_GET_ALL_DATA_REQUEST);
ENUM_EQ(eWorldMessageType, 29, CANCEL_MAP_QUEUE);
ENUM_EQ(eWorldMessageType, 30, HANDLE_FUNNESS);
ENUM_EQ(eWorldMessageType, 31, FAKE_PRG_CSR_MESSAGE);
ENUM_EQ(eWorldMessageType, 32, REQUEST_FREE_TRIAL_REFRESH);
ENUM_EQ(eWorldMessageType, 33, GM_SET_FREE_TRIAL_STATUS);
ENUM_EQ(eWorldMessageType, 91, UI_HELP_TOP_5);
ENUM_NE(eWorldMessageType, 37);
ENUM_NE(eWorldMessageType, 123);
srand(time(NULL));
auto begin = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 10000000; ++i) {
volatile auto f = StringifiedEnum::ToString(static_cast<eWorldMessageType>(i)).data();
// To ensure the compiler doesn't optimize out the call, I print it at random intervals
if (rand() % 100000 == 0) LOG("%i, %s", i, f);
}
auto end = std::chrono::high_resolution_clock::now();
LOG("Time: %lld", std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count());
delete Game::logger;
}
// Test Game Message Enum Reflection
TEST(MagicEnumTest, eGameMessageTypeTest) {
Game::logger = new Logger("./MagicEnumTest_eGameMessageTypeTest.log", true, true);
// Only doing the first and last 10 for the sake of my sanity
ENUM_EQ(eGameMessageType, 0, GET_POSITION);
ENUM_EQ(eGameMessageType, 1, GET_ROTATION);
ENUM_EQ(eGameMessageType, 2, GET_LINEAR_VELOCITY);
ENUM_EQ(eGameMessageType, 3, GET_ANGULAR_VELOCITY);
ENUM_EQ(eGameMessageType, 4, GET_FORWARD_VELOCITY);
ENUM_EQ(eGameMessageType, 5, GET_PLAYER_FORWARD);
ENUM_EQ(eGameMessageType, 6, GET_FORWARD_VECTOR);
ENUM_EQ(eGameMessageType, 7, SET_POSITION);
ENUM_EQ(eGameMessageType, 8, SET_LOCAL_POSITION);
ENUM_EQ(eGameMessageType, 9, SET_ROTATION);
ENUM_EQ(eGameMessageType, 10, SET_LINEAR_VELOCITY);
ENUM_EQ(eGameMessageType, 1762, USE_SKILL_SET);
ENUM_EQ(eGameMessageType, 1763, SET_SKILL_SET_POSSESSOR);
ENUM_EQ(eGameMessageType, 1764, POPULATE_ACTION_BAR);
ENUM_EQ(eGameMessageType, 1765, GET_COMPONENT_TEMPLATE_ID);
ENUM_EQ(eGameMessageType, 1766, GET_POSSESSABLE_SKILL_SET);
ENUM_EQ(eGameMessageType, 1767, MARK_INVENTORY_ITEM_AS_ACTIVE);
ENUM_EQ(eGameMessageType, 1768, UPDATE_FORGED_ITEM);
ENUM_EQ(eGameMessageType, 1769, CAN_ITEMS_BE_REFORGED);
ENUM_EQ(eGameMessageType, 1771, NOTIFY_CLIENT_RAIL_START_FAILED);
ENUM_EQ(eGameMessageType, 1772, GET_IS_ON_RAIL);
ENUM_NE(eGameMessageType, 32);
ENUM_NE(eGameMessageType, 1776);
srand(time(NULL));
auto begin = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 10000000; ++i) {
volatile auto f = StringifiedEnum::ToString(static_cast<eGameMessageType>(i)).data();
// To ensure the compiler doesn't optimize out the call, I print it at random intervals
if (rand() % 100000 == 0) LOG("%i, %s", i, f);
}
auto end = std::chrono::high_resolution_clock::now();
LOG("Time: %lld", std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count());
delete Game::logger;
}
#define ASSERT_EARRAY_SORTED(EARRAY_VAR)\
for (int i = 0; i < EARRAY_VAR->size(); i++) {\
const auto entryCurr = EARRAY_VAR->at(i).first;\
LOG_EARRAY(EARRAY_VAR, i, entryCurr);\
const auto entryNext = EARRAY_VAR->at(++i).first;\
LOG_EARRAY(EARRAY_VAR, i, entryNext);\
ASSERT_TRUE(entryCurr < entryNext);\
};\
#define LOG_EARRAY(EARRAY_VAR, INDICE, ENTRY)\
LOG(#EARRAY_VAR"[%i] = %i, %s", INDICE, ENTRY, magic_enum::enum_name(ENTRY).data());
// Test that the magic enum arrays are pre-sorted
TEST(MagicEnumTest, ArraysAreSorted) {
Game::logger = new Logger("./MagicEnumTest_ArraysAreSorted.log", true, true);
constexpr auto wmArray = &magic_enum::enum_entries<eWorldMessageType>();
ASSERT_EARRAY_SORTED(wmArray);
constexpr auto gmArray = &magic_enum::enum_entries<eGameMessageType>();
ASSERT_EARRAY_SORTED(gmArray);
delete Game::logger;
}

View File

@@ -19,6 +19,9 @@ add_library(bcrypt ${SOURCES_LIBBCRYPT})
# Source code for sqlite
add_subdirectory(SQLite)
# Source code for magic_enum
add_subdirectory(magic_enum)
# MariaDB C++ Connector
include(CMakeMariaDBLists.txt)