Skip to content

Commit 0393f40

Browse files
author
Roberto De Ioris
committed
Android support
1 parent 566bf86 commit 0393f40

File tree

218 files changed

+50324
-43
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

218 files changed

+50324
-43
lines changed

Source/UnrealEnginePython/Private/PyCommandlet.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,14 @@ int32 UPyCommandlet::Main(const FString& CommandLine)
9292
argv[i] = (wchar_t*)malloc(PyArgv[i].Len() + 1);
9393
#if PLATFORM_MAC || PLATFORM_LINUX
9494
wcsncpy(argv[i], *PyArgv[i].ReplaceEscapedCharWithChar(), PyArgv[i].Len() + 1);
95+
#elif PLATFORM_ANDROID
96+
wcsncpy(argv[i], (const wchar_t *)*PyArgv[i].ReplaceEscapedCharWithChar(), PyArgv[i].Len() + 1);
9597
#else
9698
wcscpy_s(argv[i], PyArgv[i].Len() + 1, *PyArgv[i].ReplaceEscapedCharWithChar());
9799
#endif
98100
#else
99101
argv[i] = (char*)malloc(PyArgv[i].Len() + 1);
100-
#if PLATFORM_MAC || PLATFORM_LINUX
102+
#if PLATFORM_MAC || PLATFORM_LINUX || PLATFORM_ANDROID
101103
strncpy(argv[i], TCHAR_TO_UTF8(*PyArgv[i].ReplaceEscapedCharWithChar()), PyArgv[i].Len() + 1);
102104
#else
103105
strcpy_s(argv[i], PyArgv[i].Len() + 1, TCHAR_TO_UTF8(*PyArgv[i].ReplaceEscapedCharWithChar()));

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2774,7 +2774,7 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject *
27742774
{
27752775
if (!prop->IsInContainer(u_function->ParmsSize))
27762776
{
2777-
return PyErr_Format(PyExc_Exception, "Attempting to import func param property that's out of bounds. %s", *u_function->GetName());
2777+
return PyErr_Format(PyExc_Exception, "Attempting to import func param property that's out of bounds. %s", TCHAR_TO_UTF8(*u_function->GetName()));
27782778
}
27792779
#if WITH_EDITOR
27802780
FString default_key = FString("CPP_Default_") + prop->GetName();

Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp

Lines changed: 20 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
#include "Tracks/MovieSceneCameraCutTrack.h"
1616
#if ENGINE_MINOR_VERSION < 20
1717
#include "Sections/IKeyframeSection.h"
18-
#else
19-
#include "Wrappers/UEPyFFrameNumber.h"
2018
#endif
2119
#include "Sections/MovieSceneFloatSection.h"
2220
#include "Sections/MovieSceneBoolSection.h"
@@ -37,6 +35,10 @@
3735
#include "Runtime/LevelSequence/Public/LevelSequence.h"
3836
#include "Engine/World.h"
3937

38+
#if ENGINE_MINOR_VERSION >= 20
39+
#include "Wrappers/UEPyFFrameNumber.h"
40+
#endif
41+
4042

4143
#if ENGINE_MINOR_VERSION >= 20
4244
static bool magic_get_frame_number(UMovieScene *MovieScene, PyObject *py_obj, FFrameNumber *dest)
@@ -1342,8 +1344,8 @@ PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *self, PyObject * ar
13421344
ue_py_check(self);
13431345

13441346
#if ENGINE_MINOR_VERSION >= 20
1345-
return PyErr_Format(PyExc_Exception, "sequencer_import_fbx_transform still not supported on 4.20");
1346-
#endif
1347+
return PyErr_Format(PyExc_Exception, "sequencer_import_fbx_transform() is still not supported in this engine version");
1348+
#else
13471349

13481350
char *filename;
13491351
char *nodename;
@@ -1403,6 +1405,7 @@ PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *self, PyObject * ar
14031405
#if ENGINE_MINOR_VERSION >= 18
14041406
CurveAPI.GetConvertedTransformCurveData(NodeName, Translation[0], Translation[1], Translation[2], EulerRotation[0], EulerRotation[1], EulerRotation[2], Scale[0], Scale[1], Scale[2], DefaultTransform);
14051407

1408+
14061409
for (int32 ChannelIndex = 0; ChannelIndex < 3; ++ChannelIndex)
14071410
{
14081411
EAxis::Type ChannelAxis = EAxis::X;
@@ -1414,14 +1417,13 @@ PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *self, PyObject * ar
14141417
{
14151418
ChannelAxis = EAxis::Z;
14161419
}
1417-
#if ENGINE_MINOR_VERSION < 20
1420+
14181421
section->GetTranslationCurve(ChannelAxis).SetDefaultValue(DefaultTransform.GetLocation()[ChannelIndex]);
14191422
section->GetRotationCurve(ChannelAxis).SetDefaultValue(DefaultTransform.GetRotation().Euler()[ChannelIndex]);
14201423
section->GetScaleCurve(ChannelAxis).SetDefaultValue(DefaultTransform.GetScale3D()[ChannelIndex]);
1421-
#else
1422-
// TODO ??
1423-
#endif
1424-
}
1424+
}
1425+
1426+
14251427
#else
14261428
CurveAPI.GetConvertedTransformCurveData(NodeName, Translation[0], Translation[1], Translation[2], EulerRotation[0], EulerRotation[1], EulerRotation[2], Scale[0], Scale[1], Scale[2]);
14271429

