rngine 0.9.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/lib/typescript/src/GameEngine.d.ts +1 -1
  2. package/lib/typescript/src/GameEngine.d.ts.map +1 -1
  3. package/lib/typescript/src/GameMethods.d.ts +2 -2
  4. package/lib/typescript/src/GameMethods.d.ts.map +1 -1
  5. package/lib/typescript/src/GameMethods.nitro.d.ts +1 -1
  6. package/lib/typescript/src/GameMethods.nitro.d.ts.map +1 -1
  7. package/lib/typescript/src/index.d.ts +4 -4
  8. package/lib/typescript/src/index.d.ts.map +1 -1
  9. package/lib/typescript/src/nativeTypes.d.ts +3 -1
  10. package/lib/typescript/src/nativeTypes.d.ts.map +1 -1
  11. package/lib/typescript/src/types.d.ts +1 -1
  12. package/lib/typescript/src/types.d.ts.map +1 -1
  13. package/nitrogen/generated/android/c++/views/JHybridGameEngineStateUpdater.cpp +34 -17
  14. package/nitrogen/generated/android/c++/views/JHybridGameEngineStateUpdater.hpp +6 -1
  15. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngine/HybridGameEngineSpec.kt +2 -0
  16. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngine/views/HybridGameEngineManager.kt +26 -10
  17. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngine/views/HybridGameEngineStateUpdater.kt +2 -2
  18. package/nitrogen/generated/ios/c++/views/HybridGameEngineComponent.mm +40 -19
  19. package/nitrogen/generated/shared/c++/Entity.hpp +5 -1
  20. package/nitrogen/generated/shared/c++/EntityUpdate.hpp +5 -1
  21. package/nitrogen/generated/shared/c++/Screen.hpp +6 -2
  22. package/nitrogen/generated/shared/c++/ScreenUpdate.hpp +6 -2
  23. package/nitrogen/generated/shared/c++/views/HybridGameEngineComponent.cpp +5 -45
  24. package/nitrogen/generated/shared/c++/views/HybridGameEngineComponent.hpp +20 -48
  25. package/package.json +21 -63
  26. package/shared/GameLoop.cpp +2 -2
  27. package/shared/GameMethods.cpp +2 -0
  28. package/shared/utils/AssetUtils.cpp +12 -5
  29. package/shared/utils/AssetUtils.hpp +3 -2
  30. package/src/nativeTypes.ts +3 -1
  31. package/android/kls_database.db +0 -0
@@ -1,4 +1,4 @@
1
- import type { GameEngineMethods, GameEngineProps } from './GameEngine.nitro';
1
+ import type { GameEngineMethods, GameEngineProps } from './GameEngine.nitro.js';
2
2
  /**
3
3
  * A game engine view component that renders the game world.
4
4
  * Size it using the style prop like any other React Native view.
@@ -1 +1 @@
1
- {"version":3,"file":"GameEngine.d.ts","sourceRoot":"","sources":["../../../src/GameEngine.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE7E;;;;;;;;GAQG;;AACH,wBAGE"}
1
+ {"version":3,"file":"GameEngine.d.ts","sourceRoot":"","sources":["../../../src/GameEngine.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,uBAAoB,CAAC;AAE7E;;;;;;;;GAQG;;AACH,wBAGE"}
@@ -1,5 +1,5 @@
1
- import type { Entity, EntityUpdate, ScreenUpdate } from './nativeTypes';
2
- import type { Config } from './types';
1
+ import type { Entity, EntityUpdate, ScreenUpdate } from './nativeTypes.js';
2
+ import type { Config } from './types.js';
3
3
  /** Sets up the game engine with the given configuration. Call this before anything else. */
4
4
  export declare const configure: ({ world, screen, entities, systems, paused, }: Config) => void;
5
5
  /** Pauses the game loop. Systems will stop running. */
