Skip to content

Commit 4aa41ea

Browse files
committed
Merge remote-tracking branch 'refs/remotes/origin/update-merge' into pr/1
# Conflicts: # Source/UnrealEnginePython/Private/UEPyModule.cpp # Source/UnrealEnginePython/Private/UnrealEnginePython.cpp # Source/UnrealEnginePython/UnrealEnginePython.Build.cs
2 parents 571dd79 + 7f9a264 commit 4aa41ea

211 files changed

Lines changed: 49344 additions & 26 deletions

File tree

Some content is hidden

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

‎.gitignore‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,3 @@ ENV/
8989
.ropeproject
9090

9191
Binaries/
92-
python35/
93-
python27/

‎Content/Scripts/debugtest.py‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#import debugtest
2+
#import imp
3+
#imp.reload(debugtest)
4+
5+
#Testing script for various writing setups
6+
7+
#import redirect_print
8+
import unreal_engine as ue
9+
import time
10+
import sys
11+
import upythread as ut
12+
from threading import Thread
13+
14+
#imp.reload(redirect_print)
15+
16+
def onfinished(args=""):
17+
ue.log(args)
18+
ue.log('finished with: <' + str(args) + '>')
19+
20+
def onfinishedempty():
21+
ue.log('finished')
22+
23+
def testaction(args=""):
24+
ue.log('starting action with <' + str(args) + '>')
25+
#onfinished()
26+
27+
#pretend you take time to finish
28+
time.sleep(1)
29+
ue.log('wait complete')
30+
ue.run_on_gt(onfinished, args)
31+
ue.run_on_gt(onfinishedempty)
32+
33+
#the test function
34+
def test(params=None):
35+
ue.log(type(params))
36+
ue.log('starting test')
37+
if not params:
38+
t = Thread(target=testaction)
39+
else:
40+
t = Thread(target=testaction, args=(params,))
41+
t.start()
42+
43+
def yolo():
44+
ue.log('yolo!')
45+
46+
def yolodone():
47+
ue.log('yolo done!')
48+
49+
#test simple fire and forget
50+
def test2():
51+
ut.run_on_bt(yolo)
52+
53+
#Test with callback
54+
def test3():
55+
ut.run_on_bt(yolo, yolodone)
56+
57+
58+
#progress callback example functions
59+
def progresscallback(progress):
60+
ue.log('at ' + str(progress))
61+
62+
def doLongTask():
63+
ue.log('started my task')
64+
65+
for x in range(1,10):
66+
time.sleep(0.5)
67+
ue.run_on_gt(progresscallback, x)
68+
69+
#test basic progress bar
70+
def testp():
71+
ut.run_on_bt(doLongTask)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import sys
2+
import unreal_engine as ue
3+
4+
class Redirector(object):
5+
def __init__(self):
6+
pass
7+
8+
def write(self, message):
9+
ue.log(message)
10+
11+
def flush(self):
12+
sys.stdout.flush()
13+
14+
def splitlines(self):
15+
sys.stdout.splitlines()
16+
17+
sys.stdout = Redirector()
18+
sys.stderr = Redirector()

‎Content/Scripts/upycmd.py‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#ue.exec('pip2.py')
2+
3+
import subprocess
4+
import sys
5+
import unreal_engine as ue
6+
import _thread as thread
7+
8+
#ue.log(sys.path)
9+
10+
#define some convenience paths
11+
def PythonHomePath():
12+
for path in sys.path:
13+
if ('UnrealEnginePython' in path and
14+
path.endswith('Binaries/Win64')):
15+
return path
16+
17+
#return sys.path[1]
18+
return "not found"
19+
20+
def PythonHomeScriptsPath():
21+
home = PythonHomePath()
22+
return home + "/Scripts"
23+
24+
_PythonHomePath = PythonHomePath()
25+
26+
def FolderCommand(folder):
27+
#replace backslashes
28+
folder = folder.replace('/','\\')
29+
30+
changefolder = "cd /d \"" + folder + "\" & "
31+
return changefolder
32+
33+
#main public function
34+
def run(process, path=_PythonHomePath, verbose=True):
35+
#todo: change folder
36+
fullcommand = FolderCommand(path) + process
37+
if verbose:
38+
ue.log("Started cmd <" + fullcommand + ">")
39+
stdoutdata = subprocess.getstatusoutput(fullcommand)
40+
if verbose:
41+
ue.log("cmd Result: ")
42+
ue.log(stdoutdata[1])
43+
return stdoutdata[1] #return the data for dependent functions
44+
45+
#convenience wrappers
46+
def dir(path=_PythonHomePath):
47+
run('dir', path)
48+
49+
def ls(path=_PythonHomePath):
50+
dir(path)
51+
52+
def md(folder, path=_PythonHomePath):
53+
run('md ' + folder, path)
54+
55+
def mkdir(folder, path=_PythonHomePath):
56+
md(folder, path)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#Imports upymodule.json modules and resolves dependencies
2+
3+
#example test
4+
#import upymodule_importer as upym
5+
#upym.parseJson("D:/Users/Admin/Documents/GitHub/tensorflow-ue4-mnist-example/Plugins/tensorflow-ue4/Content/Scripts/upymodule.json")
6+
7+
import upypip as pip
8+
import sys
9+
import unreal_engine as ue
10+
import json
11+
12+
import upypip
13+
pip = upypip.pip
14+
15+
#parse upymodule.json from path and install dependencies if missing
16+
def parseJson(packagePath):
17+
18+
try:
19+
with open(packagePath) as data_file:
20+
#TODO: catch file not found error
21+
package = json.load(data_file)
22+
ue.log('Resolving upymodule dependencies for ' + package['name'])
23+
pythonModules = package['pythonModules']
24+
25+
#loop over all the modules, check if we have them installed
26+
for module in pythonModules:
27+
version = pythonModules[module]
28+
29+
ue.log(module + " " + version + " installed? " + str(pip.isInstalled(module)))
30+
if not pip.isInstalled(module, version):
31+
ue.log('Dependency not installed, fetching via pip...')
32+
pip.install(module + '==' + version)
33+
34+
dependencyNoun = 'dependencies'
35+
if len(pythonModules) == 1:
36+
dependencyNoun = 'dependency'
37+
38+
ue.log(str(len(pythonModules)) + ' ' + package['name'] + ' upymodule ' + dependencyNoun + ' resolved (if installation in progress, more async output will stream)')
39+
except:
40+
e = sys.exc_info()[0]
41+
ue.log('upymodule.json error: ' + str(e))
42+

