Skip to content
This repository was archived by the owner on Mar 25, 2025. It is now read-only.

Commit b488657

Browse files
committed
Merge branch 'pr/7'
2 parents cdeda03 + 9143890 commit b488657

File tree

175 files changed

+7503
-2910
lines changed

Some content is hidden

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

175 files changed

+7503
-2910
lines changed

README.md

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
12
# UnrealEnginePython
23
Embed Python in Unreal Engine 4
34

45
## Fork Notes
56

67
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.
78

9+
10+
Teaser: https://twitter.com/KNLstudio/status/932657812466843648
11+
812
# How and Why ?
913

1014
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).
@@ -25,7 +29,7 @@ Once the plugin is installed and enabled, you get access to the 'PythonConsole'
2529

2630
All of the exposed engine features are under the 'unreal_engine' virtual module (it is completely coded in c into the plugin, so do not expect to run 'import unreal_engine' from a standard python shell)
2731

28-
The currently supported Unreal Engine versions are 4.12, 4.13, 4.14, 4.15, 4.16, 4.17 and 4.18.
32+
The currently supported Unreal Engine versions are 4.12, 4.13, 4.14, 4.15, 4.16, 4.17, 4.18 and 4.19
2933

3034
We support official python.org releases as well as IntelPython and Anaconda distributions.
3135

@@ -488,6 +492,30 @@ To access the fields of a struct just call the fields() method.
488492

489493
A good example of struct usage is available here: https://github.com/20tab/UnrealEnginePython/blob/master/docs/Settings.md
490494

495+
As structs are passed by value, you need to pay attention when manipulating structs fields that are structs by themselves:
496+
497+
```python
498+
from unreal_engine.structs import TerrificStruct, DumbStruct
499+
500+
ts = TerrificStruct()
501+
ts.dumb = DumbStruct(Foo=17, Bar=22)
502+
503+
# will not modify the original DumbStruct but a copy of it !!!
504+
ts.dumb.Foo = 22
505+
```
506+
507+
You can eventually force structs to be passed by ref (extremely dangerous as the internal C pointer could be a dangling one) using the ref() function:
508+
509+
```python
510+
from unreal_engine.structs import TerrificStruct, DumbStruct
511+
512+
ts = TerrificStruct()
513+
ts.dumb = DumbStruct(Foo=17, Bar=22)
514+
515+
# ref() will return a pointer to a struct
516+
ts.ref().dumb.foo().Foo = 22
517+
```
518+
491519
The ue_site.py file
492520
-------------------
493521

@@ -809,15 +837,9 @@ Memory management
809837

810838
Dealing with 2 different GC's is really challenging.
811839

