diff --git a/Assets/PopcornFX_Dependencies.xml b/Assets/PopcornFX_Dependencies.xml
index 71a5890..4b6bdd9 100644
--- a/Assets/PopcornFX_Dependencies.xml
+++ b/Assets/PopcornFX_Dependencies.xml
@@ -37,4 +37,5 @@
+
diff --git a/Code/CMakeLists.txt b/Code/CMakeLists.txt
index 7cbb325..d127a3e 100644
--- a/Code/CMakeLists.txt
+++ b/Code/CMakeLists.txt
@@ -3,7 +3,7 @@
# https://www.popcornfx.com/terms-and-conditions/
#----------------------------------------------------------------------------
-set(POPCORNFX_VERSION 2.18.1)
+set(POPCORNFX_VERSION 2.15.16)
set(POPCORNFX_LICENSE O3DE)
if (PK_O3DE_MAJOR_VERSION GREATER_EQUAL 2205)
@@ -33,6 +33,22 @@ ly_add_target(
Include
)
+set(PK_OPTIONAL_REGISTER_NODEABLE_FILES
+ *.ScriptCanvasNodeable.xml,ScriptCanvasNodeableRegistry_Header.jinja,AutoGenNodeableRegistry.generated.h
+ *.ScriptCanvasNodeable.xml,ScriptCanvasNodeableRegistry_Source.jinja,AutoGenNodeableRegistry.generated.cpp
+ )
+set(PK_OPTIONAL_REGISTER_NODEABLE_DEFINES PK_REGISTER_NODEABLE)
+
+if(DEFINED O3DE_VERSION_MAJOR)
+ # O3DE 3.x.x and higher no longer need the autogen nodeable registry source files
+ # Also include special case to handle bug where SDK 23.05.0 engine version was set to the display version
+ if(O3DE_VERSION_MAJOR GREATER_EQUAL 3 AND
+ NOT (O3DE_VERSION_MAJOR EQUAL 23 AND O3DE_VERSION_MINOR EQUAL 05 AND O3DE_VERSION_PATCH EQUAL 0))
+ unset(PK_OPTIONAL_REGISTER_NODEABLE_FILES)
+ unset(PK_OPTIONAL_REGISTER_NODEABLE_DEFINES)
+ endif()
+endif()
+
ly_add_target(
NAME PopcornFX.Static STATIC
NAMESPACE Gem
@@ -46,6 +62,7 @@ ly_add_target(
PK_USE_PHYSX
PK_USE_EMOTIONFX
PK_USE_STARTINGPOINTINPUT
+ ${PK_OPTIONAL_REGISTER_NODEABLE_DEFINES}
INCLUDE_DIRECTORIES
PRIVATE
Source
@@ -72,8 +89,7 @@ ly_add_target(
AUTOGEN_RULES
*.ScriptCanvasNodeable.xml,ScriptCanvasNodeable_Header.jinja,$path/$fileprefix.generated.h
*.ScriptCanvasNodeable.xml,ScriptCanvasNodeable_Source.jinja,$path/$fileprefix.generated.cpp
- *.ScriptCanvasNodeable.xml,ScriptCanvasNodeableRegistry_Header.jinja,AutoGenNodeableRegistry.generated.h
- *.ScriptCanvasNodeable.xml,ScriptCanvasNodeableRegistry_Source.jinja,AutoGenNodeableRegistry.generated.cpp
+ ${PK_OPTIONAL_REGISTER_NODEABLE_FILES}
)
ly_add_target(
diff --git a/Code/Platform/Linux/PAL_linux.cmake b/Code/Platform/Linux/PAL_linux.cmake
index 53df0c4..b7ff90f 100644
--- a/Code/Platform/Linux/PAL_linux.cmake
+++ b/Code/Platform/Linux/PAL_linux.cmake
@@ -6,12 +6,12 @@
set(LY_PACKAGE_SERVER_URLS ${LY_PACKAGE_SERVER_URLS} "https://downloads.popcornfx.com/o3de-packages")
if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(package_name PopcornFX-${POPCORNFX_VERSION}-${POPCORNFX_LICENSE}-linux)
- set(pk_package_hash 08e30c12813e29e53eae075f4f9f02a1a308c7e8713bcf73abd9b207659abcd9)
- set(pk_package_id Ng3RaXuqyAUWAgHy)
+ set(pk_package_hash a93262660d1f15cf86f7b5d1f674f9530b574d8b4ad480aceb8d4bb67a091836)
+ set(pk_package_id kX8RSRt2hZWQZutp)
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
set(package_name PopcornFX-${POPCORNFX_VERSION}-${POPCORNFX_LICENSE}-linux-aarch64)
- set(pk_package_hash 0a81eb7ca2d717416efe2aa9ea4c5c3014e1b56c2acdb190556b8c490214beb4)
- set(pk_package_id ZDEps23sNQA5p7q5)
+ set(pk_package_hash a93262660d1f15cf86f7b5d1f674f9530b574d8b4ad480aceb8d4bb67a091836_ARM64)
+ set(pk_package_id kX8RSRt2hZWQZutp_ARM64)
else()
message(FATAL_ERROR "Unsupported linux architecture ${CMAKE_SYSTEM_PROCESSOR}")
endif()
diff --git a/Code/Platform/Mac/PAL_mac.cmake b/Code/Platform/Mac/PAL_mac.cmake
index 5425749..4f29180 100644
--- a/Code/Platform/Mac/PAL_mac.cmake
+++ b/Code/Platform/Mac/PAL_mac.cmake
@@ -5,8 +5,8 @@
set(LY_PACKAGE_SERVER_URLS ${LY_PACKAGE_SERVER_URLS} "https://downloads.popcornfx.com/o3de-packages")
set(package_name PopcornFX-${POPCORNFX_VERSION}-${POPCORNFX_LICENSE}-mac)
-set(pk_package_hash 8e371903268af71a1a362194c7b58f43094b1ff9accc27f0fd4a117df470e760)
-set(pk_package_id Kph45AXPVnUw9u6K)
+set(pk_package_hash 5146d7599485b397f6e53c8b5cc628bbbb72e9a22b9a0feef60cf524d5e71abb)
+set(pk_package_id roDQZpBI1HS7O2SX)
ly_associate_package(PACKAGE_NAME ${package_name} TARGETS PopcornFX PACKAGE_HASH ${pk_package_hash})
pk_download_package_ifn(${package_name} ${pk_package_id})
diff --git a/Code/Platform/Windows/PAL_windows.cmake b/Code/Platform/Windows/PAL_windows.cmake
index 0435da6..2bcd9d6 100644
--- a/Code/Platform/Windows/PAL_windows.cmake
+++ b/Code/Platform/Windows/PAL_windows.cmake
@@ -5,8 +5,8 @@
set(LY_PACKAGE_SERVER_URLS ${LY_PACKAGE_SERVER_URLS} "https://downloads.popcornfx.com/o3de-packages")
set(package_name PopcornFX-${POPCORNFX_VERSION}-${POPCORNFX_LICENSE}-windows)
-set(pk_package_hash 4813982cd76ea251972abd8868f09a71d7f03fe3bd486dc1fc0ecbe243327354)
-set(pk_package_id UntkQKUXJ57BnbcB)
+set(pk_package_hash 50ef4f2879a49b9e10c438076dce1c9ea5b6f70f92bd61f8abdf8a770c26e968)
+set(pk_package_id PsvjDNhF0Trboq2I)
ly_associate_package(PACKAGE_NAME ${package_name} TARGETS PopcornFX PACKAGE_HASH ${pk_package_hash})
pk_download_package_ifn(${package_name} ${pk_package_id})
diff --git a/Code/Source/Integration/SceneInterface/SceneInterface.cpp b/Code/Source/Integration/SceneInterface/SceneInterface.cpp
index 040696c..5b28537 100644
--- a/Code/Source/Integration/SceneInterface/SceneInterface.cpp
+++ b/Code/Source/Integration/SceneInterface/SceneInterface.cpp
@@ -9,57 +9,34 @@
#if defined(O3DE_USE_PK)
+#include
+
#if defined(PK_USE_PHYSX)
#include
- #include
- #include
#include
+ #include
#include
- #include
+ #if RESOLVE_MATERIAL_PROPERTIES
+ #include
+ #endif
+ #if RESOLVE_CONTACT_OBJECT
+ #include
+ #endif
#endif
-#include
-
+#include "Integration/PopcornFXIntegrationBus.h"
#include "Integration/PopcornFXUtils.h"
namespace PopcornFX {
- static void PrintPopcornFXPhysicsSurfaceTypesConstants(const AZ::ConsoleCommandContainer&)
- {
- if (auto *materialManager = AZ::Interface::Get())
- {
- AZStd::shared_ptr defaultMaterial = materialManager->GetDefaultMaterial();
- if (defaultMaterial != null)
- {
- AZ_Printf("PopcornFX", "physics.surfaceTypes.Default %u", AZ::Crc32(defaultMaterial->GetId().ToString()));
- }
- }
-
- AZ::Data::AssetCatalogRequests::AssetEnumerationCB popcornFxAssetReloadCb = [](const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info)
- {
- if (info.m_assetType == ::Physics::MaterialAsset::RTTI_Type())
- {
- Physics::MaterialId materialId = Physics::MaterialId::CreateFromAssetId(id);
- AZStd::string materialName = info.m_relativePath;
-
- AZ::StringFunc::Replace(materialName, ".physicsmaterial", "");
- AZ::StringFunc::Replace(materialName, "/", ".");
-
- AZ_Printf("PopcornFX", "physics.surfaceTypes.%s %u", materialName.c_str(), AZ::Crc32(materialId.ToString()));
- }
- };
- AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, null, popcornFxAssetReloadCb, null);
- }
-
- AZ_CONSOLEFREEFUNC(PrintPopcornFXPhysicsSurfaceTypesConstants, AZ::ConsoleFunctorFlags::Null, "Print the physics surface types constants to add in your PopcornFX project settings.");
-
-#if defined(PK_USE_PHYSX)
void CSceneInterface::RayTracePacket(const Colliders::STraceFilter &traceFilter,
const Colliders::SRayPacket &packet,
const Colliders::STracePacket &results)
{
- AzPhysics::SceneHandle sceneHandle = AzPhysics::InvalidSceneHandle;
- AzPhysics::SceneInterface *sceneInterface = AZ::Interface::Get();
+#if defined(PK_USE_PHYSX)
+ AzPhysics::SceneHandle sceneHandle = AzPhysics::InvalidSceneHandle;
+ auto *sceneInterface = AZ::Interface::Get();
+
if (sceneInterface != null)
{
#if defined(POPCORNFX_EDITOR)
@@ -75,14 +52,6 @@ namespace PopcornFX {
if (!PK_VERIFY(sceneHandle != AzPhysics::InvalidSceneHandle))
return;
- Physics::MaterialManager *materialManager = null;
- if (results.m_ContactSurfaces_Aligned16 != null)
- {
- materialManager = AZ::Interface::Get();
- if (!PK_VERIFY(materialManager != null))
- return;
- }
-
AzPhysics::CollisionGroup collisionGroup(traceFilter.m_FilterFlags == 0 ? AzPhysics::CollisionGroup::All.GetMask() : traceFilter.m_FilterFlags);
const u32 resCount = results.Count();
@@ -109,7 +78,6 @@ namespace PopcornFX {
request.m_direction = ToAZ(dir);
request.m_distance = _rayDirAndLen.w();
request.m_collisionGroup = collisionGroup;
- PK_ASSERT(request.m_reportMultipleHits == false);
hitResult = sceneInterface->QueryScene(sceneHandle, &request);
}
@@ -121,94 +89,81 @@ namespace PopcornFX {
request.m_direction = ToAZ(dir);
request.m_shapeConfiguration = AZStd::make_shared(packet.m_RaySweepRadii_Aligned16[rayi]);
request.m_collisionGroup = collisionGroup;
- PK_ASSERT(request.m_reportMultipleHits == false);
hitResult = sceneInterface->QueryScene(sceneHandle, &request);
}
if (!hitResult.m_hits.empty())
{
- //m_reportMultipleHits in AzPhysics::RayCastRequest and AzPhysics::ShapeCastRequest are set to false by default, only 1 hit possible
+ //m_reportMultipleHits in AzPhysics::RayCastRequest and AzPhysics::ShapeCastRequest are set to false, only 1 hit possible
const AzPhysics::SceneQueryHit &hit = hitResult.m_hits[0];
results.m_HitTimes_Aligned16[rayi] = hit.m_distance;
if (results.m_ContactObjects_Aligned16 != null)
{
- const bool haveBodyHandle = hit.m_resultFlags & AzPhysics::SceneQuery::ResultFlags::BodyHandle;
- if (!haveBodyHandle)
- results.m_ContactObjects_Aligned16[rayi] = null;
- else
- results.m_ContactObjects_Aligned16[rayi] = sceneInterface->GetSimulatedBodyFromHandle(sceneHandle, hit.m_bodyHandle);
- }
- if (results.m_ContactSurfaces_Aligned16 != null)
- {
- const bool havePhysicsMaterial = hit.m_resultFlags & AzPhysics::SceneQuery::ResultFlags::Material;
- if (!havePhysicsMaterial)
- results.m_ContactSurfaces_Aligned16[rayi] = null;
- else
+#if RESOLVE_CONTACT_OBJECT
+ Physics::RigidBody *rigidbody = null;
+ AZ::Entity *entity = null;
+ EBUS_EVENT_RESULT(entity, AZ::ComponentApplicationBus, FindEntity, hit.m_body->GetEntityId());
+ if (entity)
{
- AZStd::shared_ptr material = AZStd::rtti_pointer_cast(materialManager->GetMaterial(hit.m_physicsMaterialId));
- results.m_ContactSurfaces_Aligned16[rayi] = material.get();
+ Physics::RigidBodyRequestBus::EventResult(rigidbody, hit.m_body->GetEntityId(), &Physics::RigidBodyRequests::GetRigidBody);
}
+ if (rigidbody)
+ results.m_ContactObjects_Aligned16[rayi] = rigidbody;
+ else
+#endif
+ results.m_ContactObjects_Aligned16[rayi] = CollidableObject::DEFAULT;
}
if (results.m_ContactPoints_Aligned16 != null)
results.m_ContactPoints_Aligned16[rayi].xyz() = ToPk(hit.m_position);
if (results.m_ContactNormals_Aligned16 != null)
results.m_ContactNormals_Aligned16[rayi].xyz() = ToPk(hit.m_normal);
+#if RESOLVE_MATERIAL_PROPERTIES
+ if (results.m_ContactSurfaces_Aligned16 != null)
+ {
+ AZ::Entity *entity = null;
+ EBUS_EVENT_RESULT(entity, AZ::ComponentApplicationBus, FindEntity, hit.m_entityId);
+ if (entity)
+ {
+ Physics::RigidBody *rigidbody;
+ Physics::RigidBodyRequestBus::EventResult(rigidbody, hit.m_body->GetEntityId(), &Physics::RigidBodyRequests::GetRigidBody);
+ if (rigidbody)
+ {
+ Physics::MaterialId materialId = rigidbody->GetMaterialIdForShapeHierarchy(hit.m_hitShapeIdHierarchy);
+ Physics::MaterialProperties *matProperties = null;
+ Physics::MaterialRequestBus::BroadcastResult(matProperties, &Physics::MaterialRequests::GetPhysicsMaterialProperties, materialId);
+ results.m_ContactSurfaces_Aligned16[rayi] = matProperties;
+ }
+ }
+ }
+#endif //RESOLVE_MATERIAL_PROPERTIES
}
}
+#endif
}
- void CSceneInterface::ResolveContactMaterials( [[maybe_unused]] const TMemoryView &contactObjects,
- const TMemoryView &contactSurfaces,
- const TMemoryView &outSurfaceProperties) const
- {
- PK_ASSERT(contactObjects.Count() == contactSurfaces.Count());
- PK_ASSERT(contactObjects.Count() == outSurfaceProperties.Count());
-
- static const PopcornFX::Colliders::SSurfaceProperties kDefaultSurface;
-
- const u32 materialCount = contactSurfaces.Count();
- for (u32 iMaterial = 0; iMaterial < materialCount; ++iMaterial)
- {
- PopcornFX::Colliders::SSurfaceProperties &surface = outSurfaceProperties[iMaterial];
- surface = kDefaultSurface;
+#if RESOLVE_MATERIAL_PROPERTIES
+void CSceneInterface::ResolveContactMaterials( const TMemoryView &contactObjects,
+ const TMemoryView &contactSurfaces,
+ const TMemoryView&outSurfaceProperties) const
+{
+ const u32 materialCount = contactSurfaces.Count();
- PhysX::Material *material = reinterpret_cast(contactSurfaces[iMaterial]);
- if (material == null)
- continue;
-
- surface.m_Restitution = material->GetRestitution();
- surface.m_StaticFriction = material->GetStaticFriction();
- surface.m_DynamicFriction = material->GetDynamicFriction();
- surface.m_SurfaceType = AZ::Crc32(material->GetId().ToString());
-
-#define REMAP_COMBINE_MODE(__member, __val) \
- switch (__val) \
- { \
- case PhysX::CombineMode::Average: \
- surface.__member = PopcornFX::Colliders::ECombineMode::Combine_Average; \
- break; \
- case PhysX::CombineMode::Minimum: \
- surface.__member = PopcornFX::Colliders::ECombineMode::Combine_Min; \
- break; \
- case PhysX::CombineMode::Maximum: \
- surface.__member = PopcornFX::Colliders::ECombineMode::Combine_Max; \
- break; \
- case PhysX::CombineMode::Multiply: \
- surface.__member = PopcornFX::Colliders::ECombineMode::Combine_Multiply; \
- break; \
- default: \
- PK_ASSERT_NOT_REACHED(); \
- break; \
- }
-
- REMAP_COMBINE_MODE(m_FrictionCombineMode, material->GetFrictionCombineMode());
- REMAP_COMBINE_MODE(m_RestitutionCombineMode, material->GetRestitutionCombineMode());
-
-#undef REMAP_COMBINE_MODE
- }
+ for (u32 iMaterial = 0; iMaterial < materialCount; ++iMaterial)
+ {
+ PopcornFX::Colliders::SSurfaceProperties &surface = outSurfaceProperties[iMaterial];
+ Physics::MaterialProperties *matProperties = reinterpret_cast(contactSurfaces[iMaterial]);
+ if (matProperties == null)
+ continue;
+ surface.m_Restitution = matProperties->m_restitution;
+ surface.m_StaticFriction = matProperties->m_friction;
+ surface.m_DynamicFriction = surface.m_StaticFriction;
+ surface.m_SurfaceType = AZStd::hash{}(matProperties->m_name);
+ surface.m_RestitutionCombineMode = Colliders::Combine_Average;
+ surface.m_FrictionCombineMode = Colliders::Combine_Average;
}
-#endif //PK_USE_PHYSX
+}
+#endif //RESOLVE_MATERIAL_PROPERTIES
}
diff --git a/Code/Source/Integration/SceneInterface/SceneInterface.h b/Code/Source/Integration/SceneInterface/SceneInterface.h
index b8297e9..33c6911 100644
--- a/Code/Source/Integration/SceneInterface/SceneInterface.h
+++ b/Code/Source/Integration/SceneInterface/SceneInterface.h
@@ -8,20 +8,23 @@
#include
+#define RESOLVE_MATERIAL_PROPERTIES 0
+#define RESOLVE_CONTACT_OBJECT 0
+
namespace PopcornFX {
class CSceneInterface : public IParticleScene
{
public:
-#if defined(PK_USE_PHYSX)
virtual void RayTracePacket( const Colliders::STraceFilter &traceFilter,
const Colliders::SRayPacket &packet,
const Colliders::STracePacket &results) override;
+#if RESOLVE_MATERIAL_PROPERTIES
virtual void ResolveContactMaterials(const TMemoryView &contactObjects,
const TMemoryView &contactSurfaces,
const TMemoryView&outSurfaceProperties) const override;
-#endif //PK_USE_PHYSX
+#endif
void SetInGameMode(bool inGameMode) { m_InGameMode = inGameMode; }
diff --git a/Code/Source/Integration/Startup/PopcornFxStartup.cpp b/Code/Source/Integration/Startup/PopcornFxStartup.cpp
index 0e48a0e..5822530 100644
--- a/Code/Source/Integration/Startup/PopcornFxStartup.cpp
+++ b/Code/Source/Integration/Startup/PopcornFxStartup.cpp
@@ -85,6 +85,23 @@ namespace PopcornFX {
};
}
};
+#else
+ class CLogListenerO3DERelease : public ILogListener
+ {
+ public:
+ virtual void Notify(CLog::ELogLevel level, CGuid logClass, const char* message) override
+ {
+ const CString s = CString::Format("[%s] ERROR: %s", CLog::LogClassToString(logClass), message);
+
+ switch (level)
+ {
+ case PopcornFX::CLog::Level_Error:
+ case PopcornFX::CLog::Level_ErrorCritical:
+ AZ_Printf("PopcornFX", s.Data());
+ break;
+ };
+ }
+ };
#endif
//----------------------------------------------------------------------------
@@ -95,6 +112,8 @@ namespace PopcornFX {
#ifndef PK_RETAIL
CLog::AddGlobalListener(PK_NEW(CLogListenerO3DE));
+#else
+ CLog::AddGlobalListener(PK_NEW(CLogListenerO3DERelease));
#endif
}
diff --git a/Code/Source/PopcornFXSystemComponent.cpp b/Code/Source/PopcornFXSystemComponent.cpp
index 231d7ca..8ee3d59 100644
--- a/Code/Source/PopcornFXSystemComponent.cpp
+++ b/Code/Source/PopcornFXSystemComponent.cpp
@@ -20,10 +20,14 @@
#include "Asset/PopcornFXAsset.h"
#include "Asset/PopcornFXAssetHandler.h"
+// Logic for setting PK_REGISTER_NODEABLE is in Code/CMakeLists.txt
+#if PK_REGISTER_NODEABLE
+// In O3DE versions less than 3.x.x we need to register autogenerated nodeables
#include
#include
REGISTER_SCRIPTCANVAS_AUTOGEN_NODEABLE(PopcornFXStatic);
+#endif
namespace PopcornFX {
diff --git a/Code/popcornfx_autogen_files.cmake b/Code/popcornfx_autogen_files.cmake
index a40dc29..68eaa61 100644
--- a/Code/popcornfx_autogen_files.cmake
+++ b/Code/popcornfx_autogen_files.cmake
@@ -5,10 +5,23 @@
get_property(scriptcanvas_gem_root GLOBAL PROPERTY "@GEMROOT:ScriptCanvas@")
+set(PK_OPTIONAL_REGISTER_NODEABLE_FILES
+ ${scriptcanvas_gem_root}/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeableRegistry_Header.jinja
+ ${scriptcanvas_gem_root}/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeableRegistry_Source.jinja
+ )
+
+if(DEFINED O3DE_VERSION_MAJOR)
+ # O3DE 3.x.x and higher no longer need the registry source files
+ # Also include special case to handle bug where SDK 23.05.0 engine version was set to the display version
+ if(O3DE_VERSION_MAJOR GREATER_EQUAL 3 AND
+ NOT (O3DE_VERSION_MAJOR EQUAL 23 AND O3DE_VERSION_MINOR EQUAL 05 AND O3DE_VERSION_PATCH EQUAL 0))
+ unset(PK_OPTIONAL_REGISTER_NODEABLE_FILES)
+ endif()
+endif()
+
set(FILES
${scriptcanvas_gem_root}/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Header.jinja
${scriptcanvas_gem_root}/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja
- ${scriptcanvas_gem_root}/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeableRegistry_Header.jinja
- ${scriptcanvas_gem_root}/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeableRegistry_Source.jinja
+ ${PK_OPTIONAL_REGISTER_NODEABLE_FILES}
)
diff --git a/README.md b/README.md
index 83f0a41..cfd2049 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
# O3DE PopcornFX Plugin
Integrates the **PopcornFX Runtime SDK** into **O3DE** as a Gem.
-* **Version:** `v2.18.1`
-* **O3DE:** `23.05`
+* **Version:** `v2.15.16`
+* **O3DE:** `23.05`, `23.10`
* **Supported platforms:** `Windows`, `MacOS`, `Linux`, `iOS`, `Android`
**Note:** Mobile platforms are in an experimental stage. [Contact-us](http://www.popcornfx.com/contact-us/) to request access.
diff --git a/gem.json b/gem.json
index 42eb58c..2ab604f 100644
--- a/gem.json
+++ b/gem.json
@@ -1,13 +1,13 @@
{
"gem_name": "PopcornFX",
- "display_name": "PopcornFX 2.18.1",
+ "display_name": "PopcornFX 2.15.16",
"license": "Community",
"license_url": "https://www.popcornfx.com/popcornfx-community-license",
"origin": "Persistant Studios - popcornfx.com",
"repo_uri": "https://downloads.popcornfx.com/o3de-repo",
- "origin_uri": "https://downloads.popcornfx.com/o3de-repo/PopcornFX-2.18/O3DE_PopcornFXGem_v2.18.1_Win64_Linux64_LinuxARM64_Mac64.zip",
- "version": "2.18.1",
- "last_updated": "2023-10-26",
+ "origin_uri": "https://downloads.popcornfx.com/o3de-repo/PopcornFX-2.15/O3DE_PopcornFXGem_v2.15.16_Win64_Linux64_LinuxARM64_Mac64.zip",
+ "version": "2.15.16",
+ "last_updated": "2023-12-01",
"type": "Code",
"summary": "The PopcornFX Gem provides real-time FX solution for particle effects.",
"canonical_tags": [