@@ -1 +1 @@
1
- {"version":3,"file":"GameMethods.d.ts","sourceRoot":"","sources":["../../../src/GameMethods.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAU,MAAM,eAAe,CAAC;AAChF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGtC,4FAA4F;AAC5F,eAAO,MAAM,SAAS,GAAI,+CAMvB,MAAM,SAyBR,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,KAAK,YAA4B,CAAC;AAE/C,6BAA6B;AAC7B,eAAO,MAAM,MAAM,YAA6B,CAAC;AAEjD,0EAA0E;AAC1E,eAAO,MAAM,KAAK,GAAI,UAAU,MAAM,GAAG,MAAM,EAAE,SAGhD,CAAC;AAEF,2HAA2H;AAC3H,eAAO,MAAM,OAAO,GAAI,IAAI,MAAM,SAA4B,CAAC;AAE/D,+HAA+H;AAC/H,eAAO,MAAM,YAAY,GAAI,cAAc,YAAY,SAEtD,CAAC;AAEF,oGAAoG;AACpG,eAAO,MAAM,cAAc,GAAI,eAAe,YAAY,EAAE,SAE3D,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,YAAY,GAAI,cAAc,YAAY,SAEtD,CAAC;AA2CF;;yEAEyE;AACzE,eAAO,MAAM,UAAU,GAAU,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,QAAQ,CAAC,KACR,OAAO,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,GAAE,CASpC,CAAC"}
1
+ {"version":3,"file":"GameMethods.d.ts","sourceRoot":"","sources":["../../../src/GameMethods.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAU,MAAM,kBAAe,CAAC;AAChF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAS,CAAC;AAGtC,4FAA4F;AAC5F,eAAO,MAAM,SAAS,GAAI,+CAMvB,MAAM,SAyBR,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,KAAK,YAA4B,CAAC;AAE/C,6BAA6B;AAC7B,eAAO,MAAM,MAAM,YAA6B,CAAC;AAEjD,0EAA0E;AAC1E,eAAO,MAAM,KAAK,GAAI,UAAU,MAAM,GAAG,MAAM,EAAE,SAGhD,CAAC;AAEF,2HAA2H;AAC3H,eAAO,MAAM,OAAO,GAAI,IAAI,MAAM,SAA4B,CAAC;AAE/D,+HAA+H;AAC/H,eAAO,MAAM,YAAY,GAAI,cAAc,YAAY,SAEtD,CAAC;AAEF,oGAAoG;AACpG,eAAO,MAAM,cAAc,GAAI,eAAe,YAAY,EAAE,SAE3D,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,YAAY,GAAI,cAAc,YAAY,SAEtD,CAAC;AA2CF;;yEAEyE;AACzE,eAAO,MAAM,UAAU,GAAU,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,QAAQ,CAAC,KACR,OAAO,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,GAAE,CASpC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { HybridObject } from 'react-native-nitro-modules';
2
- import type { Entity, EntityUpdate, System, Screen, World, ScreenUpdate } from './nativeTypes';
2
+ import type { Entity, EntityUpdate, System, Screen, World, ScreenUpdate } from './nativeTypes.js';
3
3
  interface GameMethods extends HybridObject<{
4
4
  ios: 'c++';
5
5
  android: 'c++';
@@ -1 +1 @@
1
- {"version":3,"file":"GameMethods.nitro.d.ts","sourceRoot":"","sources":["../../../src/GameMethods.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EACZ,MAAM,EACN,MAAM,EACN,KAAK,EACL,YAAY,EACb,MAAM,eAAe,CAAC;AAGvB,UAAU,WAAY,SAAQ,YAAY,CAAC;IACzC,GAAG,EAAE,KAAK,CAAC;IACX,OAAO,EAAE,KAAK,CAAC;CAChB,CAAC;IACA,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACtC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAEpC,2BAA2B;IAC3B,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,IAAI,CAAC;IAEf,4BAA4B;IAC5B,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAEpD,4BAA4B;IAC5B,YAAY,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAE/C,oBAAoB;IACpB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAED,eAAO,MAAM,WAAW,aACqC,CAAC"}
1
+ {"version":3,"file":"GameMethods.nitro.d.ts","sourceRoot":"","sources":["../../../src/GameMethods.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EACZ,MAAM,EACN,MAAM,EACN,KAAK,EACL,YAAY,EACb,MAAM,kBAAe,CAAC;AAGvB,UAAU,WAAY,SAAQ,YAAY,CAAC;IACzC,GAAG,EAAE,KAAK,CAAC;IACX,OAAO,EAAE,KAAK,CAAC;CAChB,CAAC;IACA,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACtC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAEpC,2BAA2B;IAC3B,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,IAAI,CAAC;IAEf,4BAA4B;IAC5B,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAEpD,4BAA4B;IAC5B,YAAY,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAE/C,oBAAoB;IACpB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAED,eAAO,MAAM,WAAW,aACqC,CAAC"}
@@ -1,6 +1,6 @@
1
- import GameEngine from './GameEngine';
2
- export * from './GameMethods';
3
- export * from './types';
4
- export type { World, Screen, Entity, CollisionPair, Collision, EntityUpdate, SystemContext, } from './nativeTypes';
1
+ import GameEngine from './GameEngine.js';
2
+ export * from './GameMethods.js';
3
+ export * from './types.js';
4
+ export type { World, Screen, Entity, CollisionPair, Collision, EntityUpdate, SystemContext, } from './nativeTypes.js';
5
5
  export { GameEngine };
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,cAAc,CAAC;AAEtC,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,YAAY,EACV,KAAK,EACL,MAAM,EACN,MAAM,EACN,aAAa,EACb,SAAS,EACT,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,iBAAc,CAAC;AAEtC,cAAc,kBAAe,CAAC;AAC9B,cAAc,YAAS,CAAC;AACxB,YAAY,EACV,KAAK,EACL,MAAM,EACN,MAAM,EACN,aAAa,EACb,SAAS,EACT,YAAY,EACZ,aAAa,GACd,MAAM,kBAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -31,8 +31,10 @@ interface Renderable {
31
31
  flipV?: boolean;
32
32
  /** Animation progress between 0 and 1, automatically advanced each tick for Lottie assets. */
33
33
  progress?: number;
34
- /** Playback speed multiplier for animated assets (1 = normal speed). */
34
+ /** Playback speed multiplier for Lottie assets (1 = normal speed). */
35
35
  speed?: number;
36
+ /** Whether the Lottie animation should restart automatically upon completion. */
37
+ loop?: boolean;
36
38
  }
37
39
  interface Kinematic {
38
40
  /** Horizontal velocity in game units per second. */
@@ -1 +1 @@
1
- {"version":3,"file":"nativeTypes.d.ts","sourceRoot":"","sources":["../../../src/nativeTypes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nativeTypes.d.ts","sourceRoot":"","sources":["../../../src/nativeTypes.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { System as NativeSystem, Screen, Entity, World, SystemContext } from './nativeTypes';
1
+ import type { System as NativeSystem, Screen, Entity, World, SystemContext } from './nativeTypes.js';
2
2
  export type System = Omit<NativeSystem, 'onTick'> & {
3
3
  /** Called every tick with the resolved entities and collisions. */
4
4
  onTick: (systemContext: SystemContext) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,IAAI,YAAY,EACtB,MAAM,EACN,MAAM,EACN,KAAK,EACL,aAAa,EACd,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,GAAG;IAClD,mEAAmE;IACnE,MAAM,EAAE,CAAC,aAAa,EAAE,aAAa,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,6CAA6C;IAC7C,KAAK,EAAE,KAAK,CAAC;IACb,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,8GAA8G;IAC9G,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,wDAAwD;IACxD,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,IAAI,YAAY,EACtB,MAAM,EACN,MAAM,EACN,KAAK,EACL,aAAa,EACd,MAAM,kBAAe,CAAC;AAEvB,MAAM,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,GAAG;IAClD,mEAAmE;IACnE,MAAM,EAAE,CAAC,aAAa,EAAE,aAAa,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,6CAA6C;IAC7C,KAAK,EAAE,KAAK,CAAC;IACb,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,8GAA8G;IAC9G,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,wDAAwD;IACxD,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC"}
@@ -15,38 +15,55 @@ namespace margelo::nitro::rngine::views {
15
15
  using namespace facebook;
16
16
  using ConcreteStateData = react::ConcreteState<HybridGameEngineState>;
17
17
 
18
- void JHybridGameEngineStateUpdater::updateViewProps(jni::alias_ref<jni::JClass> /* class */,
19
- jni::alias_ref<JHybridGameEngineSpec::JavaPart> javaView,
20
- jni::alias_ref<JStateWrapper::javaobject> stateWrapperInterface) {
21
- std::shared_ptr<JHybridGameEngineSpec> hybridView = javaView->getJHybridGameEngineSpec();
22
-
18
+ std::shared_ptr<const HybridGameEngineProps> JHybridGameEngineStateUpdater::getPropsFromStateWrapper(
19
+ jni::alias_ref<JStateWrapper::javaobject> stateWrapper) {
20
+ if (stateWrapper.get() == nullptr) {
21
+ return nullptr;
22
+ }
23
23
  // Get concrete StateWrapperImpl from passed StateWrapper interface object
24
- jobject rawStateWrapper = stateWrapperInterface.get();
25
- if (!stateWrapperInterface->isInstanceOf(react::StateWrapperImpl::javaClassStatic())) [[unlikely]] {
26
- throw std::runtime_error("StateWrapper is not a StateWrapperImpl");
24
+ jobject rawStateWrapper = stateWrapper.get();
25
+ if (!stateWrapper->isInstanceOf(react::StateWrapperImpl::javaClassStatic())) [[unlikely]] {
26
+ throw std::runtime_error("StateWrapper is not a StateWrapperImpl");
27
+ }
28
+ auto stateWrapperImpl = jni::alias_ref<react::StateWrapperImpl::javaobject>{
29
+ static_cast<react::StateWrapperImpl::javaobject>(rawStateWrapper)
30
+ };
31
+ std::shared_ptr<const react::State> state = stateWrapperImpl->cthis()->getState();
32
+ if (state == nullptr) {
33
+ return nullptr;
27
34
  }
28
- auto stateWrapper = jni::alias_ref<react::StateWrapperImpl::javaobject>{
29
- static_cast<react::StateWrapperImpl::javaobject>(rawStateWrapper)};
30
- std::shared_ptr<const react::State> state = stateWrapper->cthis()->getState();
31
35
  auto concreteState = std::static_pointer_cast<const ConcreteStateData>(state);
32
36
  const HybridGameEngineState& data = concreteState->getData();
33
- const std::shared_ptr<HybridGameEngineProps>& props = data.getProps();
37
+ const std::shared_ptr<const HybridGameEngineProps>& props = data.getProps();
34
38
  if (props == nullptr) [[unlikely]] {
35
- // Props aren't set yet!
36
39
  throw std::runtime_error("HybridGameEngineState's data doesn't contain any props!");
37
40
  }
41
+ return props;
42
+ }
43
+
44
+ void JHybridGameEngineStateUpdater::updateViewProps(jni::alias_ref<jni::JClass> /* class */,
45
+ jni::alias_ref<JHybridGameEngineSpec::JavaPart> javaView,
46
+ jni::alias_ref<JStateWrapper::javaobject> newState,
47
+ jni::alias_ref<JStateWrapper::javaobject> oldState) {
48
+ std::shared_ptr<JHybridGameEngineSpec> hybridView = javaView->getJHybridGameEngineSpec();
49
+ std::shared_ptr<const HybridGameEngineProps> newProps = getPropsFromStateWrapper(newState);
50
+ std::shared_ptr<const HybridGameEngineProps> oldProps = getPropsFromStateWrapper(oldState);
51
+ if (newProps == nullptr) [[unlikely]] {
52
+ throw std::runtime_error("Current StateWrapper doesn't contain any props!");
53
+ }
38
54
 
39
- // Update all props if they are dirty
55
+ // Update only props that differ from the previous State snapshot.
40
56
 
41
57
 
42
58
  // Update hybridRef if it changed
43
- if (props->hybridRef.isDirty) {
59
+ if (oldProps == nullptr
60
+ ? newProps->hybridRef.isProvided()
61
+ : !newProps->hybridRef.hasSameValue(oldProps->hybridRef)) {
44
62
  // hybridRef changed - call it with new this
45
- const auto& maybeFunc = props->hybridRef.value;
63
+ const auto& maybeFunc = newProps->hybridRef.get();
46
64
  if (maybeFunc.has_value()) {
47
65
  maybeFunc.value()(hybridView);
48
66
  }
49
- props->hybridRef.isDirty = false;
50
67
  }
51
68
  }
52
69
 
@@ -31,7 +31,12 @@ public:
31
31
  public:
32
32
  static void updateViewProps(jni::alias_ref<jni::JClass> /* class */,
33
33
  jni::alias_ref<JHybridGameEngineSpec::JavaPart> view,
34
- jni::alias_ref<JStateWrapper::javaobject> stateWrapperInterface);
34
+ jni::alias_ref<JStateWrapper::javaobject> newState,
35
+ jni::alias_ref<JStateWrapper::javaobject> oldState);
36
+
37
+ private:
38
+ static std::shared_ptr<const HybridGameEngineProps> getPropsFromStateWrapper(
39
+ jni::alias_ref<JStateWrapper::javaobject> stateWrapper);
35
40
 
36
41
  public:
37
42
  static void registerNatives() {
@@ -10,6 +10,7 @@ package com.margelo.nitro.rngine
10
10
  import androidx.annotation.Keep
11
11
  import com.facebook.jni.HybridData
12
12
  import com.facebook.proguard.annotations.DoNotStrip
13
+ import dalvik.annotation.optimization.FastNative
13
14
  import com.margelo.nitro.core.HybridObject
14
15
  import com.margelo.nitro.views.HybridView
15
16
 
@@ -41,6 +42,7 @@ abstract class HybridGameEngineSpec: HybridView() {
41
42
  @Keep
42
43
  protected open class CxxPart(javaPart: HybridGameEngineSpec): HybridObject.CxxPart(javaPart) {
43
44
  // C++ JHybridGameEngineSpec::CxxPart::initHybrid(...)
45
+ @FastNative
44
46
  external override fun initHybrid(): HybridData
45
47
  }
46
48
  override fun createCxxPart(): CxxPart {
@@ -20,6 +20,14 @@ import com.margelo.nitro.rngine.*
20
20
  * Represents the React Native `ViewManager` for the "GameEngine" Nitro HybridView.
21
21
  */
22
22
  public class HybridGameEngineManager: SimpleViewManager<View>() {
23
+ /**
24
+ * Represents the View and its last state snapshot (mutable)
25
+ */
26
+ private class HybridViewHolder(
27
+ val hybridView: GameEngine,
28
+ var lastState: StateWrapper? = null,
29
+ )
30
+
23
31
  init {
24
32
  if (RecyclableView::class.java.isAssignableFrom(GameEngine::class.java)) {
25
33
  // Enable view recycling
@@ -34,33 +42,41 @@ public class HybridGameEngineManager: SimpleViewManager<View>() {
34
42
  override fun createViewInstance(reactContext: ThemedReactContext): View {
35
43
  val hybridView = GameEngine(reactContext)
36
44
  val view = hybridView.view
37
- view.setTag(associated_hybrid_view_tag, hybridView)
45
+ view.setTag(associated_hybrid_view_tag, HybridViewHolder(hybridView))
38
46
  return view
39
47
  }
40
48
 
41
49
  override fun updateState(view: View, props: ReactStylesDiffMap, stateWrapper: StateWrapper): Any? {
42
- val hybridView = getHybridView(view)
50
+ val holder = getHybridViewHolder(view)
43
51
  ?: throw Error("Couldn't find view $view in local views table!")
52
+ val hybridView = holder.hybridView
53
+ val oldState = holder.lastState
54
+ val newState = stateWrapper
44
55
 
45
56
  // 1. Update each prop individually
46
57
  hybridView.beforeUpdate()
47
- HybridGameEngineStateUpdater.updateViewProps(hybridView, stateWrapper)
58
+ HybridGameEngineStateUpdater.updateViewProps(hybridView, newState, oldState)
48
59
  hybridView.afterUpdate()
60
+ holder.lastState = newState
49
61
 
50
62
  // 2. Continue in base View props
51
- return super.updateState(view, props, stateWrapper)
63
+ return super.updateState(view, props, newState)
52
64
  }
53
65
 
54
66
  override fun onDropViewInstance(view: View) {
55
- val hybridView = getHybridView(view)
56
- hybridView?.onDropView()
67
+ val holder = getHybridViewHolder(view)
68
+ holder?.lastState = null
69
+ holder?.hybridView?.onDropView()
57
70
  return super.onDropViewInstance(view)
58
71
  }
59
72
 
60
73
  protected override fun prepareToRecycleView(reactContext: ThemedReactContext, view: View): View? {
61
- super.prepareToRecycleView(reactContext, view)
62
- val hybridView = getHybridView(view)
74
+ val preparedView = super.prepareToRecycleView(reactContext, view)
75
+ ?: return null
76
+ val holder = getHybridViewHolder(preparedView)
63
77
  ?: return null
78
+ val hybridView = holder.hybridView
79
+ holder.lastState = null
64
80
 
65
81
  @Suppress("USELESS_IS_CHECK")
66
82
  if (hybridView is RecyclableView) {
@@ -74,7 +90,7 @@ public class HybridGameEngineManager: SimpleViewManager<View>() {
74
90
  }
75
91
  }
76
92
 
77
- private fun getHybridView(view: View): GameEngine? {
78
- return view.getTag(associated_hybrid_view_tag) as? GameEngine
93
+ private fun getHybridViewHolder(view: View): HybridViewHolder? {
94
+ return view.getTag(associated_hybrid_view_tag) as? HybridViewHolder
79
95
  }
80
96
  }
@@ -14,10 +14,10 @@ internal class HybridGameEngineStateUpdater {
14
14
  companion object {
15
15
  /**
16
16
  * Updates the props for [view] through C++.
17
- * The [state] prop is expected to contain [view]'s props as wrapped Fabric state.
17
+ * The [newState] prop is expected to contain [view]'s props as wrapped Fabric state.
18
18
  */
19
19
  @Suppress("KotlinJniMissingFunction")
20
20
  @JvmStatic
21
- external fun updateViewProps(view: HybridGameEngineSpec, state: StateWrapper)
21
+ external fun updateViewProps(view: HybridGameEngineSpec, newState: StateWrapper, oldState: StateWrapper?)
22
22
  }
23
23
  }
@@ -37,6 +37,7 @@ using namespace margelo::nitro::rngine::views;
37
37
 
38
38
  @implementation HybridGameEngineComponent {
39
39
  std::shared_ptr<HybridGameEngineSpecSwift> _hybridView;
40
+ BOOL _didDropView;
40
41
  }
41
42
 
42
43
  + (void) load {
@@ -50,6 +51,7 @@ using namespace margelo::nitro::rngine::views;
50
51
 
51
52
  - (instancetype) init {
52
53
  if (self = [super init]) {
54
+ _props = HybridGameEngineShadowNode::defaultSharedProps();
53
55
  std::shared_ptr<HybridGameEngineSpec> hybridView = Rngine::RngineAutolinking::createGameEngine();
54
56
  _hybridView = std::dynamic_pointer_cast<HybridGameEngineSpecSwift>(hybridView);
55
57
  [self updateView];
@@ -69,31 +71,50 @@ using namespace margelo::nitro::rngine::views;
69
71
  [self setContentView:view];
70
72
  }
71
73
 
74
+ - (void) notifyOnDropView {
75
+ // A recycled component can later be invalidated. Notify only once per mount.
76
+ if (_didDropView) {
77
+ return;
78
+ }
79
+ Rngine::HybridGameEngineSpec_cxx& swiftPart = _hybridView->getSwiftPart();
80
+ swiftPart.onDropView();
81
+ _didDropView = YES;
82
+ }
83
+
72
84
  - (void) updateProps:(const std::shared_ptr<const react::Props>&)props
73
85
  oldProps:(const std::shared_ptr<const react::Props>&)oldProps {
86
+ // A props update marks a newly mounted or still-active component.
87
+ _didDropView = NO;
88
+
74
89
  // 1. Downcast props
75
- const auto& newViewPropsConst = *std::static_pointer_cast<HybridGameEngineProps const>(props);
76
- auto& newViewProps = const_cast<HybridGameEngineProps&>(newViewPropsConst);
90
+ const auto& newViewProps = *std::static_pointer_cast<const HybridGameEngineProps>(props);
91
+ const auto* oldViewProps = static_cast<const HybridGameEngineProps*>(oldProps.get());
77
92
  Rngine::HybridGameEngineSpec_cxx& swiftPart = _hybridView->getSwiftPart();
78
93
 
79
- // 2. Update each prop individually
80
- swiftPart.beforeUpdate();
81
-
82
-
83
-
84
- swiftPart.afterUpdate();
85
-
86
- // 3. Update hybridRef if it changed
87
- if (newViewProps.hybridRef.isDirty) {
88
- // hybridRef changed - call it with new this
89
- const auto& maybeFunc = newViewProps.hybridRef.value;
90
- if (maybeFunc.has_value()) {
91
- maybeFunc.value()(_hybridView);
94
+ // 2. Update only props that differ from the previous Props snapshot.
95
+ const bool hasTransactionPropChanges = oldViewProps == nullptr
96
+ ? newViewProps.hasAnyProvidedProps()
97
+ : !newViewProps.hasSameProps(*oldViewProps);
98
+ if (hasTransactionPropChanges) {
99
+ swiftPart.beforeUpdate();
100
+
101
+
102
+
103
+ // Update hybridRef if it changed
104
+ if (oldViewProps == nullptr
105
+ ? newViewProps.hybridRef.isProvided()
106
+ : !newViewProps.hybridRef.hasSameValue(oldViewProps->hybridRef)) {
107
+ // hybridRef changed - call it with new this
108
+ const auto& maybeFunc = newViewProps.hybridRef.get();
109
+ if (maybeFunc.has_value()) {
110
+ maybeFunc.value()(_hybridView);
111
+ }
92
112
  }
93
- newViewProps.hybridRef.isDirty = false;
113
+
114
+ swiftPart.afterUpdate();
94
115
  }
95
116
 
96
- // 4. Continue in base class
117
+ // 3. Continue in base class
97
118
  [super updateProps:props oldProps:oldProps];
98
119
  }
99
120
 
@@ -102,6 +123,7 @@ using namespace margelo::nitro::rngine::views;
102
123
  }
103
124
 
104
125
  - (void)prepareForRecycle {
126
+ [self notifyOnDropView];
105
127
  [super prepareForRecycle];
106
128
  Rngine::HybridGameEngineSpec_cxx& swiftPart = _hybridView->getSwiftPart();
107
129
  swiftPart.maybePrepareForRecycle();
@@ -109,8 +131,7 @@ using namespace margelo::nitro::rngine::views;
109
131
 
110
132
  #ifdef ENABLE_RCT_COMPONENT_VIEW_INVALIDATE
111
133
  - (void)invalidate {
112
- Rngine::HybridGameEngineSpec_cxx& swiftPart = _hybridView->getSwiftPart();
113
- swiftPart.onDropView();
134
+ [self notifyOnDropView];
114
135
  [super invalidate];
115
136
  }
116
137
  #endif
@@ -57,6 +57,7 @@ namespace margelo::nitro::rngine {
57
57
  std::optional<bool> flipV SWIFT_PRIVATE;
58
58
  std::optional<double> progress SWIFT_PRIVATE;
59
59
  std::optional<double> speed SWIFT_PRIVATE;
60
+ std::optional<bool> loop SWIFT_PRIVATE;
60
61
  std::optional<double> vx SWIFT_PRIVATE;
61
62
  std::optional<double> vy SWIFT_PRIVATE;
62
63
  std::optional<double> ax SWIFT_PRIVATE;
@@ -65,7 +66,7 @@ namespace margelo::nitro::rngine {
65
66
 
66
67
  public:
67
68
  Entity() = default;
68
- explicit Entity(std::string id, double px, double py, std::variant<Rect, Circle> shape, std::optional<bool> isSensor, std::optional<std::string> color, std::optional<double> asset, std::optional<bool> flipH, std::optional<bool> flipV, std::optional<double> progress, std::optional<double> speed, std::optional<double> vx, std::optional<double> vy, std::optional<double> ax, std::optional<double> ay, std::optional<double> mass): id(id), px(px), py(py), shape(shape), isSensor(isSensor), color(color), asset(asset), flipH(flipH), flipV(flipV), progress(progress), speed(speed), vx(vx), vy(vy), ax(ax), ay(ay), mass(mass) {}
69
+ explicit Entity(std::string id, double px, double py, std::variant<Rect, Circle> shape, std::optional<bool> isSensor, std::optional<std::string> color, std::optional<double> asset, std::optional<bool> flipH, std::optional<bool> flipV, std::optional<double> progress, std::optional<double> speed, std::optional<bool> loop, std::optional<double> vx, std::optional<double> vy, std::optional<double> ax, std::optional<double> ay, std::optional<double> mass): id(id), px(px), py(py), shape(shape), isSensor(isSensor), color(color), asset(asset), flipH(flipH), flipV(flipV), progress(progress), speed(speed), loop(loop), vx(vx), vy(vy), ax(ax), ay(ay), mass(mass) {}
69
70
 
70
71
  public:
71
72
  friend bool operator==(const Entity& lhs, const Entity& rhs) = default;
@@ -92,6 +93,7 @@ namespace margelo::nitro {
92
93
  JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "flipV"))),
93
94
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress"))),
94
95
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed"))),
96
+ JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "loop"))),
95
97
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vx"))),
96
98
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vy"))),
97
99
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ax"))),
@@ -112,6 +114,7 @@ namespace margelo::nitro {
112
114
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "flipV"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.flipV));
113
115
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "progress"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.progress));
114
116
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "speed"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.speed));
117
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "loop"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.loop));
115
118
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "vx"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.vx));
116
119
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "vy"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.vy));
117
120
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "ax"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.ax));
@@ -138,6 +141,7 @@ namespace margelo::nitro {
138
141
  if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "flipV")))) return false;
139
142
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress")))) return false;
140
143
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed")))) return false;
144
+ if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "loop")))) return false;
141
145
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vx")))) return false;
142
146
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vy")))) return false;
143
147
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ax")))) return false;
@@ -57,6 +57,7 @@ namespace margelo::nitro::rngine {
57
57
  std::optional<bool> flipV SWIFT_PRIVATE;
58
58
  std::optional<double> progress SWIFT_PRIVATE;
59
59
  std::optional<double> speed SWIFT_PRIVATE;
60
+ std::optional<bool> loop SWIFT_PRIVATE;
60
61
  std::optional<double> vx SWIFT_PRIVATE;
61
62
  std::optional<double> vy SWIFT_PRIVATE;
62
63
  std::optional<double> ax SWIFT_PRIVATE;
@@ -65,7 +66,7 @@ namespace margelo::nitro::rngine {
65
66
 
66
67
  public:
67
68
  EntityUpdate() = default;
68
- explicit EntityUpdate(std::string id, std::optional<double> px, std::optional<double> py, std::optional<std::variant<Rect, Circle>> shape, std::optional<bool> isSensor, std::optional<std::string> color, std::optional<double> asset, std::optional<bool> flipH, std::optional<bool> flipV, std::optional<double> progress, std::optional<double> speed, std::optional<double> vx, std::optional<double> vy, std::optional<double> ax, std::optional<double> ay, std::optional<double> mass): id(id), px(px), py(py), shape(shape), isSensor(isSensor), color(color), asset(asset), flipH(flipH), flipV(flipV), progress(progress), speed(speed), vx(vx), vy(vy), ax(ax), ay(ay), mass(mass) {}
69
+ explicit EntityUpdate(std::string id, std::optional<double> px, std::optional<double> py, std::optional<std::variant<Rect, Circle>> shape, std::optional<bool> isSensor, std::optional<std::string> color, std::optional<double> asset, std::optional<bool> flipH, std::optional<bool> flipV, std::optional<double> progress, std::optional<double> speed, std::optional<bool> loop, std::optional<double> vx, std::optional<double> vy, std::optional<double> ax, std::optional<double> ay, std::optional<double> mass): id(id), px(px), py(py), shape(shape), isSensor(isSensor), color(color), asset(asset), flipH(flipH), flipV(flipV), progress(progress), speed(speed), loop(loop), vx(vx), vy(vy), ax(ax), ay(ay), mass(mass) {}
69
70
 
70
71
  public:
71
72
  friend bool operator==(const EntityUpdate& lhs, const EntityUpdate& rhs) = default;
@@ -92,6 +93,7 @@ namespace margelo::nitro {
92
93
  JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "flipV"))),
93
94
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress"))),
94
95
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed"))),
96
+ JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "loop"))),
95
97
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vx"))),
96
98
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vy"))),
97
99
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ax"))),
@@ -112,6 +114,7 @@ namespace margelo::nitro {
112
114
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "flipV"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.flipV));
113
115
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "progress"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.progress));
114
116
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "speed"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.speed));
117
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "loop"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.loop));
115
118
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "vx"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.vx));
116
119
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "vy"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.vy));
117
120
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "ax"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.ax));
@@ -138,6 +141,7 @@ namespace margelo::nitro {
138
141
  if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "flipV")))) return false;
