Skip to content

Commit 8ad48a4

Browse files
committed
fix: eliminate SIGSEGV in DoUpdateMotion by deferring cleanup and strictly managing native memory
1 parent cc0383f commit 8ad48a4

2 files changed

Lines changed: 59 additions & 34 deletions

File tree

binding/src/main/java/dev/eatgrapes/live2d/CubismUserModel.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,21 @@ public class CubismUserModel extends Native {
66
private Consumer<String> motionFinishedCallback;
77

88
public CubismUserModel() {
9-
super(createNative());
10-
initNative(_ptr);
9+
super(0);
10+
this.establishNative();
1111
}
1212

13-
private static native long createNative();
14-
private native void initNative(long ptr);
13+
private void establishNative() {
14+
try {
15+
java.lang.reflect.Field f = Native.class.getDeclaredField("_ptr");
16+
f.setAccessible(true);
17+
f.set(this, createNative());
18+
} catch (Exception e) {
19+
throw new RuntimeException(e);
20+
}
21+
}
22+
23+
private native long createNative();
1524

1625
public void loadModel(byte[] buffer) { loadModelNative(_ptr, buffer); }
1726
private static native void loadModelNative(long ptr, byte[] buffer);
@@ -70,4 +79,4 @@ private void onMotionFinished(String name) {
7079
@Override
7180
public void close() { deleteNative(_ptr); }
7281
private static native void deleteNative(long ptr);
73-
}
82+
}

native/src/CubismUserModel_JNI.cpp

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,16 @@
66
#include <vector>
77
#include <string>
88
#include <map>
9+
#include <mutex>
910

1011
using namespace Live2D::Cubism::Framework;
1112
using namespace Live2D::Cubism::Framework::Rendering;
1213

