Skip to content

Commit

Permalink
UPBGE: Add component scritp generation.
Browse files Browse the repository at this point in the history
To ease the definition of a component a button named "Create Component" is added.
This button ask for a path module.Class and generates a script named module.py
with a component class Class inside.
This template class contains a start and update function commented
and a definition block before the class for global game engine variable.

If the file already exists an error is raised.

The previous button named Add Component is now renamed Register Component.
  • Loading branch information
panzergame committed May 31, 2018
1 parent 2c93233 commit fba7bd3
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 14 deletions.
7 changes: 4 additions & 3 deletions release/scripts/startup/bl_ui/space_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@ def draw(self, context):
st = context.space_data

row = layout.row()
row.operator("logic.add_python_component", text="Add Component", icon="ZOOMIN")
row.operator("logic.python_component_register", text="Register Component", icon="ZOOMIN")
row.operator("logic.python_component_create", text="Create Component", icon="ZOOMIN")

for i, c in enumerate(game.components):
box = layout.box()
row = box.row()
row.prop(c, "name", text="")
row.operator("logic.component_reload", text="", icon='RECOVER_LAST').index = i
row.operator("logic.component_remove", text="", icon='X').index = i
row.operator("logic.python_component_reload", text="", icon='RECOVER_LAST').index = i
row.operator("logic.python_component_remove", text="", icon='X').index = i

for prop in c.properties:
row = box.row()
Expand Down
24 changes: 24 additions & 0 deletions release/scripts/templates_py/python_component.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import bge
from collections import OrderedDict

if not hasattr(bge, "__component__"):
# Put shared definitions here executed only in game engine.
# e.g:
# scene = bge.logic.getCurrentScene()
pass

class %Name%(bge.types.KX_PythonComponent):
# Put your arguments here of the format ("key", default_value).
# These values are exposed to the UI.
args = OrderedDict([
])

def start(self, args):
# Put your initialization code here, args stores the values from the UI.
# self.object is the owner object of this component.
pass

def update(self):
# Put your code executed every logic step here.
# self.object is the owner object of this component.
pass
1 change: 1 addition & 0 deletions source/blender/blenkernel/BKE_python_component.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ extern "C" {
#endif

struct PythonComponent *BKE_python_component_new(char *import, struct ReportList *reports, struct bContext *context);
struct PythonComponent *BKE_python_component_create_file(char *import, struct ReportList *reports, struct bContext *context);
void BKE_python_component_reload(struct PythonComponent *pc, struct ReportList *reports, struct bContext *context);
void BKE_python_component_copy_list(struct ListBase *lbn, const struct ListBase *lbo);
void BKE_python_component_free(struct PythonComponent *pc);
Expand Down
72 changes: 72 additions & 0 deletions source/blender/blenkernel/intern/python_component.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_path_util.h"
#include "BLI_fileops.h"
#include "MEM_guardedalloc.h"

#include "BKE_python_component.h"
#include "BKE_report.h"
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_text.h"
#include "BKE_appdir.h"

#include "RNA_types.h"

Expand Down Expand Up @@ -505,6 +508,75 @@ PythonComponent *BKE_python_component_new(char *import, ReportList *reports, bCo
return pc;
}

PythonComponent *BKE_python_component_create_file(char *import, ReportList *reports, bContext *context)
{
char *classname;
char *modulename;
char filename[FILE_MAX];
char respath[FILE_MAX];
size_t filesize = 0;
unsigned char *orgfilecontent;
char *filecontent;
Main *maggie = CTX_data_main(context);
struct Text *text;
PythonComponent *pc;

// Don't bother with an empty string
if (strcmp(import, "") == 0) {
BKE_report(reports, RPT_ERROR_INVALID_INPUT, "No component was specified.");
return NULL;
}

// Extract the module name and the class name.
modulename = strtok(import, ".");
classname = strtok(NULL, ".");

if (!classname) {
BKE_report(reports, RPT_ERROR_INVALID_INPUT, "No component class name was specified.");
return NULL;
}

strcpy(filename, modulename);
BLI_ensure_extension(filename, FILE_MAX, ".py");

if (BLI_findstring(&maggie->text, filename, offsetof(ID, name) + 2)) {
BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "File %s already exists.", filename);
return NULL;
}

text = BKE_text_add(maggie, filename);

BLI_strncpy(respath, BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, "templates_py"), sizeof(respath));
BLI_path_append(respath, sizeof(respath), "python_component.py");

orgfilecontent = BLI_file_read_text_as_mem(respath, 0, &filesize);
orgfilecontent[filesize] = '\0';