139
142
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress")))) return false;
140
143
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed")))) return false;
144
+ if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "loop")))) return false;
141
145
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vx")))) return false;
142
146
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vy")))) return false;
143
147
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ax")))) return false;
@@ -50,10 +50,11 @@ namespace margelo::nitro::rngine {
50
50
  std::optional<bool> flipV SWIFT_PRIVATE;
51
51
  std::optional<double> progress SWIFT_PRIVATE;
52
52
  std::optional<double> speed SWIFT_PRIVATE;
53
+ std::optional<bool> loop SWIFT_PRIVATE;
53
54
 
54
55
  public:
55
56
  Screen() = default;
56
- explicit Screen(double px, double py, double width, double height, std::optional<std::string> color, std::optional<double> asset, std::optional<bool> flipH, std::optional<bool> flipV, std::optional<double> progress, std::optional<double> speed): px(px), py(py), width(width), height(height), color(color), asset(asset), flipH(flipH), flipV(flipV), progress(progress), speed(speed) {}
57
+ explicit Screen(double px, double py, double width, double height, std::optional<std::string> color, std::optional<double> asset, std::optional<bool> flipH, std::optional<bool> flipV, std::optional<double> progress, std::optional<double> speed, std::optional<bool> loop): px(px), py(py), width(width), height(height), color(color), asset(asset), flipH(flipH), flipV(flipV), progress(progress), speed(speed), loop(loop) {}
57
58
 
58
59
  public:
59
60
  friend bool operator==(const Screen& lhs, const Screen& rhs) = default;
@@ -78,7 +79,8 @@ namespace margelo::nitro {
78
79
  JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "flipH"))),
