Android: Allow viewing/editing the actual codes
This commit is contained in:
parent
fc6c31c3db
commit
883a9f8a99
|
@ -22,12 +22,15 @@ public class ARCheat extends AbstractCheat
|
||||||
@NonNull
|
@NonNull
|
||||||
public native String getName();
|
public native String getName();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public native String getCode();
|
||||||
|
|
||||||
public native boolean getUserDefined();
|
public native boolean getUserDefined();
|
||||||
|
|
||||||
public native boolean getEnabled();
|
public native boolean getEnabled();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected native int trySetImpl(@NonNull String name);
|
protected native int trySetImpl(@NonNull String name, @NonNull String code);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected native void setEnabledImpl(boolean enabled);
|
protected native void setEnabledImpl(boolean enabled);
|
||||||
|
|
|
@ -9,12 +9,12 @@ public abstract class AbstractCheat implements Cheat
|
||||||
{
|
{
|
||||||
private Runnable mChangedCallback = null;
|
private Runnable mChangedCallback = null;
|
||||||
|
|
||||||
public int trySet(@NonNull String name)
|
public int trySet(@NonNull String name, @NonNull String code)
|
||||||
{
|
{
|
||||||
if (name.isEmpty())
|
if (name.isEmpty())
|
||||||
return TRY_SET_FAIL_NO_NAME;
|
return TRY_SET_FAIL_NO_NAME;
|
||||||
|
|
||||||
int result = trySetImpl(name);
|
int result = trySetImpl(name, code);
|
||||||
|
|
||||||
if (result == TRY_SET_SUCCESS)
|
if (result == TRY_SET_SUCCESS)
|
||||||
onChanged();
|
onChanged();
|
||||||
|
@ -39,7 +39,7 @@ public abstract class AbstractCheat implements Cheat
|
||||||
mChangedCallback.run();
|
mChangedCallback.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract int trySetImpl(@NonNull String name);
|
protected abstract int trySetImpl(@NonNull String name, @NonNull String code);
|
||||||
|
|
||||||
protected abstract void setEnabledImpl(boolean enabled);
|
protected abstract void setEnabledImpl(boolean enabled);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,19 @@ import androidx.annotation.Nullable;
|
||||||
|
|
||||||
public interface Cheat
|
public interface Cheat
|
||||||
{
|
{
|
||||||
|
int TRY_SET_FAIL_CODE_MIXED_ENCRYPTION = -3;
|
||||||
|
int TRY_SET_FAIL_NO_CODE_LINES = -2;
|
||||||
int TRY_SET_FAIL_NO_NAME = -1;
|
int TRY_SET_FAIL_NO_NAME = -1;
|
||||||
int TRY_SET_SUCCESS = 0;
|
int TRY_SET_SUCCESS = 0;
|
||||||
|
// Result codes greater than 0 represent an error on the corresponding code line (one-indexed)
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
int trySet(@NonNull String name);
|
@NonNull
|
||||||
|
String getCode();
|
||||||
|
|
||||||
|
int trySet(@NonNull String name, @NonNull String code);
|
||||||
|
|
||||||
boolean getUserDefined();
|
boolean getUserDefined();
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,15 @@ public class GeckoCheat extends AbstractCheat
|
||||||
@NonNull
|
@NonNull
|
||||||
public native String getName();
|
public native String getName();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public native String getCode();
|
||||||
|
|
||||||
public native boolean getUserDefined();
|
public native boolean getUserDefined();
|
||||||
|
|
||||||
public native boolean getEnabled();
|
public native boolean getEnabled();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected native int trySetImpl(@NonNull String name);
|
protected native int trySetImpl(@NonNull String name, @NonNull String code);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected native void setEnabledImpl(boolean enabled);
|
protected native void setEnabledImpl(boolean enabled);
|
||||||
|
|
|
@ -22,12 +22,15 @@ public class PatchCheat extends AbstractCheat
|
||||||
@NonNull
|
@NonNull
|
||||||
public native String getName();
|
public native String getName();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public native String getCode();
|
||||||
|
|
||||||
public native boolean getUserDefined();
|
public native boolean getUserDefined();
|
||||||
|
|
||||||
public native boolean getEnabled();
|
public native boolean getEnabled();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected native int trySetImpl(@NonNull String name);
|
protected native int trySetImpl(@NonNull String name, @NonNull String code);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected native void setEnabledImpl(boolean enabled);
|
protected native void setEnabledImpl(boolean enabled);
|
||||||
|
|
|
@ -23,6 +23,7 @@ public class CheatDetailsFragment extends Fragment
|
||||||
{
|
{
|
||||||
private View mRoot;
|
private View mRoot;
|
||||||
private EditText mEditName;
|
private EditText mEditName;
|
||||||
|
private EditText mEditCode;
|
||||||
private Button mButtonEdit;
|
private Button mButtonEdit;
|
||||||
private Button mButtonCancel;
|
private Button mButtonCancel;
|
||||||
private Button mButtonOk;
|
private Button mButtonOk;
|
||||||
|
@ -43,6 +44,7 @@ public class CheatDetailsFragment extends Fragment
|
||||||
{
|
{
|
||||||
mRoot = view.findViewById(R.id.root);
|
mRoot = view.findViewById(R.id.root);
|
||||||
mEditName = view.findViewById(R.id.edit_name);
|
mEditName = view.findViewById(R.id.edit_name);
|
||||||
|
mEditCode = view.findViewById(R.id.edit_code);
|
||||||
mButtonEdit = view.findViewById(R.id.button_edit);
|
mButtonEdit = view.findViewById(R.id.button_edit);
|
||||||
mButtonCancel = view.findViewById(R.id.button_cancel);
|
mButtonCancel = view.findViewById(R.id.button_cancel);
|
||||||
mButtonOk = view.findViewById(R.id.button_ok);
|
mButtonOk = view.findViewById(R.id.button_ok);
|
||||||
|
@ -65,13 +67,14 @@ public class CheatDetailsFragment extends Fragment
|
||||||
private void clearEditErrors()
|
private void clearEditErrors()
|
||||||
{
|
{
|
||||||
mEditName.setError(null);
|
mEditName.setError(null);
|
||||||
|
mEditCode.setError(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onOkClicked(View view)
|
private void onOkClicked(View view)
|
||||||
{
|
{
|
||||||
clearEditErrors();
|
clearEditErrors();
|
||||||
|
|
||||||
int result = mCheat.trySet(mEditName.getText().toString());
|
int result = mCheat.trySet(mEditName.getText().toString(), mEditCode.getText().toString());
|
||||||
|
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
|
@ -80,7 +83,16 @@ public class CheatDetailsFragment extends Fragment
|
||||||
mViewModel.setIsEditing(false);
|
mViewModel.setIsEditing(false);
|
||||||
break;
|
break;
|
||||||
case Cheat.TRY_SET_FAIL_NO_NAME:
|
case Cheat.TRY_SET_FAIL_NO_NAME:
|
||||||
mEditName.setError(getText(R.string.cheats_error_no_name));
|
mEditName.setError(getString(R.string.cheats_error_no_name));
|
||||||
|
break;
|
||||||
|
case Cheat.TRY_SET_FAIL_NO_CODE_LINES:
|
||||||
|
mEditCode.setError(getString(R.string.cheats_error_no_code_lines));
|
||||||
|
break;
|
||||||
|
case Cheat.TRY_SET_FAIL_CODE_MIXED_ENCRYPTION:
|
||||||
|
mEditCode.setError(getString(R.string.cheats_error_mixed_encryption));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mEditCode.setError(getString(R.string.cheats_error_on_line, result));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,6 +113,7 @@ public class CheatDetailsFragment extends Fragment
|
||||||
if (!isEditing && cheat != null)
|
if (!isEditing && cheat != null)
|
||||||
{
|
{
|
||||||
mEditName.setText(cheat.getName());
|
mEditName.setText(cheat.getName());
|
||||||
|
mEditCode.setText(cheat.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
mCheat = cheat;
|
mCheat = cheat;
|
||||||
|
@ -109,6 +122,7 @@ public class CheatDetailsFragment extends Fragment
|
||||||
private void onIsEditingUpdated(boolean isEditing)
|
private void onIsEditingUpdated(boolean isEditing)
|
||||||
{
|
{
|
||||||
mEditName.setEnabled(isEditing);
|
mEditName.setEnabled(isEditing);
|
||||||
|
mEditCode.setEnabled(isEditing);
|
||||||
|
|
||||||
mButtonEdit.setVisibility(isEditing ? View.GONE : View.VISIBLE);
|
mButtonEdit.setVisibility(isEditing ? View.GONE : View.VISIBLE);
|
||||||
mButtonCancel.setVisibility(isEditing ? View.VISIBLE : View.GONE);
|
mButtonCancel.setVisibility(isEditing ? View.VISIBLE : View.GONE);
|
||||||
|
|
|
@ -45,9 +45,39 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/label_name"
|
app:layout_constraintTop_toBottomOf="@id/label_name"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toTopOf="@id/label_code"
|
||||||
tools:text="Hyrule Field Speed Hack" />
|
tools:text="Hyrule Field Speed Hack" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_code"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TextAppearance.AppCompat.Headline"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/cheats_code"
|
||||||
|
android:layout_margin="@dimen/spacing_large"
|
||||||
|
android:labelFor="@id/edit_code"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/edit_name"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/edit_code" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/edit_code"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="108sp"
|
||||||
|
android:layout_marginHorizontal="@dimen/spacing_large"
|
||||||
|
android:importantForAutofill="no"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:typeface="monospace"
|
||||||
|
android:gravity="start"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/label_code"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
tools:text="0x8003d63c:dword:0x60000000\n0x8003d658:dword:0x60000000" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
|
@ -390,8 +390,12 @@
|
||||||
<string name="cheats">Cheats</string>
|
<string name="cheats">Cheats</string>
|
||||||
<string name="cheats_with_game_id">Cheats: %1$s</string>
|
<string name="cheats_with_game_id">Cheats: %1$s</string>
|
||||||
<string name="cheats_name">Name</string>
|
<string name="cheats_name">Name</string>
|
||||||
|
<string name="cheats_code">Code</string>
|
||||||
<string name="cheats_edit">Edit</string>
|
<string name="cheats_edit">Edit</string>
|
||||||
<string name="cheats_error_no_name">Name can\'t be empty</string>
|
<string name="cheats_error_no_name">Name can\'t be empty</string>
|
||||||
|
<string name="cheats_error_no_code_lines">Code can\'t be empty</string>
|
||||||
|
<string name="cheats_error_on_line">Error on line %1$d</string>
|
||||||
|
<string name="cheats_error_mixed_encryption">Lines must either be all encrypted or all decrypted</string>
|
||||||
|
|
||||||
<!-- Convert Screen -->
|
<!-- Convert Screen -->
|
||||||
<string name="convert_format">Format</string>
|
<string name="convert_format">Format</string>
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/IniFile.h"
|
#include "Common/IniFile.h"
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
|
#include "Core/ARDecrypt.h"
|
||||||
#include "Core/ActionReplay.h"
|
#include "Core/ActionReplay.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "jni/AndroidCommon/AndroidCommon.h"
|
#include "jni/AndroidCommon/AndroidCommon.h"
|
||||||
|
@ -40,6 +42,24 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCheat_getName(JNIEnv* env
|
||||||
return ToJString(env, GetPointer(env, obj)->name);
|
return ToJString(env, GetPointer(env, obj)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCheat_getCode(JNIEnv* env, jobject obj)
|
||||||
|
{
|
||||||
|
ActionReplay::ARCode* code = GetPointer(env, obj);
|
||||||
|
|
||||||
|
std::string code_string;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < code->ops.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
code_string += '\n';
|
||||||
|
|
||||||
|
code_string += ActionReplay::SerializeLine(code->ops[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToJString(env, code_string);
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCheat_getUserDefined(JNIEnv* env,
|
Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCheat_getUserDefined(JNIEnv* env,
|
||||||
jobject obj)
|
jobject obj)
|
||||||
|
@ -54,12 +74,47 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCheat_getEnabled(JNIEnv*
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCheat_trySetImpl(
|
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCheat_trySetImpl(
|
||||||
JNIEnv* env, jobject obj, jstring name)
|
JNIEnv* env, jobject obj, jstring name, jstring code_string)
|
||||||
{
|
{
|
||||||
ActionReplay::ARCode* code = GetPointer(env, obj);
|
ActionReplay::ARCode* code = GetPointer(env, obj);
|
||||||
code->name = GetJString(env, name);
|
|
||||||
|
|
||||||
return TRY_SET_SUCCESS;
|
std::vector<ActionReplay::AREntry> entries;
|
||||||
|
std::vector<std::string> encrypted_lines;
|
||||||
|
|
||||||
|
std::vector<std::string> lines = SplitString(GetJString(env, code_string), '\n');
|
||||||
|
|
||||||
|
for (size_t i = 0; i < lines.size(); i++)
|
||||||
|
{
|
||||||
|
const std::string& line = lines[i];
|
||||||
|
|
||||||
|
if (line.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto parse_result = ActionReplay::DeserializeLine(line);
|
||||||
|
|
||||||
|
if (std::holds_alternative<ActionReplay::AREntry>(parse_result))
|
||||||
|
entries.emplace_back(std::get<ActionReplay::AREntry>(std::move(parse_result)));
|
||||||
|
else if (std::holds_alternative<ActionReplay::EncryptedLine>(parse_result))
|
||||||
|
encrypted_lines.emplace_back(std::get<ActionReplay::EncryptedLine>(std::move(parse_result)));
|
||||||
|
else
|
||||||
|
return i + 1; // Parse error on line i
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!encrypted_lines.empty())
|
||||||
|
{
|
||||||
|
if (!entries.empty())
|
||||||
|
return Cheats::TRY_SET_FAIL_CODE_MIXED_ENCRYPTION;
|
||||||
|
|
||||||
|
ActionReplay::DecryptARCode(encrypted_lines, &entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries.empty())
|
||||||
|
return Cheats::TRY_SET_FAIL_NO_CODE_LINES;
|
||||||
|
|
||||||
|
code->name = GetJString(env, name);
|
||||||
|
code->ops = std::move(entries);
|
||||||
|
|
||||||
|
return Cheats::TRY_SET_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCheat_setEnabledImpl(
|
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCheat_setEnabledImpl(
|
||||||
|
|
|
@ -3,5 +3,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
namespace Cheats
|
||||||
|
{
|
||||||
|
constexpr int TRY_SET_FAIL_CODE_MIXED_ENCRYPTION = -3;
|
||||||
|
constexpr int TRY_SET_FAIL_NO_CODE_LINES = -2;
|
||||||
constexpr int TRY_SET_FAIL_NO_NAME = -1;
|
constexpr int TRY_SET_FAIL_NO_NAME = -1;
|
||||||
constexpr int TRY_SET_SUCCESS = 0;
|
constexpr int TRY_SET_SUCCESS = 0;
|
||||||
|
// Result codes greater than 0 represent an error on the corresponding code line (one-indexed)
|
||||||
|
} // namespace Cheats
|
||||||
|
|
|
@ -41,6 +41,24 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_GeckoCheat_getName(JNIEnv*
|
||||||
return ToJString(env, GetPointer(env, obj)->name);
|
return ToJString(env, GetPointer(env, obj)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_org_dolphinemu_dolphinemu_features_cheats_model_GeckoCheat_getCode(JNIEnv* env, jobject obj)
|
||||||
|
{
|
||||||
|
Gecko::GeckoCode* code = GetPointer(env, obj);
|
||||||
|
|
||||||
|
std::string code_string;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < code->codes.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
code_string += '\n';
|
||||||
|
|
||||||
|
code_string += code->codes[i].original_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToJString(env, code_string);
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_org_dolphinemu_dolphinemu_features_cheats_model_GeckoCheat_getUserDefined(JNIEnv* env,
|
Java_org_dolphinemu_dolphinemu_features_cheats_model_GeckoCheat_getUserDefined(JNIEnv* env,
|
||||||
jobject obj)
|
jobject obj)
|
||||||
|
@ -55,12 +73,34 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_GeckoCheat_getEnabled(JNIEn
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_GeckoCheat_trySetImpl(
|
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_GeckoCheat_trySetImpl(
|
||||||
JNIEnv* env, jobject obj, jstring name)
|
JNIEnv* env, jobject obj, jstring name, jstring code_string)
|
||||||
{
|
{
|
||||||
Gecko::GeckoCode* code = GetPointer(env, obj);
|
Gecko::GeckoCode* code = GetPointer(env, obj);
|
||||||
code->name = GetJString(env, name);
|
|
||||||
|
|
||||||
return TRY_SET_SUCCESS;
|
std::vector<Gecko::GeckoCode::Code> entries;
|
||||||
|
|
||||||
|
std::vector<std::string> lines = SplitString(GetJString(env, code_string), '\n');
|
||||||
|
|
||||||
|
for (size_t i = 0; i < lines.size(); i++)
|
||||||
|
{
|
||||||
|
const std::string& line = lines[i];
|
||||||
|
|
||||||
|
if (line.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (std::optional<Gecko::GeckoCode::Code> c = Gecko::DeserializeLine(line))
|
||||||
|
entries.emplace_back(*std::move(c));
|
||||||
|
else
|
||||||
|
return i + 1; // Parse error on line i
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries.empty())
|
||||||
|
return Cheats::TRY_SET_FAIL_NO_CODE_LINES;
|
||||||
|
|
||||||
|
code->name = GetJString(env, name);
|
||||||
|
code->codes = std::move(entries);
|
||||||
|
|
||||||
|
return Cheats::TRY_SET_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
|
|
|
@ -40,6 +40,24 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_PatchCheat_getName(JNIEnv*
|
||||||
return ToJString(env, GetPointer(env, obj)->name);
|
return ToJString(env, GetPointer(env, obj)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_org_dolphinemu_dolphinemu_features_cheats_model_PatchCheat_getCode(JNIEnv* env, jobject obj)
|
||||||
|
{
|
||||||
|
PatchEngine::Patch* patch = GetPointer(env, obj);
|
||||||
|
|
||||||
|
std::string code_string;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < patch->entries.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
code_string += '\n';
|
||||||
|
|
||||||
|
code_string += PatchEngine::SerializeLine(patch->entries[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToJString(env, code_string);
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_org_dolphinemu_dolphinemu_features_cheats_model_PatchCheat_getUserDefined(JNIEnv* env,
|
Java_org_dolphinemu_dolphinemu_features_cheats_model_PatchCheat_getUserDefined(JNIEnv* env,
|
||||||
jobject obj)
|
jobject obj)
|
||||||
|
@ -54,12 +72,34 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_PatchCheat_getEnabled(JNIEn
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_PatchCheat_trySetImpl(
|
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_PatchCheat_trySetImpl(
|
||||||
JNIEnv* env, jobject obj, jstring name)
|
JNIEnv* env, jobject obj, jstring name, jstring code_string)
|
||||||
{
|
{
|
||||||
PatchEngine::Patch* patch = GetPointer(env, obj);
|
PatchEngine::Patch* patch = GetPointer(env, obj);
|
||||||
patch->name = GetJString(env, name);
|
|
||||||
|
|
||||||
return TRY_SET_SUCCESS;
|
std::vector<PatchEngine::PatchEntry> entries;
|
||||||
|
|
||||||
|
std::vector<std::string> lines = SplitString(GetJString(env, code_string), '\n');
|
||||||
|
|
||||||
|
for (size_t i = 0; i < lines.size(); i++)
|
||||||
|
{
|
||||||
|
const std::string& line = lines[i];
|
||||||
|
|
||||||
|
if (line.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (std::optional<PatchEngine::PatchEntry> entry = PatchEngine::DeserializeLine(line))
|
||||||
|
entries.emplace_back(*std::move(entry));
|
||||||
|
else
|
||||||
|
return i + 1; // Parse error on line i
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries.empty())
|
||||||
|
return Cheats::TRY_SET_FAIL_NO_CODE_LINES;
|
||||||
|
|
||||||
|
patch->name = GetJString(env, name);
|
||||||
|
patch->entries = std::move(entries);
|
||||||
|
|
||||||
|
return Cheats::TRY_SET_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
|
|
Loading…
Reference in New Issue