diff --git a/blender/arm/__init__.py b/blender/arm/__init__.py index e69de29b..eb89c678 100755 --- a/blender/arm/__init__.py +++ b/blender/arm/__init__.py @@ -0,0 +1,26 @@ +import importlib +import types + +# This gets cleared if this package/the __init__ module is reloaded +_module_cache: dict[str, types.ModuleType] = {} + + +def reload_module(module: types.ModuleType) -> types.ModuleType: + """Wrapper around importlib.reload() to make sure no module is + reloaded twice. + + Make sure to call this function in the same order in which the + modules are imported to make sure that the reloading respects the + module dependencies. Otherwise modules could depend on other modules + that are not yet reloaded. + + If you import classes or functions from a module, make sure to + re-import them after the module is reloaded. + """ + mod = _module_cache.get(module.__name__, None) + + if mod is None: + mod = importlib.reload(module) + _module_cache[module.__name__] = mod + + return mod diff --git a/blender/arm/api.py b/blender/arm/api.py index ed53a290..d66c9b8c 100644 --- a/blender/arm/api.py +++ b/blender/arm/api.py @@ -4,7 +4,14 @@ from bpy.types import Material, UILayout from arm.material.shader import ShaderContext -drivers: Dict[str, Dict] = dict() +if "DO_RELOAD_MODULE" in locals(): + import arm + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import ShaderContext +else: + drivers: Dict[str, Dict] = dict() + + DO_RELOAD_MODULE = True def add_driver(driver_name: str, diff --git a/blender/arm/assets.py b/blender/arm/assets.py index b0c1bc97..1882818d 100755 --- a/blender/arm/assets.py +++ b/blender/arm/assets.py @@ -6,6 +6,12 @@ import bpy import arm.log as log import arm.utils +if "DO_RELOAD_MODULE" in locals(): + log = arm.reload_module(log) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + assets = [] reserved_names = ['return.'] khafile_params = [] diff --git a/blender/arm/exporter.py b/blender/arm/exporter.py index 10d23e13..92d28a2a 100755 --- a/blender/arm/exporter.py +++ b/blender/arm/exporter.py @@ -32,7 +32,19 @@ import arm.material.mat_batch as mat_batch import arm.utils import arm.profiler -import arm.log as log +if "DO_RELOAD_MODULE" in locals(): + assets = arm.reload_module(assets) + exporter_opt = arm.reload_module(exporter_opt) + log = arm.reload_module(log) + make_renderpath = arm.reload_module(make_renderpath) + cycles = arm.reload_module(cycles) + make_material = arm.reload_module(make_material) + mat_batch = arm.reload_module(mat_batch) + arm.utils = arm.reload_module(arm.utils) + arm.profiler = arm.reload_module(arm.profiler) +else: + DO_RELOAD_MODULE = True + @unique class NodeType(Enum): diff --git a/blender/arm/exporter_opt.py b/blender/arm/exporter_opt.py index 60c64ae6..520a83a1 100644 --- a/blender/arm/exporter_opt.py +++ b/blender/arm/exporter_opt.py @@ -1,11 +1,20 @@ +""" +Exports smaller geometry but is slower. +To be replaced with https://github.com/zeux/meshoptimizer +""" + from mathutils import * import numpy as np -import arm.utils import arm.log as log +import arm.utils + +if "DO_RELOAD_MODULE" in locals(): + log = arm.reload_module(log) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True -# Exports smaller geometry but is slower -# To be replaced with https://github.com/zeux/meshoptimizer class Vertex: __slots__ = ("co", "normal", "uvs", "col", "loop_indices", "index", "bone_weights", "bone_indices", "bone_count", "vertex_index") diff --git a/blender/arm/handlers.py b/blender/arm/handlers.py index 177a907c..f77e117a 100644 --- a/blender/arm/handlers.py +++ b/blender/arm/handlers.py @@ -15,6 +15,18 @@ import arm.make_state as state import arm.props as props import arm.utils +if "DO_RELOAD_MODULE" in locals(): + arm.api = arm.reload_module(arm.api) + live_patch = arm.reload_module(live_patch) + arm_nodes = arm.reload_module(arm_nodes) + arm.nodes_logic = arm.reload_module(arm.nodes_logic) + make = arm.reload_module(make) + state = arm.reload_module(state) + props = arm.reload_module(props) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + @persistent def on_depsgraph_update_post(self): diff --git a/blender/arm/keymap.py b/blender/arm/keymap.py index 77e09183..40dabd09 100644 --- a/blender/arm/keymap.py +++ b/blender/arm/keymap.py @@ -1,8 +1,16 @@ import bpy + import arm.props_ui as props_ui +if "DO_RELOAD_MODULE" in locals(): + import arm + props_ui = arm.reload_module(props_ui) +else: + DO_RELOAD_MODULE = True + arm_keymaps = [] + def register(): wm = bpy.context.window_manager addon_keyconfig = wm.keyconfigs.addon @@ -21,6 +29,7 @@ def register(): km.keymap_items.new("tlm.clean_lightmaps", type='F7', value='PRESS') arm_keymaps.append(km) + def unregister(): wm = bpy.context.window_manager for km in arm_keymaps: diff --git a/blender/arm/lib/armpack.py b/blender/arm/lib/armpack.py index f2f5d23d..7962608f 100755 --- a/blender/arm/lib/armpack.py +++ b/blender/arm/lib/armpack.py @@ -20,9 +20,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # -import struct import io import numpy as np +import struct + def _pack_integer(obj, fp): if obj < 0: diff --git a/blender/arm/lib/server.py b/blender/arm/lib/server.py index 9774945c..21492324 100755 --- a/blender/arm/lib/server.py +++ b/blender/arm/lib/server.py @@ -1,7 +1,7 @@ +import atexit import http.server import socketserver import subprocess -import atexit haxe_server = None diff --git a/blender/arm/live_patch.py b/blender/arm/live_patch.py index b2bf81a8..6a1c9fea 100644 --- a/blender/arm/live_patch.py +++ b/blender/arm/live_patch.py @@ -5,23 +5,37 @@ from typing import Any, Type import bpy import arm.assets -import arm.node_utils from arm.exporter import ArmoryExporter import arm.log as log from arm.logicnode.arm_nodes import ArmLogicTreeNode import arm.make as make import arm.make_state as state +import arm.node_utils import arm.utils -# Current patch id -patch_id = 0 +if "DO_RELOAD_MODULE" in locals(): + arm.assets = arm.reload_module(arm.assets) + arm.exporter = arm.reload_module(arm.exporter) + from arm.exporter import ArmoryExporter + log = arm.reload_module(log) + arm.logicnode.arm_nodes = arm.reload_module(arm.logicnode.arm_nodes) + from arm.logicnode.arm_nodes import ArmLogicTreeNode + make = arm.reload_module(make) + state = arm.reload_module(state) + arm.node_utils = arm.reload_module(arm.node_utils) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + + patch_id = 0 + """Current patch id""" + + __running = False + """Whether live patch is currently active""" # Any object can act as a message bus owner msgbus_owner = object() -# Whether live patch is currently active -__running = False - def start(): """Start the live patch session.""" @@ -43,9 +57,10 @@ def start(): def stop(): """Stop the live patch session.""" - global __running + global __running, patch_id if __running: __running = False + patch_id = 0 log.debug("Live patch session stopped") bpy.msgbus.clear_by_owner(msgbus_owner) diff --git a/blender/arm/logicnode/__init__.py b/blender/arm/logicnode/__init__.py index 716ecd37..aaaceb5d 100644 --- a/blender/arm/logicnode/__init__.py +++ b/blender/arm/logicnode/__init__.py @@ -1,13 +1,29 @@ import importlib import inspect import pkgutil +import sys +import arm import arm.logicnode.arm_nodes as arm_nodes +from arm.logicnode.arm_props import * import arm.logicnode.arm_sockets as arm_sockets +from arm.logicnode.replacement import NodeReplacement + +if "DO_RELOAD_MODULE" in locals(): + arm_nodes = arm.reload_module(arm_nodes) + arm.logicnode.arm_props = arm.reload_module(arm.logicnode.arm_props) + from arm.logicnode.arm_props import * + arm_sockets = arm.reload_module(arm_sockets) + arm.logicnode.replacement = arm.reload_module(arm.logicnode.replacement) + from arm.logicnode.replacement import NodeReplacement + + HAS_RELOADED = True +else: + DO_RELOAD_MODULE = True def init_categories(): - # Register node menu categories + """Register default node menu categories.""" arm_nodes.add_category('Logic', icon='OUTLINER', section="basic", description="Logic nodes are used to control execution flow using branching, loops, gates etc.") arm_nodes.add_category('Event', icon='INFO', section="basic") @@ -56,8 +72,15 @@ def init_nodes(): # The package must be loaded as well so that the modules from that package can be accessed (see the # pkgutil.walk_packages documentation for more information on this) loader.find_module(module_name).load_module(module_name) - else: - _module = importlib.import_module(module_name) + + # Only look at modules in sub packages + elif module_name.rsplit('.', 1)[0] != __package__: + if 'HAS_RELOADED' not in globals(): + _module = importlib.import_module(module_name) + else: + # Reload the module if the SDK was reloaded at least once + _module = importlib.reload(sys.modules[module_name]) + for name, obj in inspect.getmembers(_module, inspect.isclass): if name == "ArmLogicTreeNode": continue diff --git a/blender/arm/logicnode/arm_nodes.py b/blender/arm/logicnode/arm_nodes.py index 85ae3730..8ab7381e 100644 --- a/blender/arm/logicnode/arm_nodes.py +++ b/blender/arm/logicnode/arm_nodes.py @@ -1,5 +1,5 @@ -import itertools from collections import OrderedDict +import itertools from typing import Any, Generator, List, Optional, Type from typing import OrderedDict as ODict # Prevent naming conflicts @@ -14,6 +14,15 @@ from arm.logicnode.arm_props import * from arm.logicnode.replacement import NodeReplacement import arm.node_utils +if "DO_RELOAD_MODULE" in locals(): + arm.logicnode.arm_props = arm.reload_module(arm.logicnode.arm_props) + from arm.logicnode.arm_props import * + arm.logicnode.replacement = arm.reload_module(arm.logicnode.replacement) + from arm.logicnode.replacement import NodeReplacement + arm.node_utils = arm.reload_module(arm.node_utils) +else: + DO_RELOAD_MODULE = True + # When passed as a category to add_node(), this will use the capitalized # name of the package of the node as the category to make renaming # categories easier. diff --git a/blender/arm/logicnode/arm_props.py b/blender/arm/logicnode/arm_props.py index 1a32cb28..c87e7534 100644 --- a/blender/arm/logicnode/arm_props.py +++ b/blender/arm/logicnode/arm_props.py @@ -15,6 +15,20 @@ from typing import Any, Callable, Sequence, Union import bpy from bpy.props import * +__all__ = [ + 'HaxeBoolProperty', + 'HaxeBoolVectorProperty', + 'HaxeCollectionProperty', + 'HaxeEnumProperty', + 'HaxeFloatProperty', + 'HaxeFloatVectorProperty', + 'HaxeIntProperty', + 'HaxeIntVectorProperty', + 'HaxePointerProperty', + 'HaxeStringProperty', + 'RemoveHaxeProperty' +] + def __haxe_prop(prop_type: Callable, prop_name: str, *args, **kwargs) -> Any: """Declares a logic node property as a property that will be diff --git a/blender/arm/logicnode/arm_sockets.py b/blender/arm/logicnode/arm_sockets.py index 58f2ea70..df36658e 100644 --- a/blender/arm/logicnode/arm_sockets.py +++ b/blender/arm/logicnode/arm_sockets.py @@ -4,6 +4,11 @@ from bpy.types import NodeSocket import arm.utils +if "DO_RELOAD_MODULE" in locals(): + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + def _on_update_socket(self, context): self.node.on_socket_val_update(context, self) diff --git a/blender/arm/logicnode/replacement.py b/blender/arm/logicnode/replacement.py index b703d83b..d0efc6ec 100644 --- a/blender/arm/logicnode/replacement.py +++ b/blender/arm/logicnode/replacement.py @@ -20,6 +20,14 @@ import arm.logicnode.arm_nodes as arm_nodes import arm.logicnode.arm_sockets import arm.node_utils as node_utils +if "DO_RELOAD_MODULE" in locals(): + log = arm.reload_module(log) + arm_nodes = arm.reload_module(arm_nodes) + arm.logicnode.arm_sockets = arm.reload_module(arm.logicnode.arm_sockets) + node_utils = arm.reload_module(node_utils) +else: + DO_RELOAD_MODULE = True + # List of errors that occurred during the replacement # Format: (error identifier, node.bl_idname (or None), tree name, exception traceback (optional)) replacement_errors: List[Tuple[str, Optional[str], str, Optional[str]]] = [] diff --git a/blender/arm/make.py b/blender/arm/make.py index a4da2dbf..cc599c29 100755 --- a/blender/arm/make.py +++ b/blender/arm/make.py @@ -27,6 +27,23 @@ import arm.make_world as make_world import arm.utils import arm.write_data as write_data +if "DO_RELOAD_MODULE" in locals(): + assets = arm.reload_module(assets) + arm.exporter = arm.reload_module(arm.exporter) + from arm.exporter import ArmoryExporter + arm.lib.make_datas = arm.reload_module(arm.lib.make_datas) + arm.lib.server = arm.reload_module(arm.lib.server) + live_patch = arm.reload_module(live_patch) + log = arm.reload_module(log) + make_logic = arm.reload_module(make_logic) + make_renderpath = arm.reload_module(make_renderpath) + state = arm.reload_module(state) + make_world = arm.reload_module(make_world) + arm.utils = arm.reload_module(arm.utils) + write_data = arm.reload_module(write_data) +else: + DO_RELOAD_MODULE = True + scripts_mtime = 0 # Monitor source changes profile_time = 0 diff --git a/blender/arm/make_logic.py b/blender/arm/make_logic.py index 5ecf42a1..a4195bb8 100755 --- a/blender/arm/make_logic.py +++ b/blender/arm/make_logic.py @@ -8,6 +8,15 @@ import arm.log import arm.node_utils import arm.utils +if "DO_RELOAD_MODULE" in locals(): + arm.exporter = arm.reload_module(arm.exporter) + from arm.exporter import ArmoryExporter + arm.log = arm.reload_module(arm.log) + arm.node_utils = arm.reload_module(arm.node_utils) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + parsed_nodes = [] parsed_ids = dict() # Sharing node data function_nodes = dict() diff --git a/blender/arm/make_renderpath.py b/blender/arm/make_renderpath.py index ef296d21..7b2e0dde 100755 --- a/blender/arm/make_renderpath.py +++ b/blender/arm/make_renderpath.py @@ -1,9 +1,19 @@ import bpy + +import arm.api import arm.assets as assets -import arm.utils import arm.log as log import arm.make_state as state -import arm.api +import arm.utils + +if "DO_RELOAD_MODULE" in locals(): + arm.api = arm.reload_module(arm.api) + assets = arm.reload_module(assets) + log = arm.reload_module(log) + state = arm.reload_module(state) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True callback = None diff --git a/blender/arm/make_state.py b/blender/arm/make_state.py index b83b8726..bf6c9f97 100644 --- a/blender/arm/make_state.py +++ b/blender/arm/make_state.py @@ -1,15 +1,18 @@ -redraw_ui = False -target = 'krom' -last_target = 'krom' -export_gapi = '' -last_resx = 0 -last_resy = 0 -last_scene = '' -last_world_defs = '' -proc_play = None -proc_build = None -proc_publish_build = None -mod_scripts = [] -is_export = False -is_play = False -is_publish = False +if "DO_RELOAD_MODULE" not in locals(): + DO_RELOAD_MODULE = True + + redraw_ui = False + target = 'krom' + last_target = 'krom' + export_gapi = '' + last_resx = 0 + last_resy = 0 + last_scene = '' + last_world_defs = '' + proc_play = None + proc_build = None + proc_publish_build = None + mod_scripts = [] + is_export = False + is_play = False + is_publish = False diff --git a/blender/arm/make_world.py b/blender/arm/make_world.py index 71dac33b..3c176d06 100755 --- a/blender/arm/make_world.py +++ b/blender/arm/make_world.py @@ -12,6 +12,21 @@ import arm.node_utils as node_utils import arm.utils import arm.write_probes as write_probes +if "DO_RELOAD_MODULE" in locals(): + arm.assets = arm.reload_module(arm.assets) + arm.log = arm.reload_module(arm.log) + arm.material = arm.reload_module(arm.material) + arm.material.parser_state = arm.reload_module(arm.material.parser_state) + from arm.material.parser_state import ParserState, ParserContext + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import ShaderContext, Shader + cycles = arm.reload_module(cycles) + node_utils = arm.reload_module(node_utils) + arm.utils = arm.reload_module(arm.utils) + write_probes = arm.reload_module(write_probes) +else: + DO_RELOAD_MODULE = True + callback = None shader_datas = [] diff --git a/blender/arm/material/__init__.py b/blender/arm/material/__init__.py index e69de29b..661b7767 100755 --- a/blender/arm/material/__init__.py +++ b/blender/arm/material/__init__.py @@ -0,0 +1 @@ +import arm diff --git a/blender/arm/material/arm_nodes/custom_particle_node.py b/blender/arm/material/arm_nodes/custom_particle_node.py index 8c9d9f63..fbb28e78 100644 --- a/blender/arm/material/arm_nodes/custom_particle_node.py +++ b/blender/arm/material/arm_nodes/custom_particle_node.py @@ -5,6 +5,17 @@ from arm.material.arm_nodes.arm_nodes import add_node from arm.material.shader import Shader from arm.material.cycles import * +if "DO_RELOAD_MODULE" in locals(): + import arm + arm.material.arm_nodes.arm_nodes = arm.reload_module(arm.material.arm_nodes.arm_nodes) + from arm.material.arm_nodes.arm_nodes import add_node + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import Shader + arm.material.cycles = arm.reload_module(arm.material.cycles) + from arm.material.cycles import * +else: + DO_RELOAD_MODULE = True + class CustomParticleNode(Node): """Input data for paricles.""" @@ -174,7 +185,7 @@ class CustomParticleNode(Node): if self.posZ: vertshdr.write(f'spos.z += {pos}.z;') - + vertshdr.write('wposition = vec4(W * spos).xyz;') diff --git a/blender/arm/material/arm_nodes/shader_data_node.py b/blender/arm/material/arm_nodes/shader_data_node.py index 8ab0aaa6..ec7d2077 100644 --- a/blender/arm/material/arm_nodes/shader_data_node.py +++ b/blender/arm/material/arm_nodes/shader_data_node.py @@ -4,6 +4,15 @@ from bpy.types import Node from arm.material.arm_nodes.arm_nodes import add_node from arm.material.shader import Shader +if "DO_RELOAD_MODULE" in locals(): + import arm + arm.material.arm_nodes.arm_nodes = arm.reload_module(arm.material.arm_nodes.arm_nodes) + from arm.material.arm_nodes.arm_nodes import add_node + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import Shader +else: + DO_RELOAD_MODULE = True + class ShaderDataNode(Node): """Allows access to shader data such as uniforms and inputs.""" diff --git a/blender/arm/material/cycles.py b/blender/arm/material/cycles.py index 625c24c2..5e20f4dd 100644 --- a/blender/arm/material/cycles.py +++ b/blender/arm/material/cycles.py @@ -30,6 +30,23 @@ from arm.material.parser_state import ParserState, ParserContext from arm.material.shader import Shader, ShaderContext, floatstr, vec3str import arm.utils +if "DO_RELOAD_MODULE" in locals(): + arm.assets = arm.reload_module(arm.assets) + log = arm.reload_module(log) + arm.make_state = arm.reload_module(arm.make_state) + c_functions = arm.reload_module(c_functions) + arm.material.cycles_nodes = arm.reload_module(arm.material.cycles_nodes) + from arm.material.cycles_nodes import * + mat_state = arm.reload_module(mat_state) + arm.material.parser_state = arm.reload_module(arm.material.parser_state) + from arm.material.parser_state import ParserState, ParserContext + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import Shader, ShaderContext, floatstr, vec3str + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + + # Particle info export particle_info: Dict[str, bool] = {} diff --git a/blender/arm/material/cycles_nodes/nodes_color.py b/blender/arm/material/cycles_nodes/nodes_color.py index 1b7dff08..08a181f3 100644 --- a/blender/arm/material/cycles_nodes/nodes_color.py +++ b/blender/arm/material/cycles_nodes/nodes_color.py @@ -6,6 +6,18 @@ import arm.material.cycles_functions as c_functions from arm.material.parser_state import ParserState from arm.material.shader import floatstr, vec3str +if "DO_RELOAD_MODULE" in locals(): + import arm + log = arm.reload_module(log) + c = arm.reload_module(c) + c_functions = arm.reload_module(c_functions) + arm.material.parser_state = arm.reload_module(arm.material.parser_state) + from arm.material.parser_state import ParserState + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import floatstr, vec3str +else: + DO_RELOAD_MODULE = True + def parse_brightcontrast(node: bpy.types.ShaderNodeBrightContrast, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str: out_col = c.parse_vector_input(node.inputs[0]) diff --git a/blender/arm/material/cycles_nodes/nodes_converter.py b/blender/arm/material/cycles_nodes/nodes_converter.py index 813a1d87..8a241b2d 100644 --- a/blender/arm/material/cycles_nodes/nodes_converter.py +++ b/blender/arm/material/cycles_nodes/nodes_converter.py @@ -8,6 +8,19 @@ import arm.material.cycles_functions as c_functions from arm.material.parser_state import ParserState from arm.material.shader import floatstr, vec3str +if "DO_RELOAD_MODULE" in locals(): + import arm + log = arm.reload_module(log) + c = arm.reload_module(c) + c_functions = arm.reload_module(c_functions) + arm.material.parser_state = arm.reload_module(arm.material.parser_state) + from arm.material.parser_state import ParserState + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import floatstr, vec3str +else: + DO_RELOAD_MODULE = True + + def parse_maprange(node: bpy.types.ShaderNodeMapRange, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr: interp = node.interpolation_type @@ -40,7 +53,7 @@ def parse_maprange(node: bpy.types.ShaderNodeMapRange, out_socket: bpy.types.Nod return f'map_range_smootherstep({value}, {fromMin}, {fromMax}, {toMin}, {toMax})' def parse_blackbody(node: bpy.types.ShaderNodeBlackbody, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str: - + t = c.parse_value_input(node.inputs[0]) state.curshader.add_function(c_functions.str_blackbody) diff --git a/blender/arm/material/cycles_nodes/nodes_input.py b/blender/arm/material/cycles_nodes/nodes_input.py index 335e56f6..1eb5c5db 100644 --- a/blender/arm/material/cycles_nodes/nodes_input.py +++ b/blender/arm/material/cycles_nodes/nodes_input.py @@ -10,6 +10,18 @@ from arm.material.parser_state import ParserState, ParserContext from arm.material.shader import floatstr, vec3str import arm.utils +if "DO_RELOAD_MODULE" in locals(): + log = arm.reload_module(log) + c = arm.reload_module(c) + c_functions = arm.reload_module(c_functions) + arm.material.parser_state = arm.reload_module(arm.material.parser_state) + from arm.material.parser_state import ParserState, ParserContext + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import floatstr, vec3str + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + def parse_attribute(node: bpy.types.ShaderNodeAttribute, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]: out_type = 'float' if out_socket.type == 'VALUE' else 'vec3' diff --git a/blender/arm/material/cycles_nodes/nodes_shader.py b/blender/arm/material/cycles_nodes/nodes_shader.py index 4e593bd0..45fec6be 100644 --- a/blender/arm/material/cycles_nodes/nodes_shader.py +++ b/blender/arm/material/cycles_nodes/nodes_shader.py @@ -4,6 +4,14 @@ from bpy.types import NodeSocket import arm.material.cycles as c from arm.material.parser_state import ParserState +if "DO_RELOAD_MODULE" in locals(): + import arm + c = arm.reload_module(c) + arm.material.parser_state = arm.reload_module(arm.material.parser_state) + from arm.material.parser_state import ParserState +else: + DO_RELOAD_MODULE = True + def parse_mixshader(node: bpy.types.ShaderNodeMixShader, out_socket: NodeSocket, state: ParserState) -> None: prefix = '' if node.inputs[0].is_linked else 'const ' diff --git a/blender/arm/material/cycles_nodes/nodes_texture.py b/blender/arm/material/cycles_nodes/nodes_texture.py index 379d4ca1..406dfba1 100644 --- a/blender/arm/material/cycles_nodes/nodes_texture.py +++ b/blender/arm/material/cycles_nodes/nodes_texture.py @@ -6,13 +6,27 @@ import bpy import arm.assets as assets import arm.log as log -import arm.material.cycles_functions as c_functions import arm.material.cycles as c +import arm.material.cycles_functions as c_functions from arm.material.parser_state import ParserState, ParserContext from arm.material.shader import floatstr, vec3str import arm.utils import arm.write_probes as write_probes +if "DO_RELOAD_MODULE" in locals(): + assets = arm.reload_module(assets) + log = arm.reload_module(log) + c = arm.reload_module(c) + c_functions = arm.reload_module(c_functions) + arm.material.parser_state = arm.reload_module(arm.material.parser_state) + from arm.material.parser_state import ParserState, ParserContext + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import floatstr, vec3str + arm.utils = arm.reload_module(arm.utils) + write_probes = arm.reload_module(write_probes) +else: + DO_RELOAD_MODULE = True + def parse_tex_brick(node: bpy.types.ShaderNodeTexBrick, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]: state.curshader.add_function(c_functions.str_tex_brick) diff --git a/blender/arm/material/cycles_nodes/nodes_vector.py b/blender/arm/material/cycles_nodes/nodes_vector.py index 5f78a70b..3a40c378 100644 --- a/blender/arm/material/cycles_nodes/nodes_vector.py +++ b/blender/arm/material/cycles_nodes/nodes_vector.py @@ -8,6 +8,17 @@ import arm.material.cycles_functions as c_functions from arm.material.parser_state import ParserState from arm.material.shader import floatstr, vec3str +if "DO_RELOAD_MODULE" in locals(): + import arm + c = arm.reload_module(c) + c_functions = arm.reload_module(c_functions) + arm.material.parser_state = arm.reload_module(arm.material.parser_state) + from arm.material.parser_state import ParserState + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import floatstr, vec3str +else: + DO_RELOAD_MODULE = True + def parse_curvevec(node: bpy.types.ShaderNodeVectorCurve, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str: fac = c.parse_value_input(node.inputs[0]) @@ -144,7 +155,7 @@ def parse_displacement(node: bpy.types.ShaderNodeDisplacement, out_socket: bpy.t return f'(vec3({height}) * {scale})' def parse_vectorrotate(node: bpy.types.ShaderNodeVectorRotate, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str: - + type = node.rotation_type input_vector: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[0]) input_center: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[1]) @@ -166,9 +177,9 @@ def parse_vectorrotate(node: bpy.types.ShaderNodeVectorRotate, out_socket: bpy.t elif type == 'Y_AXIS': return f'vec3( rotate_around_axis({input_vector} - {input_center}, vec3(0.0, 1.0, 0.0), {input_angle} * {input_invert}) + {input_center} )' elif type == 'Z_AXIS': - return f'vec3( rotate_around_axis({input_vector} - {input_center}, vec3(0.0, 0.0, 1.0), {input_angle} * {input_invert}) + {input_center} )' + return f'vec3( rotate_around_axis({input_vector} - {input_center}, vec3(0.0, 0.0, 1.0), {input_angle} * {input_invert}) + {input_center} )' elif type == 'EULER_XYZ': state.curshader.add_function(c_functions.str_euler_to_mat3) return f'vec3( mat3(({input_invert} < 0.0) ? transpose(euler_to_mat3({input_rotation})) : euler_to_mat3({input_rotation})) * ({input_vector} - {input_center}) + {input_center})' - + return f'(vec3(1.0, 0.0, 0.0))' diff --git a/blender/arm/material/make.py b/blender/arm/material/make.py index 13a79d33..b067c180 100755 --- a/blender/arm/material/make.py +++ b/blender/arm/material/make.py @@ -10,6 +10,15 @@ import arm.material.mat_batch as mat_batch import arm.node_utils import arm.utils +if "DO_RELOAD_MODULE" in locals(): + cycles = arm.reload_module(cycles) + make_shader = arm.reload_module(make_shader) + mat_batch = arm.reload_module(mat_batch) + arm.node_utils = arm.reload_module(arm.node_utils) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + def glsl_value(val): if str(type(val)) == "": diff --git a/blender/arm/material/make_attrib.py b/blender/arm/material/make_attrib.py index bc23a620..f82a3ab4 100644 --- a/blender/arm/material/make_attrib.py +++ b/blender/arm/material/make_attrib.py @@ -9,6 +9,19 @@ import arm.material.make_tess as make_tess from arm.material.shader import Shader, ShaderContext import arm.utils +if "DO_RELOAD_MODULE" in locals(): + cycles = arm.reload_module(cycles) + mat_state = arm.reload_module(mat_state) + make_skin = arm.reload_module(make_skin) + make_particle = arm.reload_module(make_particle) + make_inst = arm.reload_module(make_inst) + make_tess = arm.reload_module(make_tess) + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import Shader, ShaderContext + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + def write_vertpos(vert): billboard = mat_state.material.arm_billboard diff --git a/blender/arm/material/make_decal.py b/blender/arm/material/make_decal.py index 32e896e9..c17b1ead 100644 --- a/blender/arm/material/make_decal.py +++ b/blender/arm/material/make_decal.py @@ -1,10 +1,19 @@ import bpy + import arm.material.cycles as cycles import arm.material.mat_state as mat_state -import arm.material.mat_utils as mat_utils import arm.material.make_finalize as make_finalize import arm.utils +if "DO_RELOAD_MODULE" in locals(): + cycles = arm.reload_module(cycles) + mat_state = arm.reload_module(mat_state) + make_finalize = arm.reload_module(make_finalize) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + + def make(context_id): wrd = bpy.data.worlds['Arm'] diff --git a/blender/arm/material/make_depth.py b/blender/arm/material/make_depth.py index aa1f0864..4f9115ca 100644 --- a/blender/arm/material/make_depth.py +++ b/blender/arm/material/make_depth.py @@ -1,4 +1,5 @@ import bpy + import arm.material.cycles as cycles import arm.material.mat_state as mat_state import arm.material.mat_utils as mat_utils @@ -10,6 +11,21 @@ import arm.material.make_finalize as make_finalize import arm.assets as assets import arm.utils +if "DO_RELOAD_MODULE" in locals(): + cycles = arm.reload_module(cycles) + mat_state = arm.reload_module(mat_state) + mat_utils = arm.reload_module(mat_utils) + make_skin = arm.reload_module(make_skin) + make_inst = arm.reload_module(make_inst) + make_tess = arm.reload_module(make_tess) + make_particle = arm.reload_module(make_particle) + make_finalize = arm.reload_module(make_finalize) + assets = arm.reload_module(assets) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + + def make(context_id, rpasses, shadowmap=False): is_disp = mat_utils.disp_linked(mat_state.output_node) diff --git a/blender/arm/material/make_finalize.py b/blender/arm/material/make_finalize.py index afeeee8f..6477e55c 100644 --- a/blender/arm/material/make_finalize.py +++ b/blender/arm/material/make_finalize.py @@ -3,6 +3,14 @@ import bpy import arm.material.make_tess as make_tess from arm.material.shader import ShaderContext +if "DO_RELOAD_MODULE" in locals(): + import arm + make_tess = arm.reload_module(make_tess) + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import ShaderContext +else: + DO_RELOAD_MODULE = True + def make(con_mesh: ShaderContext): vert = con_mesh.vert diff --git a/blender/arm/material/make_mesh.py b/blender/arm/material/make_mesh.py index db9a2c28..652e6d91 100644 --- a/blender/arm/material/make_mesh.py +++ b/blender/arm/material/make_mesh.py @@ -1,4 +1,5 @@ import bpy + import arm.assets as assets import arm.material.mat_state as mat_state import arm.material.mat_utils as mat_utils @@ -10,6 +11,20 @@ import arm.material.make_finalize as make_finalize import arm.material.make_attrib as make_attrib import arm.utils +if "DO_RELOAD_MODULE" in locals(): + assets = arm.reload_module(assets) + mat_state = arm.reload_module(mat_state) + mat_utils = arm.reload_module(mat_utils) + cycles = arm.reload_module(cycles) + make_tess = arm.reload_module(make_tess) + make_particle = arm.reload_module(make_particle) + make_cluster = arm.reload_module(make_cluster) + make_finalize = arm.reload_module(make_finalize) + make_attrib = arm.reload_module(make_attrib) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + is_displacement = False write_material_attribs = None write_material_attribs_post = None diff --git a/blender/arm/material/make_overlay.py b/blender/arm/material/make_overlay.py index 47c71df3..de0b0b35 100644 --- a/blender/arm/material/make_overlay.py +++ b/blender/arm/material/make_overlay.py @@ -3,6 +3,15 @@ import arm.material.make_mesh as make_mesh import arm.material.mat_state as mat_state import arm.material.mat_utils as mat_utils +if "DO_RELOAD_MODULE" in locals(): + import arm + make_finalize = arm.reload_module(make_finalize) + make_mesh = arm.reload_module(make_mesh) + mat_state = arm.reload_module(mat_state) + mat_utils = arm.reload_module(mat_utils) +else: + DO_RELOAD_MODULE = True + def make(context_id): con = { 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise' } diff --git a/blender/arm/material/make_particle.py b/blender/arm/material/make_particle.py index 2c9a71e2..c62d2040 100644 --- a/blender/arm/material/make_particle.py +++ b/blender/arm/material/make_particle.py @@ -1,7 +1,13 @@ - import arm.utils import arm.material.mat_state as mat_state +if "DO_RELOAD_MODULE" in locals(): + arm.utils = arm.reload_module(arm.utils) + mat_state = arm.reload_module(mat_state) +else: + DO_RELOAD_MODULE = True + + def write(vert, particle_info=None, shadowmap=False): # Outs @@ -17,7 +23,7 @@ def write(vert, particle_info=None, shadowmap=False): str_tex_hash = "float fhash(float n) { return fract(sin(n) * 43758.5453); }\n" vert.add_function(str_tex_hash) - + prep = 'float ' if out_age: prep = '' @@ -45,7 +51,7 @@ def write(vert, particle_info=None, shadowmap=False): vert.write('}') # vert.write('p_age /= 2;') # Match - + # object_align_factor / 2 + gxyz prep = 'vec3 ' if out_velocity: diff --git a/blender/arm/material/make_shader.py b/blender/arm/material/make_shader.py index 93b40391..87307799 100644 --- a/blender/arm/material/make_shader.py +++ b/blender/arm/material/make_shader.py @@ -22,6 +22,26 @@ import arm.material.mat_utils as mat_utils from arm.material.shader import Shader, ShaderContext, ShaderData import arm.utils +if "DO_RELOAD_MODULE" in locals(): + arm.api = arm.reload_module(arm.api) + assets = arm.reload_module(assets) + arm.exporter = arm.reload_module(arm.exporter) + log = arm.reload_module(log) + cycles = arm.reload_module(cycles) + make_decal = arm.reload_module(make_decal) + make_depth = arm.reload_module(make_depth) + make_mesh = arm.reload_module(make_mesh) + make_overlay = arm.reload_module(make_overlay) + make_transluc = arm.reload_module(make_transluc) + make_voxel = arm.reload_module(make_voxel) + mat_state = arm.reload_module(mat_state) + mat_utils = arm.reload_module(mat_utils) + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import Shader, ShaderContext, ShaderData + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + rpass_hook = None diff --git a/blender/arm/material/make_skin.py b/blender/arm/material/make_skin.py index d6ea4177..8730b089 100644 --- a/blender/arm/material/make_skin.py +++ b/blender/arm/material/make_skin.py @@ -1,5 +1,11 @@ import arm.utils +if "DO_RELOAD_MODULE" in locals(): + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + + def skin_pos(vert): vert.add_include('compiled.inc') @@ -15,6 +21,7 @@ def skin_pos(vert): vert.write_attrib('spos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate') vert.write_attrib('spos.xyz /= posUnpack;') + def skin_nor(vert, prep): rpdat = arm.utils.get_rp() vert.write_attrib(prep + 'wnormal = normalize(N * (vec3(nor.xy, pos.w) + 2.0 * cross(skinA.xyz, cross(skinA.xyz, vec3(nor.xy, pos.w)) + skinA.w * vec3(nor.xy, pos.w))));') diff --git a/blender/arm/material/make_transluc.py b/blender/arm/material/make_transluc.py index 4257b53e..a1ea5162 100644 --- a/blender/arm/material/make_transluc.py +++ b/blender/arm/material/make_transluc.py @@ -1,10 +1,22 @@ import bpy + import arm.material.cycles as cycles import arm.material.mat_state as mat_state import arm.material.make_mesh as make_mesh import arm.material.make_finalize as make_finalize import arm.assets as assets +if "DO_RELOAD_MODULE" in locals(): + import arm + cycles = arm.reload_module(cycles) + mat_state = arm.reload_module(mat_state) + make_mesh = arm.reload_module(make_mesh) + make_finalize = arm.reload_module(make_finalize) + assets = arm.reload_module(assets) +else: + DO_RELOAD_MODULE = True + + def make(context_id): con_transluc = mat_state.data.add_context({ 'name': context_id, 'depth_write': False, 'compare_mode': 'less', 'cull_mode': 'clockwise', \ 'blend_source': 'blend_one', 'blend_destination': 'blend_one', 'blend_operation': 'add', \ @@ -26,7 +38,7 @@ def make(context_id): if '_VoxelAOvar' in wrd.world_defs: frag.write('indirect *= 0.25;') frag.write('vec4 premultipliedReflect = vec4(vec3(direct + indirect * 0.5) * opacity, opacity);') - + frag.write('float w = clamp(pow(min(1.0, premultipliedReflect.a * 10.0) + 0.01, 3.0) * 1e8 * pow(1.0 - (gl_FragCoord.z) * 0.9, 3.0), 1e-2, 3e3);') frag.write('fragColor[0] = vec4(premultipliedReflect.rgb * w, premultipliedReflect.a);') frag.write('fragColor[1] = vec4(premultipliedReflect.a * w, 0.0, 0.0, 1.0);') diff --git a/blender/arm/material/make_voxel.py b/blender/arm/material/make_voxel.py index d86fac29..90dad58d 100644 --- a/blender/arm/material/make_voxel.py +++ b/blender/arm/material/make_voxel.py @@ -1,11 +1,16 @@ import bpy + import arm.utils import arm.assets as assets -import arm.material.cycles as cycles import arm.material.mat_state as mat_state -import arm.material.mat_utils as mat_utils -import arm.material.make_particle as make_particle -import arm.make_state as state + +if "DO_RELOAD_MODULE" in locals(): + arm.utils = arm.reload_module(arm.utils) + assets = arm.reload_module(assets) + mat_state = arm.reload_module(mat_state) +else: + DO_RELOAD_MODULE = True + def make(context_id): rpdat = arm.utils.get_rp() @@ -108,7 +113,7 @@ def make_ao(context_id): if rpdat.arm_voxelgi_revoxelize and rpdat.arm_voxelgi_camera: vert.add_uniform('vec3 eyeSnap', '_cameraPositionSnap') vert.write('voxpositionGeom = (vec3(W * vec4(pos.xyz, 1.0)) - eyeSnap) / voxelgiHalfExtents;') - else: + else: vert.write('voxpositionGeom = vec3(W * vec4(pos.xyz, 1.0)) / voxelgiHalfExtents;') geom.add_out('vec3 voxposition') diff --git a/blender/arm/material/mat_batch.py b/blender/arm/material/mat_batch.py index dc86eefe..fca06750 100644 --- a/blender/arm/material/mat_batch.py +++ b/blender/arm/material/mat_batch.py @@ -1,8 +1,15 @@ -import bpy import arm.material.cycles as cycles import arm.material.make_shader as make_shader import arm.material.mat_state as mat_state +if "DO_RELOAD_MODULE" in locals(): + import arm + cycles = arm.reload_module(cycles) + make_shader = arm.reload_module(make_shader) + mat_state = arm.reload_module(mat_state) +else: + DO_RELOAD_MODULE = True + # TODO: handle groups # TODO: handle cached shaders @@ -21,7 +28,7 @@ def traverse_tree(node, sign): def get_signature(mat): nodes = mat.node_tree.nodes output_node = cycles.node_by_type(nodes, 'OUTPUT_MATERIAL') - + if output_node != None: sign = traverse_tree(output_node, '') # Append flags @@ -40,7 +47,7 @@ def traverse_tree2(node, ar): def get_sorted(mat): nodes = mat.node_tree.nodes output_node = cycles.node_by_type(nodes, 'OUTPUT_MATERIAL') - + if output_node != None: ar = [] traverse_tree2(output_node, ar) diff --git a/blender/arm/material/mat_utils.py b/blender/arm/material/mat_utils.py index b1567a72..497061d8 100644 --- a/blender/arm/material/mat_utils.py +++ b/blender/arm/material/mat_utils.py @@ -1,9 +1,18 @@ import bpy + import arm.utils import arm.make_state as make_state import arm.material.cycles as cycles import arm.log as log +if "DO_RELOAD_MODULE" in locals(): + arm.utils = arm.reload_module(arm.utils) + make_state = arm.reload_module(make_state) + cycles = arm.reload_module(cycles) + log = arm.reload_module(log) +else: + DO_RELOAD_MODULE = True + add_mesh_contexts = [] def disp_linked(output_node): @@ -42,7 +51,7 @@ def get_rpasses(material): ar.append('voxel') if rpdat.rp_renderer == 'Forward' and rpdat.rp_depthprepass and not material.arm_blending and not material.arm_particle_flag: ar.append('depth') - + if material.arm_cast_shadow and rpdat.rp_shadows and ('mesh' in ar): ar.append('shadowmap') diff --git a/blender/arm/material/parser_state.py b/blender/arm/material/parser_state.py index 8606e63f..6bd5a1b2 100644 --- a/blender/arm/material/parser_state.py +++ b/blender/arm/material/parser_state.py @@ -5,6 +5,13 @@ import bpy from arm.material.shader import Shader, ShaderContext, vec3str, floatstr +if "DO_RELOAD_MODULE" in locals(): + import arm + arm.material.shader = arm.reload_module(arm.material.shader) + from arm.material.shader import Shader, ShaderContext, vec3str, floatstr +else: + DO_RELOAD_MODULE = True + class ParserContext(Enum): """Describes which kind of node tree is parsed.""" diff --git a/blender/arm/material/shader.py b/blender/arm/material/shader.py index 8e107628..afddb2f1 100644 --- a/blender/arm/material/shader.py +++ b/blender/arm/material/shader.py @@ -1,5 +1,10 @@ import arm.utils +if "DO_RELOAD_MODULE" in locals(): + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + # Type aliases for type hints to make it easier to see which kind of # shader data type is stored in a string floatstr = str diff --git a/blender/arm/node_utils.py b/blender/arm/node_utils.py index ef465b32..339aef1c 100755 --- a/blender/arm/node_utils.py +++ b/blender/arm/node_utils.py @@ -10,6 +10,13 @@ import arm.log import arm.logicnode.arm_sockets import arm.utils +if "DO_RELOAD_MODULE" in locals(): + arm.log = arm.reload_module(arm.log) + arm.logicnode.arm_sockets = arm.reload_module(arm.logicnode.arm_sockets) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + def find_node_by_link(node_group, to_node, inp): for link in node_group.links: diff --git a/blender/arm/nodes_logic.py b/blender/arm/nodes_logic.py index 87b73869..d266f920 100755 --- a/blender/arm/nodes_logic.py +++ b/blender/arm/nodes_logic.py @@ -11,6 +11,16 @@ import arm.props_traits import arm.ui_icons as ui_icons import arm.utils +if "DO_RELOAD_MODULE" in locals(): + arm_nodes = arm.reload_module(arm_nodes) + arm.logicnode.replacement = arm.reload_module(arm.logicnode.replacement) + arm.logicnode = arm.reload_module(arm.logicnode) + arm.props_traits = arm.reload_module(arm.props_traits) + ui_icons = arm.reload_module(ui_icons) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + registered_nodes = [] registered_categories = [] diff --git a/blender/arm/nodes_material.py b/blender/arm/nodes_material.py index ef9a8f1e..04bfd8a7 100644 --- a/blender/arm/nodes_material.py +++ b/blender/arm/nodes_material.py @@ -7,6 +7,14 @@ import arm.material.arm_nodes.arm_nodes as arm_nodes # even if it looks unused from arm.material.arm_nodes import * +if "DO_RELOAD_MODULE" in locals(): + import arm + arm_nodes = arm.reload_module(arm_nodes) + arm.material.arm_nodes = arm.reload_module(arm.material.arm_nodes) + from arm.material.arm_nodes import * +else: + DO_RELOAD_MODULE = True + registered_nodes = [] diff --git a/blender/arm/profiler.py b/blender/arm/profiler.py index 87f7a0a2..ca96b70f 100644 --- a/blender/arm/profiler.py +++ b/blender/arm/profiler.py @@ -5,6 +5,13 @@ import pstats import arm.log as log import arm.utils as utils +if "DO_RELOAD_MODULE" in locals(): + import arm + log = arm.reload_module(log) + utils = arm.reload_module(utils) +else: + DO_RELOAD_MODULE = True + class Profile: """Context manager for profiling the enclosed code when the given condition is true. diff --git a/blender/arm/props.py b/blender/arm/props.py index 8f3d9af2..80d8fb5c 100755 --- a/blender/arm/props.py +++ b/blender/arm/props.py @@ -10,6 +10,16 @@ import arm.nodes_logic import arm.proxy import arm.utils +if "DO_RELOAD_MODULE" in locals(): + assets = arm.reload_module(assets) + arm.logicnode.replacement = arm.reload_module(arm.logicnode.replacement) + arm.make = arm.reload_module(arm.make) + arm.nodes_logic = arm.reload_module(arm.nodes_logic) + arm.proxy = arm.reload_module(arm.proxy) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + # Armory version arm_version = '2021.7' arm_commit = '$Id$' diff --git a/blender/arm/props_bake.py b/blender/arm/props_bake.py index e433e682..b096b36d 100644 --- a/blender/arm/props_bake.py +++ b/blender/arm/props_bake.py @@ -1,10 +1,19 @@ -import arm.utils -import arm.assets import bpy from bpy.types import Menu, Panel, UIList from bpy.props import * + from arm.lightmapper import operators, properties, utility +import arm.assets +import arm.utils + +if "DO_RELOAD_MODULE" in locals(): + arm.assets = arm.reload_module(arm.assets) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + + class ArmBakeListItem(bpy.types.PropertyGroup): obj: PointerProperty(type=bpy.types.Object, description="The object to bake") res_x: IntProperty(name="X", description="Texture resolution", default=1024) @@ -166,7 +175,7 @@ class ArmBakeButton(bpy.types.Operator): img_node.image = img img_node.select = True nodes.active = img_node - + obs = bpy.context.view_layer.objects # Unwrap @@ -379,4 +388,4 @@ def unregister(): #Unregister lightmapper operators.unregister() - properties.unregister() \ No newline at end of file + properties.unregister() diff --git a/blender/arm/props_exporter.py b/blender/arm/props_exporter.py index 0dc2f143..775489c2 100644 --- a/blender/arm/props_exporter.py +++ b/blender/arm/props_exporter.py @@ -1,14 +1,23 @@ import os import shutil -import arm.assets as assets -import arm.utils -import bpy import stat import subprocess import webbrowser + +import bpy from bpy.types import Menu, Panel, UIList from bpy.props import * +import arm.assets as assets +import arm.utils + +if "DO_RELOAD_MODULE" in locals(): + assets = arm.reload_module(assets) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + + def remove_readonly(func, path, excinfo): os.chmod(path, stat.S_IWRITE) func(path) @@ -417,7 +426,7 @@ def register(): bpy.types.World.arm_exporterlist = CollectionProperty(type=ArmExporterListItem) bpy.types.World.arm_exporterlist_index = IntProperty(name="Index for my_list", default=0) bpy.types.World.arm_exporter_android_permission_list = CollectionProperty(type=ArmExporterAndroidPermissionListItem) - bpy.types.World.arm_exporter_android_permission_list_index = IntProperty(name="Index for my_list", default=0) + bpy.types.World.arm_exporter_android_permission_list_index = IntProperty(name="Index for my_list", default=0) bpy.types.World.arm_exporter_android_abi_list = CollectionProperty(type=ArmExporterAndroidAbiListItem) bpy.types.World.arm_exporter_android_abi_list_index = IntProperty(name="Index for my_list", default=0) diff --git a/blender/arm/props_lod.py b/blender/arm/props_lod.py index 44bfdca9..2ad67bf2 100755 --- a/blender/arm/props_lod.py +++ b/blender/arm/props_lod.py @@ -1,5 +1,4 @@ import bpy -from bpy.types import Menu, Panel, UIList from bpy.props import * def update_size_prop(self, context): diff --git a/blender/arm/props_renderpath.py b/blender/arm/props_renderpath.py index cd7db3ea..08aa947a 100644 --- a/blender/arm/props_renderpath.py +++ b/blender/arm/props_renderpath.py @@ -4,6 +4,12 @@ from bpy.props import * import arm.assets as assets import arm.utils +if "DO_RELOAD_MODULE" in locals(): + assets = arm.reload_module(assets) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + atlas_sizes = [ ('256', '256', '256'), ('512', '512', '512'), ('1024', '1024', '1024'), diff --git a/blender/arm/props_traits.py b/blender/arm/props_traits.py index eba08da8..74918ee2 100755 --- a/blender/arm/props_traits.py +++ b/blender/arm/props_traits.py @@ -6,6 +6,7 @@ from typing import Union import webbrowser from bpy.types import NodeTree +from bpy.props import * import bpy.utils.previews import arm.make as make @@ -15,6 +16,17 @@ import arm.ui_icons as ui_icons import arm.utils import arm.write_data as write_data +if "DO_RELOAD_MODULE" in locals(): + arm.make = arm.reload_module(arm.make) + arm.props_traits_props = arm.reload_module(arm.props_traits_props) + from arm.props_traits_props import * + proxy = arm.reload_module(proxy) + ui_icons = arm.reload_module(ui_icons) + arm.utils = arm.reload_module(arm.utils) + arm.write_data = arm.reload_module(arm.write_data) +else: + DO_RELOAD_MODULE = True + ICON_HAXE = ui_icons.get_id('haxe') ICON_NODES = 'NODETREE' ICON_CANVAS = 'NODE_COMPOSITING' @@ -103,13 +115,13 @@ class ARM_UL_TraitList(bpy.types.UIList): custom_icon = "NONE" custom_icon_value = 0 if item.type_prop == "Haxe Script": - custom_icon_value = ui_icons.get_id("haxe") + custom_icon_value = ICON_HAXE elif item.type_prop == "WebAssembly": - custom_icon_value = ui_icons.get_id("wasm") + custom_icon_value = ICON_WASM elif item.type_prop == "UI Canvas": custom_icon = "NODE_COMPOSITING" elif item.type_prop == "Bundled Script": - custom_icon_value = ui_icons.get_id("bundle") + custom_icon_value = ICON_BUNDLED elif item.type_prop == "Logic Nodes": custom_icon = 'NODETREE' diff --git a/blender/arm/props_traits_props.py b/blender/arm/props_traits_props.py index 24931612..b65072cf 100644 --- a/blender/arm/props_traits_props.py +++ b/blender/arm/props_traits_props.py @@ -1,6 +1,8 @@ import bpy from bpy.props import * +__all__ = ['ArmTraitPropWarning', 'ArmTraitPropListItem', 'ARM_UL_PropList'] + PROP_TYPE_ICONS = { "String": "SORTALPHA", "Int": "CHECKBOX_DEHLT", diff --git a/blender/arm/props_ui.py b/blender/arm/props_ui.py index 4a37b470..3132880d 100644 --- a/blender/arm/props_ui.py +++ b/blender/arm/props_ui.py @@ -5,6 +5,8 @@ import shutil import bpy from bpy.props import * +from arm.lightmapper.panels import scene + import arm.api import arm.assets as assets from arm.exporter import ArmoryExporter @@ -20,10 +22,24 @@ import arm.proxy import arm.ui_icons as ui_icons import arm.utils -from arm.lightmapper.utility import icon -from arm.lightmapper.properties.denoiser import oidn, optix -from arm.lightmapper.panels import scene -import importlib +if "DO_RELOAD_MODULE" in locals(): + arm.api = arm.reload_module(arm.api) + assets = arm.reload_module(assets) + arm.exporter = arm.reload_module(arm.exporter) + from arm.exporter import ArmoryExporter + log = arm.reload_module(log) + arm.logicnode.replacement = arm.reload_module(arm.logicnode.replacement) + make = arm.reload_module(make) + state = arm.reload_module(state) + props = arm.reload_module(props) + arm.props_properties = arm.reload_module(arm.props_properties) + arm.props_traits = arm.reload_module(arm.props_traits) + arm.nodes_logic = arm.reload_module(arm.nodes_logic) + arm.proxy = arm.reload_module(arm.proxy) + ui_icons = arm.reload_module(ui_icons) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True class ARM_PT_ObjectPropsPanel(bpy.types.Panel): @@ -213,7 +229,7 @@ class ARM_PT_PhysicsPropsPanel(bpy.types.Panel): if obj.soft_body is not None: layout.prop(obj, 'arm_soft_body_margin') - + if obj.rigid_body_constraint is not None: layout.prop(obj, 'arm_relative_physics_constraint') diff --git a/blender/arm/ui_icons.py b/blender/arm/ui_icons.py index ed2649f5..9a40b4f0 100644 --- a/blender/arm/ui_icons.py +++ b/blender/arm/ui_icons.py @@ -6,6 +6,19 @@ from typing import Optional import bpy.utils.previews +if "DO_RELOAD_MODULE" in locals(): + # _unload_icons is not available in the module scope yet + def __unload(): + _unload_icons() + + # Refresh icons after reload + __unload() +else: + DO_RELOAD_MODULE = True + + +__all__ = ["get_id"] + _icons_dict: Optional[bpy.utils.previews.ImagePreviewCollection] = None """Dictionary of all loaded icons, or `None` if not loaded""" @@ -13,21 +26,28 @@ _icons_dir = os.path.join(os.path.dirname(__file__), "custom_icons") """Directory of the icon files""" -def _load_icons() -> None: - """(Re)loads all icons""" +def _load_icons(): + """(Re)loads all icons.""" global _icons_dict - if _icons_dict is not None: - bpy.utils.previews.remove(_icons_dict) + _unload_icons() _icons_dict = bpy.utils.previews.new() - _icons_dict.load("bundle", os.path.join(_icons_dir, "bundle.png"), 'IMAGE') - _icons_dict.load("haxe", os.path.join(_icons_dir, "haxe.png"), 'IMAGE') - _icons_dict.load("wasm", os.path.join(_icons_dir, "wasm.png"), 'IMAGE') + _icons_dict.load("bundle", os.path.join(_icons_dir, "bundle.png"), 'IMAGE', force_reload=True) + _icons_dict.load("haxe", os.path.join(_icons_dir, "haxe.png"), 'IMAGE', force_reload=True) + _icons_dict.load("wasm", os.path.join(_icons_dir, "wasm.png"), 'IMAGE', force_reload=True) + + +def _unload_icons(): + """Unloads all icons.""" + global _icons_dict + if _icons_dict is not None: + bpy.utils.previews.remove(_icons_dict) + _icons_dict = None def get_id(identifier: str) -> int: - """Returns the icon ID from the given identifier""" + """Returns the icon ID from the given identifier.""" if _icons_dict is None: _load_icons() return _icons_dict[identifier].icon_id diff --git a/blender/arm/utils.py b/blender/arm/utils.py index 7a9f1084..40a7c6d6 100755 --- a/blender/arm/utils.py +++ b/blender/arm/utils.py @@ -1,13 +1,14 @@ +from enum import Enum, unique import glob import json +import locale import os import platform import re +import shlex import subprocess from typing import Any, Dict, List, Optional, Tuple import webbrowser -import shlex -import locale import numpy as np @@ -18,7 +19,17 @@ from arm.lib.lz4 import LZ4 import arm.log as log import arm.make_state as state import arm.props_renderpath -from enum import Enum, unique + +if "DO_RELOAD_MODULE" in locals(): + arm.lib.armpack = arm.reload_module(arm.lib.armpack) + arm.lib.lz4 = arm.reload_module(arm.lib.lz4) + from arm.lib.lz4 import LZ4 + log = arm.reload_module(log) + state = arm.reload_module(state) + arm.props_renderpath = arm.reload_module(arm.props_renderpath) +else: + DO_RELOAD_MODULE = True + class NumpyEncoder(json.JSONEncoder): def default(self, obj): diff --git a/blender/arm/write_data.py b/blender/arm/write_data.py index 0eb56dc9..0e0cac42 100755 --- a/blender/arm/write_data.py +++ b/blender/arm/write_data.py @@ -11,6 +11,14 @@ import arm.assets as assets import arm.make_state as state import arm.utils +if "DO_RELOAD_MODULE" in locals(): + import arm + assets = arm.reload_module(assets) + state = arm.reload_module(state) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + def on_same_drive(path1: str, path2: str) -> bool: drive_path1, _ = os.path.splitdrive(path1) diff --git a/blender/arm/write_probes.py b/blender/arm/write_probes.py index f6ca036e..83a55a37 100644 --- a/blender/arm/write_probes.py +++ b/blender/arm/write_probes.py @@ -11,6 +11,14 @@ import arm.assets as assets import arm.log as log import arm.utils +if "DO_RELOAD_MODULE" in locals(): + import arm + assets = arm.reload_module(assets) + log = arm.reload_module(log) + arm.utils = arm.reload_module(arm.utils) +else: + DO_RELOAD_MODULE = True + def add_irr_assets(output_file_irr): assets.add(output_file_irr + '.arm') diff --git a/blender/start.py b/blender/start.py index d53cc4b3..19d75bd2 100755 --- a/blender/start.py +++ b/blender/start.py @@ -1,3 +1,7 @@ +import time + +import arm +import arm.log import arm.nodes_logic import arm.nodes_material import arm.props_traits_props @@ -15,8 +19,38 @@ import arm.handlers import arm.utils import arm.keymap +reload_started = 0 + +if "DO_RELOAD_MODULE" in locals(): + arm.log.debug('Reloading Armory SDK...') + reload_started = time.time() + + # Clear the module cache + import importlib + arm = importlib.reload(arm) # type: ignore + + arm.nodes_logic = arm.reload_module(arm.nodes_logic) + arm.nodes_material = arm.reload_module(arm.nodes_material) + arm.props_traits_props = arm.reload_module(arm.props_traits_props) + arm.props_traits = arm.reload_module(arm.props_traits) + arm.props_lod = arm.reload_module(arm.props_lod) + arm.props_tilesheet = arm.reload_module(arm.props_tilesheet) + arm.props_exporter = arm.reload_module(arm.props_exporter) + arm.props_bake = arm.reload_module(arm.props_bake) + arm.props_renderpath = arm.reload_module(arm.props_renderpath) + arm.props_properties = arm.reload_module(arm.props_properties) + arm.props_collision_filter_mask = arm.reload_module(arm.props_collision_filter_mask) + arm.props = arm.reload_module(arm.props) + arm.props_ui = arm.reload_module(arm.props_ui) + arm.handlers = arm.reload_module(arm.handlers) + arm.utils = arm.reload_module(arm.utils) + arm.keymap = arm.reload_module(arm.keymap) +else: + DO_RELOAD_MODULE = True + registered = False + def register(local_sdk=False): global registered registered = True @@ -37,6 +71,10 @@ def register(local_sdk=False): arm.handlers.register() arm.props_collision_filter_mask.register() + if reload_started != 0: + arm.log.debug(f'Armory SDK: Reloading finished in {time.time() - reload_started:.3f}s') + + def unregister(): global registered registered = False