79
80
  JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "flipV"))),
80
81
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress"))),
81
- JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed")))
82
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed"))),
83
+ JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "loop")))
82
84
  );
83
85
  }
84
86
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::rngine::Screen& arg) {
@@ -93,6 +95,7 @@ namespace margelo::nitro {
93
95
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "flipV"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.flipV));
94
96
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "progress"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.progress));
95
97
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "speed"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.speed));
98
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "loop"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.loop));
96
99
  return obj;
97
100
  }
98
101
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
@@ -113,6 +116,7 @@ namespace margelo::nitro {
113
116
  if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "flipV")))) return false;
114
117
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress")))) return false;
115
118
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed")))) return false;
119
+ if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "loop")))) return false;
116
120
  return true;
117
121
  }
118
122
  };
@@ -50,10 +50,11 @@ namespace margelo::nitro::rngine {
50
50
  std::optional<bool> flipV SWIFT_PRIVATE;
51
51
  std::optional<double> progress SWIFT_PRIVATE;
52
52
  std::optional<double> speed SWIFT_PRIVATE;
53
+ std::optional<bool> loop SWIFT_PRIVATE;
53
54
 
54
55
  public:
55
56
  ScreenUpdate() = default;
56
- explicit ScreenUpdate(std::optional<double> px, std::optional<double> py, std::optional<double> width, std::optional<double> height, std::optional<std::string> color, std::optional<double> asset, std::optional<bool> flipH, std::optional<bool> flipV, std::optional<double> progress, std::optional<double> speed): px(px), py(py), width(width), height(height), color(color), asset(asset), flipH(flipH), flipV(flipV), progress(progress), speed(speed) {}
57
+ explicit ScreenUpdate(std::optional<double> px, std::optional<double> py, std::optional<double> width, std::optional<double> height, std::optional<std::string> color, std::optional<double> asset, std::optional<bool> flipH, std::optional<bool> flipV, std::optional<double> progress, std::optional<double> speed, std::optional<bool> loop): px(px), py(py), width(width), height(height), color(color), asset(asset), flipH(flipH), flipV(flipV), progress(progress), speed(speed), loop(loop) {}
57
58
 
58
59
  public:
59
60
  friend bool operator==(const ScreenUpdate& lhs, const ScreenUpdate& rhs) = default;
@@ -78,7 +79,8 @@ namespace margelo::nitro {
78
79
  JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "flipH"))),
