Skip to content

Commit 4fd5090

Browse files
author
Roberto De Ioris
committed
merge with official
2 parents be32fea + 080faa9 commit 4fd5090

File tree

9 files changed

+140
-17
lines changed

9 files changed

+140
-17
lines changed

Source/UnrealEnginePython/Private/Slate/UEPySVectorInputBox.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ PyTypeObject ue_PySVectorInputBoxType = {
4343
static int ue_py_svector_input_box_init(ue_PySVectorInputBox *self, PyObject *args, PyObject *kwargs) {
4444
ue_py_slate_setup_farguments(SVectorInputBox);
4545

46-
//ue_py_slate_farguments_optional_float("delta", Delta);
47-
#if ENGINE_MINOR_VERSION > 15
46+
#if WITH_KNL_PYEXT
47+
ue_py_slate_farguments_optional_float("delta", Delta);
48+
#endif
49+
#if ENGINE_MINOR_VERSION > 15 || WITH_KNL_PYEXT
4850
ue_py_slate_farguments_optional_bool("allow_spin", AllowSpin);
4951
#endif
5052
ue_py_slate_farguments_optional_bool("allow_responsive_layout", AllowResponsiveLayout);

Source/UnrealEnginePython/Private/UEPyEngine.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ PyObject *py_unreal_engine_get_content_dir(PyObject * self, PyObject * args) {
144144
return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::GameContentDir()));
145145
}
146146