812-
PyActor, PyPawn and PythonComponent automatically DECREF's the mapped classes. This should be enough unless you hold references
813-
in the python modules themselves. As this would be a bad programming practice, the current approach should be safe enough.
814-
815-
In addition to this, every time a uobject has to return its UObject mapping, it checks for its validity and safety:
840+
Starting from release 20180226 a new memory management system has been added (FUnrealEnginePythonHouseKeeper, available here https://github.com/20tab/UnrealEnginePython/blob/master/Source/UnrealEnginePython/Public/PythonHouseKeeper.h). This new system is completely integrated with the Unreal Engine reflection-based GC and will hold track of each ue_PyUObject abd the related UObject to understand when a python object can be safely destroyed.
816841

817-
```c
818-
#define ue_py_check(py_u) if (!py_u->ue_object || !py_u->ue_object->IsValidLowLevel() || py_u->ue_object->IsPendingKillOrUnreachable())\
819-
return PyErr_Format(PyExc_Exception, "PyUObject is in invalid state")
820-
```
842+
The same system works for delegates, as well as Slate.
821843

822844

823845
Unit Testing

Source/PythonConsole/Private/PythonConsoleModule.cpp

Lines changed: 1 addition & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include "SDockTab.h"
99
#include "Editor/WorkspaceMenuStructure/Public/WorkspaceMenuStructure.h"
1010

11-
IMPLEMENT_MODULE( FPythonConsoleModule, PythonLog );
11+
IMPLEMENT_MODULE( FPythonConsoleModule, PythonConsole );
1212

1313
namespace PythonConsoleModule
1414
{
@@ -94,71 +94,4 @@ TSharedRef< SWidget > FPythonConsoleModule::MakeConsoleInputBox( TSharedPtr< SEd
9494
TSharedRef< SPythonConsoleInputBox > NewConsoleInputBox = SNew( SPythonConsoleInputBox );
9595
OutExposedEditableTextBox = NewConsoleInputBox->GetEditableTextBox();
9696
return NewConsoleInputBox;
97-
}
98-
99-
100-
void FPythonConsoleModule::TogglePythonConsoleForWindow( const TSharedRef< SWindow >& Window, const EPythonConsoleStyle::Type InStyle, const FPythonConsoleDelegates& PythonConsoleDelegates )
101-
{
102-
bool bShouldOpen = true;
103-
// Close an existing console box, if there is one
104-
TSharedPtr< SWidget > PinnedPythonConsole( PythonConsole.Pin() );
105-
if( PinnedPythonConsole.IsValid() )
106-
{
107-
// If the console is already open close it unless it is in a different window. In that case reopen it on that window
108-
bShouldOpen = false;
109-
TSharedPtr< SWindow > WindowForExistingConsole = FSlateApplication::Get().FindWidgetWindow(PinnedPythonConsole.ToSharedRef());
110-
if (WindowForExistingConsole.IsValid())
111-
{
112-
WindowForExistingConsole->RemoveOverlaySlot(PinnedPythonConsole.ToSharedRef());
113-
PythonConsole.Reset();
114-
}
115-
116-
if( WindowForExistingConsole != Window )
117-
{
118-
// Console is being opened on another window
119-
bShouldOpen = true;
120-
}
121-
}
122-
123-
TSharedPtr<SDockTab> ActiveTab = FGlobalTabmanager::Get()->GetActiveTab();
124-
if (ActiveTab.IsValid() && ActiveTab->GetLayoutIdentifier() == FTabId(PythonConsoleModule::PythonLogTabName))
125-
{
126-
FGlobalTabmanager::Get()->DrawAttention(ActiveTab.ToSharedRef());
127-
bShouldOpen = false;
128-
}
129-
130-
if( bShouldOpen )
131-
{
132-
const EPythonConsoleStyle::Type PythonConsoleStyle = InStyle;
133-
TSharedRef< SPythonConsole > PythonConsoleRef = SNew( SPythonConsole, PythonConsoleStyle, this, &PythonConsoleDelegates );
134-
PythonConsole = PythonConsoleRef;
135-
136-
const int32 MaximumZOrder = MAX_int32;
137-
Window->AddOverlaySlot( MaximumZOrder )
138-
.VAlign(VAlign_Bottom)
139-
.HAlign(HAlign_Center)
140-
.Padding( 10.0f )
141-
[
142-
PythonConsoleRef
143-
];
144-
145-
// Force keyboard focus
146-
PythonConsoleRef->SetFocusToEditableText();
147-
}
148-
}
149-
150-
151-
void FPythonConsoleModule::ClosePythonConsole()
152-
{
153-
TSharedPtr< SWidget > PinnedPythonConsole( PythonConsole.Pin() );
154-
155-
if( PinnedPythonConsole.IsValid() )
156-
{
157-
TSharedPtr< SWindow > WindowForExistingConsole = FSlateApplication::Get().FindWidgetWindow(PinnedPythonConsole.ToSharedRef());
158-
if (WindowForExistingConsole.IsValid())
159-
{
160-
WindowForExistingConsole->RemoveOverlaySlot( PinnedPythonConsole.ToSharedRef() );
161-
PythonConsole.Reset();
162-
}
163-
}
16497
}

Source/PythonConsole/Public/PythonConsoleModule.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
1+
// Copyright 1998-2018 20Tab S.r.l. All Rights Reserved.
22

33
#pragma once
44

@@ -33,12 +33,6 @@ class FPythonConsoleModule : public IModuleInterface
3333
output log DLL is unloaded on the fly. */
3434
virtual TSharedRef< SWidget > MakeConsoleInputBox( TSharedPtr< SEditableTextBox >& OutExposedEditableTextBox ) const;
3535

36-
/** Opens a debug console in the specified window, if not already open */
37-
virtual void TogglePythonConsoleForWindow( const TSharedRef< SWindow >& Window, const EPythonConsoleStyle::Type InStyle, const FPythonConsoleDelegates& PythonConsoleDelegates );
38-
39-
/** Closes the debug console for the specified window */
40-
virtual void ClosePythonConsole();
41-
4236

4337
private:
4438

Source/PythonEditor/Private/PYRichTextSyntaxHighlighterTextLayoutMarshaller.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,11 @@ void FPYRichTextSyntaxHighlighterTextLayoutMarshaller::ParseTokens(const FString
311311
FRunInfo RunInfo(TEXT("SyntaxHighlight.PY.Normal"));
312312
FTextBlockStyle TextBlockStyle = SyntaxTextStyle.NormalTextStyle;
313313

314+
#if ENGINE_MINOR_VERSION >= 18
314315
const bool bIsWhitespace = FString(TokenText).TrimEnd().IsEmpty();
316+
#else
317+
const bool bIsWhitespace = FString(TokenText).TrimTrailing().IsEmpty();
318+
#endif
315319
if(!bIsWhitespace)
316320
{
317321
bool bHasMatchedSyntax = false;

0 commit comments

Comments
 (0)