mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-10-30 20:22:04 +00:00 
			
		
		
		
	Merge remote-tracking branch 'upstream/main'
This commit is contained in:
		| @@ -89,8 +89,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) | ||||
| set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) | ||||
| set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) | ||||
|  | ||||
| # Create a /res directory | ||||
| make_directory(${CMAKE_BINARY_DIR}/res) | ||||
| # Create a /resServer directory | ||||
| make_directory(${CMAKE_BINARY_DIR}/resServer) | ||||
|  | ||||
| # Create a /logs directory | ||||
| make_directory(${CMAKE_BINARY_DIR}/logs) | ||||
| @@ -176,6 +176,7 @@ set(INCLUDED_DIRECTORIES | ||||
| 	"dScripts/ai" | ||||
| 	"dScripts/client" | ||||
| 	"dScripts/EquipmentScripts" | ||||
| 	"dScripts/EquipmentTriggers" | ||||
| 	"dScripts/zone" | ||||
| 	"dScripts/02_server/DLU" | ||||
| 	"dScripts/02_server/Enemy" | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
|  | ||||
| #include "eSqliteDataType.h" | ||||
|  | ||||
| std::map<eSqliteDataType, std::string> FdbToSqlite::Convert::sqliteType = { | ||||
| std::map<eSqliteDataType, std::string> FdbToSqlite::Convert::m_SqliteType = { | ||||
| 			{ eSqliteDataType::NONE, "none"}, | ||||
| 			{ eSqliteDataType::INT32, "int32"}, | ||||
| 			{ eSqliteDataType::REAL, "real"}, | ||||
| @@ -23,15 +23,21 @@ std::map<eSqliteDataType, std::string> FdbToSqlite::Convert::sqliteType = { | ||||
| 			{ eSqliteDataType::TEXT_8, "text_8"} | ||||
| }; | ||||
|  | ||||
| FdbToSqlite::Convert::Convert(std::string basePath) { | ||||
| 	this->basePath = basePath; | ||||
| FdbToSqlite::Convert::Convert(std::string basePath, std::string binaryOutPath) { | ||||
| 	this->m_BasePath = basePath; | ||||
| 	this->m_BinaryOutPath = binaryOutPath; | ||||
| 	m_Fdb.open(m_BasePath + "/cdclient.fdb", std::ios::binary); | ||||
| } | ||||
|  | ||||
| FdbToSqlite::Convert::~Convert() { | ||||
| 	this->m_Fdb.close(); | ||||
| } | ||||
|  | ||||
| bool FdbToSqlite::Convert::ConvertDatabase() { | ||||
| 	fdb.open(basePath + "/cdclient.fdb", std::ios::binary); | ||||
|  | ||||
| 	if (m_ConversionStarted) return false; | ||||
| 	this->m_ConversionStarted = true; | ||||
| 	try { | ||||
| 		CDClientDatabase::Connect(basePath + "/CDServer.sqlite"); | ||||
| 		CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite"); | ||||
|  | ||||
| 		CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;"); | ||||
|  | ||||
| @@ -44,13 +50,12 @@ bool FdbToSqlite::Convert::ConvertDatabase() { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	fdb.close(); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| int32_t FdbToSqlite::Convert::ReadInt32() { | ||||
| 	int32_t nextInt{}; | ||||
| 	BinaryIO::BinaryRead(fdb, nextInt); | ||||
| 	BinaryIO::BinaryRead(m_Fdb, nextInt); | ||||
| 	return nextInt; | ||||
| } | ||||
|  | ||||
| @@ -58,26 +63,26 @@ int64_t FdbToSqlite::Convert::ReadInt64() { | ||||
| 	int32_t prevPosition = SeekPointer(); | ||||
|  | ||||
| 	int64_t value{}; | ||||
| 	BinaryIO::BinaryRead(fdb, value); | ||||
| 	BinaryIO::BinaryRead(m_Fdb, value); | ||||
|  | ||||
| 	fdb.seekg(prevPosition); | ||||
| 	m_Fdb.seekg(prevPosition); | ||||
| 	return value; | ||||
| } | ||||
|  | ||||
| std::string FdbToSqlite::Convert::ReadString() { | ||||
| 	int32_t prevPosition = SeekPointer(); | ||||
|  | ||||
| 	auto readString = BinaryIO::ReadString(fdb); | ||||
| 	auto readString = BinaryIO::ReadString(m_Fdb); | ||||
|  | ||||
| 	fdb.seekg(prevPosition); | ||||
| 	m_Fdb.seekg(prevPosition); | ||||
| 	return readString; | ||||
| } | ||||
|  | ||||
| int32_t FdbToSqlite::Convert::SeekPointer() { | ||||
| 	int32_t position{}; | ||||
| 	BinaryIO::BinaryRead(fdb, position); | ||||
| 	int32_t prevPosition = fdb.tellg(); | ||||
| 	fdb.seekg(position); | ||||
| 	BinaryIO::BinaryRead(m_Fdb, position); | ||||
| 	int32_t prevPosition = m_Fdb.tellg(); | ||||
| 	m_Fdb.seekg(position); | ||||
| 	return prevPosition; | ||||
| } | ||||
|  | ||||
| @@ -91,7 +96,7 @@ std::string FdbToSqlite::Convert::ReadColumnHeader() { | ||||
| 	std::string newTable = "CREATE TABLE IF NOT EXISTS '" + tableName + "' (" + columns + ");"; | ||||
| 	CDClientDatabase::ExecuteDML(newTable); | ||||
|  | ||||
| 	fdb.seekg(prevPosition); | ||||
| 	m_Fdb.seekg(prevPosition); | ||||
|  | ||||
| 	return tableName; | ||||
| } | ||||
| @@ -104,7 +109,7 @@ void FdbToSqlite::Convert::ReadTables(int32_t& numberOfTables) { | ||||
| 		ReadRowHeader(columnHeader); | ||||
| 	} | ||||
|  | ||||
| 	fdb.seekg(prevPosition); | ||||
| 	m_Fdb.seekg(prevPosition); | ||||
| } | ||||
|  | ||||
| std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns) { | ||||
| @@ -117,10 +122,10 @@ std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns) { | ||||
| 		if (i != 0) columnsToCreate << ", "; | ||||
| 		dataType = static_cast<eSqliteDataType>(ReadInt32()); | ||||
| 		name = ReadString(); | ||||
| 		columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::sqliteType[dataType]; | ||||
| 		columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::m_SqliteType[dataType]; | ||||
| 	} | ||||
|  | ||||
| 	fdb.seekg(prevPosition); | ||||
| 	m_Fdb.seekg(prevPosition); | ||||
| 	return columnsToCreate.str(); | ||||
| } | ||||
|  | ||||
| @@ -131,7 +136,7 @@ void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName) { | ||||
| 	if (numberOfAllocatedRows != 0) assert((numberOfAllocatedRows & (numberOfAllocatedRows - 1)) == 0);  // assert power of 2 allocation size | ||||
| 	ReadRows(numberOfAllocatedRows, tableName); | ||||
|  | ||||
| 	fdb.seekg(prevPosition); | ||||
| 	m_Fdb.seekg(prevPosition); | ||||
| } | ||||
|  | ||||
| void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName) { | ||||
| @@ -141,28 +146,24 @@ void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& | ||||
| 	for (int32_t row = 0; row < numberOfAllocatedRows; row++) { | ||||
| 		int32_t rowPointer = ReadInt32(); | ||||
| 		if (rowPointer == -1) rowid++; | ||||
| 		else ReadRow(rowid, rowPointer, tableName); | ||||
| 		else ReadRow(rowPointer, tableName); | ||||
| 	} | ||||
|  | ||||
| 	fdb.seekg(prevPosition); | ||||
| 	m_Fdb.seekg(prevPosition); | ||||
| } | ||||
|  | ||||
| void FdbToSqlite::Convert::ReadRow(int32_t& rowid, int32_t& position, std::string& tableName) { | ||||
| 	int32_t prevPosition = fdb.tellg(); | ||||
| 	fdb.seekg(position); | ||||
| void FdbToSqlite::Convert::ReadRow(int32_t& position, std::string& tableName) { | ||||
| 	int32_t prevPosition = m_Fdb.tellg(); | ||||
| 	m_Fdb.seekg(position); | ||||
|  | ||||
| 	while (true) { | ||||
| 		ReadRowInfo(tableName); | ||||
| 		int32_t linked = ReadInt32(); | ||||
|  | ||||
| 		rowid += 1; | ||||
|  | ||||
| 		if (linked == -1) break; | ||||
|  | ||||
| 		fdb.seekg(linked); | ||||
| 		m_Fdb.seekg(linked); | ||||
| 	} | ||||
|  | ||||
| 	fdb.seekg(prevPosition); | ||||
| 	m_Fdb.seekg(prevPosition); | ||||
| } | ||||
|  | ||||
| void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName) { | ||||
| @@ -171,7 +172,7 @@ void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName) { | ||||
| 	int32_t numberOfColumns = ReadInt32(); | ||||
| 	ReadRowValues(numberOfColumns, tableName); | ||||
|  | ||||
| 	fdb.seekg(prevPosition); | ||||
| 	m_Fdb.seekg(prevPosition); | ||||
| } | ||||
|  | ||||
| void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName) { | ||||
| @@ -191,7 +192,7 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& | ||||
| 		if (i != 0) insertedRow << ", "; // Only append comma and space after first entry in row. | ||||
| 		switch (static_cast<eSqliteDataType>(ReadInt32())) { | ||||
| 		case eSqliteDataType::NONE: | ||||
| 			BinaryIO::BinaryRead(fdb, emptyValue); | ||||
| 			BinaryIO::BinaryRead(m_Fdb, emptyValue); | ||||
| 			assert(emptyValue == 0); | ||||
| 			insertedRow << "NULL"; | ||||
| 			break; | ||||
| @@ -202,7 +203,7 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& | ||||
| 			break; | ||||
|  | ||||
| 		case eSqliteDataType::REAL: | ||||
| 			BinaryIO::BinaryRead(fdb, floatValue); | ||||
| 			BinaryIO::BinaryRead(m_Fdb, floatValue); | ||||
| 			insertedRow << std::fixed << std::setprecision(34) << floatValue; // maximum precision of floating point number | ||||
| 			break; | ||||
|  | ||||
| @@ -224,7 +225,7 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& | ||||
| 		} | ||||
|  | ||||
| 		case eSqliteDataType::INT_BOOL: | ||||
| 			BinaryIO::BinaryRead(fdb, boolValue); | ||||
| 			BinaryIO::BinaryRead(m_Fdb, boolValue); | ||||
| 			insertedRow << static_cast<bool>(boolValue); | ||||
| 			break; | ||||
|  | ||||
| @@ -244,5 +245,5 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& | ||||
|  | ||||
| 	auto copiedString = insertedRow.str(); | ||||
| 	CDClientDatabase::ExecuteDML(copiedString); | ||||
| 	fdb.seekg(prevPosition); | ||||
| 	m_Fdb.seekg(prevPosition); | ||||
| } | ||||
|   | ||||
| @@ -12,38 +12,142 @@ enum class eSqliteDataType : int32_t; | ||||
| namespace FdbToSqlite { | ||||
| 	class Convert { | ||||
| 	public: | ||||
| 		Convert(std::string inputFile); | ||||
| 		/** | ||||
| 		 * Create a new convert object with an input .fdb file and an output binary path. | ||||
| 		 *  | ||||
| 		 * @param inputFile The file which ends in .fdb to be converted | ||||
| 		 * @param binaryPath The base path where the file will be saved | ||||
| 		 */ | ||||
| 		Convert(std::string inputFile, std::string binaryOutPath); | ||||
|  | ||||
| 		/** | ||||
| 		 * Destroy the convert object and close the fdb file. | ||||
| 		 */ | ||||
| 		~Convert(); | ||||
|  | ||||
| 		/** | ||||
| 		 * Converts the input file to sqlite.  Calling multiple times is safe. | ||||
| 		 *  | ||||
| 		 * @return true if the database was converted properly, false otherwise.  | ||||
| 		 */ | ||||
| 		bool ConvertDatabase(); | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Reads a 32 bit int from the fdb file. | ||||
| 		 *  | ||||
| 		 * @return The read value | ||||
| 		 */ | ||||
| 		int32_t ReadInt32(); | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Reads a 64 bit integer from the fdb file. | ||||
| 		 *  | ||||
| 		 * @return The read value | ||||
| 		 */ | ||||
| 		int64_t ReadInt64(); | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Reads a string from the fdb file. | ||||
| 		 *  | ||||
| 		 * @return The read string | ||||
| 		 *  | ||||
| 		 * TODO This needs to be translated to latin-1! | ||||
| 		 */ | ||||
| 		std::string ReadString(); | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Seeks to a pointer position. | ||||
| 		 *  | ||||
| 		 * @return The previous position before the seek | ||||
| 		 */ | ||||
| 		int32_t SeekPointer(); | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Reads a column header from the fdb file and creates the table in the database | ||||
| 		 *  | ||||
| 		 * @return The table name | ||||
| 		 */ | ||||
| 		std::string ReadColumnHeader(); | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Read the tables from the fdb file. | ||||
| 		 *  | ||||
| 		 * @param numberOfTables The number of tables to read | ||||
| 		 */ | ||||
| 		void ReadTables(int32_t& numberOfTables); | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Reads the columns from the fdb file. | ||||
| 		 *  | ||||
| 		 * @param numberOfColumns The number of columns to read | ||||
| 		 * @return All columns of the table formatted for a sql query | ||||
| 		 */ | ||||
| 		std::string ReadColumns(int32_t& numberOfColumns); | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Reads the row header from the fdb file. | ||||
| 		 *  | ||||
| 		 * @param tableName The tables name | ||||
| 		 */ | ||||
| 		void ReadRowHeader(std::string& tableName); | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Read the rows from the fdb file., | ||||
| 		 *  | ||||
| 		 * @param numberOfAllocatedRows The number of rows that were allocated.  Always a power of 2!  | ||||
| 		 * @param tableName The tables name. | ||||
| 		 */ | ||||
| 		void ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName); | ||||
|  | ||||
| 		void ReadRow(int32_t& rowid, int32_t& position, std::string& tableName); | ||||
| 		/** | ||||
| 		 * @brief Reads a row from the fdb file. | ||||
| 		 *  | ||||
| 		 * @param position The position to seek in the fdb to | ||||
| 		 * @param tableName The tables name | ||||
| 		 */ | ||||
| 		void ReadRow(int32_t& position, std::string& tableName); | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Reads the row info from the fdb file. | ||||
| 		 *  | ||||
| 		 * @param tableName The tables name | ||||
| 		 */ | ||||
| 		void ReadRowInfo(std::string& tableName); | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Reads each row and its values from the fdb file and inserts them into the database | ||||
| 		 *  | ||||
| 		 * @param numberOfColumns The number of columns to read in | ||||
| 		 * @param tableName The tables name | ||||
| 		 */ | ||||
| 		void ReadRowValues(int32_t& numberOfColumns, std::string& tableName); | ||||
| 	private: | ||||
| 		static std::map<eSqliteDataType, std::string> sqliteType; | ||||
| 		std::string basePath{}; | ||||
| 		std::ifstream fdb{}; | ||||
| 	}; // class FdbToSqlite | ||||
|  | ||||
| 		/** | ||||
| 		 * Maps each sqlite data type to its string equivalent. | ||||
| 		 */ | ||||
| 		static std::map<eSqliteDataType, std::string> m_SqliteType; | ||||
|  | ||||
| 		/** | ||||
| 		 * Base path of the folder containing the fdb file | ||||
| 		 */ | ||||
| 		std::string m_BasePath{}; | ||||
|  | ||||
| 		/** | ||||
| 		 * ifstream containing the fdb file | ||||
| 		 */ | ||||
| 		std::ifstream m_Fdb{}; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Whether or not a conversion was started.  If one was started, do not attempt to convert the file again. | ||||
| 		 */ | ||||
| 		bool m_ConversionStarted{}; | ||||
|  | ||||
| 		/** | ||||
| 		 * The path where the CDServer will be stored | ||||
| 		 */ | ||||
| 		std::string m_BinaryOutPath{}; | ||||
| 	}; //! class FdbToSqlite | ||||
| }; //! namespace FdbToSqlite | ||||
|  | ||||
| #endif  //!__FDBTOSQLITE__H__ | ||||
|   | ||||
| @@ -54,7 +54,7 @@ void MigrationRunner::RunMigrations() { | ||||
| 		if (doExit) continue; | ||||
|  | ||||
| 		Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str()); | ||||
| 		if (migration.name == "5_brick_model_sd0.sql") { | ||||
| 		if (migration.name == "dlu/5_brick_model_sd0.sql") { | ||||
| 			runSd0Migrations = true; | ||||
| 		} else { | ||||
| 			finalSQL.append(migration.data.c_str()); | ||||
|   | ||||
| @@ -824,6 +824,22 @@ std::vector<ScriptComponent*> Entity::GetScriptComponents() { | ||||
| 	return comps; | ||||
| } | ||||
|  | ||||
| void Entity::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName) { | ||||
| 	if (notificationName == "HitOrHealResult" || notificationName == "Hit") { | ||||
| 		auto* destroyableComponent = GetComponent<DestroyableComponent>(); | ||||
| 		if (!destroyableComponent) return; | ||||
| 		destroyableComponent->Subscribe(scriptObjId, scriptToAdd); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void Entity::Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationName) { | ||||
| 	if (notificationName == "HitOrHealResult" || notificationName == "Hit") { | ||||
| 		auto* destroyableComponent = GetComponent<DestroyableComponent>(); | ||||
| 		if (!destroyableComponent) return; | ||||
| 		destroyableComponent->Unsubscribe(scriptObjId); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void Entity::SetProximityRadius(float proxRadius, std::string name) { | ||||
| 	ProximityMonitorComponent* proxMon = GetComponent<ProximityMonitorComponent>(); | ||||
| 	if (!proxMon) { | ||||
|   | ||||
| @@ -26,8 +26,13 @@ class Spawner; | ||||
| class ScriptComponent; | ||||
| class dpEntity; | ||||
| class Component; | ||||
| class Item; | ||||
| class Character; | ||||
|  | ||||
| namespace CppScripts { | ||||
| 	class Script; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * An entity in the world. Has multiple components. | ||||
|  */ | ||||
| @@ -139,6 +144,9 @@ public: | ||||
|  | ||||
| 	std::vector<ScriptComponent*> GetScriptComponents(); | ||||
|  | ||||
| 	void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName); | ||||
| 	void Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationName); | ||||
|  | ||||
| 	void SetProximityRadius(float proxRadius, std::string name); | ||||
| 	void SetProximityRadius(dpEntity* entity, std::string name); | ||||
|  | ||||
|   | ||||
| @@ -631,6 +631,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32 | ||||
| 	auto* attacker = EntityManager::Instance()->GetEntity(source); | ||||
| 	m_Parent->OnHit(attacker); | ||||
| 	m_Parent->OnHitOrHealResult(attacker, sourceDamage); | ||||
| 	NotifySubscribers(attacker, sourceDamage); | ||||
|  | ||||
| 	for (const auto& cb : m_OnHitCallbacks) { | ||||
| 		cb(attacker); | ||||
| @@ -648,6 +649,29 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32 | ||||
| 	Smash(source, eKillType::VIOLENT, u"", skillID); | ||||
| } | ||||
|  | ||||
| void DestroyableComponent::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd) { | ||||
| 	m_SubscribedScripts.insert(std::make_pair(scriptObjId, scriptToAdd)); | ||||
| 	Game::logger->LogDebug("DestroyableComponent", "Added script %llu to entity %llu", scriptObjId, m_Parent->GetObjectID()); | ||||
| 	Game::logger->LogDebug("DestroyableComponent", "Number of subscribed scripts %i", m_SubscribedScripts.size()); | ||||
| } | ||||
|  | ||||
| void DestroyableComponent::Unsubscribe(LWOOBJID scriptObjId) { | ||||
| 	auto foundScript = m_SubscribedScripts.find(scriptObjId); | ||||
| 	if (foundScript != m_SubscribedScripts.end()) { | ||||
| 		m_SubscribedScripts.erase(foundScript); | ||||
| 		Game::logger->LogDebug("DestroyableComponent", "Removed script %llu from entity %llu", scriptObjId, m_Parent->GetObjectID()); | ||||
| 	} else { | ||||
| 		Game::logger->LogDebug("DestroyableComponent", "Tried to remove a script for Entity %llu but script %llu didnt exist", m_Parent->GetObjectID(), scriptObjId); | ||||
| 	} | ||||
| 	Game::logger->LogDebug("DestroyableComponent", "Number of subscribed scripts %i", m_SubscribedScripts.size()); | ||||
| } | ||||
|  | ||||
| void DestroyableComponent::NotifySubscribers(Entity* attacker, uint32_t damage) { | ||||
| 	for (auto script : m_SubscribedScripts) { | ||||
| 		script.second->NotifyHitOrHealResult(m_Parent, attacker, damage); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType, uint32_t skillID) { | ||||
| 	if (m_iHealth > 0) { | ||||
| 		SetArmor(0); | ||||
|   | ||||
| @@ -7,6 +7,10 @@ | ||||
| #include "Entity.h" | ||||
| #include "Component.h" | ||||
|  | ||||
| namespace CppScripts { | ||||
| 	class Script; | ||||
| }; //! namespace CppScripts | ||||
|  | ||||
| /** | ||||
|  * Represents the stats of an entity, for example its health, imagination and armor. Also handles factions, which | ||||
|  * indicate which enemies this entity has. | ||||
| @@ -422,6 +426,17 @@ public: | ||||
| 	 */ | ||||
| 	void AddFactionNoLookup(int32_t faction) { m_FactionIDs.push_back(faction); }; | ||||
|  | ||||
| 	/** | ||||
| 	 * Notify subscribed scripts of Damage actions. | ||||
| 	 *  | ||||
| 	 * @param attacker The attacking Entity | ||||
| 	 * @param damage The amount of damage that was done | ||||
| 	 */ | ||||
| 	void NotifySubscribers(Entity* attacker, uint32_t damage); | ||||
|  | ||||
| 	void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd); | ||||
| 	void Unsubscribe(LWOOBJID scriptObjId); | ||||
|  | ||||
| private: | ||||
| 	/** | ||||
| 	 * Whether or not the health should be serialized | ||||
| @@ -557,6 +572,11 @@ private: | ||||
| 	 * The list of callbacks that will be called when this entity gets hit | ||||
| 	 */ | ||||
| 	std::vector<std::function<void(Entity*)>> m_OnHitCallbacks; | ||||
|  | ||||
| 	/** | ||||
| 	 * The list of scripts subscribed to this components actions | ||||
| 	 */ | ||||
| 	std::map<LWOOBJID, CppScripts::Script*> m_SubscribedScripts; | ||||
| }; | ||||
|  | ||||
| #endif // DESTROYABLECOMPONENT_H | ||||
|   | ||||
| @@ -27,8 +27,9 @@ | ||||
| #include "dConfig.h" | ||||
| #include "eItemType.h" | ||||
| #include "eUnequippableActiveType.h" | ||||
| #include "CppScripts.h" | ||||
|  | ||||
| InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) { | ||||
| InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document): Component(parent) { | ||||
| 	this->m_Dirty = true; | ||||
| 	this->m_Equipped = {}; | ||||
| 	this->m_Pushed = {}; | ||||
| @@ -867,6 +868,8 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { | ||||
|  | ||||
| 	AddItemSkills(item->GetLot()); | ||||
|  | ||||
| 	EquipScripts(item); | ||||
|  | ||||
| 	EntityManager::Instance()->SerializeEntity(m_Parent); | ||||
| } | ||||
|  | ||||
| @@ -895,6 +898,8 @@ void InventoryComponent::UnEquipItem(Item* item) { | ||||
|  | ||||
| 	PurgeProxies(item); | ||||
|  | ||||
| 	UnequipScripts(item); | ||||
|  | ||||
| 	EntityManager::Instance()->SerializeEntity(m_Parent); | ||||
|  | ||||
| 	// Trigger property event | ||||
| @@ -904,6 +909,37 @@ void InventoryComponent::UnEquipItem(Item* item) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| void InventoryComponent::EquipScripts(Item* equippedItem) { | ||||
| 	CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry"); | ||||
| 	if (!compRegistryTable) return; | ||||
| 	int32_t scriptComponentID = compRegistryTable->GetByIDAndType(equippedItem->GetLot(), COMPONENT_TYPE_SCRIPT, -1); | ||||
| 	if (scriptComponentID > -1) { | ||||
| 		CDScriptComponentTable* scriptCompTable = CDClientManager::Instance()->GetTable<CDScriptComponentTable>("ScriptComponent"); | ||||
| 		CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID); | ||||
| 		auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name); | ||||
| 		if (!itemScript) { | ||||
| 			Game::logger->Log("InventoryComponent", "null script?"); | ||||
| 		} | ||||
| 		itemScript->OnFactionTriggerItemEquipped(m_Parent, equippedItem->GetId()); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void InventoryComponent::UnequipScripts(Item* unequippedItem) { | ||||
| 	CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry"); | ||||
| 	if (!compRegistryTable) return; | ||||
| 	int32_t scriptComponentID = compRegistryTable->GetByIDAndType(unequippedItem->GetLot(), COMPONENT_TYPE_SCRIPT, -1); | ||||
| 	if (scriptComponentID > -1) { | ||||
| 		CDScriptComponentTable* scriptCompTable = CDClientManager::Instance()->GetTable<CDScriptComponentTable>("ScriptComponent"); | ||||
| 		CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID); | ||||
| 		auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name); | ||||
| 		if (!itemScript) { | ||||
| 			Game::logger->Log("InventoryComponent", "null script?"); | ||||
| 		} | ||||
| 		itemScript->OnFactionTriggerItemUnequipped(m_Parent, unequippedItem->GetId()); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void InventoryComponent::HandlePossession(Item* item) { | ||||
| 	auto* characterComponent = m_Parent->GetComponent<CharacterComponent>(); | ||||
| 	if (!characterComponent) return; | ||||
|   | ||||
| @@ -352,6 +352,20 @@ public: | ||||
| 	 */ | ||||
| 	static uint32_t FindSkill(LOT lot); | ||||
|  | ||||
| 	/** | ||||
| 	 * Call this when you equip an item.  This calls OnFactionTriggerItemEquipped for any scripts found on the items. | ||||
| 	 *  | ||||
| 	 * @param equippedItem The item script to lookup and call equip on | ||||
| 	 */ | ||||
| 	void EquipScripts(Item* equippedItem); | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Call this when you unequip an item.  This calls OnFactionTriggerItemUnequipped for any scripts found on the items. | ||||
| 	 *  | ||||
| 	 * @param unequippedItem The item script to lookup and call unequip on | ||||
| 	 */ | ||||
| 	void UnequipScripts(Item* unequippedItem); | ||||
|  | ||||
| 	~InventoryComponent() override; | ||||
|  | ||||
| private: | ||||
|   | ||||
| @@ -98,7 +98,7 @@ void RacingControlComponent::OnPlayerLoaded(Entity* player) { | ||||
| } | ||||
|  | ||||
| void RacingControlComponent::LoadPlayerVehicle(Entity* player, | ||||
| 	bool initialLoad) { | ||||
| 	uint32_t positionNumber, bool initialLoad) { | ||||
| 	// Load the player's vehicle. | ||||
|  | ||||
| 	if (player == nullptr) { | ||||
| @@ -126,33 +126,18 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player, | ||||
| 	auto* path = dZoneManager::Instance()->GetZone()->GetPath( | ||||
| 		GeneralUtils::UTF16ToWTF8(m_PathName)); | ||||
|  | ||||
| 	auto startPosition = path->pathWaypoints[0].position + NiPoint3::UNIT_Y * 3; | ||||
|  | ||||
| 	const auto spacing = 15; | ||||
|  | ||||
| 	// This sometimes spawns the vehicle out of the map if there are lots of | ||||
| 	// players loaded. | ||||
|  | ||||
| 	const auto range = m_LoadedPlayers * spacing; | ||||
|  | ||||
| 	startPosition = | ||||
| 		startPosition + NiPoint3::UNIT_Z * ((m_LeadingPlayer / 2) + | ||||
| 			m_RacingPlayers.size() * spacing); | ||||
|  | ||||
| 	auto startRotation = | ||||
| 		NiQuaternion::LookAt(startPosition, startPosition + NiPoint3::UNIT_X); | ||||
|  | ||||
| 	auto angles = startRotation.GetEulerAngles(); | ||||
|  | ||||
| 	angles.y -= M_PI; | ||||
|  | ||||
| 	startRotation = NiQuaternion::FromEulerAngles(angles); | ||||
|  | ||||
| 	Game::logger->Log("RacingControlComponent", | ||||
| 		"Start position <%f, %f, %f>, <%f, %f, %f>", | ||||
| 		startPosition.x, startPosition.y, startPosition.z, | ||||
| 		angles.x * (180.0f / M_PI), angles.y * (180.0f / M_PI), | ||||
| 		angles.z * (180.0f / M_PI)); | ||||
| 	auto spawnPointEntities = EntityManager::Instance()->GetEntitiesByLOT(4843); | ||||
| 	auto startPosition = NiPoint3::ZERO; | ||||
| 	auto startRotation = NiQuaternion::IDENTITY; | ||||
| 	const std::string placementAsString = std::to_string(positionNumber); | ||||
| 	for (auto entity : spawnPointEntities) { | ||||
| 		if (!entity) continue; | ||||
| 		if (entity->GetVarAsString(u"placement") == placementAsString) { | ||||
| 			startPosition = entity->GetPosition(); | ||||
| 			startRotation = entity->GetRotation(); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Make sure the player is at the correct position. | ||||
|  | ||||
| @@ -567,12 +552,12 @@ void RacingControlComponent::Update(float deltaTime) { | ||||
| 			Game::logger->Log("RacingControlComponent", | ||||
| 				"Loading all players..."); | ||||
|  | ||||
| 			for (size_t i = 0; i < m_LobbyPlayers.size(); i++) { | ||||
| 			for (size_t positionNumber = 0; positionNumber < m_LobbyPlayers.size(); positionNumber++) { | ||||
| 				Game::logger->Log("RacingControlComponent", | ||||
| 					"Loading player now!"); | ||||
|  | ||||
| 				auto* player = | ||||
| 					EntityManager::Instance()->GetEntity(m_LobbyPlayers[i]); | ||||
| 					EntityManager::Instance()->GetEntity(m_LobbyPlayers[positionNumber]); | ||||
|  | ||||
| 				if (player == nullptr) { | ||||
| 					return; | ||||
| @@ -581,7 +566,7 @@ void RacingControlComponent::Update(float deltaTime) { | ||||
| 				Game::logger->Log("RacingControlComponent", | ||||
| 					"Loading player now NOW!"); | ||||
|  | ||||
| 				LoadPlayerVehicle(player, true); | ||||
| 				LoadPlayerVehicle(player, positionNumber + 1, true); | ||||
|  | ||||
| 				m_Loaded = true; | ||||
| 			} | ||||
|   | ||||
| @@ -123,7 +123,7 @@ public: | ||||
| 	 * @param player The player who's vehicle to initialize. | ||||
| 	 * @param initialLoad Is this the first time the player is loading in this race? | ||||
| 	 */ | ||||
| 	void LoadPlayerVehicle(Entity* player, bool initialLoad = false); | ||||
| 	void LoadPlayerVehicle(Entity* player, uint32_t positionNumber, bool initialLoad = false); | ||||
|  | ||||
| 	/** | ||||
| 	 * Invoked when the client says it has loaded in. | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
| #include "Spawner.h" | ||||
| #include "MovingPlatformComponent.h" | ||||
| #include "Preconditions.h" | ||||
| #include "TeamManager.h" | ||||
|  | ||||
| #include "CppScripts.h" | ||||
|  | ||||
| @@ -464,12 +465,20 @@ void RebuildComponent::CompleteRebuild(Entity* user) { | ||||
|  | ||||
| 	auto* builder = GetBuilder(); | ||||
|  | ||||
| 	if (builder != nullptr) { | ||||
| 		auto* missionComponent = builder->GetComponent<MissionComponent>(); | ||||
| 		if (missionComponent != nullptr) { | ||||
| 			missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityId); | ||||
| 	if (builder) { | ||||
| 		auto* team = TeamManager::Instance()->GetTeam(builder->GetObjectID()); | ||||
| 		if (team) { | ||||
| 			for (const auto memberId : team->members) { // progress missions for all team members | ||||
| 				auto* member = EntityManager::Instance()->GetEntity(memberId); | ||||
| 				if (member) { | ||||
| 					auto* missionComponent = member->GetComponent<MissionComponent>(); | ||||
| 					if (missionComponent) missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityId); | ||||
| 				} | ||||
| 			} | ||||
| 		} else{ | ||||
| 			auto* missionComponent = builder->GetComponent<MissionComponent>(); | ||||
| 			if (missionComponent) missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityId); | ||||
| 		} | ||||
|  | ||||
| 		LootGenerator::Instance().DropActivityLoot(builder, m_Parent, m_ActivityId, 1); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -3924,14 +3924,16 @@ void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string | ||||
| } | ||||
|  | ||||
|  | ||||
| void GameMessages::SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags FlagsOn, eAnimationFlags FlagsOff, const SystemAddress& sysAddr) { | ||||
| void GameMessages::SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags flagsOn, eAnimationFlags flagsOff, const SystemAddress& sysAddr) { | ||||
| 	CBITSTREAM; | ||||
| 	CMSGHEADER; | ||||
|  | ||||
| 	bitStream.Write(objectId); | ||||
| 	bitStream.Write(GAME_MSG::GAME_MSG_CHANGE_IDLE_FLAGS); | ||||
| 	bitStream.Write(FlagsOff); | ||||
| 	bitStream.Write(FlagsOn); | ||||
| 	bitStream.Write<bool>(flagsOff != eAnimationFlags::IDLE_NONE); | ||||
| 	if (flagsOff != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOff); | ||||
| 	bitStream.Write<bool>(flagsOn != eAnimationFlags::IDLE_NONE); | ||||
| 	if (flagsOn != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOn); | ||||
|  | ||||
| 	SEND_PACKET_BROADCAST; | ||||
| } | ||||
|   | ||||
| @@ -1762,6 +1762,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit | ||||
|  | ||||
| 			scriptedActivityComponent->ReloadConfig(); | ||||
| 		} | ||||
| 		Game::server->UpdateMaximumMtuSize(); | ||||
| 		Game::server->UpdateBandwidthLimit(); | ||||
| 		ChatPackets::SendSystemMessage(sysAddr, u"Successfully reloaded config for world!"); | ||||
| 	} | ||||
|   | ||||
| @@ -146,26 +146,38 @@ int main(int argc, char** argv) { | ||||
|  | ||||
| 	MigrationRunner::RunMigrations(); | ||||
|  | ||||
| 	// Check CDClient exists | ||||
| 	if (!std::filesystem::exists(Game::assetManager->GetResPath() / "CDServer.sqlite")) { | ||||
| 		Game::logger->Log("WorldServer", "CDServer.sqlite could not be opened. Looking for cdclient.fdb to convert to sqlite."); | ||||
| 	const bool cdServerExists = std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite"); | ||||
| 	const bool oldCDServerExists = std::filesystem::exists(Game::assetManager->GetResPath() / "CDServer.sqlite"); | ||||
| 	const bool fdbExists = std::filesystem::exists(Game::assetManager->GetResPath() / "cdclient.fdb"); | ||||
|  | ||||
| 		if (!std::filesystem::exists(Game::assetManager->GetResPath() / "cdclient.fdb")) { | ||||
| 			Game::logger->Log("WorldServer", "cdclient.fdb could not be opened. Please move a cdclient.fdb or an already converted database to build/res."); | ||||
| 			return EXIT_FAILURE; | ||||
| 		} | ||||
|  | ||||
| 		Game::logger->Log("WorldServer", "Found cdclient.fdb.  Converting to SQLite"); | ||||
|  | ||||
| 		if (FdbToSqlite::Convert(Game::assetManager->GetResPath().string()).ConvertDatabase() == false) { | ||||
| 			Game::logger->Log("MasterServer", "Failed to convert fdb to sqlite"); | ||||
| 			return EXIT_FAILURE; | ||||
| 	if (!cdServerExists) { | ||||
| 		if (oldCDServerExists) { | ||||
| 			// If the file doesn't exist in the new CDServer location, copy it there.  We copy because we may not have write permissions from the previous directory. | ||||
| 			Game::logger->Log("MasterServer", "CDServer.sqlite is not located at resServer, but is located at res path.  Copying file..."); | ||||
| 			std::filesystem::copy_file(Game::assetManager->GetResPath() / "CDServer.sqlite", BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite"); | ||||
| 		} else { | ||||
| 			Game::logger->Log("WorldServer", | ||||
| 				"%s could not be found in resServer or res. Looking for %s to convert to sqlite.", | ||||
| 				(BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").c_str(), | ||||
| 				(Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); | ||||
| 			if (!fdbExists) { | ||||
| 				Game::logger->Log("WorldServer", | ||||
| 					"%s could not be opened. Please move cdclient.fdb to %s", | ||||
| 					(Game::assetManager->GetResPath() / "cdclient.fdb").c_str(), | ||||
| 					(Game::assetManager->GetResPath().c_str())); | ||||
| 				return FinalizeShutdown(); | ||||
| 			} | ||||
| 			Game::logger->Log("WorldServer", "Found cdclient.fdb.  Converting to SQLite"); | ||||
| 			if (FdbToSqlite::Convert(Game::assetManager->GetResPath().string(), (BinaryPathFinder::GetBinaryDir() / "resServer").string()).ConvertDatabase() == false) { | ||||
| 				Game::logger->Log("MasterServer", "Failed to convert fdb to sqlite."); | ||||
| 				return FinalizeShutdown(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//Connect to CDClient | ||||
| 	try { | ||||
| 		CDClientDatabase::Connect((Game::assetManager->GetResPath() / "CDServer.sqlite").string()); | ||||
| 		CDClientDatabase::Connect((BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").string()); | ||||
| 	} catch (CppSQLite3Exception& e) { | ||||
| 		Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); | ||||
| 		Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); | ||||
|   | ||||
| @@ -68,7 +68,7 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect | ||||
| 	} else { mLogger->Log("dServer", "FAILED TO START SERVER ON IP/PORT: %s:%i", ip.c_str(), port); return; } | ||||
|  | ||||
| 	mLogger->SetLogToConsole(prevLogSetting); | ||||
| 	mPeer->SetMTUSize(1228); // This is hard coded by lu for some reason. | ||||
|  | ||||
| 	//Connect to master if we are not master: | ||||
| 	if (serverType != ServerType::Master) { | ||||
| 		SetupForMasterConnection(); | ||||
| @@ -188,6 +188,7 @@ bool dServer::Startup() { | ||||
| 		mPeer->SetIncomingPassword("3.25 DARKFLAME1", 15); | ||||
| 	} else { | ||||
| 		UpdateBandwidthLimit(); | ||||
| 		UpdateMaximumMtuSize(); | ||||
| 		mPeer->SetIncomingPassword("3.25 ND1", 8); | ||||
| 	} | ||||
|  | ||||
| @@ -197,6 +198,11 @@ bool dServer::Startup() { | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void dServer::UpdateMaximumMtuSize() { | ||||
| 	auto maxMtuSize = mConfig->GetValue("maximum_mtu_size"); | ||||
| 	mPeer->SetMTUSize(maxMtuSize.empty() ? 1228 : std::stoi(maxMtuSize)); | ||||
| } | ||||
|  | ||||
| void dServer::UpdateBandwidthLimit() { | ||||
| 	auto newBandwidth = mConfig->GetValue("maximum_outgoing_bandwidth"); | ||||
| 	mPeer->SetPerConnectionOutgoingBandwidthLimit(!newBandwidth.empty() ? std::stoi(newBandwidth) : 0); | ||||
|   | ||||
| @@ -57,6 +57,7 @@ public: | ||||
| 	ReplicaManager* GetReplicaManager() { return mReplicaManager; } | ||||
| 	void UpdateReplica(); | ||||
| 	void UpdateBandwidthLimit(); | ||||
| 	void UpdateMaximumMtuSize(); | ||||
|  | ||||
| 	int GetPing(const SystemAddress& sysAddr) const; | ||||
| 	int GetLatestPing(const SystemAddress& sysAddr) const; | ||||
|   | ||||
| @@ -63,10 +63,11 @@ void AmDarklingDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t | ||||
|  | ||||
| 			if (skillComponent != nullptr) { | ||||
| 				skillComponent->Interrupt(); | ||||
| 				skillComponent->Reset(); | ||||
| 			} | ||||
|  | ||||
| 			self->SetVar<int32_t>(u"weakpoint", 2); | ||||
|  | ||||
| 			GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); | ||||
| 			GameMessages::SendPlayAnimation(self, u"stunstart", 1.7f); | ||||
|  | ||||
| 			self->AddTimer("timeToStunLoop", 1); | ||||
| @@ -131,7 +132,9 @@ void AmDarklingDragon::OnTimerDone(Entity* self, std::string timerName) { | ||||
| 		} | ||||
| 		if (skillComponent != nullptr) { | ||||
| 			skillComponent->Interrupt(); | ||||
| 			skillComponent->Reset(); | ||||
| 		} | ||||
| 		GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); | ||||
| 		self->SetVar<int32_t>(u"weakspot", -1); | ||||
| 		GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); | ||||
| 	} | ||||
|   | ||||
| @@ -59,8 +59,6 @@ void FvMaelstromDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_ | ||||
| 	auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); | ||||
|  | ||||
| 	if (destroyableComponent != nullptr) { | ||||
| 		Game::logger->Log("FvMaelstromDragon", "Hit %i", destroyableComponent->GetArmor()); | ||||
|  | ||||
| 		if (destroyableComponent->GetArmor() > 0) return; | ||||
|  | ||||
| 		auto weakpoint = self->GetVar<int32_t>(u"weakpoint"); | ||||
| @@ -80,10 +78,12 @@ void FvMaelstromDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_ | ||||
|  | ||||
| 			if (skillComponent != nullptr) { | ||||
| 				skillComponent->Interrupt(); | ||||
| 				skillComponent->Reset(); | ||||
| 			} | ||||
|  | ||||
| 			self->SetVar<int32_t>(u"weakpoint", 2); | ||||
|  | ||||
| 			GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); | ||||
| 			GameMessages::SendPlayAnimation(self, u"stunstart", 1.7f); | ||||
|  | ||||
| 			self->AddTimer("timeToStunLoop", 1); | ||||
| @@ -150,8 +150,9 @@ void FvMaelstromDragon::OnTimerDone(Entity* self, std::string timerName) { | ||||
|  | ||||
| 		if (skillComponent != nullptr) { | ||||
| 			skillComponent->Interrupt(); | ||||
| 			skillComponent->Reset(); | ||||
| 		} | ||||
|  | ||||
| 		GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); | ||||
| 		self->SetVar<int32_t>(u"weakspot", -1); | ||||
|  | ||||
| 		GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); | ||||
|   | ||||
| @@ -31,9 +31,12 @@ void BaseEnemyApe::OnHit(Entity* self, Entity* attacker) { | ||||
| 	if (destroyableComponent != nullptr && destroyableComponent->GetArmor() < 1 && !self->GetBoolean(u"knockedOut")) { | ||||
| 		StunApe(self, true); | ||||
| 		self->CancelTimer("spawnQBTime"); | ||||
|  | ||||
| 		auto* skillComponent = self->GetComponent<SkillComponent>(); | ||||
| 		if (skillComponent) { | ||||
| 			skillComponent->Reset(); | ||||
| 		} | ||||
| 		GameMessages::SendPlayAnimation(self, u"disable", 1.7f); | ||||
|  | ||||
| 		GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); | ||||
| 		const auto reviveTime = self->GetVar<float_t>(u"reviveTime") != 0.0f | ||||
| 			? self->GetVar<float_t>(u"reviveTime") : 12.0f; | ||||
| 		self->AddTimer("reviveTime", reviveTime); | ||||
| @@ -50,6 +53,7 @@ void BaseEnemyApe::OnTimerDone(Entity* self, std::string timerName) { | ||||
| 			destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor() / timesStunned); | ||||
| 		} | ||||
| 		EntityManager::Instance()->SerializeEntity(self); | ||||
| 		GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); | ||||
| 		self->SetVar<uint32_t>(u"timesStunned", timesStunned + 1); | ||||
| 		StunApe(self, false); | ||||
|  | ||||
|   | ||||
| @@ -39,6 +39,12 @@ foreach(file ${DSCRIPTS_SOURCES_EQUIPMENTSCRIPTS}) | ||||
| 	set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "EquipmentScripts/${file}") | ||||
| endforeach() | ||||
|  | ||||
| add_subdirectory(EquipmentTriggers) | ||||
|  | ||||
| foreach(file ${DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS}) | ||||
| 	set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "EquipmentTriggers/${file}") | ||||
| endforeach() | ||||
|  | ||||
| add_subdirectory(zone) | ||||
|  | ||||
| foreach(file ${DSCRIPTS_SOURCES_ZONE}) | ||||
|   | ||||
| @@ -278,6 +278,9 @@ | ||||
| #include "ImaginationBackpackHealServer.h" | ||||
| #include "LegoDieRoll.h" | ||||
| #include "BuccaneerValiantShip.h" | ||||
| #include "GemPack.h" | ||||
| #include "ShardArmor.h" | ||||
| #include "TeslaPack.h" | ||||
|  | ||||
| // Survival scripts | ||||
| #include "AgSurvivalStromling.h" | ||||
| @@ -837,6 +840,12 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr | ||||
| 		script = new BuccaneerValiantShip(); | ||||
| 	else if (scriptName == "scripts\\EquipmentScripts\\FireFirstSkillonStartup.lua") | ||||
| 		script = new FireFirstSkillonStartup(); | ||||
| 	else if (scriptName == "scripts\\equipmenttriggers\\gempack.lua") | ||||
| 		script = new GemPack(); | ||||
| 	else if (scriptName == "scripts\\equipmenttriggers\\shardarmor.lua") | ||||
| 		script = new ShardArmor(); | ||||
| 	else if (scriptName == "scripts\\equipmenttriggers\\coilbackpack.lua") | ||||
| 		script = new TeslaPack(); | ||||
|  | ||||
| 	// FB | ||||
| 	else if (scriptName == "scripts\\ai\\NS\\WH\\L_ROCKHYDRANT_BROKEN.lua") | ||||
|   | ||||
| @@ -172,6 +172,13 @@ namespace CppScripts { | ||||
| 		 */ | ||||
| 		virtual void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {}; | ||||
|  | ||||
| 		/** | ||||
| 		 * Invoked when self has received either a hit or heal.  Only used for scripts subscribed to an entity. | ||||
| 		 * | ||||
| 		 * Equivalent to 'function notifyHitOrHealResult(self, msg)' | ||||
| 		 */ | ||||
| 		virtual void NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {}; | ||||
|  | ||||
| 		/** | ||||
| 		 * Invoked when a player has responsed to a mission. | ||||
| 		 * | ||||
| @@ -316,6 +323,22 @@ namespace CppScripts { | ||||
| 		virtual void OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, const std::u16string& pathName, | ||||
| 			float_t pathTime, float_t totalTime, int32_t waypoint) { | ||||
| 		}; | ||||
|  | ||||
| 		/** | ||||
| 		 * Used by items to tell their owner that they were equipped. | ||||
| 		 *  | ||||
| 		 * @param itemOwner The owner of the item | ||||
| 		 * @param itemObjId The items Object ID | ||||
| 		 */ | ||||
| 		virtual void OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) {}; | ||||
|  | ||||
| 		/** | ||||
| 		 * Used by items to tell their owner that they were unequipped. | ||||
| 		 *  | ||||
| 		 * @param itemOwner The owner of the item | ||||
| 		 * @param itemObjId The items Object ID | ||||
| 		 */ | ||||
| 		virtual void OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) {}; | ||||
| 	}; | ||||
|  | ||||
| 	Script* GetScript(Entity* parent, const std::string& scriptName); | ||||
|   | ||||
							
								
								
									
										3
									
								
								dScripts/EquipmentTriggers/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								dScripts/EquipmentTriggers/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| set(DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS | ||||
| 	"CoilBackpackBase.cpp" | ||||
| 	PARENT_SCOPE) | ||||
							
								
								
									
										25
									
								
								dScripts/EquipmentTriggers/CoilBackpackBase.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								dScripts/EquipmentTriggers/CoilBackpackBase.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #include "CoilBackpackBase.h" | ||||
|  | ||||
| #include "Entity.h" | ||||
| #include "SkillComponent.h" | ||||
|  | ||||
| void CoilBackpackBase::OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) { | ||||
| 	itemOwner->Subscribe(itemObjId, this, "HitOrHealResult"); | ||||
| 	itemOwner->SetVar<uint8_t>(u"coilCount", 0); | ||||
| } | ||||
|  | ||||
| void CoilBackpackBase::NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { | ||||
| 	if (damage > 0) { | ||||
| 		self->SetVar<uint8_t>(u"coilCount", self->GetVar<uint8_t>(u"coilCount") + 1); | ||||
| 		if (self->GetVar<uint8_t>(u"coilCount") > 4) { | ||||
| 			auto* skillComponent = self->GetComponent<SkillComponent>(); | ||||
| 			if (!skillComponent) return; | ||||
| 			skillComponent->CalculateBehavior(m_SkillId, m_BehaviorId, self->GetObjectID()); | ||||
| 			self->SetVar<uint8_t>(u"coilCount", 0); | ||||
| 		} | ||||
| 	}	 | ||||
| } | ||||
|  | ||||
| void CoilBackpackBase::OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) { | ||||
| 	itemOwner->Unsubscribe(itemObjId, "HitOrHealResult"); | ||||
| } | ||||
							
								
								
									
										21
									
								
								dScripts/EquipmentTriggers/CoilBackpackBase.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								dScripts/EquipmentTriggers/CoilBackpackBase.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| #ifndef __GemPackBase__H__ | ||||
| #define __GemPackBase__H__ | ||||
|  | ||||
| #include "CppScripts.h" | ||||
|  | ||||
| class CoilBackpackBase: public CppScripts::Script { | ||||
| public: | ||||
| 	CoilBackpackBase(uint32_t skillId, uint32_t behaviorId) { | ||||
| 		m_SkillId = skillId; | ||||
| 		m_BehaviorId = behaviorId; | ||||
| 	}; | ||||
|  | ||||
| 	void OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) override; | ||||
| 	void NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; | ||||
| 	void OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) override; | ||||
| private: | ||||
| 	uint32_t m_SkillId = 0; | ||||
| 	uint32_t m_BehaviorId = 0; | ||||
| }; | ||||
|  | ||||
| #endif  //!__GemPackBase__H__ | ||||
							
								
								
									
										14
									
								
								dScripts/EquipmentTriggers/GemPack.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								dScripts/EquipmentTriggers/GemPack.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #ifndef __GEMPACK__H__ | ||||
| #define __GEMPACK__H__ | ||||
|  | ||||
| #include "CoilBackpackBase.h" | ||||
|  | ||||
| class GemPack : public CoilBackpackBase { | ||||
| public: | ||||
| 	GemPack() : CoilBackpackBase(skillId, behaviorId) {}; | ||||
| private: | ||||
| 	static const uint32_t skillId = 1488; | ||||
| 	static const uint32_t behaviorId = 36779; | ||||
| }; | ||||
|  | ||||
| #endif  //!__GEMPACK__H__ | ||||
							
								
								
									
										14
									
								
								dScripts/EquipmentTriggers/ShardArmor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								dScripts/EquipmentTriggers/ShardArmor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #ifndef __SHARDARMOR__H__ | ||||
| #define __SHARDARMOR__H__ | ||||
|  | ||||
| #include "CoilBackpackBase.h" | ||||
|  | ||||
| class ShardArmor : public CoilBackpackBase { | ||||
| public: | ||||
| 	ShardArmor() : CoilBackpackBase(skillId, behaviorId) {}; | ||||
| private: | ||||
| 	static const uint32_t skillId = 1249; | ||||
| 	static const uint32_t behaviorId = 29086; | ||||
| }; | ||||
|  | ||||
| #endif  //!__SHARDARMOR__H__ | ||||
							
								
								
									
										14
									
								
								dScripts/EquipmentTriggers/TeslaPack.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								dScripts/EquipmentTriggers/TeslaPack.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #ifndef __TESLAPACK__H__ | ||||
| #define __TESLAPACK__H__ | ||||
|  | ||||
| #include "CoilBackpackBase.h" | ||||
|  | ||||
| class TeslaPack : public CoilBackpackBase { | ||||
| public: | ||||
| 	TeslaPack() : CoilBackpackBase(skillId, behaviorId) {}; | ||||
| private: | ||||
| 	static const uint32_t skillId = 1001; | ||||
| 	static const uint32_t behaviorId = 20917; | ||||
| }; | ||||
|  | ||||
| #endif  //!__TESLAPACK__H__ | ||||
| @@ -154,7 +154,7 @@ int main(int argc, char** argv) { | ||||
|  | ||||
| 	// Connect to CDClient | ||||
| 	try { | ||||
| 		CDClientDatabase::Connect((Game::assetManager->GetResPath() / "CDServer.sqlite").string()); | ||||
| 		CDClientDatabase::Connect((BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").string()); | ||||
| 	} catch (CppSQLite3Exception& e) { | ||||
| 		Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); | ||||
| 		Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); | ||||
|   | ||||
| @@ -26,5 +26,13 @@ dump_folder= | ||||
| # Either the folder with /res or with /client and /versions | ||||
| client_location= | ||||
|  | ||||
| # The maximum outgoing bandwidth in bits | ||||
| # The maximum outgoing bandwidth in bits.  If your clients are having | ||||
| # issues with enemies taking a while to catch up to them, increse this value. | ||||
| maximum_outgoing_bandwidth=80000 | ||||
|  | ||||
| # The Maximum Translation Unit (MTU) size for packets.  If players are  | ||||
| # getting stuck at 55% on the loading screen, lower this number to  | ||||
| # reduce the chances of packet loss.  This value only has an effect | ||||
| # from 512 <= maximum_mtu_size <= 1492 so make sure to keep this | ||||
| # value within that range. | ||||
| maximum_mtu_size=1228 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 EmosewaMC
					EmosewaMC