@@ -1443,7 +1445,7 @@ PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *self, PyObject * ar
14431445
else if (ChannelIndex == 2)
14441446
{
14451447
ChannelAxis = EAxis::Z;
1446-
}
1448+
}
14471449

14481450
FInterpCurveFloat* CurveFloat = nullptr;
14491451
FRichCurve* ChannelCurve = nullptr;
@@ -1452,11 +1454,7 @@ PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *self, PyObject * ar
14521454
if (CurveIndex == 0)
14531455
{
14541456
CurveFloat = &Translation[ChannelIndex];
1455-
#if ENGINE_MINOR_VERSION < 20
14561457
ChannelCurve = &section->GetTranslationCurve(ChannelAxis);
1457-
#else
1458-
// TODO ???
1459-
#endif
14601458
if (ChannelIndex == 1)
14611459
{
14621460
bNegative = true;
@@ -1465,11 +1463,7 @@ PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *self, PyObject * ar
14651463
else if (CurveIndex == 1)
14661464
{
14671465
CurveFloat = &EulerRotation[ChannelIndex];
1468-
#if ENGINE_MINOR_VERSION < 20
14691466
ChannelCurve = &section->GetRotationCurve(ChannelAxis);
1470-
#else
1471-
// TODO ???
1472-
#endif
14731467
if (ChannelIndex == 1 || ChannelIndex == 2)
14741468
{
14751469
bNegative = true;
@@ -1478,11 +1472,7 @@ PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *self, PyObject * ar
14781472
else if (CurveIndex == 2)
14791473
{
14801474
CurveFloat = &Scale[ChannelIndex];
1481-
#if ENGINE_MINOR_VERSION < 20
14821475
ChannelCurve = &section->GetScaleCurve(ChannelAxis);
1483-
#else
1484-
// TODO ???
1485-
#endif
14861476
}
14871477

14881478
if (ChannelCurve != nullptr && CurveFloat != nullptr)
@@ -1504,41 +1494,34 @@ PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *self, PyObject * ar
15041494
if (KeyIndex < CurveFloat->Points.Num() - 1)
15051495
{
15061496
LeaveTangent = LeaveTangent / (CurveFloat->Points[KeyIndex + 1].InVal - CurveFloat->Points[KeyIndex].InVal);
1507-
}
1497+
}
15081498

15091499
if (bNegative)
15101500
{
15111501
ArriveTangent = -ArriveTangent;
15121502
LeaveTangent = -LeaveTangent;
15131503
}
15141504

1515-
#if ENGINE_MINOR_VERSION < 20
15161505
FMatineeImportTools::SetOrAddKey(*ChannelCurve, CurveFloat->Points[KeyIndex].InVal, CurveFloat->Points[KeyIndex].OutVal, ArriveTangent, LeaveTangent, CurveFloat->Points[KeyIndex].InterpMode);
1517-
#else
1518-
// TODO ???
1519-
#endif
1520-
}
1506+
1507+
}
15211508

15221509
ChannelCurve->RemoveRedundantKeys(KINDA_SMALL_NUMBER);
15231510
ChannelCurve->AutoSetTangents();
1524-
}
1525-
}
1511+
}
1512+
}
15261513
}
15271514