79
80
  JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "flipV"))),
80
81
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress"))),
81
- JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed")))
82
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed"))),
83
+ JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "loop")))
82
84
  );
83
85
  }
84
86
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::rngine::ScreenUpdate& arg) {
@@ -93,6 +95,7 @@ namespace margelo::nitro {
93
95
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "flipV"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.flipV));
94
96
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "progress"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.progress));
95
97
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "speed"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.speed));
98
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "loop"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.loop));
96
99
  return obj;
97
100
  }
98
101
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
@@ -113,6 +116,7 @@ namespace margelo::nitro {
113
116
  if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "flipV")))) return false;
114
117
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress")))) return false;
115
118
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed")))) return false;
119
+ if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "loop")))) return false;
116
120
  return true;
117
121
  }
118
122
  };
@@ -7,35 +7,20 @@
7
7
 
8
8
  #include "HybridGameEngineComponent.hpp"
9
9
 
10
- #include <string>
11
- #include <exception>
12
- #include <utility>
13
- #include <NitroModules/NitroDefines.hpp>
14
- #include <NitroModules/JSIConverter.hpp>
15
- #include <NitroModules/PropNameIDCache.hpp>
16
- #include <react/renderer/core/RawValue.h>
17
- #include <react/renderer/core/ShadowNode.h>
18
- #include <react/renderer/core/ComponentDescriptor.h>
19
- #include <react/renderer/components/view/ViewProps.h>
10
+ #include <NitroModules/NitroHash.hpp>
11
+ #include <NitroModules/ReactProp.hpp>
20
12
 