147+
PyObject *py_unreal_engine_get_game_saved_dir(PyObject * self, PyObject * args) {
148+
return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::GameSavedDir()));
149+
}
150+
151+
PyObject * py_unreal_engine_get_game_user_developer_dir(PyObject *, PyObject *) {
152+
return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::GameUserDeveloperDir()));
153+
}
154+
147155
PyObject *py_unreal_engine_convert_relative_path_to_full(PyObject * self, PyObject * args) {
148156
char *path;
149157
if (!PyArg_ParseTuple(args, "s:convert_relative_path_to_full", &path)) {

Source/UnrealEnginePython/Private/UEPyEngine.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ PyObject *py_unreal_engine_get_game_viewport_size(PyObject *, PyObject *);
1717
PyObject *py_unreal_engine_get_resolution(PyObject *, PyObject *);
1818

1919
PyObject *py_unreal_engine_get_content_dir(PyObject *, PyObject *);
20+
PyObject *py_unreal_engine_get_game_saved_dir(PyObject *, PyObject *);
21+
PyObject *py_unreal_engine_get_game_user_developer_dir(PyObject *, PyObject *);
2022

2123
PyObject *py_unreal_engine_find_object(PyObject *, PyObject *);
2224
PyObject *py_unreal_engine_find_class(PyObject *, PyObject *);

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ static PyMethodDef unreal_engine_methods[] = {
155155
{ "get_right_vector", py_unreal_engine_get_right_vector, METH_VARARGS, "" },
156156

157157
{ "get_content_dir", py_unreal_engine_get_content_dir, METH_VARARGS, "" },
158+
{ "get_game_saved_dir", py_unreal_engine_get_game_saved_dir, METH_VARARGS, "" },
159+
{ "get_game_user_developer_dir", py_unreal_engine_get_game_user_developer_dir, METH_VARARGS, "" },
158160
{ "convert_relative_path_to_full", py_unreal_engine_convert_relative_path_to_full, METH_VARARGS, "" },
159161

160162
{ "get_path", py_unreal_engine_get_path, METH_VARARGS, "" },
@@ -504,6 +506,7 @@ static PyMethodDef ue_PyUObject_methods[] = {
504506
{ "get_raw_animation_data", (PyCFunction)py_ue_anim_sequence_get_raw_animation_data, METH_VARARGS, "" },
505507
{ "get_raw_animation_track", (PyCFunction)py_ue_anim_sequence_get_raw_animation_track, METH_VARARGS, "" },
506508
{ "add_new_raw_track", (PyCFunction)py_ue_anim_sequence_add_new_raw_track, METH_VARARGS, "" },
509+
{ "add_anim_composite_section", (PyCFunction)py_ue_add_anim_composite_section, METH_VARARGS, "" },
507510
#endif
508511
{ "add_anim_composite_section", (PyCFunction)py_ue_add_anim_composite_section, METH_VARARGS, "" },
509512
#endif

Source/UnrealEnginePython/Private/UObject/UEPyAnimSequence.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,22 @@ PyObject *py_ue_anim_sequence_add_new_raw_track(ue_PyUObject * self, PyObject *
9595

9696
return PyLong_FromLong(index);
9797
}
98+
99+
PyObject *py_ue_add_anim_composite_section(ue_PyUObject * self, PyObject * args) {
100+
ue_py_check(self);
101+
102+
char *name;
103+
float time;
104+
if (!PyArg_ParseTuple(args, "sf:add_anim_composite_section", &name, &time))
105+
return nullptr;
106+
107+
UAnimMontage *anim = ue_py_check_type<UAnimMontage>(self);
108+
if (!anim)
109+
return PyErr_Format(PyExc_Exception, "UObject is not a UAnimMontage.");
110+
111+
return PyLong_FromLong(anim->AddAnimCompositeSection(FName(UTF8_TO_TCHAR(name)), time));
112+
}
113+
98114
#endif
99115
#endif
100116

Source/UnrealEnginePython/Private/UObject/UEPyAnimSequence.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ PyObject *py_ue_add_anim_composite_section(ue_PyUObject *, PyObject *);
1515
PyObject *py_ue_anim_set_skeleton(ue_PyUObject *, PyObject *);
1616

1717
PyObject *py_ue_get_blend_parameter(ue_PyUObject *, PyObject *);
18-
PyObject *py_ue_set_blend_parameter(ue_PyUObject *, PyObject *);
18+
PyObject *py_ue_set_blend_parameter(ue_PyUObject *, PyObject *);

Source/UnrealEnginePython/Private/UnrealEnginePython.cpp

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -153,26 +153,31 @@ void FUnrealEnginePythonModule::StartupModule()
153153
BrutalFinalize = false;
154154

155155
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
156-
FString IniValue;
157-
if (GConfig->GetString(UTF8_TO_TCHAR("Python"), UTF8_TO_TCHAR("Home"), IniValue, GEngineIni)) {
156+
FString PythonHome;
157+
if (GConfig->GetString(UTF8_TO_TCHAR("Python"), UTF8_TO_TCHAR("Home"), PythonHome, GEngineIni)) {
158158
#if PY_MAJOR_VERSION >= 3
159-
wchar_t *home = (wchar_t *)*IniValue;
159+
wchar_t *home = (wchar_t *)*PythonHome;
160160
#else
161-
char *home = TCHAR_TO_UTF8(*IniValue);
161+
char *home = TCHAR_TO_UTF8(*PythonHome);
162162
#endif
163+
FPlatformMisc::SetEnvironmentVar(TEXT("PYTHONHOME"), *PythonHome);
163164
Py_SetPythonHome(home);
164165
}
165166

166-
if (GConfig->GetString(UTF8_TO_TCHAR("Python"), UTF8_TO_TCHAR("RelativeHome"), IniValue, GEngineIni)) {
167-
IniValue = FPaths::Combine(*FPaths::GameContentDir(), *IniValue);
167+
if (GConfig->GetString(UTF8_TO_TCHAR("Python"), UTF8_TO_TCHAR("RelativeHome"), PythonHome, GEngineIni)) {
168+
PythonHome = FPaths::Combine(*FPaths::GameContentDir(), *PythonHome);
169+
FPaths::NormalizeFilename(PythonHome);
170+
PythonHome = FPaths::ConvertRelativePathToFull(PythonHome);
168171
#if PY_MAJOR_VERSION >= 3
169-
wchar_t *home = (wchar_t *)*IniValue;
172+
wchar_t *home = (wchar_t *)*PythonHome;
170173
#else
171-
char *home = TCHAR_TO_UTF8(*IniValue);
174+
char *home = TCHAR_TO_UTF8(*PythonHome);
172175
#endif
176+
173177
Py_SetPythonHome(home);
174178
}
175179

180+
FString IniValue;
176181
if (GConfig->GetString(UTF8_TO_TCHAR("Python"), UTF8_TO_TCHAR("ProgramName"), IniValue, GEngineIni)) {
177182
#if PY_MAJOR_VERSION >= 3
178183
wchar_t *program_name = (wchar_t *)*IniValue;
@@ -184,6 +189,8 @@ void FUnrealEnginePythonModule::StartupModule()
184189

185190
if (GConfig->GetString(UTF8_TO_TCHAR("Python"), UTF8_TO_TCHAR("RelativeProgramName"), IniValue, GEngineIni)) {
186191
IniValue = FPaths::Combine(*FPaths::GameContentDir(), *IniValue);
192+
FPaths::NormalizeFilename(IniValue);
193+
IniValue = FPaths::ConvertRelativePathToFull(IniValue);
187194
#if PY_MAJOR_VERSION >= 3
188195
wchar_t *program_name = (wchar_t *)*IniValue;
189196
#else
@@ -227,6 +234,45 @@ void FUnrealEnginePythonModule::StartupModule()
227234
if (!FPaths::DirectoryExists(ScriptsPath)) {
228235
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
229236
PlatformFile.CreateDirectory(*ScriptsPath);
237+
238+
// To ensure there are no path conflicts, if we have a valid python home at this point,
239+
// we override the current environment entirely with the environment we want to use,
240+
// removing any paths to other python environments we aren't using.
241+
if (PythonHome.Len() > 0)
242+
{
243+
FPlatformMisc::SetEnvironmentVar(TEXT("PYTHONHOME"), *PythonHome);
244+
245+
const int32 MaxPathVarLen = 32768;
246+
FString OrigPathVar = FString::ChrN(MaxPathVarLen, TEXT('\0'));
247+
FPlatformMisc::GetEnvironmentVariable(TEXT("PATH"), OrigPathVar.GetCharArray().GetData(), MaxPathVarLen);
248+
249+
// Get the current path and remove elements with python in them, we don't want any conflicts
250+
const TCHAR* PathDelimiter = FPlatformMisc::GetPathVarDelimiter();
251+
TArray<FString> PathVars;
252+
OrigPathVar.ParseIntoArray(PathVars, PathDelimiter, true);
253+
for (int32 PathRemoveIndex = PathVars.Num() - 1; PathRemoveIndex >= 0; --PathRemoveIndex)
254+
{
255+
if (PathVars[PathRemoveIndex].Contains(TEXT("python"), ESearchCase::IgnoreCase))
256+
{
257+
UE_LOG(LogPython, Verbose, TEXT("Removing other python Path: '%s'"), *PathVars[PathRemoveIndex]);
258+
PathVars.RemoveAt(PathRemoveIndex);
259+
}
260+
}
261+
262+
// Setup our own paths for PYTHONPATH
263+
TArray<FString> OurPythonPaths = {
264+
PythonHome,
265+
FPaths::Combine(PythonHome, TEXT("Lib")),
266+
FPaths::Combine(PythonHome, TEXT("Lib/site-packages")),
267+
};
268+
FString PythonPathVars = FString::Join(OurPythonPaths, PathDelimiter);
269+
FPlatformMisc::SetEnvironmentVar(TEXT("PYTHONPATH"), *PythonPathVars);
270+
271+
// Also add our paths to PATH, just so any searching will find our local python
272+
PathVars.Append(OurPythonPaths);
273+
FString ModifiedPath = FString::Join(PathVars, PathDelimiter);
274+
FPlatformMisc::SetEnvironmentVar(TEXT("PATH"), *ModifiedPath);
275+
>>>>>>> 080faa94f9c97ddbb1185001c9603d37d4811525
230276
}
231277

232278
Py_Initialize();

Source/UnrealEnginePython/UnrealEnginePython.Build.cs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class UnrealEnginePython : ModuleRules
1919

2020
private string[] windowsKnownPaths =
2121
{
22+
"../../../../../ThirdParty/Python3",
2223
"C:/Program Files/Python36",
2324
"C:/Program Files/Python35",
2425
"C:/Python27",
@@ -76,6 +77,7 @@ public UnrealEnginePython(ReadOnlyTargetRules Target) : base(Target)
7677
public UnrealEnginePython(TargetInfo Target)
7778
#endif
7879
{
80+
Definitions.Add("WITH_KNL_PYEXT=1");
7981

8082
PublicIncludePaths.AddRange(
8183
new string[] {
@@ -175,6 +177,33 @@ public UnrealEnginePython(TargetInfo Target)
175177
string libPath = GetWindowsPythonLibFile(pythonHome);
176178
PublicLibraryPaths.Add(Path.GetDirectoryName(libPath));
177179
PublicAdditionalLibraries.Add(libPath);
180+
181+
// copy the dlls into the plugins dlls folder, so they don't have to be on the path
182+
string dllsDir = Path.Combine(ModuleDirectory, "../../Binaries", Target.Platform == UnrealTargetPlatform.Win32 ? "Win32" : "Win64");
183+
try
184+
{
185+
string[] dllsToCopy =
186+
{
187+
"python3.dll",
188+
"python36.dll"
189+
};
190+
foreach (string dllToCopy in dllsToCopy)
191+
{
192+
// If the dll exist, make sure to set attributes so they are actually accessible
193+
if (File.Exists(Path.Combine(dllsDir, dllToCopy)))
194+
{
195+
File.SetAttributes(Path.Combine(dllsDir, dllToCopy), FileAttributes.Normal);
196+
}
197+
198+
File.Copy(Path.Combine(pythonHome, dllToCopy), Path.Combine(dllsDir, dllToCopy), true);
199+
File.SetAttributes(Path.Combine(dllsDir, dllToCopy), FileAttributes.Normal);
200+
}
201+
}
202+
catch(System.IO.IOException) { }
203+
catch(System.UnauthorizedAccessException)
204+
{
205+
System.Console.WriteLine("WARNING: Unable to copy python dlls, they are probably in use...");
206+
}
178207
}
179208
else if (Target.Platform == UnrealTargetPlatform.Mac)
180209
{
@@ -227,6 +256,15 @@ public UnrealEnginePython(TargetInfo Target)
227256

228257
}
229258

259+
private bool IsPathRelative(string Path)
260+
{
261+
bool IsRooted = Path.StartsWith("\\", System.StringComparison.Ordinal) || // Root of the current directory on Windows. Also covers "\\" for UNC or "network" paths.
262+
Path.StartsWith("/", System.StringComparison.Ordinal) || // Root of the current directory on Windows, root on UNIX-likes.
263+
// Also covers "\\", considering normalization replaces "\\" with "//".
264+
(Path.Length >= 2 && char.IsLetter(Path[0]) && Path[1] == ':'); // Starts with "<DriveLetter>:"
265+
return !IsRooted;
266+
}
267+
230268
private string DiscoverPythonPath(string[] knownPaths)
231269
{
232270
// insert the PYTHONHOME content as the first known path
@@ -237,16 +275,23 @@ private string DiscoverPythonPath(string[] knownPaths)
237275

238276
foreach (string path in paths)
239277
{
240-
string headerFile = Path.Combine(path, "include", "Python.h");
278+
string actualPath = path;
279+
280+
if (IsPathRelative(actualPath))
281+
{
282+
actualPath = Path.GetFullPath(Path.Combine(ModuleDirectory, actualPath));
283+
}
284+
285+
string headerFile = Path.Combine(actualPath, "include", "Python.h");
241286
if (File.Exists(headerFile))
242287
{
243-
return path;
288+
return actualPath;
244289
}
245290
// this is mainly useful for OSX
246-
headerFile = Path.Combine(path, "Headers", "Python.h");
291+
headerFile = Path.Combine(actualPath, "Headers", "Python.h");
247292
if (File.Exists(headerFile))
248293
{
249-
return path;
294+
return actualPath;
250295
}
251296
}
252297
return "";
@@ -337,7 +382,8 @@ private string GetWindowsPythonLibFile(string basePath)
337382
}
338383
if (!found)
339384
{
340-
System.Console.WriteLine("[WARNING] Your Python installation is not in the system PATH environment variable, very probably the plugin will fail to load");
385+
System.Console.WriteLine("[WARNING] Your Python installation is not in the system PATH environment variable.");
386+
System.Console.WriteLine("[WARNING] Ensure your python paths are set in GlobalConfig (DefaultEngine.ini) so the path can be corrected at runtime.");
341387
}
342388
// first try with python3
343389
for (int i = 9; i >= 0; i--)

UnrealEnginePython.uplugin

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"Modules": [
1818
{
1919
"Name": "UnrealEnginePython",
20-
"Type": "Runtime",
20+
"Type": "Editor",
2121
"LoadingPhase": "Default"
2222
},
2323
{

0 commit comments

Comments
 (0)