1528-
#if ENGINE_MINOR_VERSION < 20
1515+
15291516
section->SetStartTime(MinTime);
15301517
section->SetEndTime(MaxTime);
1531-
#else
1532-
// TODO
1533-
const TRange<FFrameNumber> Range;
1534-
//Range.SetLowerBoundValue();
1535-
section->SetRange(Range);
1536-
#endif
1518+
15371519

15381520
FbxImporter->ReleaseScene();
15391521
ImportOptions->bConvertScene = bConverteScene;
15401522
ImportOptions->bConvertSceneUnit = bConverteScene;
15411523
ImportOptions->bForceFrontXAxis = bConverteScene;
1524+
#endif
15421525
Py_RETURN_NONE;
15431526
}
15441527

Source/UnrealEnginePython/Private/UnrealEnginePython.cpp

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ const char *ue4_module_options = "linux_global_symbols";
3535
#include "Runtime/Core/Public/Misc/ConfigCacheIni.h"
3636
#include "Runtime/Core/Public/GenericPlatform/GenericPlatformFile.h"
3737

38+
#include "Runtime/Core/Public/HAL/FileManagerGeneric.h"
39+
40+
#if PLATFORM_ANDROID
41+
#include "Android/AndroidJNI.h"
42+
#include "Android/AndroidApplication.h"
43+
#endif
44+
3845

3946
const char *UEPyUnicode_AsUTF8(PyObject *py_str)
4047
{
@@ -223,9 +230,9 @@ FAutoConsoleCommand ExecPythonStringCommand(
223230
*NSLOCTEXT("UnrealEnginePython", "CommandText_Cmd", "Execute python string").ToString(),
224231
FConsoleCommandWithArgsDelegate::CreateStatic(consoleExecString));
225232

233+
226234
void FUnrealEnginePythonModule::StartupModule()
227235
{
228-
229236
BrutalFinalize = false;
230237

231238
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
@@ -377,8 +384,57 @@ void FUnrealEnginePythonModule::StartupModule()
377384
FPlatformMisc::SetEnvironmentVar(TEXT("PATH"), *ModifiedPath);
378385
}
379386

387+
388+
380389
#if PY_MAJOR_VERSION >= 3
381390
init_unreal_engine_builtin();
391+
#if PLATFORM_ANDROID
392+
extern FString GOBBFilePathBase;
393+
extern FString GFilePathBase;
394+
extern FString GExternalFilePath;
395+
extern FString GPackageName;
396+
extern int32 GAndroidPackageVersion;
397+
FString OBBDir1 = GOBBFilePathBase + FString(TEXT("/Android/obb/") + GPackageName);
398+
FString OBBDir2 = GOBBFilePathBase + FString(TEXT("/obb/") + GPackageName);
399+
FString MainOBBName = FString::Printf(TEXT("main.%d.%s.obb"), GAndroidPackageVersion, *GPackageName);
400+
FString PatchOBBName = FString::Printf(TEXT("patch.%d.%s.obb"), GAndroidPackageVersion, *GPackageName);
401+
FString UnrealEnginePython_OBBPath;
402+
if (FPaths::FileExists(*(OBBDir1 / MainOBBName)))
403+
{
404+
UnrealEnginePython_OBBPath = OBBDir1 / MainOBBName / FApp::GetProjectName() / FString(TEXT("Content/Scripts"));
405+
}
406+
else if (FPaths::FileExists(*(OBBDir2 / MainOBBName)))
407+
{
408+
UnrealEnginePython_OBBPath = OBBDir2 / MainOBBName / FApp::GetProjectName() / FString(TEXT("Content/Scripts"));
409+
}
410+
if (FPaths::FileExists(*(OBBDir1 / PatchOBBName)))
411+
{
412+
UnrealEnginePython_OBBPath = OBBDir1 / PatchOBBName / FApp::GetProjectName() / FString(TEXT("Content/Scripts"));
413+
}
414+
else if (FPaths::FileExists(*(OBBDir2 / PatchOBBName)))
415+
{
416+
UnrealEnginePython_OBBPath = OBBDir1 / PatchOBBName / FApp::GetProjectName() / FString(TEXT("Content/Scripts"));
417+
}
418+
419+
if (!UnrealEnginePython_OBBPath.IsEmpty())
420+
{
421+
ScriptsPaths.Add(UnrealEnginePython_OBBPath);
422+
}
423+
424+
FString FinalPath = GFilePathBase / FString("UE4Game") / FApp::GetProjectName() / FApp::GetProjectName() / FString(TEXT("Content/Scripts"));
425+
ScriptsPaths.Add(FinalPath);
426+
427+
FString BasePythonPath = FinalPath / FString(TEXT("stdlib.zip")) + FString(":") + FinalPath;
428+
429+
if (!UnrealEnginePython_OBBPath.IsEmpty())
430+
{
431+
BasePythonPath += FString(":") + UnrealEnginePython_OBBPath;
432+
}
433+
434+
UE_LOG(LogPython, Warning, TEXT("Setting Base Path to %s"), *BasePythonPath);
435+
436+
Py_SetPath(Py_DecodeLocale(TCHAR_TO_UTF8(*BasePythonPath), NULL));
437+
#endif
382438
#endif
383439

384440
Py_Initialize();
@@ -422,11 +478,11 @@ void FUnrealEnginePythonModule::StartupModule()
422478
#else
423479
unreal_engine_py_log_error();
424480
#endif
425-
}
481+
}
426482