21
13
  namespace margelo::nitro::rngine::views {
22
14
 
15
+ using namespace facebook;
16
+
23
17
  extern const char HybridGameEngineComponentName[] = "GameEngine";
24
18
 
25
19
  HybridGameEngineProps::HybridGameEngineProps(const react::PropsParserContext& context,
26
20
  const HybridGameEngineProps& sourceProps,
27
21
  const react::RawProps& rawProps):
28
22
  react::ViewProps(context, sourceProps, rawProps, filterObjectKeys),
29
- hybridRef([&]() -> CachedProp<std::optional<std::function<void(const std::shared_ptr<HybridGameEngineSpec>& /* ref */)>>> {
30
- try {
31
- const react::RawValue* rawValue = rawProps.at("hybridRef", nullptr, nullptr);
32
- if (rawValue == nullptr) return sourceProps.hybridRef;
33
- const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
34
- return CachedProp<std::optional<std::function<void(const std::shared_ptr<HybridGameEngineSpec>& /* ref */)>>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.hybridRef);
35
- } catch (const std::exception& exc) {
36
- throw std::runtime_error(std::string("GameEngine.hybridRef: ") + exc.what());
37
- }
38
- }()) { }
23
+ hybridRef(nitro::ReactProp<std::optional<std::function<void(const std::shared_ptr<HybridGameEngineSpec>& /* ref */)>>>::fromRawValue("GameEngine", "hybridRef", rawProps, sourceProps.hybridRef)) { }
39
24
 
40
25
  bool HybridGameEngineProps::filterObjectKeys(const std::string& propName) {
41
26
  switch (hashString(propName)) {
@@ -44,29 +29,4 @@ namespace margelo::nitro::rngine::views {
44
29
  }
45
30
  }
46
31
 
47
- HybridGameEngineComponentDescriptor::HybridGameEngineComponentDescriptor(const react::ComponentDescriptorParameters& parameters)
48
- : ConcreteComponentDescriptor(parameters,
49
- react::RawPropsParser(/* enableJsiParser */ true)) {}
50
-
51
- std::shared_ptr<const react::Props> HybridGameEngineComponentDescriptor::cloneProps(const react::PropsParserContext& context,
52
- const std::shared_ptr<const react::Props>& props,
53
- react::RawProps rawProps) const {
54
- // 1. Prepare raw props parser
55
- rawProps.parse(rawPropsParser_);
56
- // 2. Copy props with Nitro's cached copy constructor
57
- return HybridGameEngineShadowNode::Props(context, /* & */ rawProps, props);
58
- }
59
-
60
- #ifdef ANDROID
61
- void HybridGameEngineComponentDescriptor::adopt(react::ShadowNode& shadowNode) const {
62
- // This is called immediately after `ShadowNode` is created, cloned or in progress.
63
- // On Android, we need to wrap props in our state, which gets routed through Java and later unwrapped in JNI/C++.
64
- auto& concreteShadowNode = static_cast<HybridGameEngineShadowNode&>(shadowNode);
65
- const std::shared_ptr<const HybridGameEngineProps>& constProps = concreteShadowNode.getConcreteSharedProps();
66
- const std::shared_ptr<HybridGameEngineProps>& props = std::const_pointer_cast<HybridGameEngineProps>(constProps);
67
- HybridGameEngineState state{props};
68
- concreteShadowNode.setStateData(std::move(state));
69
- }
70
- #endif
71
-
72
32
  } // namespace margelo::nitro::rngine::views
@@ -7,14 +7,15 @@
7
7
 
8
8
  #pragma once
