Skip to content

Commit 1baf91a

Browse files
author
Roberto De Ioris
committed
initial HUD api implementation
1 parent 32e523c commit 1baf91a

9 files changed

Lines changed: 204 additions & 4 deletions

File tree

‎Source/UnrealEnginePython/Private/PyActor.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ void APyActor::BeginPlay()
7575
if (!PythonDisableAutoBinding)
7676
ue_autobind_events_for_pyclass(py_uobject, py_actor_instance);
7777

78+
ue_bind_events_for_py_class_by_attribute(this, py_actor_instance);
7879

7980
if (!PyObject_HasAttrString(py_actor_instance, (char *)"begin_play"))
8081
return;

‎Source/UnrealEnginePython/Private/PyCharacter.cpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ void APyCharacter::BeginPlay()
7777
if (!PythonDisableAutoBinding)
7878
ue_autobind_events_for_pyclass(py_uobject, py_character_instance);
7979

80+
ue_bind_events_for_py_class_by_attribute(this, py_character_instance);
81+
8082
if (!PyObject_HasAttrString(py_character_instance, (char *)"begin_play")) {
8183
return;
8284
}

‎Source/UnrealEnginePython/Private/PyPawn.cpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ void APyPawn::BeginPlay()
7575
if (!PythonDisableAutoBinding)
7676
ue_autobind_events_for_pyclass(py_uobject, py_pawn_instance);
7777

78+
ue_bind_events_for_py_class_by_attribute(this, py_pawn_instance);
79+
7880
if (!PyObject_HasAttrString(py_pawn_instance, (char *)"begin_play"))
7981
return;
8082

‎Source/UnrealEnginePython/Private/PythonComponent.cpp‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,18 @@ void UPythonComponent::InitializePythonComponent() {
7575
if (!PythonDisableAutoBinding)
7676
ue_autobind_events_for_pyclass(py_uobject, py_component_instance);
7777

78+
ue_bind_events_for_py_class_by_attribute(this, py_component_instance);
79+
7880
if (!PyObject_HasAttrString(py_component_instance, (char *)"begin_play")) {
7981
return;
8082
}
8183

8284
PyObject *bp_ret = PyObject_CallMethod(py_component_instance, (char *)"begin_play", NULL);
8385
if (!bp_ret) {
8486
unreal_engine_py_log_error();
85-
return;
8687
}
87-
Py_DECREF(bp_ret);
88+
Py_XDECREF(bp_ret);
89+
8890
}
8991

9092
// Called when the game starts
@@ -451,7 +453,7 @@ void UPythonComponent::CallPythonComponentMethodStringArray(FString method_name,
451453
}
452454

453455
Py_DECREF(ret);
454-
}
456+
}
455457

456458

457459
UPythonComponent::~UPythonComponent()

‎Source/UnrealEnginePython/Private/UEPyModule.cpp‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "UObject/UEPyMaterial.h"
3131
#include "UObject/UEPyPawn.h"
3232
#include "UObject/UEPyController.h"
33+
#include "UObject/UEPyHUD.h"
3334

3435

3536

