From a026aea23e6d1ba35dedbe2b670a4f1518fb1747 Mon Sep 17 00:00:00 2001 From: Anonymous CCP Employee Date: Thu, 7 May 2026 13:57:11 +0000 Subject: [PATCH 01/11] Update booster persistance We've been having trouble preserving booster data with red file loading. A common scenario is when a user loads a scene state. The boosters on the ships in those scenes would be dead since the sof locator hookup required to set up the boosters correctly is missing. We've been compensating for this by employing EveBoosterSet2.RebuildBoosterSet. This method however doesn't preserve the data from the booster, and sometimes ends up setting wrong atlasIndices for instance which can majorly affect the booster visual. So we'd end up in a scenario where we can't load scenes properly through trinity.Load because there's no feasible way to make the sof connection through that avenue, something that LoadFromDNA has no trouble doing. The proposed solution to this is to persist the m_singleBoosters data and make it public. This way it can be serialized upon save and smoothly loaded back up when loading a scene. Some of the params there are non-desirable to persist, being randomized per instance, which was accounted for here. `RebuildBoosterSet` was also modified to persist the relevant data from the old booster data (effect, glows, trails, visual settings) when rebuilding the boosters. --- .../Attachments/EveBoosterSet2.cpp | 58 ++++++++++++++++++- .../SpaceObject/Attachments/EveBoosterSet2.h | 35 +++++++---- .../Attachments/EveBoosterSet2_Blue.cpp | 1 + trinity/Eve/SpaceObject/EveShip2.cpp | 33 ++++++++++- 4 files changed, 110 insertions(+), 17 deletions(-) diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp index 33a99b9d0..2c52c4d02 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp @@ -734,10 +734,24 @@ EveBoosterSet2::~EveBoosterSet2() // -------------------------------------------------------------------------------- // Description: -// If loading from a .red file, we now can start creating resources +// If loading from a .red file, we now can start creating resources. +// If m_boosters was loaded from persistence, the entries contain source data +// but not the derived runtime fields (lightPosition, lightRadius, lightPhase). +// We snapshot the loaded entries, clear, then re-add through Add() which +// computes all derived fields correctly. // -------------------------------------------------------------------------------- bool EveBoosterSet2::Initialize() { + if( !m_singleBoosters.empty() ) + { + std::vector loaded = m_singleBoosters; + m_singleBoosters.clear(); + for( const auto& item : loaded ) + { + Add( &item.transform, &item.functionality, item.hasTrail, item.atlasIndex0, item.atlasIndex1, item.lightScale ); + } + FinalizeRebuild(); + } PrepareResources(); return true; } @@ -846,10 +860,48 @@ void EveBoosterSet2::Clear() ReleaseResources( TRISTORAGE_ALL ); } +// -------------------------------------------------------------------------------- +// Description: +// Rebuild boosters while preserving effects, glows, trails and visual settings. +// This is used when locators change but the booster configuration should remain. +// -------------------------------------------------------------------------------- +void EveBoosterSet2::RebuildPreservingSettings() +{ + // Clear only the booster items, not the effects/glows/trails + m_singleBoosters.clear(); + if( m_glows ) + { + m_glows->Clear(); + } + if( m_trails ) + { + m_trails->Clear(); + } + + // Reset bounding info + BoundingSphereInitialize( m_boosterBoundingSphere ); + + // Release only the instance buffer resources + ReleaseResources( TRISTORAGE_ALL ); +} + +// -------------------------------------------------------------------------------- +// Description: +// Finalize the rebuild by rebuilding glows after all boosters have been added. +// Call this after RebuildPreservingSettings() and all Add() calls. +// -------------------------------------------------------------------------------- +void EveBoosterSet2::FinalizeRebuild() +{ + if( m_glows ) + { + m_glows->Rebuild(); + } +} + // -------------------------------------------------------------------------------- void EveBoosterSet2::Add( const Matrix* localMatrix, const Vector4* functionality, bool hasTrail, uint32_t atlasIndex0, uint32_t atlasIndex1, float lightScale ) { - // keep it in our list of boosters + // keep source data for persistence and rebuild SingleBoosterData sbd; sbd.transform = *localMatrix; sbd.functionality = *functionality; @@ -859,6 +911,8 @@ void EveBoosterSet2::Add( const Matrix* localMatrix, const Vector4* functionalit sbd.lightPhase = float( g_lightNoiseSize ) * float( rand() ) / float( RAND_MAX ); sbd.atlasIndex0 = atlasIndex0; sbd.atlasIndex1 = atlasIndex1; + sbd.hasTrail = hasTrail; + sbd.lightScale = lightScale; m_singleBoosters.push_back( sbd ); Vector3 pos( localMatrix->_41, localMatrix->_42, localMatrix->_43 ); diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h index 1e9fb2c03..937c5d477 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h @@ -234,7 +234,29 @@ BLUE_CLASS( EveBoosterSet2 ): void UpdateTrails( float deltaT, Be::Time t ); // manage individual exhaust points void Clear(); + void RebuildPreservingSettings(); + void FinalizeRebuild(); + + // Per-booster data. The first six fields are the source data persisted to .red + // files so boosters survive save/load cycles. The remaining three are derived + // at runtime inside Add() and are never persisted. + struct SingleBoosterData + { + // --- persisted --- + Matrix transform; + Vector4 functionality; + uint32_t atlasIndex0; + uint32_t atlasIndex1; + bool hasTrail; + float lightScale; + // --- runtime derived, not persisted --- + Vector3 lightPosition; + float lightRadius; + float lightPhase; + }; + void Add( const Matrix* localMatrix, const Vector4* functionality, bool hasTrail, uint32_t atlasIndex0, uint32_t atlasIndex1, float lightScale = 1 ); + const std::vector& GetSingleBoosters() const { return m_singleBoosters; } // set internal visual data void SetData( float glowScale, @@ -269,18 +291,7 @@ BLUE_CLASS( EveBoosterSet2 ): void GetLights( Tr2LightManager& lightManager ) const override; private: - // indivual data of each booster (position, etc.) - struct SingleBoosterData - { - Matrix transform; - Vector4 functionality; - Vector3 lightPosition; - float lightRadius; - float lightPhase; - uint32_t atlasIndex0; - uint32_t atlasIndex1; - }; - std::vector m_singleBoosters; + std::vector m_singleBoosters; // re-alloc and init the instance vertex buffers void RebuildInstanceData( Tr2RenderContext& renderContext ); diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp index b6584edac..7622dbb38 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp @@ -166,6 +166,7 @@ const Be::ClassInfo* EveBoosterSet2::ExposeToBlue() MAP_ATTRIBUTE( "effectFar", m_effectFar, "Effect to use to render the boosters at a distance", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "glows", m_glows, "Sprite set to use to render the glows on the boosters", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "trails", m_trails, "Trails set used to render the trails of this booster", Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( "singleBoosters", m_singleBoosters, "Per-booster source data (transform, atlas indices, etc.)", Be::READWRITE | Be::PERSIST ) EXPOSURE_END() diff --git a/trinity/Eve/SpaceObject/EveShip2.cpp b/trinity/Eve/SpaceObject/EveShip2.cpp index 193af7c4d..5d257b6b4 100644 --- a/trinity/Eve/SpaceObject/EveShip2.cpp +++ b/trinity/Eve/SpaceObject/EveShip2.cpp @@ -236,23 +236,50 @@ void EveShip2::RebuildBoosterSet() return; } - m_boosters->Clear(); + // Snapshot the currently persisted booster data before clearing + std::vector snapshot = m_boosters->GetSingleBoosters(); + // Clear only the booster items while preserving effects, glows, trails, and visual settings + m_boosters->RebuildPreservingSettings(); + + // Rebuild boosters from locators, restoring their original settings static const char* kLocatorPrefix = "locator_booster"; const unsigned int kLocatorPrefixLength = (unsigned int)strlen( kLocatorPrefix ); + unsigned int boosterIndex = 0; unsigned int n = (unsigned int)m_locators.size(); - for( unsigned int i = 0; i < n ; ++i ) + for( unsigned int i = 0; i < n; ++i ) { EveLocator2Ptr locator = m_locators[i]; const char* locatorName = locator->GetName(); if( strncmp( locatorName, kLocatorPrefix, kLocatorPrefixLength ) == 0 ) { + // Restore saved data if available, otherwise use defaults Vector4 functionality( 0.f, 1.f, 1.f, 1.f ); - m_boosters->Add( &locator->GetTransform(), &functionality, true, 0, 0 ); + bool hasTrail = true; + uint32_t atlasIndex0 = 0; + uint32_t atlasIndex1 = 0; + float lightScale = 1.0f; + + if( boosterIndex < snapshot.size() ) + { + const auto& saved = snapshot[boosterIndex]; + functionality = saved.functionality; + hasTrail = saved.hasTrail; + atlasIndex0 = saved.atlasIndex0; + atlasIndex1 = saved.atlasIndex1; + lightScale = saved.lightScale; + } + + m_boosters->Add( &locator->GetTransform(), &functionality, hasTrail, atlasIndex0, atlasIndex1, lightScale ); + ++boosterIndex; } } + // Finalize the rebuild by rebuilding glows + m_boosters->FinalizeRebuild(); + + // Prepare resources to rebuild instance buffer and finalize m_boosters->PrepareResources(); } From 669d3bb5873304ff7530e609b23f7ef332f578e1 Mon Sep 17 00:00:00 2001 From: Anonymous CCP Employee Date: Thu, 7 May 2026 15:30:35 +0000 Subject: [PATCH 02/11] update error --- trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h index 937c5d477..5372b077a 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h @@ -290,9 +290,9 @@ BLUE_CLASS( EveBoosterSet2 ): // ITr2LightOwner void GetLights( Tr2LightManager& lightManager ) const override; -private: - std::vector m_singleBoosters; + std::vector m_singleBoosters; +private: // re-alloc and init the instance vertex buffers void RebuildInstanceData( Tr2RenderContext& renderContext ); From ef8eae3fc7a7fd6906afc9f9edbc3adfdac16f2d Mon Sep 17 00:00:00 2001 From: Anonymous CCP Employee Date: Thu, 7 May 2026 17:43:20 +0000 Subject: [PATCH 03/11] make the booster set item official --- trinity/CMakeLists.txt | 2 ++ .../Attachments/EveBoosterSet2.cpp | 22 ++++++++---- .../SpaceObject/Attachments/EveBoosterSet2.h | 36 ++++++++++--------- .../Attachments/EveBoosterSetItem.h | 35 ++++++++++++++++++ .../Attachments/EveBoosterSetItem_Blue.cpp | 18 ++++++++++ trinity/Eve/SpaceObject/EveShip2.cpp | 2 +- 6 files changed, 91 insertions(+), 24 deletions(-) create mode 100644 trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h create mode 100644 trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem_Blue.cpp diff --git a/trinity/CMakeLists.txt b/trinity/CMakeLists.txt index c31ccaf8c..02d6b0f06 100644 --- a/trinity/CMakeLists.txt +++ b/trinity/CMakeLists.txt @@ -297,6 +297,8 @@ set(_SOURCES Eve/SpaceObject/Attachments/EveBoosterSet2.cpp Eve/SpaceObject/Attachments/EveBoosterSet2.h Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp + Eve/SpaceObject/Attachments/EveBoosterSetItem.h + Eve/SpaceObject/Attachments/EveBoosterSetItem_Blue.cpp Eve/SpaceObject/Attachments/EveImpactOverlay.cpp Eve/SpaceObject/Attachments/EveImpactOverlay.h Eve/SpaceObject/Attachments/EveImpactOverlay_Blue.cpp diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp index 2c52c4d02..22a25a071 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp @@ -1,5 +1,6 @@ #include "StdAfx.h" #include "EveBoosterSet2.h" +#include "EveBoosterSetItem.h" #include "Utilities/BoundingSphere.h" #include "Utilities/BoundingBox.h" @@ -742,13 +743,13 @@ EveBoosterSet2::~EveBoosterSet2() // -------------------------------------------------------------------------------- bool EveBoosterSet2::Initialize() { - if( !m_singleBoosters.empty() ) + if( !m_persistedItems.empty() ) { - std::vector loaded = m_singleBoosters; m_singleBoosters.clear(); - for( const auto& item : loaded ) + for( unsigned int i = 0; i < m_persistedItems.size(); ++i ) { - Add( &item.transform, &item.functionality, item.hasTrail, item.atlasIndex0, item.atlasIndex1, item.lightScale ); + const EveBoosterSetItem* item = m_persistedItems[i]; + Add( &item->transform, &item->functionality, item->hasTrail, item->atlasIndex0, item->atlasIndex1, item->lightScale ); } FinalizeRebuild(); } @@ -869,6 +870,7 @@ void EveBoosterSet2::RebuildPreservingSettings() { // Clear only the booster items, not the effects/glows/trails m_singleBoosters.clear(); + m_persistedItems.Clear(); if( m_glows ) { m_glows->Clear(); @@ -911,10 +913,18 @@ void EveBoosterSet2::Add( const Matrix* localMatrix, const Vector4* functionalit sbd.lightPhase = float( g_lightNoiseSize ) * float( rand() ) / float( RAND_MAX ); sbd.atlasIndex0 = atlasIndex0; sbd.atlasIndex1 = atlasIndex1; - sbd.hasTrail = hasTrail; - sbd.lightScale = lightScale; m_singleBoosters.push_back( sbd ); + EveBoosterSetItemPtr item; + item.CreateInstance(); + item->transform = *localMatrix; + item->functionality = *functionality; + item->atlasIndex0 = atlasIndex0; + item->atlasIndex1 = atlasIndex1; + item->hasTrail = hasTrail; + item->lightScale = lightScale; + m_persistedItems.Append( item->GetRawRoot() ); + Vector3 pos( localMatrix->_41, localMatrix->_42, localMatrix->_43 ); float scale = std::max( Length( localMatrix->GetX() ), Length( localMatrix->GetY() ) ); diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h index 5372b077a..ccb298c82 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h @@ -13,6 +13,7 @@ #include "Eve/EveUpdateContext.h" #include "Eve/EveEntity.h" #include "Lights/ITr2LightOwner.h" +#include "EveBoosterSetItem.h" // forwards class ITriRenderBatchAccumulator; @@ -237,26 +238,24 @@ BLUE_CLASS( EveBoosterSet2 ): void RebuildPreservingSettings(); void FinalizeRebuild(); - // Per-booster data. The first six fields are the source data persisted to .red - // files so boosters survive save/load cycles. The remaining three are derived - // at runtime inside Add() and are never persisted. + // Runtime per-booster data used for rendering, lighting, and debug. + // transform, functionality, atlasIndex0, and atlasIndex1 mirror the + // corresponding fields in EveBoosterSetItem (m_persistedItems), which + // is the Blue-serialized source of truth for save/load cycles. + // lightPosition, lightRadius, and lightPhase are derived in Add() and + // are never persisted. struct SingleBoosterData { - // --- persisted --- - Matrix transform; - Vector4 functionality; - uint32_t atlasIndex0; - uint32_t atlasIndex1; - bool hasTrail; - float lightScale; - // --- runtime derived, not persisted --- - Vector3 lightPosition; - float lightRadius; - float lightPhase; + Matrix transform; + Vector4 functionality; + uint32_t atlasIndex0; + uint32_t atlasIndex1; + Vector3 lightPosition; + float lightRadius; + float lightPhase; }; void Add( const Matrix* localMatrix, const Vector4* functionality, bool hasTrail, uint32_t atlasIndex0, uint32_t atlasIndex1, float lightScale = 1 ); - const std::vector& GetSingleBoosters() const { return m_singleBoosters; } // set internal visual data void SetData( float glowScale, @@ -290,9 +289,11 @@ BLUE_CLASS( EveBoosterSet2 ): // ITr2LightOwner void GetLights( Tr2LightManager& lightManager ) const override; - std::vector m_singleBoosters; + const PEveBoosterSetItemVector& GetPersistedItems() const { return m_persistedItems; } private: + std::vector m_singleBoosters; + PEveBoosterSetItemVector m_persistedItems; // re-alloc and init the instance vertex buffers void RebuildInstanceData( Tr2RenderContext& renderContext ); @@ -364,4 +365,5 @@ BLUE_CLASS( EveBoosterSet2 ): TYPEDEF_BLUECLASS( EveBoosterSet2 ); -#endif // EveBoosterSet2_H \ No newline at end of file +#endif // EveBoosterSet2_H + diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h new file mode 100644 index 000000000..8b12c8b54 --- /dev/null +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h @@ -0,0 +1,35 @@ +#pragma once +#ifndef EveBoosterSetItem_H +#define EveBoosterSetItem_H + +BLUE_DECLARE( EveBoosterSetItem ); +BLUE_DECLARE_VECTOR( EveBoosterSetItem ); + +// -------------------------------------------------------------------------------- +// Description: +// Persisted per-booster source data. Holds only the fields needed to reconstruct +// a booster after a .red file load. Runtime-derived fields (lightPosition, +// lightRadius, lightPhase) are NOT stored here — they are recomputed by +// EveBoosterSet2::Add() at load time. +// SeeAlso: +// EveBoosterSet2 +// -------------------------------------------------------------------------------- +BLUE_CLASS( EveBoosterSetItem ) +{ +public: + EXPOSE_TO_BLUE(); + + EveBoosterSetItem( IRoot* lockobj = NULL ) {} + + Matrix transform; + Vector4 functionality; + uint32_t atlasIndex0; + uint32_t atlasIndex1; + bool hasTrail; + float lightScale; +}; + +TYPEDEF_BLUECLASS( EveBoosterSetItem ); + +#endif // EveBoosterSetItem_H + diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem_Blue.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem_Blue.cpp new file mode 100644 index 000000000..5b2121c82 --- /dev/null +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem_Blue.cpp @@ -0,0 +1,18 @@ +#include "StdAfx.h" +#include "EveBoosterSetItem.h" + +BLUE_DEFINE( EveBoosterSetItem ); + +const Be::ClassInfo* EveBoosterSetItem::ExposeToBlue() +{ + EXPOSURE_BEGIN( EveBoosterSetItem, "" ) + MAP_INTERFACE( EveBoosterSetItem ) + MAP_ATTRIBUTE( "transform", transform, "Local transform of this booster exhaust point", Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( "functionality", functionality, "Booster behaviour flags", Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( "atlasIndex0", atlasIndex0, "Shape map index (primary)", Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( "atlasIndex1", atlasIndex1, "Shape map index (secondary)", Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( "hasTrail", hasTrail, "Whether this booster contributes to trails", Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( "lightScale", lightScale, "Scaling factor for dynamic light radius", Be::READWRITE | Be::PERSIST ) + EXPOSURE_END() +} + diff --git a/trinity/Eve/SpaceObject/EveShip2.cpp b/trinity/Eve/SpaceObject/EveShip2.cpp index 5d257b6b4..9a9035a22 100644 --- a/trinity/Eve/SpaceObject/EveShip2.cpp +++ b/trinity/Eve/SpaceObject/EveShip2.cpp @@ -237,7 +237,7 @@ void EveShip2::RebuildBoosterSet() } // Snapshot the currently persisted booster data before clearing - std::vector snapshot = m_boosters->GetSingleBoosters(); + PEveBoosterSetItemVector snapshot = m_boosters->GetPersistedItems(); // Clear only the booster items while preserving effects, glows, trails, and visual settings m_boosters->RebuildPreservingSettings(); From dafeea0007b24fe8e7a98ef4b76aa911018d24ea Mon Sep 17 00:00:00 2001 From: Anonymous CCP Employee Date: Thu, 7 May 2026 17:50:40 +0000 Subject: [PATCH 04/11] make inherit iroot --- trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h index 8b12c8b54..d21ab7a3b 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h @@ -14,7 +14,8 @@ BLUE_DECLARE_VECTOR( EveBoosterSetItem ); // SeeAlso: // EveBoosterSet2 // -------------------------------------------------------------------------------- -BLUE_CLASS( EveBoosterSetItem ) +BLUE_CLASS( EveBoosterSetItem ) : + public IRoot { public: EXPOSE_TO_BLUE(); @@ -33,3 +34,4 @@ TYPEDEF_BLUECLASS( EveBoosterSetItem ); #endif // EveBoosterSetItem_H + From 9b7835a6d1bbe1e44d29fe8522a9444e87f12fb1 Mon Sep 17 00:00:00 2001 From: Anonymous CCP Employee Date: Wed, 13 May 2026 15:06:54 +0000 Subject: [PATCH 05/11] change implementation to make use of structure lists instead --- trinity/CMakeLists.txt | 2 - .../Attachments/EveBoosterSet2.cpp | 198 +++++++++++++----- .../SpaceObject/Attachments/EveBoosterSet2.h | 66 ++++-- .../Attachments/EveBoosterSet2_Blue.cpp | 2 +- .../Attachments/EveBoosterSetItem.h | 37 ---- .../Attachments/EveBoosterSetItem_Blue.cpp | 18 -- trinity/Eve/SpaceObject/EveShip2.cpp | 6 +- 7 files changed, 196 insertions(+), 133 deletions(-) delete mode 100644 trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h delete mode 100644 trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem_Blue.cpp diff --git a/trinity/CMakeLists.txt b/trinity/CMakeLists.txt index 02d6b0f06..c31ccaf8c 100644 --- a/trinity/CMakeLists.txt +++ b/trinity/CMakeLists.txt @@ -297,8 +297,6 @@ set(_SOURCES Eve/SpaceObject/Attachments/EveBoosterSet2.cpp Eve/SpaceObject/Attachments/EveBoosterSet2.h Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp - Eve/SpaceObject/Attachments/EveBoosterSetItem.h - Eve/SpaceObject/Attachments/EveBoosterSetItem_Blue.cpp Eve/SpaceObject/Attachments/EveImpactOverlay.cpp Eve/SpaceObject/Attachments/EveImpactOverlay.h Eve/SpaceObject/Attachments/EveImpactOverlay_Blue.cpp diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp index 22a25a071..04280e80d 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp @@ -1,6 +1,5 @@ #include "StdAfx.h" #include "EveBoosterSet2.h" -#include "EveBoosterSetItem.h" #include "Utilities/BoundingSphere.h" #include "Utilities/BoundingBox.h" @@ -45,7 +44,38 @@ float g_lightNoise[g_lightNoiseSize]; bool g_lightNoiseInitialized = false; -EveBoosterSet2Renderable::EveBoosterSet2Renderable( IRoot* lockobj ) : +namespace +{ + BlueStructureDefinition s_boosterItemStructureDef[] = + { + { "transformRow0", Be::FLOAT32_4, offsetof( EveBoosterItem, transform ) + 0 }, + { "transformRow1", Be::FLOAT32_4, offsetof( EveBoosterItem, transform ) + 16 }, + { "transformRow2", Be::FLOAT32_4, offsetof( EveBoosterItem, transform ) + 32 }, + { "transformRow3", Be::FLOAT32_4, offsetof( EveBoosterItem, transform ) + 48 }, + { "functionality", Be::FLOAT32_4, offsetof( EveBoosterItem, functionality ) }, + { "atlasIndex0", Be::UINT32_1, offsetof( EveBoosterItem, atlasIndex0 ) }, + { "atlasIndex1", Be::UINT32_1, offsetof( EveBoosterItem, atlasIndex1 ) }, + { "hasTrail", Be::INT32_1, offsetof( EveBoosterItem, hasTrail ) }, + { "lightScale", Be::FLOAT32_1, offsetof( EveBoosterItem, lightScale ) }, + { 0 } + }; + + EveBoosterItem s_defaultBoosterItem; +} + + +EveBoosterItem::EveBoosterItem() + : transform( IdentityMatrix() ), + functionality( 0.f, 1.f, 1.f, 1.f ), + atlasIndex0( 0 ), + atlasIndex1( 0 ), + hasTrail( 1 ), + lightScale( 1.f ) +{ +} + + +EveBoosterSet2Renderable::EveBoosterSet2Renderable( IRoot* lockobj ) : m_isVisible( false ), m_parentRotation( 0.f, 0.f, 0.f, 1.f ), m_parentSpeed( 0.f ), @@ -214,7 +244,7 @@ void EveBoosterSet2Renderable::GetBatches( ITriRenderBatchAccumulator* batches, batch.SetDrawIndexedInstanced( 3 * 2 * EVE_BOOSTER_PLANES_COUNT[shape], - uint32_t( m_boosterSet->m_singleBoosters.size() ), + uint32_t( m_boosterSet->m_boosters.Size() ), indexBuffer.GetStartIndex() , vb.GetOffset() / vb.GetStride(), m_boosterSet->m_instanceBuffer.GetOffset() / m_boosterSet->m_instanceBuffer.GetStride() ); @@ -689,6 +719,10 @@ EveBoosterSet2::EveBoosterSet2( IRoot* lockobj ) : m_lightWarpColor( 0.f, 0.f, 0.f, 0.f ), m_vertexBuffer( BlueSharedString( "BoosterBoxVB" ), GetBoxVB ) { + m_boosters.SetStructureDefinition( s_boosterItemStructureDef ); + m_boosters.SetDefaultValue( &s_defaultBoosterItem ); + m_boosters.SetNotify( this ); + BoundingSphereInitialize( m_boosterBoundingSphere ); for( unsigned int i = 0; i < EVE_MAX_CONTROL_POINT_COUNT; ++i ) @@ -743,15 +777,9 @@ EveBoosterSet2::~EveBoosterSet2() // -------------------------------------------------------------------------------- bool EveBoosterSet2::Initialize() { - if( !m_persistedItems.empty() ) + if( m_boosters.Size() > 0 ) { - m_singleBoosters.clear(); - for( unsigned int i = 0; i < m_persistedItems.size(); ++i ) - { - const EveBoosterSetItem* item = m_persistedItems[i]; - Add( &item->transform, &item->functionality, item->hasTrail, item->atlasIndex0, item->atlasIndex1, item->lightScale ); - } - FinalizeRebuild(); + RebuildRuntimeFromPersistedItems(); } PrepareResources(); return true; @@ -766,9 +794,9 @@ bool EveBoosterSet2::OnModified( Be::Var* value ) IsMatch( value, m_glowColor ) || IsMatch( value, m_warpGlowColor ) || IsMatch( value, m_haloColor ) || IsMatch( value, m_warpHaloColor ) ) { m_glows->Clear(); - for( auto it = m_singleBoosters.begin(); it != m_singleBoosters.end(); ++it ) + for( size_t i = 0; i < m_boosters.Size(); ++i ) { - CreateFlares( *it ); + CreateFlares( m_boosters[i] ); } m_glows->Rebuild(); } @@ -843,7 +871,8 @@ void EveBoosterSet2::UpdateTrails( float deltaT, Be::Time t ) void EveBoosterSet2::Clear() { // clear everything - m_singleBoosters.clear(); + m_boosters.Clear(); + m_runtimeLights.clear(); if( m_glows ) { m_glows->Clear(); @@ -869,8 +898,8 @@ void EveBoosterSet2::Clear() void EveBoosterSet2::RebuildPreservingSettings() { // Clear only the booster items, not the effects/glows/trails - m_singleBoosters.clear(); - m_persistedItems.Clear(); + m_boosters.Clear(); + m_runtimeLights.clear(); if( m_glows ) { m_glows->Clear(); @@ -903,34 +932,27 @@ void EveBoosterSet2::FinalizeRebuild() // -------------------------------------------------------------------------------- void EveBoosterSet2::Add( const Matrix* localMatrix, const Vector4* functionality, bool hasTrail, uint32_t atlasIndex0, uint32_t atlasIndex1, float lightScale ) { - // keep source data for persistence and rebuild - SingleBoosterData sbd; - sbd.transform = *localMatrix; - sbd.functionality = *functionality; - Vector3 lightOffset( 0.f, 0.f, -m_lightOffset ); - sbd.lightPosition = TransformCoord( lightOffset, *localMatrix ); - sbd.lightRadius = std::max( Length( localMatrix->GetX() ), Length( localMatrix->GetY() ) ) * lightScale; - sbd.lightPhase = float( g_lightNoiseSize ) * float( rand() ) / float( RAND_MAX ); - sbd.atlasIndex0 = atlasIndex0; - sbd.atlasIndex1 = atlasIndex1; - m_singleBoosters.push_back( sbd ); - - EveBoosterSetItemPtr item; - item.CreateInstance(); - item->transform = *localMatrix; - item->functionality = *functionality; - item->atlasIndex0 = atlasIndex0; - item->atlasIndex1 = atlasIndex1; - item->hasTrail = hasTrail; - item->lightScale = lightScale; - m_persistedItems.Append( item->GetRawRoot() ); + // keep source data for persistence + EveBoosterItem item; + item.transform = *localMatrix; + item.functionality = *functionality; + item.atlasIndex0 = atlasIndex0; + item.atlasIndex1 = atlasIndex1; + item.hasTrail = hasTrail ? 1 : 0; + item.lightScale = lightScale; + + RuntimeLightData rt; + ComputeRuntimeLightData( item, rt ); + + m_boosters.Append( item ); + m_runtimeLights.push_back( rt ); Vector3 pos( localMatrix->_41, localMatrix->_42, localMatrix->_43 ); float scale = std::max( Length( localMatrix->GetX() ), Length( localMatrix->GetY() ) ); if( m_glows ) { - CreateFlares( sbd ); + CreateFlares( item ); } // also add it to the trails @@ -958,9 +980,78 @@ void EveBoosterSet2::Add( const Matrix* localMatrix, const Vector4* functionalit } } -void EveBoosterSet2::CreateFlares( SingleBoosterData& boosterData ) +void EveBoosterSet2::ComputeRuntimeLightData( const EveBoosterItem& item, RuntimeLightData& out ) const +{ + Vector3 lightOffset( 0.f, 0.f, -m_lightOffset ); + out.position = TransformCoord( lightOffset, item.transform ); + out.radius = std::max( Length( item.transform.GetX() ), Length( item.transform.GetY() ) ) * item.lightScale; + out.phase = float( g_lightNoiseSize ) * float( rand() ) / float( RAND_MAX ); +} + +void EveBoosterSet2::RebuildRuntimeFromPersistedItems() +{ + m_runtimeLights.clear(); + m_runtimeLights.resize( m_boosters.Size() ); + for( size_t i = 0; i < m_boosters.Size(); ++i ) + { + const EveBoosterItem& item = m_boosters[i]; + ComputeRuntimeLightData( item, m_runtimeLights[i] ); + + Vector3 pos( item.transform._41, item.transform._42, item.transform._43 ); + float scale = std::max( Length( item.transform.GetX() ), Length( item.transform.GetY() ) ); + + if( m_glows ) + { + CreateFlares( item ); + } + + if( m_trails && item.hasTrail ) + { + Matrix offset = item.transform; + offset.GetTranslation() -= offset.GetZ() * 0.5f; + m_trails->Add( &offset, scale ); + } + + BoundingSphereUpdate( pos, m_boosterBoundingSphere ); + + if( scale > m_maxSize ) + { + m_maxSize = scale; + } + } + + FinalizeRebuild(); +} + +std::vector EveBoosterSet2::SnapshotPersistedItems() const +{ + std::vector out; + out.reserve( m_boosters.Size() ); + for( size_t i = 0; i < m_boosters.Size(); ++i ) + { + out.push_back( m_boosters[i] ); + } + return out; +} + +void EveBoosterSet2::OnStructureListModified( Event /*event*/, const void* /*item*/, size_t /*index*/, IBlueStructureList* /*list*/ ) +{ + // External edit to m_boosters (e.g. Jessica). Mirror runtime light data so + // rendering/lighting stay in sync. + const size_t count = m_boosters.Size(); + if( m_runtimeLights.size() != count ) + { + m_runtimeLights.resize( count ); + } + for( size_t i = 0; i < count; ++i ) + { + ComputeRuntimeLightData( m_boosters[i], m_runtimeLights[i] ); + } +} + +void EveBoosterSet2::CreateFlares( const EveBoosterItem& item ) { - auto localMatrix = boosterData.transform; + const Matrix& localMatrix = item.transform; // grab pos/dir/scale from the local transform matrix Vector3 pos( localMatrix._41, localMatrix._42, localMatrix._43 ); Vector3 dir( localMatrix._31, localMatrix._32, localMatrix._33 ); @@ -1131,23 +1222,24 @@ void EveBoosterSet2::RebuildInstanceData( Tr2RenderContext& /*renderContext*/ ) g_sharedBuffer.Free( m_instanceBuffer ); // something there? - if( m_singleBoosters.empty() ) + if( m_boosters.Size() == 0 ) { return; } // how many indiviual boosters are in this set? - unsigned int boosterCount = (unsigned int)m_singleBoosters.size(); + unsigned int boosterCount = (unsigned int)m_boosters.Size(); // create and fill with star-shape's position and some random-value std::vector vertices( boosterCount ); for( unsigned int i = 0; i < boosterCount ; ++i ) { - vertices[i].transform = m_singleBoosters[i].transform; + const EveBoosterItem& item = m_boosters[i]; + vertices[i].transform = item.transform; vertices[i].wavePhase = (float)rand() / (float)RAND_MAX; - vertices[i].functionality = m_singleBoosters[i].functionality; - vertices[i].atlasIndex0 = float( m_singleBoosters[i].atlasIndex0 ); - vertices[i].atlasIndex1 = float( m_singleBoosters[i].atlasIndex1 ); + vertices[i].functionality = item.functionality; + vertices[i].atlasIndex0 = float( item.atlasIndex0 ); + vertices[i].atlasIndex1 = float( item.atlasIndex1 ); } USE_MAIN_THREAD_RENDER_CONTEXT(); CR_RETURN( g_sharedBuffer.Allocate( sizeof( InstanceVertex ), @@ -1256,10 +1348,10 @@ void EveBoosterSet2::RenderDebugInfo( ITr2DebugRenderer2& renderer ) { for( auto it = m_boosterRenderables.begin(); it != m_boosterRenderables.end(); it++ ) { - for( uint32_t j = 0; j < m_singleBoosters.size(); ++j ) + for( uint32_t j = 0; j < m_boosters.Size(); ++j ) { - Matrix transform = m_singleBoosters[j].transform * ( *it )->m_parentTransform; - renderer.DrawCylinder( + Matrix transform = m_boosters[j].transform * ( *it )->m_parentTransform; + renderer.DrawCylinder( Tr2DebugObjectReference( this, j ), transform, Vector3( 0, 0, 0 ), @@ -1368,16 +1460,16 @@ void EveBoosterSet2::GetLights( Tr2LightManager& lightManager ) const radiusFactor *= (*dit)->m_overallIntensity; Color color = m_lightColor * ( 1.f - warpIntensity ) + m_lightWarpColor * warpIntensity; XMMATRIX transform = (*dit)->m_parentTransform; - for( auto it = std::begin( m_singleBoosters ); it != std::end( m_singleBoosters ); ++it ) + for( const RuntimeLightData& light : m_runtimeLights ) { - float phase = ( it->lightPhase + Tr2Renderer::GetAnimationTime() ) * m_lightFlickerFrequency; + float phase = ( light.phase + Tr2Renderer::GetAnimationTime() ) * m_lightFlickerFrequency; float p0 = g_lightNoise[int( phase ) % g_lightNoiseSize]; float p1 = g_lightNoise[( int( phase ) + 1 ) % g_lightNoiseSize]; float t = phase - std::floor( phase ); float flicker = 1 + m_lightFlickerAmplitude * 2.0f * ( p0 * ( 1.0f - t ) + p1 * t ) - m_lightFlickerAmplitude; lightManager.AddPointLight( - Vector3( XMVector3TransformCoord( it->lightPosition, transform ) ), - it->lightRadius * radiusFactor, + Vector3( XMVector3TransformCoord( light.position, transform ) ), + light.radius * radiusFactor, color * flicker ); } diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h index ccb298c82..c85564fc8 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h @@ -13,7 +13,6 @@ #include "Eve/EveUpdateContext.h" #include "Eve/EveEntity.h" #include "Lights/ITr2LightOwner.h" -#include "EveBoosterSetItem.h" // forwards class ITriRenderBatchAccumulator; @@ -30,6 +29,27 @@ BLUE_DECLARE_INTERFACE( ITriVectorFunction ); BLUE_DECLARE_INTERFACE( ITriQuaternionFunction ); BLUE_DECLARE( Tr2DebugRenderer ); +// -------------------------------------------------------------------------------- +// Description: +// Persisted per-booster source data. POD record exposed to Blue via a +// BLUE_DECLARE_STRUCTURE_LIST. Runtime-derived fields (light position, +// radius, phase) are NOT stored here — they live in EveBoosterSet2's +// m_runtimeLights vector, parallel to the persisted m_boosters list. +// -------------------------------------------------------------------------------- +struct EveBoosterItem +{ + EveBoosterItem(); + + Matrix transform; + Vector4 functionality; + uint32_t atlasIndex0; + uint32_t atlasIndex1; + int32_t hasTrail; + float lightScale; +}; + +BLUE_DECLARE_STRUCTURE_LIST( EveBoosterItem ); + // constants // maximum number of spline control points per trail const unsigned int EVE_MAX_CONTROL_POINT_COUNT = 5; @@ -238,21 +258,13 @@ BLUE_CLASS( EveBoosterSet2 ): void RebuildPreservingSettings(); void FinalizeRebuild(); - // Runtime per-booster data used for rendering, lighting, and debug. - // transform, functionality, atlasIndex0, and atlasIndex1 mirror the - // corresponding fields in EveBoosterSetItem (m_persistedItems), which - // is the Blue-serialized source of truth for save/load cycles. - // lightPosition, lightRadius, and lightPhase are derived in Add() and - // are never persisted. - struct SingleBoosterData + // Per-booster runtime light data, computed from EveBoosterItem entries by Add(). + // Parallel to m_boosters: same index, same count. Never persisted. + struct RuntimeLightData { - Matrix transform; - Vector4 functionality; - uint32_t atlasIndex0; - uint32_t atlasIndex1; - Vector3 lightPosition; - float lightRadius; - float lightPhase; + Vector3 position; + float radius; + float phase; }; void Add( const Matrix* localMatrix, const Vector4* functionality, bool hasTrail, uint32_t atlasIndex0, uint32_t atlasIndex1, float lightScale = 1 ); @@ -289,16 +301,30 @@ BLUE_CLASS( EveBoosterSet2 ): // ITr2LightOwner void GetLights( Tr2LightManager& lightManager ) const override; - const PEveBoosterSetItemVector& GetPersistedItems() const { return m_persistedItems; } + ////////////////////////////////////////////////////////////////////////////////////// + // IBlueStructureListNotify + void OnStructureListModified( Event event, const void* item, size_t index, IBlueStructureList* list ) override; + + // Returns a defensive copy of the persisted booster items. Used by code that + // needs to snapshot data before clearing/rebuilding the structure list. + std::vector SnapshotPersistedItems() const; private: - std::vector m_singleBoosters; - PEveBoosterSetItemVector m_persistedItems; + PEveBoosterItemStructureList m_boosters; + std::vector m_runtimeLights; // re-alloc and init the instance vertex buffers void RebuildInstanceData( Tr2RenderContext& renderContext ); + // derive runtime light data for one booster from its persisted entry + void ComputeRuntimeLightData( const EveBoosterItem& item, RuntimeLightData& out ) const; + + // rebuild m_runtimeLights (and resources that depend on items) from the + // currently persisted m_boosters entries. Used on .red load and on + // structure-list edits. + void RebuildRuntimeFromPersistedItems(); + // function to create the flares from boosterdata - void CreateFlares( SingleBoosterData& boosterData ); + void CreateFlares( const EveBoosterItem& item ); // toggle display bool m_display; @@ -367,3 +393,5 @@ TYPEDEF_BLUECLASS( EveBoosterSet2 ); #endif // EveBoosterSet2_H + + diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp index 7622dbb38..4f52ae5ea 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp @@ -166,7 +166,7 @@ const Be::ClassInfo* EveBoosterSet2::ExposeToBlue() MAP_ATTRIBUTE( "effectFar", m_effectFar, "Effect to use to render the boosters at a distance", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "glows", m_glows, "Sprite set to use to render the glows on the boosters", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "trails", m_trails, "Trails set used to render the trails of this booster", Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( "singleBoosters", m_singleBoosters, "Per-booster source data (transform, atlas indices, etc.)", Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( "boosters", m_boosters, "Per-booster source data (transform, atlas indices, etc.)", Be::READ | Be::PERSIST ) EXPOSURE_END() diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h deleted file mode 100644 index d21ab7a3b..000000000 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#ifndef EveBoosterSetItem_H -#define EveBoosterSetItem_H - -BLUE_DECLARE( EveBoosterSetItem ); -BLUE_DECLARE_VECTOR( EveBoosterSetItem ); - -// -------------------------------------------------------------------------------- -// Description: -// Persisted per-booster source data. Holds only the fields needed to reconstruct -// a booster after a .red file load. Runtime-derived fields (lightPosition, -// lightRadius, lightPhase) are NOT stored here — they are recomputed by -// EveBoosterSet2::Add() at load time. -// SeeAlso: -// EveBoosterSet2 -// -------------------------------------------------------------------------------- -BLUE_CLASS( EveBoosterSetItem ) : - public IRoot -{ -public: - EXPOSE_TO_BLUE(); - - EveBoosterSetItem( IRoot* lockobj = NULL ) {} - - Matrix transform; - Vector4 functionality; - uint32_t atlasIndex0; - uint32_t atlasIndex1; - bool hasTrail; - float lightScale; -}; - -TYPEDEF_BLUECLASS( EveBoosterSetItem ); - -#endif // EveBoosterSetItem_H - - diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem_Blue.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem_Blue.cpp deleted file mode 100644 index 5b2121c82..000000000 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSetItem_Blue.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "StdAfx.h" -#include "EveBoosterSetItem.h" - -BLUE_DEFINE( EveBoosterSetItem ); - -const Be::ClassInfo* EveBoosterSetItem::ExposeToBlue() -{ - EXPOSURE_BEGIN( EveBoosterSetItem, "" ) - MAP_INTERFACE( EveBoosterSetItem ) - MAP_ATTRIBUTE( "transform", transform, "Local transform of this booster exhaust point", Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( "functionality", functionality, "Booster behaviour flags", Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( "atlasIndex0", atlasIndex0, "Shape map index (primary)", Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( "atlasIndex1", atlasIndex1, "Shape map index (secondary)", Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( "hasTrail", hasTrail, "Whether this booster contributes to trails", Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( "lightScale", lightScale, "Scaling factor for dynamic light radius", Be::READWRITE | Be::PERSIST ) - EXPOSURE_END() -} - diff --git a/trinity/Eve/SpaceObject/EveShip2.cpp b/trinity/Eve/SpaceObject/EveShip2.cpp index 9a9035a22..d3b567758 100644 --- a/trinity/Eve/SpaceObject/EveShip2.cpp +++ b/trinity/Eve/SpaceObject/EveShip2.cpp @@ -237,7 +237,7 @@ void EveShip2::RebuildBoosterSet() } // Snapshot the currently persisted booster data before clearing - PEveBoosterSetItemVector snapshot = m_boosters->GetPersistedItems(); + std::vector snapshot = m_boosters->SnapshotPersistedItems(); // Clear only the booster items while preserving effects, glows, trails, and visual settings m_boosters->RebuildPreservingSettings(); @@ -263,9 +263,9 @@ void EveShip2::RebuildBoosterSet() if( boosterIndex < snapshot.size() ) { - const auto& saved = snapshot[boosterIndex]; + const EveBoosterItem& saved = snapshot[boosterIndex]; functionality = saved.functionality; - hasTrail = saved.hasTrail; + hasTrail = saved.hasTrail != 0; atlasIndex0 = saved.atlasIndex0; atlasIndex1 = saved.atlasIndex1; lightScale = saved.lightScale; From 001ef2ec13972965004ee438b4bfcd6b9ff07012 Mon Sep 17 00:00:00 2001 From: Anonymous CCP Employee Date: Wed, 13 May 2026 18:27:12 +0000 Subject: [PATCH 06/11] fix build errors --- .../Attachments/EveBoosterSet2.cpp | 27 ++++++++++--------- .../SpaceObject/Attachments/EveBoosterSet2.h | 3 ++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp index 04280e80d..2eecdcf7d 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp @@ -244,7 +244,7 @@ void EveBoosterSet2Renderable::GetBatches( ITriRenderBatchAccumulator* batches, batch.SetDrawIndexedInstanced( 3 * 2 * EVE_BOOSTER_PLANES_COUNT[shape], - uint32_t( m_boosterSet->m_boosters.Size() ), + uint32_t( m_boosterSet->m_boosters.GetSize() ), indexBuffer.GetStartIndex() , vb.GetOffset() / vb.GetStride(), m_boosterSet->m_instanceBuffer.GetOffset() / m_boosterSet->m_instanceBuffer.GetStride() ); @@ -689,6 +689,7 @@ namespace // -------------------------------------------------------------------------------- EveBoosterSet2::EveBoosterSet2( IRoot* lockobj ) : PARENTLOCK( m_boosterRenderables ), + PARENTLOCK( m_boosters ), m_glowColor( 0.0f, 0.0f, 0.0f, 0.0f ), m_haloColor( 0.0f, 0.0f, 0.0f, 0.0f ), m_warpGlowColor( 0.0f, 0.0f, 0.0f, 0.0f ), @@ -777,7 +778,7 @@ EveBoosterSet2::~EveBoosterSet2() // -------------------------------------------------------------------------------- bool EveBoosterSet2::Initialize() { - if( m_boosters.Size() > 0 ) + if( m_boosters.GetSize() > 0 ) { RebuildRuntimeFromPersistedItems(); } @@ -794,7 +795,7 @@ bool EveBoosterSet2::OnModified( Be::Var* value ) IsMatch( value, m_glowColor ) || IsMatch( value, m_warpGlowColor ) || IsMatch( value, m_haloColor ) || IsMatch( value, m_warpHaloColor ) ) { m_glows->Clear(); - for( size_t i = 0; i < m_boosters.Size(); ++i ) + for( size_t i = 0; i < m_boosters.GetSize(); ++i ) { CreateFlares( m_boosters[i] ); } @@ -944,7 +945,7 @@ void EveBoosterSet2::Add( const Matrix* localMatrix, const Vector4* functionalit RuntimeLightData rt; ComputeRuntimeLightData( item, rt ); - m_boosters.Append( item ); + m_boosters.Append( &item ); m_runtimeLights.push_back( rt ); Vector3 pos( localMatrix->_41, localMatrix->_42, localMatrix->_43 ); @@ -991,8 +992,8 @@ void EveBoosterSet2::ComputeRuntimeLightData( const EveBoosterItem& item, Runtim void EveBoosterSet2::RebuildRuntimeFromPersistedItems() { m_runtimeLights.clear(); - m_runtimeLights.resize( m_boosters.Size() ); - for( size_t i = 0; i < m_boosters.Size(); ++i ) + m_runtimeLights.resize( m_boosters.GetSize() ); + for( size_t i = 0; i < m_boosters.GetSize(); ++i ) { const EveBoosterItem& item = m_boosters[i]; ComputeRuntimeLightData( item, m_runtimeLights[i] ); @@ -1023,11 +1024,11 @@ void EveBoosterSet2::RebuildRuntimeFromPersistedItems() FinalizeRebuild(); } -std::vector EveBoosterSet2::SnapshotPersistedItems() const +std::vector EveBoosterSet2::SnapshotPersistedItems() { std::vector out; - out.reserve( m_boosters.Size() ); - for( size_t i = 0; i < m_boosters.Size(); ++i ) + out.reserve( m_boosters.GetSize() ); + for( size_t i = 0; i < m_boosters.GetSize(); ++i ) { out.push_back( m_boosters[i] ); } @@ -1038,7 +1039,7 @@ void EveBoosterSet2::OnStructureListModified( Event /*event*/, const void* /*ite { // External edit to m_boosters (e.g. Jessica). Mirror runtime light data so // rendering/lighting stay in sync. - const size_t count = m_boosters.Size(); + const size_t count = m_boosters.GetSize(); if( m_runtimeLights.size() != count ) { m_runtimeLights.resize( count ); @@ -1222,13 +1223,13 @@ void EveBoosterSet2::RebuildInstanceData( Tr2RenderContext& /*renderContext*/ ) g_sharedBuffer.Free( m_instanceBuffer ); // something there? - if( m_boosters.Size() == 0 ) + if( m_boosters.GetSize() == 0 ) { return; } // how many indiviual boosters are in this set? - unsigned int boosterCount = (unsigned int)m_boosters.Size(); + unsigned int boosterCount = (unsigned int)m_boosters.GetSize(); // create and fill with star-shape's position and some random-value std::vector vertices( boosterCount ); @@ -1348,7 +1349,7 @@ void EveBoosterSet2::RenderDebugInfo( ITr2DebugRenderer2& renderer ) { for( auto it = m_boosterRenderables.begin(); it != m_boosterRenderables.end(); it++ ) { - for( uint32_t j = 0; j < m_boosters.Size(); ++j ) + for( uint32_t j = 0; j < m_boosters.GetSize(); ++j ) { Matrix transform = m_boosters[j].transform * ( *it )->m_parentTransform; renderer.DrawCylinder( diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h index c85564fc8..e797b7a7a 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h @@ -192,6 +192,7 @@ BLUE_CLASS( EveBoosterSet2 ): public INotify, public Tr2DeviceResource, public ITr2LightOwner, + public IBlueStructureListNotify, public EveEntity { public: @@ -307,7 +308,7 @@ BLUE_CLASS( EveBoosterSet2 ): // Returns a defensive copy of the persisted booster items. Used by code that // needs to snapshot data before clearing/rebuilding the structure list. - std::vector SnapshotPersistedItems() const; + std::vector SnapshotPersistedItems(); private: PEveBoosterItemStructureList m_boosters; From d6503426803582c20f5ef711c70ce47cc747f5c8 Mon Sep 17 00:00:00 2001 From: Anonymous CCP Employee Date: Wed, 13 May 2026 20:41:45 +0000 Subject: [PATCH 07/11] Address feedback --- .../Attachments/EveBoosterSet2.cpp | 26 +++++++++++-------- .../SpaceObject/Attachments/EveBoosterSet2.h | 2 -- trinity/Eve/SpaceObject/EveShip2.cpp | 16 +++++++++--- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp index 2eecdcf7d..ff21957ae 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp @@ -991,6 +991,17 @@ void EveBoosterSet2::ComputeRuntimeLightData( const EveBoosterItem& item, Runtim void EveBoosterSet2::RebuildRuntimeFromPersistedItems() { + if( m_glows ) + { + m_glows->Clear(); + } + if( m_trails ) + { + m_trails->Clear(); + } + BoundingSphereInitialize( m_boosterBoundingSphere ); + m_maxSize = 0.f; + m_runtimeLights.clear(); m_runtimeLights.resize( m_boosters.GetSize() ); for( size_t i = 0; i < m_boosters.GetSize(); ++i ) @@ -1037,17 +1048,10 @@ std::vector EveBoosterSet2::SnapshotPersistedItems() void EveBoosterSet2::OnStructureListModified( Event /*event*/, const void* /*item*/, size_t /*index*/, IBlueStructureList* /*list*/ ) { - // External edit to m_boosters (e.g. Jessica). Mirror runtime light data so - // rendering/lighting stay in sync. - const size_t count = m_boosters.GetSize(); - if( m_runtimeLights.size() != count ) - { - m_runtimeLights.resize( count ); - } - for( size_t i = 0; i < count; ++i ) - { - ComputeRuntimeLightData( m_boosters[i], m_runtimeLights[i] ); - } + // External edit to m_boosters. Fully rebuild dependent state from the new list: + // runtime lights, glow sprites, trail entries, bounding sphere, m_maxSize and the GPU instance buffer. + RebuildRuntimeFromPersistedItems(); + PrepareResources(); } void EveBoosterSet2::CreateFlares( const EveBoosterItem& item ) diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h index e797b7a7a..dd6dcd501 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h @@ -394,5 +394,3 @@ TYPEDEF_BLUECLASS( EveBoosterSet2 ); #endif // EveBoosterSet2_H - - diff --git a/trinity/Eve/SpaceObject/EveShip2.cpp b/trinity/Eve/SpaceObject/EveShip2.cpp index d3b567758..844b21863 100644 --- a/trinity/Eve/SpaceObject/EveShip2.cpp +++ b/trinity/Eve/SpaceObject/EveShip2.cpp @@ -246,22 +246,32 @@ void EveShip2::RebuildBoosterSet() static const char* kLocatorPrefix = "locator_booster"; const unsigned int kLocatorPrefixLength = (unsigned int)strlen( kLocatorPrefix ); - unsigned int boosterIndex = 0; + unsigned int boosterLocatorCount = 0; unsigned int n = (unsigned int)m_locators.size(); for( unsigned int i = 0; i < n; ++i ) + { + const char* locatorName = m_locators[i]->GetName(); + if( strncmp( locatorName, kLocatorPrefix, kLocatorPrefixLength ) == 0 ) + { + ++boosterLocatorCount; + } + } + const bool useSnapshot = ( snapshot.size() == boosterLocatorCount ); + + unsigned int boosterIndex = 0; + for( unsigned int i = 0; i < n; ++i ) { EveLocator2Ptr locator = m_locators[i]; const char* locatorName = locator->GetName(); if( strncmp( locatorName, kLocatorPrefix, kLocatorPrefixLength ) == 0 ) { - // Restore saved data if available, otherwise use defaults Vector4 functionality( 0.f, 1.f, 1.f, 1.f ); bool hasTrail = true; uint32_t atlasIndex0 = 0; uint32_t atlasIndex1 = 0; float lightScale = 1.0f; - if( boosterIndex < snapshot.size() ) + if( useSnapshot ) { const EveBoosterItem& saved = snapshot[boosterIndex]; functionality = saved.functionality; From faf80566c34625bf50aca28a30d55a5c7d1f49ed Mon Sep 17 00:00:00 2001 From: sorensen Date: Mon, 20 Jul 2026 13:04:35 +0000 Subject: [PATCH 08/11] Address review feedback on booster persistence - boosters attribute: keep Be::READ | Be::PERSIST (not PERSISTONLY) - platformtools' make-compatible-with-trinity-booster-update branch detects this feature via hasattr(trinity.EveBoosterSet2, "boosters"), which needs the attribute visible to Python; WRITE stays withheld since nothing should reassign the whole list from Python. - Move RebuildBoosterSet's snapshot/restore/rebuild logic into a single EveBoosterSet2::RebuildBoosters(locatorTransforms), so EveShip2 just gathers locator transforms and delegates. - Remove IBlueStructureListNotify: it fired unconditionally on every internal Append(), causing Add() to redundantly reprocess the whole list on every call and leaving m_runtimeLights permanently one entry longer than m_boosters after the last Add() in a batch (a real duplicated glow/trail/phantom-light bug). Add() alone is sufficient once nothing external can mutate the list. - Drop SnapshotPersistedItems() as a separate public method (folded inline). - Stop persisting transform (the ship owns locator authority); move the rebuild-from-locators responsibility to EveShip2::Initialize(), mirroring EveMobile::Initialize()'s unconditional call to RebuildTurretPositions(). - Fix RebuildPreservingSettings() not resetting m_maxSize, found while consolidating the two rebuild paths into one. Co-Authored-By: Claude Sonnet 5 --- .../Attachments/EveBoosterSet2.cpp | 99 +++++++------------ .../SpaceObject/Attachments/EveBoosterSet2.h | 36 +++---- .../Attachments/EveBoosterSet2_Blue.cpp | 5 +- trinity/Eve/SpaceObject/EveShip2.cpp | 54 +++------- 4 files changed, 69 insertions(+), 125 deletions(-) diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp index ff21957ae..a5fb4501f 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp @@ -48,10 +48,6 @@ namespace { BlueStructureDefinition s_boosterItemStructureDef[] = { - { "transformRow0", Be::FLOAT32_4, offsetof( EveBoosterItem, transform ) + 0 }, - { "transformRow1", Be::FLOAT32_4, offsetof( EveBoosterItem, transform ) + 16 }, - { "transformRow2", Be::FLOAT32_4, offsetof( EveBoosterItem, transform ) + 32 }, - { "transformRow3", Be::FLOAT32_4, offsetof( EveBoosterItem, transform ) + 48 }, { "functionality", Be::FLOAT32_4, offsetof( EveBoosterItem, functionality ) }, { "atlasIndex0", Be::UINT32_1, offsetof( EveBoosterItem, atlasIndex0 ) }, { "atlasIndex1", Be::UINT32_1, offsetof( EveBoosterItem, atlasIndex1 ) }, @@ -722,7 +718,6 @@ EveBoosterSet2::EveBoosterSet2( IRoot* lockobj ) : { m_boosters.SetStructureDefinition( s_boosterItemStructureDef ); m_boosters.SetDefaultValue( &s_defaultBoosterItem ); - m_boosters.SetNotify( this ); BoundingSphereInitialize( m_boosterBoundingSphere ); @@ -771,17 +766,14 @@ EveBoosterSet2::~EveBoosterSet2() // -------------------------------------------------------------------------------- // Description: // If loading from a .red file, we now can start creating resources. -// If m_boosters was loaded from persistence, the entries contain source data -// but not the derived runtime fields (lightPosition, lightRadius, lightPhase). -// We snapshot the loaded entries, clear, then re-add through Add() which -// computes all derived fields correctly. +// transform is not persisted (the owning ship is the authority on booster +// locations), so the persisted m_boosters entries alone aren't enough to +// rebuild anything here. The owning ship is responsible for gathering its +// locator transforms and calling RebuildBoosters() from its own Initialize() +// once its locators are available (see EveShip2::Initialize). // -------------------------------------------------------------------------------- bool EveBoosterSet2::Initialize() { - if( m_boosters.GetSize() > 0 ) - { - RebuildRuntimeFromPersistedItems(); - } PrepareResources(); return true; } @@ -912,6 +904,7 @@ void EveBoosterSet2::RebuildPreservingSettings() // Reset bounding info BoundingSphereInitialize( m_boosterBoundingSphere ); + m_maxSize = 0.f; // Release only the instance buffer resources ReleaseResources( TRISTORAGE_ALL ); @@ -989,68 +982,48 @@ void EveBoosterSet2::ComputeRuntimeLightData( const EveBoosterItem& item, Runtim out.phase = float( g_lightNoiseSize ) * float( rand() ) / float( RAND_MAX ); } -void EveBoosterSet2::RebuildRuntimeFromPersistedItems() +// -------------------------------------------------------------------------------- +// Description: +// Rebuilds all boosters from the given locator transforms (in order), restoring +// each booster's previously-set functionality/atlasIndex0/atlasIndex1/hasTrail/ +// lightScale by index where a prior entry exists, and falling back to the same +// defaults SOF construction uses otherwise. Called by the owning ship whenever +// its locators change and once from its own Initialize() (see EveShip2). +// -------------------------------------------------------------------------------- +void EveBoosterSet2::RebuildBoosters( const std::vector& locatorTransforms ) { - if( m_glows ) - { - m_glows->Clear(); - } - if( m_trails ) - { - m_trails->Clear(); - } - BoundingSphereInitialize( m_boosterBoundingSphere ); - m_maxSize = 0.f; - - m_runtimeLights.clear(); - m_runtimeLights.resize( m_boosters.GetSize() ); + // snapshot current per-booster metadata before clearing, to restore by index below + std::vector previous; + previous.reserve( m_boosters.GetSize() ); for( size_t i = 0; i < m_boosters.GetSize(); ++i ) { - const EveBoosterItem& item = m_boosters[i]; - ComputeRuntimeLightData( item, m_runtimeLights[i] ); + previous.push_back( m_boosters[i] ); + } - Vector3 pos( item.transform._41, item.transform._42, item.transform._43 ); - float scale = std::max( Length( item.transform.GetX() ), Length( item.transform.GetY() ) ); + RebuildPreservingSettings(); - if( m_glows ) - { - CreateFlares( item ); - } + for( size_t i = 0; i < locatorTransforms.size(); ++i ) + { + Vector4 functionality( 0.f, 1.f, 1.f, 1.f ); + bool hasTrail = true; + uint32_t atlasIndex0 = 0; + uint32_t atlasIndex1 = 0; + float lightScale = 1.0f; - if( m_trails && item.hasTrail ) + if( i < previous.size() ) { - Matrix offset = item.transform; - offset.GetTranslation() -= offset.GetZ() * 0.5f; - m_trails->Add( &offset, scale ); + const EveBoosterItem& saved = previous[i]; + functionality = saved.functionality; + hasTrail = saved.hasTrail != 0; + atlasIndex0 = saved.atlasIndex0; + atlasIndex1 = saved.atlasIndex1; + lightScale = saved.lightScale; } - BoundingSphereUpdate( pos, m_boosterBoundingSphere ); - - if( scale > m_maxSize ) - { - m_maxSize = scale; - } + Add( &locatorTransforms[i], &functionality, hasTrail, atlasIndex0, atlasIndex1, lightScale ); } FinalizeRebuild(); -} - -std::vector EveBoosterSet2::SnapshotPersistedItems() -{ - std::vector out; - out.reserve( m_boosters.GetSize() ); - for( size_t i = 0; i < m_boosters.GetSize(); ++i ) - { - out.push_back( m_boosters[i] ); - } - return out; -} - -void EveBoosterSet2::OnStructureListModified( Event /*event*/, const void* /*item*/, size_t /*index*/, IBlueStructureList* /*list*/ ) -{ - // External edit to m_boosters. Fully rebuild dependent state from the new list: - // runtime lights, glow sprites, trail entries, bounding sphere, m_maxSize and the GPU instance buffer. - RebuildRuntimeFromPersistedItems(); PrepareResources(); } diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h index dd6dcd501..0eeaf1653 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h @@ -31,9 +31,12 @@ BLUE_DECLARE( Tr2DebugRenderer ); // -------------------------------------------------------------------------------- // Description: -// Persisted per-booster source data. POD record exposed to Blue via a -// BLUE_DECLARE_STRUCTURE_LIST. Runtime-derived fields (light position, -// radius, phase) are NOT stored here — they live in EveBoosterSet2's +// Per-booster source data. functionality/atlasIndex0/atlasIndex1/hasTrail/lightScale +// are persisted to Blue via a BLUE_DECLARE_STRUCTURE_LIST (see s_boosterItemStructureDef +// in EveBoosterSet2.cpp) so boosters survive save/load cycles. transform is NOT +// persisted: the ship owns locator authority and supplies a fresh transform on every +// rebuild via EveBoosterSet2::RebuildBoosters(). Runtime-derived fields (light position, +// radius, phase) are NOT stored here either — they live in EveBoosterSet2's // m_runtimeLights vector, parallel to the persisted m_boosters list. // -------------------------------------------------------------------------------- struct EveBoosterItem @@ -192,7 +195,6 @@ BLUE_CLASS( EveBoosterSet2 ): public INotify, public Tr2DeviceResource, public ITr2LightOwner, - public IBlueStructureListNotify, public EveEntity { public: @@ -256,8 +258,6 @@ BLUE_CLASS( EveBoosterSet2 ): void UpdateTrails( float deltaT, Be::Time t ); // manage individual exhaust points void Clear(); - void RebuildPreservingSettings(); - void FinalizeRebuild(); // Per-booster runtime light data, computed from EveBoosterItem entries by Add(). // Parallel to m_boosters: same index, same count. Never persisted. @@ -269,6 +269,13 @@ BLUE_CLASS( EveBoosterSet2 ): }; void Add( const Matrix* localMatrix, const Vector4* functionality, bool hasTrail, uint32_t atlasIndex0, uint32_t atlasIndex1, float lightScale = 1 ); + + // Rebuilds all boosters from the given locator transforms (in order), restoring each + // booster's previously-set functionality/atlasIndex0/atlasIndex1/hasTrail/lightScale by + // index where available, and falling back to defaults otherwise. The ship owns locator + // authority, so it is responsible for gathering locatorTransforms and calling this + // whenever locators change and on load (see EveShip2::RebuildBoosterSet/Initialize). + void RebuildBoosters( const std::vector& locatorTransforms ); // set internal visual data void SetData( float glowScale, @@ -302,14 +309,6 @@ BLUE_CLASS( EveBoosterSet2 ): // ITr2LightOwner void GetLights( Tr2LightManager& lightManager ) const override; - ////////////////////////////////////////////////////////////////////////////////////// - // IBlueStructureListNotify - void OnStructureListModified( Event event, const void* item, size_t index, IBlueStructureList* list ) override; - - // Returns a defensive copy of the persisted booster items. Used by code that - // needs to snapshot data before clearing/rebuilding the structure list. - std::vector SnapshotPersistedItems(); - private: PEveBoosterItemStructureList m_boosters; std::vector m_runtimeLights; @@ -319,10 +318,11 @@ BLUE_CLASS( EveBoosterSet2 ): // derive runtime light data for one booster from its persisted entry void ComputeRuntimeLightData( const EveBoosterItem& item, RuntimeLightData& out ) const; - // rebuild m_runtimeLights (and resources that depend on items) from the - // currently persisted m_boosters entries. Used on .red load and on - // structure-list edits. - void RebuildRuntimeFromPersistedItems(); + // clear boosters/glows/trails/bounding info while preserving effects and visual + // settings; used internally by RebuildBoosters() before re-adding from fresh locators + void RebuildPreservingSettings(); + // rebuild glows after all boosters have been re-added; used internally by RebuildBoosters() + void FinalizeRebuild(); // function to create the flares from boosterdata void CreateFlares( const EveBoosterItem& item ); diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp index 4f52ae5ea..983a16b10 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp @@ -166,7 +166,10 @@ const Be::ClassInfo* EveBoosterSet2::ExposeToBlue() MAP_ATTRIBUTE( "effectFar", m_effectFar, "Effect to use to render the boosters at a distance", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "glows", m_glows, "Sprite set to use to render the glows on the boosters", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "trails", m_trails, "Trails set used to render the trails of this booster", Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( "boosters", m_boosters, "Per-booster source data (transform, atlas indices, etc.)", Be::READ | Be::PERSIST ) + // Be::READ (not PERSISTONLY) is deliberate: platformtools' make-compatible-with-trinity-booster-update + // branch detects this build via hasattr(trinity.EveBoosterSet2, "boosters"), which requires the + // attribute to not be Be::HIDDEN. WRITE is still withheld since nothing should reassign this from Python. + MAP_ATTRIBUTE( "boosters", m_boosters, "Per-booster source data: functionality, atlas indices, trail flag, light scale", Be::READ | Be::PERSIST ) EXPOSURE_END() diff --git a/trinity/Eve/SpaceObject/EveShip2.cpp b/trinity/Eve/SpaceObject/EveShip2.cpp index 844b21863..fc1cd8b85 100644 --- a/trinity/Eve/SpaceObject/EveShip2.cpp +++ b/trinity/Eve/SpaceObject/EveShip2.cpp @@ -236,67 +236,35 @@ void EveShip2::RebuildBoosterSet() return; } - // Snapshot the currently persisted booster data before clearing - std::vector snapshot = m_boosters->SnapshotPersistedItems(); - - // Clear only the booster items while preserving effects, glows, trails, and visual settings - m_boosters->RebuildPreservingSettings(); - - // Rebuild boosters from locators, restoring their original settings + // Gather this ship's booster locator transforms; EveBoosterSet2 owns restoring + // each booster's previous functionality/atlasIndex0/atlasIndex1/hasTrail/lightScale + // by index internally. static const char* kLocatorPrefix = "locator_booster"; const unsigned int kLocatorPrefixLength = (unsigned int)strlen( kLocatorPrefix ); - unsigned int boosterLocatorCount = 0; + std::vector locatorTransforms; unsigned int n = (unsigned int)m_locators.size(); for( unsigned int i = 0; i < n; ++i ) { const char* locatorName = m_locators[i]->GetName(); if( strncmp( locatorName, kLocatorPrefix, kLocatorPrefixLength ) == 0 ) { - ++boosterLocatorCount; + locatorTransforms.push_back( m_locators[i]->GetTransform() ); } } - const bool useSnapshot = ( snapshot.size() == boosterLocatorCount ); - unsigned int boosterIndex = 0; - for( unsigned int i = 0; i < n; ++i ) - { - EveLocator2Ptr locator = m_locators[i]; - const char* locatorName = locator->GetName(); - if( strncmp( locatorName, kLocatorPrefix, kLocatorPrefixLength ) == 0 ) - { - Vector4 functionality( 0.f, 1.f, 1.f, 1.f ); - bool hasTrail = true; - uint32_t atlasIndex0 = 0; - uint32_t atlasIndex1 = 0; - float lightScale = 1.0f; - - if( useSnapshot ) - { - const EveBoosterItem& saved = snapshot[boosterIndex]; - functionality = saved.functionality; - hasTrail = saved.hasTrail != 0; - atlasIndex0 = saved.atlasIndex0; - atlasIndex1 = saved.atlasIndex1; - lightScale = saved.lightScale; - } - - m_boosters->Add( &locator->GetTransform(), &functionality, hasTrail, atlasIndex0, atlasIndex1, lightScale ); - ++boosterIndex; - } - } - - // Finalize the rebuild by rebuilding glows - m_boosters->FinalizeRebuild(); - - // Prepare resources to rebuild instance buffer and finalize - m_boosters->PrepareResources(); + m_boosters->RebuildBoosters( locatorTransforms ); } bool EveShip2::Initialize() { EveMobile::Initialize(); + // boosters own no positional data of their own once locators are available; + // rebuild them from this ship's locators now (mirrors RebuildTurretPositions() + // in EveMobile::Initialize()) + RebuildBoosterSet(); + return true; } From f4e0f85c29e4efc27596983ad175afd29bc66949 Mon Sep 17 00:00:00 2001 From: sorensen Date: Mon, 20 Jul 2026 13:11:12 +0000 Subject: [PATCH 09/11] Add dedicated feature-detection marker instead of exposing boosters to Python Keep "boosters" as Be::PERSISTONLY per review feedback -- there's no reason for Python to see the per-item art data. platformtools' upcoming make-compatible-with-trinity-booster-update branch needs to detect this build though (to skip a redundant RebuildBoosterSet() call and hide its now-unnecessary "Fix Boosters" Jessica action), so add a minimal read-only hasPersistentBoosterItems property whose only job is that detection -- it exposes a flag, not the underlying data. Co-Authored-By: Claude Sonnet 5 --- trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h | 6 ++++++ .../Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h index 0eeaf1653..591c4e734 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h @@ -276,6 +276,12 @@ BLUE_CLASS( EveBoosterSet2 ): // authority, so it is responsible for gathering locatorTransforms and calling this // whenever locators change and on load (see EveShip2::RebuildBoosterSet/Initialize). void RebuildBoosters( const std::vector& locatorTransforms ); + + // Feature-detection marker for cross-repo compatibility tooling (e.g. platformtools' + // HasPersistentBoosterItems()). Always true on any build where this is exposed to Blue. + // Deliberately exposes only this flag, not the per-booster data itself, which stays + // Be::PERSISTONLY (see the "boosters" MAP_ATTRIBUTE in EveBoosterSet2_Blue.cpp). + bool HasPersistentBoosterItems() const { return true; } // set internal visual data void SetData( float glowScale, diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp index 983a16b10..6adfa7546 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2_Blue.cpp @@ -166,10 +166,10 @@ const Be::ClassInfo* EveBoosterSet2::ExposeToBlue() MAP_ATTRIBUTE( "effectFar", m_effectFar, "Effect to use to render the boosters at a distance", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "glows", m_glows, "Sprite set to use to render the glows on the boosters", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "trails", m_trails, "Trails set used to render the trails of this booster", Be::READWRITE | Be::PERSIST ) - // Be::READ (not PERSISTONLY) is deliberate: platformtools' make-compatible-with-trinity-booster-update - // branch detects this build via hasattr(trinity.EveBoosterSet2, "boosters"), which requires the - // attribute to not be Be::HIDDEN. WRITE is still withheld since nothing should reassign this from Python. - MAP_ATTRIBUTE( "boosters", m_boosters, "Per-booster source data: functionality, atlas indices, trail flag, light scale", Be::READ | Be::PERSIST ) + MAP_ATTRIBUTE( "boosters", m_boosters, "Per-booster source data: functionality, atlas indices, trail flag, light scale", Be::PERSISTONLY ) + // Cross-repo compatibility marker only (see platformtools' HasPersistentBoosterItems()); + // deliberately not the "boosters" data itself, which stays Be::PERSISTONLY above. + MAP_PROPERTY_READONLY( "hasPersistentBoosterItems", HasPersistentBoosterItems, "Feature-detection marker: true when per-booster art data persists across .red load/save" ) EXPOSURE_END() From b2c87c313bd741c9f02668d23e41aaa7700c0ad6 Mon Sep 17 00:00:00 2001 From: Selph Date: Mon, 10 Aug 2026 10:00:25 +0000 Subject: [PATCH 10/11] update naming of booster lights --- .../Eve/SpaceObject/Attachments/EveBoosterSet2.cpp | 14 +++++++------- .../Eve/SpaceObject/Attachments/EveBoosterSet2.h | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp index c6b9d4abb..7028b2c53 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp @@ -867,7 +867,7 @@ void EveBoosterSet2::Clear() { // clear everything m_boosters.Clear(); - m_runtimeLights.clear(); + m_boosterLights.clear(); if( m_glows ) { m_glows->Clear(); @@ -894,7 +894,7 @@ void EveBoosterSet2::RebuildPreservingSettings() { // Clear only the booster items, not the effects/glows/trails m_boosters.Clear(); - m_runtimeLights.clear(); + m_boosterLights.clear(); if( m_glows ) { m_glows->Clear(); @@ -937,11 +937,11 @@ void EveBoosterSet2::Add( const Matrix* localMatrix, const Vector4* functionalit item.hasTrail = hasTrail ? 1 : 0; item.lightScale = lightScale; - RuntimeLightData rt; - ComputeRuntimeLightData( item, rt ); + BoosterLight light; + ComputeBoosterLight( item, light ); m_boosters.Append( &item ); - m_runtimeLights.push_back( rt ); + m_boosterLights.push_back( light ); Vector3 pos( localMatrix->_41, localMatrix->_42, localMatrix->_43 ); float scale = std::max( Length( localMatrix->GetX() ), Length( localMatrix->GetY() ) ); @@ -976,7 +976,7 @@ void EveBoosterSet2::Add( const Matrix* localMatrix, const Vector4* functionalit } } -void EveBoosterSet2::ComputeRuntimeLightData( const EveBoosterItem& item, RuntimeLightData& out ) const +void EveBoosterSet2::ComputeBoosterLight( const EveBoosterItem& item, BoosterLight& out ) const { Vector3 lightOffset( 0.f, 0.f, -m_lightOffset ); out.position = TransformCoord( lightOffset, item.transform ); @@ -1437,7 +1437,7 @@ void EveBoosterSet2::GetLights( Tr2LightManager& lightManager ) const radiusFactor *= ( *dit )->m_overallIntensity; Color color = m_lightColor * ( 1.f - warpIntensity ) + m_lightWarpColor * warpIntensity; XMMATRIX transform = ( *dit )->m_parentTransform; - for( const RuntimeLightData& light : m_runtimeLights ) + for( const BoosterLight& light : m_boosterLights ) { float phase = ( light.phase + Tr2Renderer::GetAnimationTime() ) * m_lightFlickerFrequency; float p0 = g_lightNoise[int( phase ) % g_lightNoiseSize]; diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h index 2c7ad6330..a638b8fd9 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h @@ -37,9 +37,9 @@ BLUE_DECLARE( Tr2DebugRenderer ); // are persisted to Blue via a BLUE_DECLARE_STRUCTURE_LIST (see s_boosterItemStructureDef // in EveBoosterSet2.cpp) so boosters survive save/load cycles. transform is NOT // persisted: the ship owns locator authority and supplies a fresh transform on every -// rebuild via EveBoosterSet2::RebuildBoosters(). Runtime-derived fields (light position, +// rebuild via EveBoosterSet2::RebuildBoosters(). The derived point-light fields (position, // radius, phase) are NOT stored here either — they live in EveBoosterSet2's -// m_runtimeLights vector, parallel to the persisted m_boosters list. +// m_boosterLights vector, parallel to the persisted m_boosters list. // -------------------------------------------------------------------------------- struct EveBoosterItem { @@ -265,9 +265,9 @@ BLUE_CLASS( EveBoosterSet2 ) : // manage individual exhaust points void Clear(); - // Per-booster runtime light data, computed from EveBoosterItem entries by Add(). + // The point light contributed by one booster, computed from its EveBoosterItem by Add(). // Parallel to m_boosters: same index, same count. Never persisted. - struct RuntimeLightData + struct BoosterLight { Vector3 position; float radius; @@ -323,12 +323,12 @@ BLUE_CLASS( EveBoosterSet2 ) : private: PEveBoosterItemStructureList m_boosters; - std::vector m_runtimeLights; + std::vector m_boosterLights; // re-alloc and init the instance vertex buffers void RebuildInstanceData( Tr2RenderContext & renderContext ); - // derive runtime light data for one booster from its persisted entry - void ComputeRuntimeLightData( const EveBoosterItem& item, RuntimeLightData& out ) const; + // derive the point light for one booster from its persisted entry + void ComputeBoosterLight( const EveBoosterItem& item, BoosterLight& out ) const; // clear boosters/glows/trails/bounding info while preserving effects and visual // settings; used internally by RebuildBoosters() before re-adding from fresh locators From ab0d5a7376f066b19d9ea1c8da08e502052441f0 Mon Sep 17 00:00:00 2001 From: Selph Date: Mon, 10 Aug 2026 16:41:56 +0000 Subject: [PATCH 11/11] Address review feedback --- .../Attachments/EveBoosterSet2.cpp | 79 ++++++++----------- .../SpaceObject/Attachments/EveBoosterSet2.h | 25 +++--- 2 files changed, 48 insertions(+), 56 deletions(-) diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp index 7028b2c53..5032985a5 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.cpp @@ -48,22 +48,21 @@ bool g_lightNoiseInitialized = false; namespace { - BlueStructureDefinition s_boosterItemStructureDef[] = - { - { "functionality", Be::FLOAT32_4, offsetof( EveBoosterItem, functionality ) }, - { "atlasIndex0", Be::UINT32_1, offsetof( EveBoosterItem, atlasIndex0 ) }, - { "atlasIndex1", Be::UINT32_1, offsetof( EveBoosterItem, atlasIndex1 ) }, - { "hasTrail", Be::INT32_1, offsetof( EveBoosterItem, hasTrail ) }, - { "lightScale", Be::FLOAT32_1, offsetof( EveBoosterItem, lightScale ) }, - { 0 } - }; - - EveBoosterItem s_defaultBoosterItem; +BlueStructureDefinition s_boosterItemStructureDef[] = { + { "functionality", Be::FLOAT32_4, offsetof( EveBoosterItem, functionality ) }, + { "atlasIndex0", Be::UINT32_1, offsetof( EveBoosterItem, atlasIndex0 ) }, + { "atlasIndex1", Be::UINT32_1, offsetof( EveBoosterItem, atlasIndex1 ) }, + { "hasTrail", Be::INT32_1, offsetof( EveBoosterItem, hasTrail ) }, + { "lightScale", Be::FLOAT32_1, offsetof( EveBoosterItem, lightScale ) }, + { 0 } +}; + +EveBoosterItem s_defaultBoosterItem; } -EveBoosterItem::EveBoosterItem() - : transform( IdentityMatrix() ), +EveBoosterItem::EveBoosterItem() : + transform( IdentityMatrix() ), functionality( 0.f, 1.f, 1.f, 1.f ), atlasIndex0( 0 ), atlasIndex1( 0 ), @@ -887,35 +886,25 @@ void EveBoosterSet2::Clear() // -------------------------------------------------------------------------------- // Description: -// Rebuild boosters while preserving effects, glows, trails and visual settings. -// This is used when locators change but the booster configuration should remain. +// Drop all per-booster state ahead of a rebuild. Boosters, glows and trails are +// all cleared here and re-created by the Add() calls that follow; what survives is +// the set-level configuration (effects, glow/halo/light settings), since those live +// outside the per-booster arrays. The per-booster metadata that RebuildBoosters() +// restores is snapshotted by that caller before this runs, not preserved here. // -------------------------------------------------------------------------------- -void EveBoosterSet2::RebuildPreservingSettings() +void EveBoosterSet2::PrepareForRebuild() { - // Clear only the booster items, not the effects/glows/trails - m_boosters.Clear(); - m_boosterLights.clear(); - if( m_glows ) - { - m_glows->Clear(); - } - if( m_trails ) - { - m_trails->Clear(); - } + Clear(); - // Reset bounding info - BoundingSphereInitialize( m_boosterBoundingSphere ); + // Clear() leaves m_maxSize alone; a rebuild re-derives it from the boosters it + // re-adds, so reset it here to avoid carrying over a stale maximum. m_maxSize = 0.f; - - // Release only the instance buffer resources - ReleaseResources( TRISTORAGE_ALL ); } // -------------------------------------------------------------------------------- // Description: // Finalize the rebuild by rebuilding glows after all boosters have been added. -// Call this after RebuildPreservingSettings() and all Add() calls. +// Call this after PrepareForRebuild() and all Add() calls. // -------------------------------------------------------------------------------- void EveBoosterSet2::FinalizeRebuild() { @@ -930,12 +919,12 @@ void EveBoosterSet2::Add( const Matrix* localMatrix, const Vector4* functionalit { // keep source data for persistence EveBoosterItem item; - item.transform = *localMatrix; + item.transform = *localMatrix; item.functionality = *functionality; - item.atlasIndex0 = atlasIndex0; - item.atlasIndex1 = atlasIndex1; - item.hasTrail = hasTrail ? 1 : 0; - item.lightScale = lightScale; + item.atlasIndex0 = atlasIndex0; + item.atlasIndex1 = atlasIndex1; + item.hasTrail = hasTrail ? 1 : 0; + item.lightScale = lightScale; BoosterLight light; ComputeBoosterLight( item, light ); @@ -980,8 +969,8 @@ void EveBoosterSet2::ComputeBoosterLight( const EveBoosterItem& item, BoosterLig { Vector3 lightOffset( 0.f, 0.f, -m_lightOffset ); out.position = TransformCoord( lightOffset, item.transform ); - out.radius = std::max( Length( item.transform.GetX() ), Length( item.transform.GetY() ) ) * item.lightScale; - out.phase = float( g_lightNoiseSize ) * float( rand() ) / float( RAND_MAX ); + out.radius = std::max( Length( item.transform.GetX() ), Length( item.transform.GetY() ) ) * item.lightScale; + out.phase = float( g_lightNoiseSize ) * float( rand() ) / float( RAND_MAX ); } // -------------------------------------------------------------------------------- @@ -1002,7 +991,7 @@ void EveBoosterSet2::RebuildBoosters( const std::vector& locatorTransfor previous.push_back( m_boosters[i] ); } - RebuildPreservingSettings(); + PrepareForRebuild(); for( size_t i = 0; i < locatorTransforms.size(); ++i ) { @@ -1016,10 +1005,10 @@ void EveBoosterSet2::RebuildBoosters( const std::vector& locatorTransfor { const EveBoosterItem& saved = previous[i]; functionality = saved.functionality; - hasTrail = saved.hasTrail != 0; - atlasIndex0 = saved.atlasIndex0; - atlasIndex1 = saved.atlasIndex1; - lightScale = saved.lightScale; + hasTrail = saved.hasTrail != 0; + atlasIndex0 = saved.atlasIndex0; + atlasIndex1 = saved.atlasIndex1; + lightScale = saved.lightScale; } Add( &locatorTransforms[i], &functionality, hasTrail, atlasIndex0, atlasIndex1, lightScale ); diff --git a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h index a638b8fd9..ff99b4ffe 100644 --- a/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h +++ b/trinity/Eve/SpaceObject/Attachments/EveBoosterSet2.h @@ -45,12 +45,12 @@ struct EveBoosterItem { EveBoosterItem(); - Matrix transform; - Vector4 functionality; - uint32_t atlasIndex0; - uint32_t atlasIndex1; - int32_t hasTrail; - float lightScale; + Matrix transform; + Vector4 functionality; + uint32_t atlasIndex0; + uint32_t atlasIndex1; + int32_t hasTrail; + float lightScale; }; BLUE_DECLARE_STRUCTURE_LIST( EveBoosterItem ); @@ -270,8 +270,8 @@ BLUE_CLASS( EveBoosterSet2 ) : struct BoosterLight { Vector3 position; - float radius; - float phase; + float radius; + float phase; }; void Add( const Matrix* localMatrix, const Vector4* functionality, bool hasTrail, uint32_t atlasIndex0, uint32_t atlasIndex1, float lightScale = 1 ); @@ -287,7 +287,10 @@ BLUE_CLASS( EveBoosterSet2 ) : // HasPersistentBoosterItems()). Always true on any build where this is exposed to Blue. // Deliberately exposes only this flag, not the per-booster data itself, which stays // Be::PERSISTONLY (see the "boosters" MAP_ATTRIBUTE in EveBoosterSet2_Blue.cpp). - bool HasPersistentBoosterItems() const { return true; } + bool HasPersistentBoosterItems() const + { + return true; + } // set internal visual data void SetData( float glowScale, @@ -332,12 +335,12 @@ BLUE_CLASS( EveBoosterSet2 ) : // clear boosters/glows/trails/bounding info while preserving effects and visual // settings; used internally by RebuildBoosters() before re-adding from fresh locators - void RebuildPreservingSettings(); + void PrepareForRebuild(); // rebuild glows after all boosters have been re-added; used internally by RebuildBoosters() void FinalizeRebuild(); // function to create the flares from boosterdata - void CreateFlares( const EveBoosterItem & item ); + void CreateFlares( const EveBoosterItem& item ); // toggle display bool m_display;