9
9
 
10
- #include <optional>
11
- #include <NitroModules/NitroDefines.hpp>
12
- #include <NitroModules/NitroHash.hpp>
13
- #include <NitroModules/CachedProp.hpp>
14
- #include <react/renderer/core/ConcreteComponentDescriptor.h>
15
- #include <react/renderer/core/PropsParserContext.h>
10
+ #include <NitroModules/ReactProp.hpp>
11
+ #include <NitroModules/ViewComponentDescriptor.hpp>
12
+ #include <NitroModules/ViewPropsHolderState.hpp>
16
13
  #include <react/renderer/components/view/ConcreteViewShadowNode.h>
17
14
  #include <react/renderer/components/view/ViewProps.h>
15
+ #include <react/renderer/core/PropsParserContext.h>
16
+ #include <react/renderer/core/RawProps.h>
17
+
18
+ #include <string>
18
19
 
19
20
  #include <memory>
20
21
  #include "HybridGameEngineSpec.hpp"
@@ -41,7 +42,17 @@ namespace margelo::nitro::rngine::views {
41
42
  const react::RawProps& rawProps);
42
43
 
43
44
  public:
44
- CachedProp<std::optional<std::function<void(const std::shared_ptr<HybridGameEngineSpec>& /* ref */)>>> hybridRef;
45
+ nitro::ReactProp<std::optional<std::function<void(const std::shared_ptr<HybridGameEngineSpec>& /* ref */)>>> hybridRef;
46
+
47
+ [[nodiscard]]
48
+ bool hasSameProps(const HybridGameEngineProps& other) const noexcept {
49
+ return hybridRef.hasSameValue(other.hybridRef);
50
+ }
51
+
52
+ [[nodiscard]]
53
+ bool hasAnyProvidedProps() const noexcept {
54
+ return hybridRef.isProvided();
55
+ }
45
56
 
46
57
  private:
47
58
  static bool filterObjectKeys(const std::string& propName);
@@ -50,32 +61,7 @@ namespace margelo::nitro::rngine::views {
50
61
  /**
51
62
  * State for the "GameEngine" View.
52
63
  */
53
- class HybridGameEngineState final {
54
- public:
55
- HybridGameEngineState() = default;
56
- explicit HybridGameEngineState(const std::shared_ptr<HybridGameEngineProps>& props):
57
- _props(props) {}
58
-
59
- public:
60
- [[nodiscard]]
61
- const std::shared_ptr<HybridGameEngineProps>& getProps() const {
62
- return _props;
63
- }
64
-
65
- public:
66
- #ifdef ANDROID
67
- HybridGameEngineState(const HybridGameEngineState& /* previousState */, folly::dynamic /* data */) {}
68
- folly::dynamic getDynamic() const {
69
- throw std::runtime_error("HybridGameEngineState does not support folly!");
70
- }
71
- react::MapBuffer getMapBuffer() const {
72
- throw std::runtime_error("HybridGameEngineState does not support MapBuffer!");
73
- };
74
- #endif
75
-
76
- private:
77
- std::shared_ptr<HybridGameEngineProps> _props;
78
- };
64
+ using HybridGameEngineState = nitro::ViewPropsHolderState<HybridGameEngineProps>;
79
65
 
80
66
  /**
81
67
  * The Shadow Node for the "GameEngine" View.
@@ -88,21 +74,7 @@ namespace margelo::nitro::rngine::views {
88
74
  /**
89
75
  * The Component Descriptor for the "GameEngine" View.
90
76
  */
91
- class HybridGameEngineComponentDescriptor final: public react::ConcreteComponentDescriptor<HybridGameEngineShadowNode> {
92
- public:
93
- explicit HybridGameEngineComponentDescriptor(const react::ComponentDescriptorParameters& parameters);
94
-
95
- public:
96
- /**
97
- * A faster path for cloning props - reuses the caching logic from `HybridGameEngineProps`.
98
- */
99
- std::shared_ptr<const react::Props> cloneProps(const react::PropsParserContext& context,
100
- const std::shared_ptr<const react::Props>& props,
101
- react::RawProps rawProps) const override;
102
- #ifdef ANDROID
103
- void adopt(react::ShadowNode& shadowNode) const override;
104
- #endif
105
- };
77
+ using HybridGameEngineComponentDescriptor = nitro::ViewComponentDescriptor<HybridGameEngineShadowNode>;
106
78
 
107
79
  /* The actual view for "GameEngine" needs to be implemented in platform-specific code. */
108
80
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rngine",
3
- "version": "0.9.1",
3
+ "version": "0.11.0",
4
4
  "description": "React Native 2D game engine powered by Nitro Modules",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -28,9 +28,6 @@
28
28
  "!android/gradlew",
29
29
  "!android/gradlew.bat",
30
30
  "!android/local.properties",
31
- "!**/__tests__",
32
- "!**/__fixtures__",
33
- "!**/__mocks__",
34
31
  "!**/.*"
35
32
  ],
36
33
  "scripts": {
@@ -39,11 +36,7 @@
39
36
  "prepare": "bob build && node scripts/nitrogen-patch.js",
40
37
  "nitrogen": "nitrogen",
41
38
  "typecheck": "tsc",
42
- "lint": "eslint \"**/*.{js,ts,tsx}\"",
43
- "test": "jest",
44
- "release": "release-it --only-version",
45
- "web": "vite",
46
- "build:web": "vite build"
39
+ "lint": "eslint \"**/*.{js,ts,tsx}\""
47
40
  },
48
41
  "keywords": [
49
42
  "react-native",
@@ -64,39 +57,33 @@
64
57
  "registry": "https://registry.npmjs.org/"
65
58
  },
66
59
  "devDependencies": {
67
- "@commitlint/config-conventional": "^20.5.0",
68
- "@eslint/compat": "^2.0.3",
69
- "@eslint/eslintrc": "^3.3.5",
60
+ "@commitlint/config-conventional": "^21.2.3",
61
+ "@eslint/compat": "^2.1.1",
62
+ "@eslint/eslintrc": "^3.3.7",
70
63
  "@eslint/js": "^10.0.1",
71
- "@jest/globals": "^30.0.0",
72
- "@react-native/babel-preset": "0.85.0",
73
- "@react-native/eslint-config": "0.85.0",
74
- "@react-native/jest-preset": "0.85.0",
75
- "@release-it/conventional-changelog": "^10.0.6",
76
- "@types/react": "^19.2.0",
77
- "commitlint": "^20.5.0",
64
+ "@react-native/babel-preset": "^0.87.1",
65
+ "@react-native/eslint-config": "^0.87.1",
66
+ "@types/react": "^19.3.0",
67
+ "commitlint": "^21.2.3",
78
68
  "del-cli": "^7.0.0",
79
- "eslint": "^9.39.4",
69
+ "eslint": "9.39.5",
80
70
  "eslint-config-prettier": "^10.1.8",
81
71
  "eslint-plugin-ft-flow": "^3.0.11",
82
- "eslint-plugin-prettier": "^5.5.5",
83
- "jest": "^30.3.0",
84
- "lefthook": "^2.1.4",
85
- "nitrogen": "^0.35.3",
86
- "prettier": "^3.8.1",
72
+ "eslint-plugin-prettier": "^5.5.6",
73
+ "lefthook": "^2.1.14",
74
+ "nitrogen": "^0.37.1",
75
+ "prettier": "^3.9.8",
87
76
  "react": "19.2.3",
88
- "react-native": "0.85.0",
89
- "react-native-builder-bob": "^0.41.0",
90
- "react-native-nitro-modules": "^0.35.3",
91
- "react-native-web": "~0.21.1",
92
- "release-it": "^19.2.4",
93
- "turbo": "^2.8.21",
77
+ "react-native": "0.85.3",
78
+ "react-native-builder-bob": "^0.43.1",
79
+ "react-native-nitro-modules": "^0.37.1",
80
+ "turbo": "^2.11.2",
94
81
  "typescript": "^6.0.2"
95
82
  },