1314
class JniUserModel : public CubismUserModel {
1415
public:
15-
JniUserModel(JNIEnv* env) {
16+
JniUserModel(JNIEnv* env, jobject javaObj) {
1617
env->GetJavaVM(&_jvm);
17-
}
18-
19-
void setJavaObj(JNIEnv* env, jobject obj) {
20-
_javaObj = env->NewGlobalRef(obj);
18+
_javaObj = env->NewGlobalRef(javaObj);
2119
}
2220

2321
~JniUserModel() {
@@ -45,38 +43,41 @@ class JniUserModel : public CubismUserModel {
4543
std::vector<csmByte> motionBuf(buffer, buffer + size);
4644
auto* motion = CubismMotion::Create(motionBuf.data(), (csmSizeInt)motionBuf.size());
4745
if (!motion) return;
46+
4847
_motionBuffers[motion] = std::move(motionBuf);
48+
4949
motion->SetFinishedMotionHandlerAndMotionCustomData([](ACubismMotion* self) {
5050
auto* m = static_cast<CubismMotion*>(self);
5151
auto* model = static_cast<JniUserModel*>(m->GetFinishedMotionCustomData());
52-
model->onMotionEnd(m);
52+
model->queueFinishedMotion(m);
5353
}, this);
54-
_motionManager->StartMotionPriority(motion, true, priority);
55-
}
5654

57-
void onMotionEnd(CubismMotion* motion) {
58-
_motionBuffers.erase(motion);
59-
CubismMotion::Delete(motion);
60-
JNIEnv* env = getEnv();
61-
if (!env || !_javaObj) return;
62-
jclass cls = env->GetObjectClass(_javaObj);
63-
jmethodID mid = env->GetMethodID(cls, "onMotionFinished", "(Ljava/lang/String;)V");
64-
jstring name = env->NewStringUTF("motion");
65-
env->CallVoidMethod(_javaObj, mid, name);
66-
env->DeleteLocalRef(name);
55+
_motionManager->StartMotionPriority(motion, true, priority);
6756
}
6857

69-
bool isHitTransformed(const char* id, float x, float y) {
70-
if (!_model || !_modelMatrix) return false;
71-
return IsHit(CubismFramework::GetIdManager()->GetId(id), _modelMatrix->InvertTransformX(x), _modelMatrix->InvertTransformY(y));
58+
void queueFinishedMotion(CubismMotion* motion) {
59+
std::lock_guard<std::mutex> lock(_pendingMutex);
60+
_pendingDeletion.push_back(motion);
7261
}
7362

7463
void update(float dt) {
7564
if (!_model) return;
65+
66+
{
67+
std::lock_guard<std::mutex> lock(_pendingMutex);
68+
for (auto* m : _pendingDeletion) {
69+
_motionBuffers.erase(m);
70+
CubismMotion::Delete(m);
71+
notifyFinished();
72+
}
73+
_pendingDeletion.clear();
74+
}
75+
7676
_model->LoadParameters();
7777
_motionManager->UpdateMotion(_model, dt);
7878
_model->SaveParameters();
7979
if (_pose) _pose->UpdateParameters(_model, dt);
80+
8081
if (_dragManager) {
8182
_dragManager->Update(dt);
8283
auto* idm = CubismFramework::GetIdManager();
@@ -85,30 +86,45 @@ class JniUserModel : public CubismUserModel {
8586
_model->AddParameterValue(idm->GetId("ParamEyeBallX"), _dragManager->GetX());
8687
_model->AddParameterValue(idm->GetId("ParamEyeBallY"), _dragManager->GetY());
8788
}
89+
8890
if (_physics) _physics->Evaluate(_model, dt);
8991
_model->Update();
9092
}
9193

94+
void notifyFinished() {
95+
JNIEnv* env = getEnv();
96+
if (!env || !_javaObj) return;
97+
jclass cls = env->GetObjectClass(_javaObj);
98+
jmethodID mid = env->GetMethodID(cls, "onMotionFinished", "(Ljava/lang/String;)V");
99+
jstring name = env->NewStringUTF("motion");
100+
env->CallVoidMethod(_javaObj, mid, name);
101+
env->DeleteLocalRef(name);
102+
}
103+
104+
bool isHitTransformed(const char* id, float x, float y) {
105+
if (!_model || !_modelMatrix) return false;
106+
return IsHit(CubismFramework::GetIdManager()->GetId(id), _modelMatrix->InvertTransformX(x), _modelMatrix->InvertTransformY(y));
107+
}
108+
92109
private:
93110
JNIEnv* getEnv() {
94111
JNIEnv* env;
95112
if (_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) == JNI_EDETACHED) _jvm->AttachCurrentThread((void**)&env, nullptr);
96113
return env;
97114
}
115+
98116
JavaVM* _jvm;
99-
jobject _javaObj = nullptr;
117+
jobject _javaObj;
100118
std::vector<csmByte> _mocBuffer, _physicsBuffer, _poseBuffer;
101119
std::map<CubismMotion*, std::vector<csmByte>> _motionBuffers;
120+
std::vector<CubismMotion*> _pendingDeletion;
121+
std::mutex _pendingMutex;
102122
};
103123

104124
extern "C" {
105125

106-
JNIEXPORT jlong JNICALL Java_dev_eatgrapes_live2d_CubismUserModel_createNative(JNIEnv* env, jclass) {
107-
return (jlong) new JniUserModel(env);
108-
}
109-
110-
JNIEXPORT void JNICALL Java_dev_eatgrapes_live2d_CubismUserModel_initNative(JNIEnv* env, jobject thiz, jlong ptr) {
111-
((JniUserModel*)ptr)->setJavaObj(env, thiz);
126+
JNIEXPORT jlong JNICALL Java_dev_eatgrapes_live2d_CubismUserModel_createNative(JNIEnv* env, jobject thiz) {
127+
return (jlong) new JniUserModel(env, thiz);
112128
}
113129

114130
JNIEXPORT void JNICALL Java_dev_eatgrapes_live2d_CubismUserModel_deleteNative(JNIEnv*, jclass, jlong ptr) {
@@ -210,4 +226,4 @@ JNIEXPORT void JNICALL Java_dev_eatgrapes_live2d_CubismUserModel_drawNative(JNIE
210226
env->ReleaseFloatArrayElements(matrix, m_ptr, JNI_ABORT);
211227
}
212228

213-
}
229+
}

0 commit comments

Comments
 (0)