filecontent = BLI_str_replaceN((char *)orgfilecontent, "%Name%", classname);

BKE_text_write(text, (char *)filecontent);

MEM_freeN(filecontent);

pc = MEM_callocN(sizeof(PythonComponent), "PythonComponent");

// Copy module and class names.
strcpy(pc->module, modulename);
if (classname) {
strcpy(pc->name, classname);
}

// Try load the component.
if (!load_component(pc, reports, CTX_data_main(context))) {
BKE_python_component_free(pc);
return NULL;
}

BKE_reportf(reports, RPT_INFO, "File %s created.", filename);

return pc;
}

void BKE_python_component_reload(PythonComponent *pc, ReportList *reports, bContext *context)
{
load_component(pc, reports, CTX_data_main(context));
Expand Down
65 changes: 54 additions & 11 deletions source/blender/editors/space_logic/logic_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ static void LOGIC_OT_view_all(wmOperatorType *ot)
}

/* Component operators */
static int component_add_exec(bContext *C, wmOperator *op)
static int component_register_exec(bContext *C, wmOperator *op)
{
PythonComponent *pycomp;
Object *ob = CTX_data_active_object(C);
Expand Down Expand Up @@ -770,20 +770,62 @@ static int component_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}

static int component_create_exec(bContext *C, wmOperator *op)
{
PythonComponent *pycomp;
Object *ob = CTX_data_active_object(C);
char import[MAX_NAME];

if (!ob) {
return OPERATOR_CANCELLED;
}

RNA_string_get(op->ptr, "component_name", import);
pycomp = BKE_python_component_create_file(import, op->reports, C);

if(!pycomp) {
return OPERATOR_CANCELLED;
}

BLI_addtail(&ob->components, pycomp);
WM_event_add_notifier(C, NC_LOGIC, NULL);

return OPERATOR_FINISHED;
}

static int component_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
/* Better for user feedback. */
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, UI_UNIT_Y);
}

static void LOGIC_OT_component_add(wmOperatorType *ot)
static void LOGIC_OT_python_component_register(wmOperatorType *ot)
{
ot->name = "Add Python Component";
ot->idname = "LOGIC_OT_add_python_component";
ot->idname = "LOGIC_OT_python_component_register";
ot->description = "Add a python component to the selected object";

/* api callbacks */
ot->exec = component_add_exec;
ot->exec = component_register_exec;
ot->invoke = component_new_invoke;
ot->poll = ED_operator_object_active_editable;

/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;

PropertyRNA *parm;
parm = RNA_def_string(ot->srna, "component_name", "module.Component", 64, "Component", "The component class name with module (module.ComponentName)");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}

static void LOGIC_OT_python_component_create(wmOperatorType *ot)
{
ot->name = "Create Python Component";
ot->idname = "LOGIC_OT_python_component_create";
ot->description = "Create a python component to the selected object";

/* api callbacks */
ot->exec = component_create_exec;
ot->invoke = component_new_invoke;
ot->poll = ED_operator_object_active_editable;

Expand Down Expand Up @@ -819,12 +861,12 @@ static int component_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}

static void LOGIC_OT_component_remove(wmOperatorType *ot)
static void LOGIC_OT_python_component_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Component";
ot->description = "Remove Component";
ot->idname = "LOGIC_OT_component_remove";
ot->idname = "LOGIC_OT_python_component_remove";

/* api callbacks */
ot->exec = component_remove_exec;
Expand Down Expand Up @@ -871,12 +913,12 @@ static int component_reload_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}

static void LOGIC_OT_component_reload(wmOperatorType *ot)
static void LOGIC_OT_python_component_reload(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Reload Component";
ot->description = "Reload Component";
ot->idname = "LOGIC_OT_component_reload";
ot->idname = "LOGIC_OT_python_component_reload";

/* api callbacks */
ot->exec = component_reload_exec;
Expand All @@ -903,9 +945,10 @@ void ED_operatortypes_logic(void)
WM_operatortype_append(LOGIC_OT_actuator_add);
WM_operatortype_append(LOGIC_OT_actuator_move);

WM_operatortype_append(LOGIC_OT_component_add);
WM_operatortype_append(LOGIC_OT_component_remove);
WM_operatortype_append(LOGIC_OT_component_reload);
WM_operatortype_append(LOGIC_OT_python_component_register);
WM_operatortype_append(LOGIC_OT_python_component_create);
WM_operatortype_append(LOGIC_OT_python_component_remove);
WM_operatortype_append(LOGIC_OT_python_component_reload);

WM_operatortype_append(LOGIC_OT_view_all);
}

0 comments on commit fba7bd3

Please sign in to comment.