@@ -478,6 +479,11 @@ static PyMethodDef ue_PyUObject_methods[] = {
478479
{ "bind_pressed_key", (PyCFunction)py_ue_bind_pressed_key, METH_VARARGS, "" },
479480
{ "bind_released_key", (PyCFunction)py_ue_bind_released_key, METH_VARARGS, "" },
480481

482+
// HUD
483+
{ "hud_draw_2d_line", (PyCFunction)py_ue_hud_draw_2d_line, METH_VARARGS, "" },
484+
{ "hud_draw_line", (PyCFunction)py_ue_hud_draw_line, METH_VARARGS, "" },
485+
{ "hud_draw_texture", (PyCFunction)py_ue_hud_draw_texture, METH_VARARGS, "" },
486+
481487

482488
// Movements
483489

@@ -1912,6 +1918,77 @@ ue_PyUObject *ue_is_pyuobject(PyObject *obj) {
19121918
return (ue_PyUObject *)obj;
19131919
}
19141920

1921+
void ue_bind_events_for_py_class_by_attribute(UObject *u_obj, PyObject *py_class) {
1922+
// attempt to register events
1923+
PyObject *attrs = PyObject_Dir(py_class);
1924+
if (!attrs)
1925+
return;
1926+
1927+
AActor *actor = Cast<AActor>(u_obj);
1928+
if (!actor) {
1929+
UActorComponent *component = Cast<UActorComponent>(u_obj);
1930+
if (!component)
1931+
return;
1932+
actor = component->GetOwner();
1933+
}
1934+
1935+
Py_ssize_t len = PyList_Size(attrs);
1936+
for (Py_ssize_t i = 0; i < len; i++) {
1937+
PyObject *py_attr_name = PyList_GetItem(attrs, i);
1938+
if (!py_attr_name || !PyUnicodeOrString_Check(py_attr_name))
1939+
continue;
1940+
PyObject *item = PyObject_GetAttrString(py_class, PyUnicode_AsUTF8(py_attr_name));
1941+
if (item && PyCallable_Check(item)) {
1942+
// check for ue_event signature
1943+
PyObject *event_signature = PyObject_GetAttrString(item, (char*)"ue_event");
1944+
if (event_signature) {
1945+
if (PyUnicode_Check(event_signature)) {
1946+
FString event_name = FString(UTF8_TO_TCHAR(PyUnicode_AsUTF8(event_signature)));
1947+
TArray<FString> parts;
1948+
int n = event_name.ParseIntoArray(parts, UTF8_TO_TCHAR("."));
1949+
if (n < 1 || n > 2) {
1950+
PyErr_SetString(PyExc_Exception, "invalid ue_event syntax, must be the name of an event or ComponentName.Event");
1951+
unreal_engine_py_log_error();
1952+
}
1953+
else {
1954+
if (n == 1) {
1955+
if (!ue_bind_pyevent(ue_get_python_wrapper(actor), parts[0], item, true)) {
1956+
unreal_engine_py_log_error();
1957+
}
1958+
}
1959+
else {
1960+
bool found = false;
1961+
for (UActorComponent *component : actor->GetComponents()) {
1962+
if (component->GetFName() == FName(*parts[0])) {
1963+
if (!ue_bind_pyevent(ue_get_python_wrapper(component), parts[1], item, true)) {
1964+
unreal_engine_py_log_error();
1965+
}
1966+
found = true;
1967+
break;
1968+
}
1969+
}
1970+
1971+
if (!found) {
1972+
PyErr_SetString(PyExc_Exception, "unable to find component by name");
1973+
unreal_engine_py_log_error();
1974+
}
1975+
}
1976+
}
1977+
}
1978+
else {
1979+
PyErr_SetString(PyExc_Exception, "ue_event attribute must be a string");
1980+
unreal_engine_py_log_error();
1981+
}
1982+
}
1983+
Py_XDECREF(event_signature);
1984+
}
1985+
Py_XDECREF(item);
1986+
}
1987+
Py_DECREF(attrs);
1988+
1989+
PyErr_Clear();
1990+
}
1991+
19151992
// automatically bind events based on class methods names
19161993
void ue_autobind_events_for_pyclass(ue_PyUObject *u_obj, PyObject *py_class) {
19171994
PyObject *attrs = PyObject_Dir(py_class);

‎Source/UnrealEnginePython/Private/UEPyModule.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ PyObject *ue_py_convert_property(UProperty *, uint8 *);
2929
bool ue_py_convert_pyobject(PyObject *, UProperty *, uint8 *);
3030
ue_PyUObject *ue_is_pyuobject(PyObject *);
3131

32+
void ue_bind_events_for_py_class_by_attribute(UObject *, PyObject *);
33+
3234
void ue_autobind_events_for_pyclass(ue_PyUObject *, PyObject *);
3335
PyObject *ue_bind_pyevent(ue_PyUObject *, FString, PyObject *, bool);
3436

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#include "UnrealEnginePythonPrivatePCH.h"
2+
#include "Runtime/Engine/Classes/GameFramework/HUD.h"
3+
4+
PyObject *py_ue_hud_draw_2d_line(ue_PyUObject *self, PyObject * args) {
5+
6+
ue_py_check(self);
7+
8+
int x1, y1, x2, y2;
9+
PyObject *py_fcolor;
10+
11+
if (!PyArg_ParseTuple(args, "iiiiO:hud_draw_2d_line", &x1, &y1, &x2, &y2, &py_fcolor)) {
12+
return nullptr;
13+
}
14+
15+
AHUD *hud = ue_py_check_type<AHUD>(self);
16+
if (!hud)
17+
return PyErr_Format(PyExc_Exception, "UObject is not a AHUD.");
18+
19+
ue_PyFColor *fcolor = py_ue_is_fcolor(py_fcolor);
20+
if (!fcolor)
21+
return PyErr_Format(PyExc_Exception, "argument is not a FColor.");
22+
23+
hud->Draw2DLine(x1, y1, x2, y2, fcolor->color);
24+
25+
Py_RETURN_NONE;
26+
}
27+
28+
PyObject *py_ue_hud_draw_line(ue_PyUObject *self, PyObject * args) {
29+
30+
ue_py_check(self);
31+
32+
float x1, y1, x2, y2;
33+
PyObject *py_fcolor;
34+
float thickness;
35+
36+
if (!PyArg_ParseTuple(args, "ffffOf:hud_draw_line", &x1, &y1, &x2, &y2, &py_fcolor, &thickness)) {
37+
return nullptr;
38+
}
39+
40+
AHUD *hud = ue_py_check_type<AHUD>(self);
41+
if (!hud)
42+
return PyErr_Format(PyExc_Exception, "UObject is not a AHUD.");
43+
44+
ue_PyFColor *fcolor = py_ue_is_fcolor(py_fcolor);
45+
if (!fcolor)
46+
return PyErr_Format(PyExc_Exception, "argument is not a FColor.");
47+
48+
hud->DrawLine(x1, y1, x2, y2, fcolor->color, thickness);
49+
50+
Py_RETURN_NONE;
51+
}
52+
53+
PyObject *py_ue_hud_draw_texture(ue_PyUObject *self, PyObject * args) {
54+
55+
ue_py_check(self);
56+
57+
PyObject *py_texture;
58+
float x, y, w, h;
59+
float u = 0, v = 0, uw = 1, vh = 1;
60+
PyObject *py_flinear_color = nullptr;
61+
int blend_mode = EBlendMode::BLEND_Translucent;
62+
float scale = 1;
63+
PyObject *py_scale_position = nullptr;
64+
float rotation = 0;
65+
float pivot_rot_x = 0, pivot_rot_y = 0;
66+
67+
68+
if (!PyArg_ParseTuple(args, "Offff|ffffOifOf(ff):hud_draw_texture", &py_texture, &x, &y, &w, &h, &u, &v, &uw, &vh, &py_flinear_color, &blend_mode, &scale, &py_scale_position, &rotation, &pivot_rot_x, &pivot_rot_y)) {
69+
return nullptr;
70+
}
71+
72+
AHUD *hud = ue_py_check_type<AHUD>(self);
73+
if (!hud)
74+
return PyErr_Format(PyExc_Exception, "UObject is not a AHUD.");
75+
76+
UTexture *texture = ue_py_check_type<UTexture>(py_texture);
77+
if (!texture)
78+
return PyErr_Format(PyExc_Exception, "argument is not a UTexture.");
79+
80+
FLinearColor tint = FLinearColor::White;
81+
82+
if (py_flinear_color) {
83+
ue_PyFLinearColor *flinear_color = py_ue_is_flinearcolor(py_flinear_color);
84+
if (!flinear_color)
85+
return PyErr_Format(PyExc_Exception, "argument is not a FLinearColor.");
86+
tint = flinear_color->color;
87+
}
88+
89+
bool scale_position = false;
90+
if (py_scale_position && PyObject_IsTrue(py_scale_position))
91+
scale_position = true;
92+
93+
hud->DrawTexture(texture, x, y, w, h, u, v, uw, vh, tint, (EBlendMode)blend_mode, scale, scale_position, rotation, FVector2D(pivot_rot_x, pivot_rot_y));
94+
95+
Py_RETURN_NONE;
96+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#pragma once
2+
3+
4+
5+
#include "UnrealEnginePython.h"
6+
7+
PyObject *py_ue_hud_draw_2d_line(ue_PyUObject *self, PyObject * args);
8+
PyObject *py_ue_hud_draw_line(ue_PyUObject *self, PyObject * args);
9+
PyObject *py_ue_hud_draw_texture(ue_PyUObject *self, PyObject * args);

‎Source/UnrealEnginePython/Private/UnrealEnginePython.cpp‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,16 @@ static void setup_stdout_stderr() {
111111
" def isatty(self):\n"
112112
" return False\n"
113113
"sys.stdout = UnrealEngineOutput(unreal_engine.log)\n"
114-
"sys.stderr = UnrealEngineOutput(unreal_engine.log_error)\n";
114+
"sys.stderr = UnrealEngineOutput(unreal_engine.log_error)\n"
115+
"\n"
116+
"class event:\n"
117+
" def __init__(self, event_signature):\n"
118+
" self.event_signature = event_signature\n"
119+
" def __call__(self, f):\n"
120+
" f.ue_event = self.event_signature\n"
121+
" return f\n"
122+
"\n"
123+
"unreal_engine.event = event";
115124
PyRun_SimpleString(code);
116125
}
117126

0 commit comments

Comments
 (0)