‎Content/Scripts/upypip.py‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import upycmd as cmd
2+
import sys
3+
from threading import Thread
4+
from distutils.version import LooseVersion
5+
6+
7+
class PipInstall:
8+
#global modules class static variable
9+
modules = None
10+
11+
def __init__(self):
12+
return None
13+
14+
#blocking actions, should be run on off-thread
15+
def pipModuleAction(self, command, args, verbose=True):
16+
return cmd.run('pip ' + command + ' ' + args, cmd.PythonHomeScriptsPath(), verbose)
17+
18+
#use this if you need to work on the resulting list to query current dependencies
19+
def listDict(self, verbose=True):
20+
#get the list of all the modules from pip
21+
resultString = self.pipModuleAction('list','--format=columns', verbose)
22+
23+
#convert to lines for parsing
24+
lines = resultString.split("\n")
25+
resultDict = {}
26+
27+
#exclude first two lines, then pair up the results
28+
for i in range(2,len(lines)):
29+
splitEntry = lines[i].split() #split and ignore all whitespace
30+
resultDict[splitEntry[0]] = splitEntry[1]
31+
32+
#save list to cache
33+
PipInstall.modules = resultDict
34+
return resultDict
35+
36+
def isDesiredVersionSufficient(self, desired, current):
37+
return LooseVersion(desired) <= LooseVersion(current)
38+
39+
def isInstalled(self, module, desiredVersion=None):
40+
if PipInstall.modules == None:
41+
PipInstall.modules = self.listDict(False)
42+
if module in PipInstall.modules:
43+
#did we specify a version? ensure we've installed that version at least
44+
if desiredVersion:
45+
#print('current version: ' + str(PipInstall.modules[module]))
46+
#print('desired version: ' + str(desiredVersion))
47+
return self.isDesiredVersionSufficient(desiredVersion, PipInstall.modules[module])
48+
else:
49+
return True
50+
else:
51+
return False
52+
53+
#Threaded actions
54+
def install(self, module):
55+
PipInstall.modules = None #our cache is no longer valid
56+
action = self.pipModuleAction
57+
t = Thread(target=action, args=('install',module,))
58+
t.start()
59+
60+
def uninstall(self, module):
61+
PipInstall.modules = None #our cache is no longer valid
62+
action = self.pipModuleAction
63+
t = Thread(target=action, args=('uninstall -y',module,))
64+
t.start()
65+
66+
def list(self):
67+
action = self.listDict
68+
t = Thread(target=action)
69+
t.start()
70+
71+
pip = PipInstall()

‎Content/Scripts/upythread.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import unreal_engine as ue
2+
from threading import Thread
3+
4+
#internal, don't call directly
5+
def backgroundAction(args=None):
6+
#ue.log(args)
7+
action = args[0]
8+
if len(args) >1:
9+
callback = args[1]
10+
11+
#call the blocking action
12+
action()
13+
14+
#return the result if we have a callback
15+
if callback:
16+
ue.run_on_gt(callback)
17+
18+
#run function on a background thread, optional callback when complete on game thread
19+
def run_on_bt(actionfunction, callback=None):
20+
t = Thread(target=backgroundAction, args=([actionfunction, callback],))
21+
t.start()

‎README.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# UnrealEnginePython
22
Embed Python in Unreal Engine 4
33

4+
## Fork Notes
5+
6+
This fork is meant to encapsulate python + pip + scripts fully in the plugin and to allow dependency plugins to be built on top of the python plugin. Specifically it means adding automatic pip dependency resolution and automatic sys.path additions such that the resulting two plugins can be fully drag and dropped into a new project.
7+
48
# How and Why ?
59

610
This is a plugin embedding a whole Python VM (versions 3.x [the default and suggested one] and 2.7) In Unreal Engine 4 (both the editor and runtime).

‎Source/PythonConsole/Private/PythonConsoleModule.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "PythonConsolePrivatePCH.h"
44
#include "SPythonConsole.h"
55
#include "SPythonLog.h"
6+
#include "TabManager.h"
67
#include "Editor/WorkspaceMenuStructure/Public/WorkspaceMenuStructureModule.h"
78
#include "SDockTab.h"
89
#include "Editor/WorkspaceMenuStructure/Public/WorkspaceMenuStructure.h"

0 commit comments

Comments
 (0)