diff --git a/release/scripts/startup/bl_ui/space_logic.py b/release/scripts/startup/bl_ui/space_logic.py index 65cf588e898c..88237a6884b2 100644 --- a/release/scripts/startup/bl_ui/space_logic.py +++ b/release/scripts/startup/bl_ui/space_logic.py @@ -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() diff --git a/release/scripts/templates_py/python_component.py b/release/scripts/templates_py/python_component.py new file mode 100644 index 000000000000..23d4ad061077 --- /dev/null +++ b/release/scripts/templates_py/python_component.py @@ -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 diff --git a/source/blender/blenkernel/BKE_python_component.h b/source/blender/blenkernel/BKE_python_component.h index adba141e3662..6381d5ec4bb8 100644 --- a/source/blender/blenkernel/BKE_python_component.h +++ b/source/blender/blenkernel/BKE_python_component.h @@ -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); diff --git a/source/blender/blenkernel/intern/python_component.c b/source/blender/blenkernel/intern/python_component.c index 0913ff88ae19..ec771cc95f57 100644 --- a/source/blender/blenkernel/intern/python_component.c +++ b/source/blender/blenkernel/intern/python_component.c @@ -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" @@ -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)); diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c index beabdba71325..bf990f96fe12 100644 --- a/source/blender/editors/space_logic/logic_ops.c +++ b/source/blender/editors/space_logic/logic_ops.c @@ -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); @@ -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; @@ -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; @@ -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; @@ -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); }