mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-11-02 21:51:54 +00:00 
			
		
		
		
	Normalize model positions when placing in the world
Have tested that placing a small and very large model both place and are located at the correct position.
This commit is contained in:
		@@ -8,6 +8,7 @@
 | 
			
		||||
 | 
			
		||||
#include "Database.h"
 | 
			
		||||
#include "Game.h"
 | 
			
		||||
#include "Sd0.h"
 | 
			
		||||
#include "ZCompression.h"
 | 
			
		||||
#include "Logger.h"
 | 
			
		||||
 | 
			
		||||
@@ -44,10 +45,10 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Ignore the valgrind warning about uninitialized values.  These are discarded later when we know the actual uncompressed size.
 | 
			
		||||
				std::unique_ptr<uint8_t[]> uncompressedChunk(new uint8_t[ZCompression::MAX_SD0_CHUNK_SIZE]);
 | 
			
		||||
				std::unique_ptr<uint8_t[]> uncompressedChunk(new uint8_t[Sd0::MAX_UNCOMPRESSED_CHUNK_SIZE]);
 | 
			
		||||
				int32_t err{};
 | 
			
		||||
				int32_t actualUncompressedSize = ZCompression::Decompress(
 | 
			
		||||
					compressedChunk.get(), chunkSize, uncompressedChunk.get(), ZCompression::MAX_SD0_CHUNK_SIZE, err);
 | 
			
		||||
					compressedChunk.get(), chunkSize, uncompressedChunk.get(), Sd0::MAX_UNCOMPRESSED_CHUNK_SIZE, err);
 | 
			
		||||
 | 
			
		||||
				if (actualUncompressedSize != -1) {
 | 
			
		||||
					uint32_t previousSize = completeUncompressedModel.size();
 | 
			
		||||
 
 | 
			
		||||
@@ -29,8 +29,8 @@ constexpr const char* GetFileNameFromAbsolutePath(const char* path) {
 | 
			
		||||
// they will not be valid constexpr and will be evaluated at runtime instead of compile time!
 | 
			
		||||
// The full string is still stored in the binary, however the offset of the filename in the absolute paths
 | 
			
		||||
// is used in the instruction instead of the start of the absolute path.
 | 
			
		||||
#define LOG(message, ...) do { auto str = FILENAME_AND_LINE; Game::logger->Log(str, message, ##__VA_ARGS__); } while(0)
 | 
			
		||||
#define LOG_DEBUG(message, ...) do { auto str = FILENAME_AND_LINE; Game::logger->LogDebug(str, message, ##__VA_ARGS__); } while(0)
 | 
			
		||||
#define LOG(message, ...) do { auto str_ = FILENAME_AND_LINE; Game::logger->Log(str_, message, ##__VA_ARGS__); } while(0)
 | 
			
		||||
#define LOG_DEBUG(message, ...) do { auto str_ = FILENAME_AND_LINE; Game::logger->LogDebug(str_, message, ##__VA_ARGS__); } while(0)
 | 
			
		||||
 | 
			
		||||
// Writer class for writing data to files.
 | 
			
		||||
class Writer {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,11 +8,5 @@ namespace ZCompression {
 | 
			
		||||
	int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst);
 | 
			
		||||
 | 
			
		||||
	int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @brief Max size of an inflated sd0 zlib chunk
 | 
			
		||||
	 *
 | 
			
		||||
	 */
 | 
			
		||||
	constexpr uint32_t MAX_SD0_CHUNK_SIZE = 1024 * 256;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#include "Pack.h"
 | 
			
		||||
 | 
			
		||||
#include "BinaryIO.h"
 | 
			
		||||
#include "Sd0.h"
 | 
			
		||||
#include "ZCompression.h"
 | 
			
		||||
 | 
			
		||||
Pack::Pack(const std::filesystem::path& filePath) {
 | 
			
		||||
@@ -106,7 +107,7 @@ bool Pack::ReadFileFromPack(const uint32_t crc, char** data, uint32_t* len) cons
 | 
			
		||||
		pos += size; // Move pointer position the amount of bytes read to the right
 | 
			
		||||
 | 
			
		||||
		int32_t err;
 | 
			
		||||
		currentReadPos += ZCompression::Decompress(reinterpret_cast<uint8_t*>(chunk), size, reinterpret_cast<uint8_t*>(decompressedData + currentReadPos), ZCompression::MAX_SD0_CHUNK_SIZE, err);
 | 
			
		||||
		currentReadPos += ZCompression::Decompress(reinterpret_cast<uint8_t*>(chunk), size, reinterpret_cast<uint8_t*>(decompressedData + currentReadPos), Sd0::MAX_UNCOMPRESSED_CHUNK_SIZE, err);
 | 
			
		||||
 | 
			
		||||
		free(chunk);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ public:
 | 
			
		||||
 | 
			
		||||
	// Inserts a new UGC model into the database.
 | 
			
		||||
	virtual void InsertNewUgcModel(
 | 
			
		||||
		std::istringstream& sd0Data,
 | 
			
		||||
		std::stringstream& sd0Data,
 | 
			
		||||
		const uint32_t blueprintId,
 | 
			
		||||
		const uint32_t accountId,
 | 
			
		||||
		const uint32_t characterId) = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,7 @@ public:
 | 
			
		||||
	void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override;
 | 
			
		||||
	void InsertNewMail(const MailInfo& mail) override;
 | 
			
		||||
	void InsertNewUgcModel(
 | 
			
		||||
		std::istringstream& sd0Data,
 | 
			
		||||
		std::stringstream& sd0Data,
 | 
			
		||||
		const uint32_t blueprintId,
 | 
			
		||||
		const uint32_t accountId,
 | 
			
		||||
		const uint32_t characterId) override;
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ void MySQLDatabase::RemoveUnreferencedUgcModels() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MySQLDatabase::InsertNewUgcModel(
 | 
			
		||||
	std::istringstream& sd0Data, // cant be const sad
 | 
			
		||||
	std:: stringstream& sd0Data, // cant be const sad
 | 
			
		||||
	const uint32_t blueprintId,
 | 
			
		||||
	const uint32_t accountId,
 | 
			
		||||
	const uint32_t characterId) {
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@ public:
 | 
			
		||||
	void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override;
 | 
			
		||||
	void InsertNewMail(const MailInfo& mail) override;
 | 
			
		||||
	void InsertNewUgcModel(
 | 
			
		||||
		std::istringstream& sd0Data,
 | 
			
		||||
		std::stringstream& sd0Data,
 | 
			
		||||
		const uint32_t blueprintId,
 | 
			
		||||
		const uint32_t accountId,
 | 
			
		||||
		const uint32_t characterId) override;
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ void SQLiteDatabase::RemoveUnreferencedUgcModels() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SQLiteDatabase::InsertNewUgcModel(
 | 
			
		||||
	std::istringstream& sd0Data, // cant be const sad
 | 
			
		||||
	std::stringstream& sd0Data, // cant be const sad
 | 
			
		||||
	const uint32_t blueprintId,
 | 
			
		||||
	const uint32_t accountId,
 | 
			
		||||
	const uint32_t characterId) {
 | 
			
		||||
 
 | 
			
		||||
@@ -188,7 +188,7 @@ void TestSQLDatabase::InsertNewMail(const MailInfo& mail) {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestSQLDatabase::InsertNewUgcModel(std::istringstream& sd0Data, const uint32_t blueprintId, const uint32_t accountId, const uint32_t characterId) {
 | 
			
		||||
void TestSQLDatabase::InsertNewUgcModel(std::stringstream& sd0Data, const uint32_t blueprintId, const uint32_t accountId, const uint32_t characterId) {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ class TestSQLDatabase : public GameDatabase {
 | 
			
		||||
	void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override;
 | 
			
		||||
	void InsertNewMail(const MailInfo& mail) override;
 | 
			
		||||
	void InsertNewUgcModel(
 | 
			
		||||
		std::istringstream& sd0Data,
 | 
			
		||||
		std::stringstream& sd0Data,
 | 
			
		||||
		const uint32_t blueprintId,
 | 
			
		||||
		const uint32_t accountId,
 | 
			
		||||
		const uint32_t characterId) override;
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentE
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Exclude the zone control object from any flags
 | 
			
		||||
		if (!controller && info.lot != 14) {
 | 
			
		||||
		if (!controller) {
 | 
			
		||||
 | 
			
		||||
			// The client flags means the client should render the entity
 | 
			
		||||
			GeneralUtils::SetBit(id, eObjectBits::CLIENT);
 | 
			
		||||
 
 | 
			
		||||
@@ -102,6 +102,8 @@
 | 
			
		||||
#include "CDComponentsRegistryTable.h"
 | 
			
		||||
#include "CDObjectsTable.h"
 | 
			
		||||
#include "eItemType.h"
 | 
			
		||||
#include "Lxfml.h"
 | 
			
		||||
#include "Sd0.h"
 | 
			
		||||
 | 
			
		||||
void GameMessages::SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender) {
 | 
			
		||||
	CBITSTREAM;
 | 
			
		||||
@@ -2613,16 +2615,26 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream& inStream, Entity* ent
 | 
			
		||||
		LWOOBJID propertyId = LWOOBJID_EMPTY;
 | 
			
		||||
		if (propertyInfo) propertyId = propertyInfo->id;
 | 
			
		||||
 | 
			
		||||
		//Insert into ugc:
 | 
			
		||||
		// Save the binary data to the Sd0 buffer
 | 
			
		||||
		std::string str(sd0Data.get(), sd0Size);
 | 
			
		||||
		std::istringstream sd0DataStream(str);
 | 
			
		||||
		Database::Get()->InsertNewUgcModel(sd0DataStream, blueprintIDSmall, entity->GetCharacter()->GetParentUser()->GetAccountID(), entity->GetCharacter()->GetID());
 | 
			
		||||
		Sd0 sd0(sd0DataStream);
 | 
			
		||||
 | 
			
		||||
		// Uncompress the data and normalize the position
 | 
			
		||||
		const auto asStr = sd0.GetAsStringUncompressed();
 | 
			
		||||
		const auto [newLxfml, newCenter] = Lxfml::NormalizePosition(asStr);
 | 
			
		||||
		auto [x, y, z] = newCenter;
 | 
			
		||||
 | 
			
		||||
		// Recompress the data and save to the database
 | 
			
		||||
		sd0.FromData(reinterpret_cast<const uint8_t*>(newLxfml.data()), newLxfml.size());
 | 
			
		||||
		auto sd0AsStream = sd0.GetAsStream();
 | 
			
		||||
		Database::Get()->InsertNewUgcModel(sd0AsStream, blueprintIDSmall, entity->GetCharacter()->GetParentUser()->GetAccountID(), entity->GetCharacter()->GetID());
 | 
			
		||||
 | 
			
		||||
		//Insert into the db as a BBB model:
 | 
			
		||||
		IPropertyContents::Model model;
 | 
			
		||||
		model.id = newIDL;
 | 
			
		||||
		model.ugcId = blueprintIDSmall;
 | 
			
		||||
		model.position = NiPoint3Constant::ZERO;
 | 
			
		||||
		model.position = newCenter;
 | 
			
		||||
		model.rotation = NiQuaternion(0.0f, 0.0f, 0.0f, 0.0f);
 | 
			
		||||
		model.lot = 14;
 | 
			
		||||
		Database::Get()->InsertNewPropertyModel(propertyId, model, "Objects_14_name");
 | 
			
		||||
@@ -2648,6 +2660,9 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream& inStream, Entity* ent
 | 
			
		||||
		//}
 | 
			
		||||
 | 
			
		||||
		//Tell the client their model is saved: (this causes us to actually pop out of our current state):
 | 
			
		||||
		const auto& newSd0 = sd0.GetAsVector();
 | 
			
		||||
		uint32_t sd0Size{};
 | 
			
		||||
		for (const auto& chunk : newSd0) sd0Size += chunk.size();
 | 
			
		||||
		CBITSTREAM;
 | 
			
		||||
		BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::BLUEPRINT_SAVE_RESPONSE);
 | 
			
		||||
		bitStream.Write(localId);
 | 
			
		||||
@@ -2655,9 +2670,9 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream& inStream, Entity* ent
 | 
			
		||||
		bitStream.Write<uint32_t>(1);
 | 
			
		||||
		bitStream.Write(blueprintID);
 | 
			
		||||
 | 
			
		||||
		bitStream.Write<uint32_t>(sd0Size);
 | 
			
		||||
		bitStream.Write(sd0Size);
 | 
			
		||||
 | 
			
		||||
		bitStream.WriteAlignedBytes(reinterpret_cast<unsigned char*>(sd0Data.get()), sd0Size);
 | 
			
		||||
		for (const auto& chunk : newSd0) bitStream.WriteAlignedBytes(reinterpret_cast<const unsigned char*>(chunk.data()), chunk.size());
 | 
			
		||||
 | 
			
		||||
		SEND_PACKET;
 | 
			
		||||
 | 
			
		||||
@@ -2665,7 +2680,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream& inStream, Entity* ent
 | 
			
		||||
 | 
			
		||||
		EntityInfo info;
 | 
			
		||||
		info.lot = 14;
 | 
			
		||||
		info.pos = {};
 | 
			
		||||
		info.pos = newCenter;
 | 
			
		||||
		info.rot = {};
 | 
			
		||||
		info.spawner = nullptr;
 | 
			
		||||
		info.spawnerID = entity->GetObjectID();
 | 
			
		||||
 
 | 
			
		||||
@@ -1417,7 +1417,6 @@ void WorldShutdownProcess(uint32_t zoneId) {
 | 
			
		||||
	if (PropertyManagementComponent::Instance() != nullptr) {
 | 
			
		||||
		LOG("Saving ALL property data for zone %i clone %i!", zoneId, PropertyManagementComponent::Instance()->GetCloneId());
 | 
			
		||||
		PropertyManagementComponent::Instance()->Save();
 | 
			
		||||
		Database::Get()->RemoveUnreferencedUgcModels();
 | 
			
		||||
		LOG("ALL property data saved for zone %i clone %i!", zoneId, PropertyManagementComponent::Instance()->GetCloneId());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user