427483
// release the GIL
428484
PyThreadState *UEPyGlobalState = PyEval_SaveThread();
429-
}
485+
}
430486

431487
void FUnrealEnginePythonModule::ShutdownModule()
432488
{
@@ -593,7 +649,7 @@ void FUnrealEnginePythonModule::RunFile(char *filename)
593649
}
594650
unreal_engine_py_log_error();
595651
return;
596-
}
652+
}
597653
#endif
598654

599655
}

Source/UnrealEnginePython/Public/UnrealEnginePython.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
#elif PLATFORM_LINUX
2222
#include <Python.h>
2323
#include <structmember.h>
24+
#elif PLATFORM_ANDROID
25+
#include <Python.h>
26+
#include <structmember.h>
2427
#elif PLATFORM_WINDOWS
2528
#include <include/pyconfig.h>
2629
#ifndef SIZEOF_PID_T

Source/UnrealEnginePython/UnrealEnginePython.Build.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,16 @@ public UnrealEnginePython(TargetInfo Target)
258258
PublicAdditionalLibraries.Add(items[1]);
259259
}
260260
}
261+
else if (Target.Platform == UnrealTargetPlatform.Android)
262+
{
263+
PublicIncludePaths.Add(System.IO.Path.Combine(ModuleDirectory, "../../android/python35/include"));
264+
PublicLibraryPaths.Add(System.IO.Path.Combine(ModuleDirectory, "../../android/armeabi-v7a"));
265+
PublicAdditionalLibraries.Add("python3.5m");
266+
267+
string APLName = "UnrealEnginePython_APL.xml";
268+
string RelAPLPath = Utils.MakePathRelativeTo(System.IO.Path.Combine(ModuleDirectory, APLName), Target.RelativeEnginePath);
269+
AdditionalPropertiesForReceipt.Add("AndroidPlugin", RelAPLPath);
270+
}
261271

262272
}
263273

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--Plugin additions-->
3+
<root xmlns:android="http://schemas.android.com/apk/res/android">
4+
<!-- init section is always evaluated once per architecture -->
5+
<init>
6+
<log text="python APL init"/>
7+
</init>
8+
9+
<!-- optional files or directories to copy to Intermediate/Android/APK -->
10+
<resourceCopies>
11+
<log text="python APL copying files for $S(Architecture)/"/>
12+
<copyFile src="$S(PluginDir)/../../android/armeabi-v7a/libcrystax.so"
13+
dst="$S(BuildDir)/libs/armeabi-v7a/libcrystax.so" />
14+
<copyFile src="$S(PluginDir)/../../android/armeabi-v7a/libpython3.5m.so"
15+
dst="$S(BuildDir)/libs/armeabi-v7a/libpython3.5m.so" />
16+
</resourceCopies>
17+
18+
<soLoadLibrary>
19+
<log text="Python APL adding loadLibrary references"/>
20+
<loadLibrary name="crystax" failmsg="libcrystax not loaded and required!" />
21+
<loadLibrary name="python3.5m" failmsg="libpython3.5m not loaded and required!" />
22+
</soLoadLibrary>
23+
</root>
24+

android/armeabi-v7a/libcrystax.so

3.37 MB
Binary file not shown.
6.78 MB
Binary file not shown.
8.41 MB
Binary file not shown.

0 commit comments

Comments
 (0)