96
83
  "peerDependencies": {
97
84
  "react": "*",
98
85
  "react-native": "*",
99
- "react-native-nitro-modules": "^0.35.3"
86
+ "react-native-nitro-modules": "^0.37.1"
100
87
  },
101
88
  "workspaces": [
102
89
  "example"
@@ -134,50 +121,21 @@
134
121
  "trailingComma": "es5",
135
122
  "useTabs": false
136
123
  },
137
- "jest": {
138
- "preset": "@react-native/jest-preset",
139
- "modulePathIgnorePatterns": [
140
- "<rootDir>/example/node_modules",
141
- "<rootDir>/lib/"
142
- ]
143
- },
144
124
  "commitlint": {
145
125
  "extends": [
146
126
  "@commitlint/config-conventional"
147
127
  ]
148
128
  },
149
- "release-it": {
150
- "git": {
151
- "commitMessage": "chore: release ${version}",
152
- "tagName": "v${version}"
153
- },
154
- "npm": {
155
- "publish": true
156
- },
157
- "github": {
158
- "release": true
159
- },
160
- "plugins": {
161
- "@release-it/conventional-changelog": {
162
- "preset": {
163
- "name": "angular"
164
- }
165
- }
166
- }
167
- },
168
129
  "create-react-native-library": {
169
130
  "type": "nitro-view",
170
131
  "languages": "kotlin-swift",
171
132
  "tools": [
172
133
  "eslint",
173
- "jest",
174
- "lefthook",
175
- "release-it",
176
- "vite"
134
+ "lefthook"
177
135
  ],
178
136
  "version": "0.61.0"
179
137
  },
180
138
  "dependencies": {
181
- "react-native-skia-android": "^152.0.0"
139
+ "react-native-skia-android": "^154.0.0"
182
140
  }
183
141
  }
@@ -185,7 +185,7 @@ void GameLoop::updateStats(double deltaTime) {
185
185
  void GameLoop::updateScreen(double deltaTime) {
186
186
  std::lock_guard<std::mutex> lock(_mutex);
187
187
  if (_screen.asset.has_value()) {
188
- AssetUtils::updateProgress(_screen.progress, _screen.speed,
188
+ AssetUtils::updateProgress(_screen.progress, _screen.speed, _screen.loop,
189
189
  _screen.asset.value(), deltaTime);
190
190
  }
191
191
  }
@@ -220,7 +220,7 @@ void GameLoop::updateEntities(double deltaTime) {
220
220
  }
221
221
 
222
222
  if (entity.asset.has_value()) {
223
- AssetUtils::updateProgress(entity.progress, entity.speed,
223
+ AssetUtils::updateProgress(entity.progress, entity.speed, entity.loop,
224
224
  entity.asset.value(), deltaTime);
225
225
  }
226
226
  }
@@ -134,6 +134,7 @@ void GameMethods::updateEntities(
134
134
  patch(entityUpdate.asset, entity->asset);
135
135
  patch(entityUpdate.progress, entity->progress);
136
136
  patch(entityUpdate.speed, entity->speed);
137
+ patch(entityUpdate.loop, entity->loop);
137
138
  patch(entityUpdate.color, entity->color);
138
139
  patch(entityUpdate.flipH, entity->flipH);
139
140
  patch(entityUpdate.flipV, entity->flipV);
@@ -163,6 +164,7 @@ void GameMethods::updateScreen(const ScreenUpdate &screenUpdate) {
163
164
  patch(screenUpdate.asset, screen.asset);
164
165
  patch(screenUpdate.progress, screen.progress);
165
166
  patch(screenUpdate.speed, screen.speed);
167
+ patch(screenUpdate.loop, screen.loop);
166
168
  patch(screenUpdate.color, screen.color);
167
169
  patch(screenUpdate.flipH, screen.flipH);
168
170
  patch(screenUpdate.flipV, screen.flipV);
@@ -73,16 +73,23 @@ void drawAsset(SkCanvas *canvas, double asset, float targetWidth,
73
73
  }
74
74
 
75
75
  void updateProgress(std::optional<double> &progress,
76
- std::optional<double> &speed, double asset,
77
- double deltaTime) {
76
+ const std::optional<double> &speed,
77
+ const std::optional<bool> &loop, const double asset,
78
+ const double deltaTime) {
78
79
  if (asset < 0) {
79
80
  auto &lottieCache = GameRenderer::getInstance().getLottieCacheInternal();
80
81
  auto it = lottieCache.find(asset);
81
82
  if (it != lottieCache.end() && it->second) {
82
83
  if (speed.has_value() && speed.value() > 0) {
83
- progress = fmod(progress.value_or(0.0) + (deltaTime * speed.value()) /
84
- it->second->duration(),
85
- 1.0);
84
+ double newProgress =
85
+ progress.value_or(0.0) +
86
+ (deltaTime * speed.value()) / it->second->duration();
87
+
88
+ if (loop.value_or(false)) {
89
+ progress = std::fmod(newProgress, 1.0);
90
+ } else {
91
+ progress = std::min(newProgress, 1.0);
92
+ }
86
93
  }
87
94
  }
88
95
  } else if (progress.has_value()) {
@@ -6,6 +6,7 @@ namespace margelo::nitro::rngine::AssetUtils {
6
6
  void drawAsset(SkCanvas *canvas, double asset, float targetWidth,
7
7
  float targetHeight, bool flipH, bool flipV, double progress);
8
8
  void updateProgress(std::optional<double> &progress,
9
- std::optional<double> &speed, double asset,
10
- double deltaTime);
9
+ const std::optional<double> &speed,
10
+ const std::optional<bool> &loop, const double asset,
11
+ const double deltaTime);
11
12
  } // namespace margelo::nitro::rngine::AssetUtils
@@ -35,8 +35,10 @@ interface Renderable {
35
35
  flipV?: boolean;
36
36
  /** Animation progress between 0 and 1, automatically advanced each tick for Lottie assets. */
37
37
  progress?: number;
38
- /** Playback speed multiplier for animated assets (1 = normal speed). */
38
+ /** Playback speed multiplier for Lottie assets (1 = normal speed). */
39
39
  speed?: number;
40
+ /** Whether the Lottie animation should restart automatically upon completion. */
41
+ loop?: boolean;
40
42
  }
41
43
 
42
44
  interface Kinematic {
Binary file