| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654 | from .utilities import (prRed, prGreen, prPurple, prWhite,                              prOrange,                              wrapRed, wrapGreen, wrapPurple, wrapWhite,                              wrapOrange,)from .utilities import init_connections, init_dependenciesfrom .utilities import class_for_mantis_prototype_nodefrom .base_definitions import SchemaUINode, replace_types, custom_props_typesfrom .node_container_common import setup_custom_props_from_np# a class that solves Schema nodesfrom uuid import uuid4# currently this is fairly ugly and a lot of cooupling but it is at least within the class# basically tho the idea is to make solving happen one iteration at time so that I can have nested structures# ultimately it will be much less messy, because I can simplify it# the initializer __init__ does all the necessary initialization# then solve_iteration should both solve the iteration and do all the cleanup# so the interface should be able to solve_iteration on this node until it is done# actually.. that wasn't necesary. Maybe the current solution is even... better?# I donno. Maybe doing one iteration at a time would be a better way to do things.# Now that it works, I can very easily write a second class and replace this one#example UUID and index#9e6df689-3d71-425e-be6c-fe768e7417ec.0000# def strip_uuid(signature):#     # prOrange("strip uuid",signature)#     ret_sig=[]#     for name in signature:#         if name is None:#             ret_sig.append(None)#             continue # this is normal, first element#         ret_sig.append(strip_uuid_string(name))#     return tuple(ret_sig)# def strip_uuid_string(string):#     import re#     split = re.split("\.[a-z,A-Z,0-9]{8}-[a-z,A-Z,0-9]{4}-[a-z,A-Z,0-9]{4}-[a-z,A-Z,0-9]{4}-[a-z,A-Z,0-9]{12}\.[0-9]{4}", string)#     prRed(string, split)#     return split[0]        # to get this working with groups.... ensure that group node sockets and such are all working (names, identifiers...)# current error seems to occur only when schema are nested# error is probably caused by the lack of auto-get nodes for Schema Group inputs that are not connected# but it may simply be caused by bad routing# both bugs should be fixed (if it is two bugs and not one)class SchemaSolver:    def __init__(self, schema_dummy, nodes, prototype, signature=None):        self.all_nodes = nodes # this is the parsed tree from Mantis        self.node = schema_dummy        # ugly.. but we are getting the Schema node's prototype, then its node tree        from .utilities import get_node_prototype        self.tree = prototype.node_tree# get_node_prototype(self.node.signature, self.node.base_tree).node_tree        self.uuid = self.node.uuid        self.schema_nodes={}        self.solved_nodes = {}        # self.out_nodes = {}        self.incoming_connections = {}        self.outgoing_connections = {}        self.constant_in = {}        self.constant_out = {}        self.array_input_connections = {}        self.array_output_connections = {}        # prGreen(self.node.signature[:-1])        # This singature/natural_signature thing is so, so bad and stupid and wrong... but it works so I won't change it        if signature:            self.natural_signature=signature            # print (signature)        else:            self.natural_signature=self.node.signature                self.tree_path_names  = [*self.node.signature[:-1]] # same tree as the schema node        self.autogen_path_names = ['SCHEMA_AUTOGENERATED', *self.node.signature[1:-1]]        self.index_link = self.node.inputs['Schema Length'].links[0]        # TODO UNBREAK ME FIXME NOW        # identifiers are unfortunately not somethign I can set or predict in the items_tree        # but I can set them in the node.        # I either need to set them properly in the node so they always match        # or: I need to ignore the names and get the identifiers correctly        # self.node is a NC        # node_identifier_map_in = []        # node_identifier_map_out = []        for item in self.tree.interface.items_tree:            if item.item_type == 'PANEL': continue            if item.parent and item.parent.name == 'Connection':                if item.in_out == 'INPUT':                    if incoming_links := self.node.inputs[item.identifier].links:                        self.incoming_connections[item.name] = incoming_links[0]                    else:                        self.incoming_connections[item.name] = None # it isn't linked                        # print (self.node)                        # prRed("candidates...", self.node.inputs)                        # for k,v in self.node.inputs.items():                        #     print (k,v)                        # print(self.node.outputs)                        # print (self.node.parameters)                        # raise RuntimeError(f"Cannot find incoming connection \"{item.identifier}\" .")                else:                    if outgoing_links := self.node.outputs[item.identifier].links:                        self.outgoing_connections[item.name] = outgoing_links.copy()                    else:                        self.outgoing_connections[item.name] = []            if item.parent and item.parent.name == 'Constant':                if item.in_out == 'INPUT':                    if constant_in_links := self.node.inputs[item.identifier].links:                        self.constant_in[item.name] = constant_in_links[0]                    else:                        self.constant_in[item.name] = None                else:                    if constant_out_links := self.node.outputs[item.identifier].links:                        self.constant_out[item.name] = constant_out_links.copy()                    else:                        self.constant_out[item.name] = []            if item.parent and item.parent.name == 'Array':                if item.in_out == 'INPUT':                    if item.identifier not in self.array_input_connections.keys():                        self.array_input_connections[item.identifier]=[]                    if in_links := self.node.inputs[item.identifier].links:                        self.array_input_connections[item.identifier]=in_links.copy()                if item.in_out == 'OUTPUT':                    if item.identifier not in self.array_output_connections.keys():                        self.array_output_connections[item.identifier]=[]                    if out_links := self.node.outputs[item.identifier].links:                        self.array_output_connections[item.identifier] = out_links.copy()        self.held_links = []        # just define them for now... we redefine them properly later when they are needed. THis is messy.        self.index_str = lambda : '.'+str(self.uuid)+'.'+str(0).zfill(4)        self.prev_index_str = lambda : '.'+str(self.uuid)+'.'+str(0-1).zfill(4)        self.nested_schemas={}        self.autogenerated_nodes = {} # this is a bad ugly HACK, but I think I need to mark these and deal with them later        # Create the Schema Nodes        # prGreen(self.tree_path_names)        for n in self.tree.nodes:            if isinstance(n, SchemaUINode):                # first we need to fill the parameters of the schema nodes.                # the node is actually in the Schema group so we include the schema_dummy name                # and we use the bl_idname because I think all schema nodes should be single-instance                signature = (*self.tree_path_names, self.node.signature[-1], n.bl_idname)                # get_sig = [*self.tree_path_names, strip_uuid_string(self.node.signature[-1]), n.bl_idname]                # get_sig[0] = None; get_sig = tuple(get_sig) # this is so dumb haha                get_sig = (*self.natural_signature, n.bl_idname)                                if not (nc := self.all_nodes.get(get_sig)): raise RuntimeError(wrapRed(f"Not found: {get_sig}"))                self.schema_nodes[signature] = nc                # nc.signature = signature # I don't really intend for this value to be mutable... but... HACK                # there is no need to mutate this. also I may need to reuse it later                nc.fill_parameters(n)                # print (nc)                def solve(self, schema_length):        import time        start_time = time.time()        # from .schema_containers import SchemaIndex        # for nc in self.schema_nodes.values():        #     if isinstance(nc, SchemaIndex):        #         #HACK? I thought for sure this was being done elsewhere...        #         nc.parameters["Schema Length"]=schema_length        #         prRed(nc.parameters)        frame_nc={}        for index in range(schema_length):            frame_nc = self.solve_iteration(index, schema_length)            for sig, nc in frame_nc.items():                if nc.node_type == 'DUMMY_SCHEMA':                    self.nested_schemas[sig] = nc                # prRed (self.array_output_connections)        # for k,v in self.array_output_connections.items():        #     prRed(k,v)        self.finalize(frame_nc)        # prRed (self.array_output_connections)        # for k,v in self.array_output_connections.items():        #     prRed(k,v)        return self.solved_nodes    def solve_nested_schema(self, schema_nc):        if schema_nc.prepared == False:            all_nodes = self.all_nodes.copy()            # for k,v in self.solved_nodes.items():            #     all_nodes[k]=v            # from .utilities import get_node_prototype            np = schema_nc.prototype            # for n in self.node.base_tree.nodes:            #     print (n.name)            # print (schema_nc.signature[-1])            from .schema_solve import SchemaSolver            length = schema_nc.evaluate_input("Schema Length")            tree = np.node_tree            prOrange(f"Expanding schema {tree.name} in node {schema_nc} with length {length}.")            solver = SchemaSolver(schema_nc, all_nodes, np, schema_nc.natural_signature)            solved_nodes = solver.solve(length)            schema_nc.prepared = True            for k,v in solved_nodes.items():                self.solved_nodes[k]=v    def finalize(self, frame_nc):        from .schema_definitions import (SchemaOutgoingConnection,)        for i in range(len(self.held_links)):            link = self.held_links.pop()            to_np = link.to_socket.node; from_np = link.from_socket.node            if isinstance(to_np, SchemaOutgoingConnection):                if link.to_socket.name in self.outgoing_connections.keys():                    if (outgoing_links := self.outgoing_connections[link.to_socket.name]) is None: continue                    for outgoing in outgoing_links:                        if outgoing:                            to_node = outgoing.to_node                            from_node =frame_nc.get( (*self.autogen_path_names, from_np.name+self.index_str()) )                            connection = from_node.outputs[link.from_socket.name].connect(node=to_node, socket=outgoing.to_socket)                            # we need to kill the link between the Schema itself and the next node and update the deps. Otherwise:confusing bugs.                            outgoing.die(); init_dependencies(to_node)                    # else: # the node just isn't connected out this socket.                # # solve all unsolved nested schemas...        for schema_sig, schema_nc in self.nested_schemas.items():                self.solve_nested_schema(schema_nc)        for n in self.autogenerated_nodes.values():            init_connections(n)            for c in n.connections:                init_dependencies(c)        all_outgoing_links = []        for conn in self.outgoing_connections.values():            for outgoing in conn:                all_outgoing_links.append(outgoing)        for conn in self.constant_out.values():            for outgoing in conn:                all_outgoing_links.append(outgoing)        for conn in self.array_output_connections.values():            for outgoing in conn:                all_outgoing_links.append(outgoing)                for outgoing in all_outgoing_links:            to_node = outgoing.to_node            for l in to_node.inputs[outgoing.to_socket].links:                other = l.to_node                other_input = l.to_socket                if self.node == l.from_node:                    l.die()                for inp in self.node.inputs.values():            for l in inp.links:                init_connections(l.from_node) # to force it to have hierarchy connections with the new nodes.                                def solve_iteration(self, index, schema_length):        from .schema_definitions import (SchemaIndex,                                        SchemaArrayInput,                                        SchemaArrayInputGet,                                        SchemaArrayOutput,                                        SchemaConstInput,                                        SchemaConstOutput,                                        SchemaOutgoingConnection,                                        SchemaIncomingConnection,)        from bpy.types import (NodeFrame)                from .utilities import clear_reroutes        from .utilities import get_link_in_out, link_node_containers        # if index_nc:        #     index_nc.parameters['Index']=index        self.index_str = lambda : '.'+str(self.uuid)+'.'+str(index).zfill(4)        # index_str = str(index).zfill(4)        self.prev_index_str = lambda : '.'+str(self.uuid)+'.'+str(index-1).zfill(4)        frame_nc = {}        # At this point, GENERATE all the nodes for the frame        for n in self.tree.nodes:            if isinstance(n, SchemaUINode) or isinstance(n, NodeFrame):                continue            if n.bl_idname in ['NodeReroute']:                continue            # this is the N.C. which is a prototype of the NC we actually want to make...            signature = (*self.autogen_path_names, n.name+self.index_str())            # proto_nc = self.all_nodes.get((*self.tree_path_names, self.node.signature[-1], n.name))            proto_nc = self.all_nodes.get((*self.natural_signature, n.name))            # this proto_nc was generated inside the schema when we parsed the tree.            if not proto_nc:                raise RuntimeError(f"Node not found: {(*self.tree_path_names, self.node.signature[-1], n.name)}")            # for Schema sub-nodes ... they need a prototype to init.            if proto_nc.node_type in ['DUMMY', 'DUMMY_SCHEMA']:                from .utilities import get_node_prototype                np = get_node_prototype(proto_nc.signature, proto_nc.base_tree)                # assert np is not None                if proto_nc.node_type == 'DUMMY_SCHEMA':                    nat_sig = (*self.node.signature, np.name)                    nc = proto_nc.__class__(signature, proto_nc.base_tree, prototype=np, natural_signature=nat_sig)                else:                    nc = proto_nc.__class__(signature, proto_nc.base_tree, prototype=np)            else:            # try:                nc = proto_nc.__class__(signature, proto_nc.base_tree)            # except AttributeError:            #     from .utilities import get_node_prototype            #     np = get_node_prototype(proto_nc.signature, proto_nc.base_tree)            #     nc = proto_nc.__class__(signature, proto_nc.base_tree, prototype=np)            frame_nc[nc.signature] = nc            #            if nc.__class__.__name__ in custom_props_types:                setup_custom_props_from_np(nc, n)            nc.fill_parameters(n) # this is the best place to do this..        # This is where we handle node connections BETWEEN frames        for i in range(len(self.held_links)):            link = self.held_links.pop()            to_np = link.to_socket.node; from_np = link.from_socket.node            if isinstance(to_np, SchemaOutgoingConnection):                # incoming connection tells us where to take this.                incoming_node = self.schema_nodes[*self.tree_path_names, self.node.signature[-1], 'SchemaIncomingConnection']                for l in incoming_node.outputs[link.to_socket.name].links:                    to_node, to_socket = l.to_node, l.to_socket                    from_name = get_link_in_out(link)[0]                    from_node = self.solved_nodes.get( (*self.autogen_path_names, from_name+self.prev_index_str()) )                    #                    to_node = frame_nc.get( (*self.autogen_path_names, to_node.signature[-1]+self.index_str()) )                    # the to_node and to_socket don't really matter, the incoming connection will handle this part                                        connection = from_node.outputs[link.from_socket.name].connect(node=to_node, socket=to_socket)                    if existing_link := self.incoming_connections[link.to_socket.name]:                        # if index == 0:                        if self.node.signature[-1] in existing_link.to_node.signature:                        # not sure this is helping                            existing_link.die()                        # could be better to make it a dummy link?                    self.incoming_connections[link.to_socket.name] = connection        links = clear_reroutes(list(self.tree.links))        # frame_nc_with_schema = frame_nc.copy()        # for k,v in self.schema_nodes.items(): frame_nc_with_schema[k]=v        # Now we handle links in the current frame, including those links between Schema nodes and "real" nodes        # this gets really complicated :\        awaiting_prep_stage = []        for link in links:        # at THIS POINT I should make a buncha dummy links to deal        #   with the schema node connections...            to_np = link.to_socket.node; from_np = link.from_socket.node            if isinstance(to_np, SchemaConstOutput) or isinstance(to_np, SchemaArrayOutput) or \                isinstance(from_np, SchemaArrayInputGet):# or isinstance(from_np, SchemaArrayInput):                awaiting_prep_stage.append(link)                continue            if isinstance(from_np, SchemaIndex):                if link.from_socket.name == "Index":                    _from_name, to_name = get_link_in_out(link)                    to_node = frame_nc.get( (*self.autogen_path_names, to_name+self.index_str()) )                    if to_node.node_type in ['DUMMY', 'DUMMY_SCHEMA']:                        # prRed("This is causing the problem, right?")                        from .utilities import gen_nc_input_for_data                        nc_cls = gen_nc_input_for_data(link.from_socket)                        if (nc_cls): #HACK                            sig = ("MANTIS_AUTOGENERATED", *self.tree_path_names[1:], self.index_str(), link.from_socket.name, link.from_socket.identifier)                            nc_from = nc_cls(sig, self.node.base_tree)                            # ugly! maybe even a HACK!                            nc_from.inputs = {}                            from .base_definitions import NodeSocket                            nc_from.outputs = {link.from_socket.name:NodeSocket(name = link.from_socket.name, node=nc_from)}                            from .base_definitions import get_socket_value                            nc_from.parameters = {link.from_socket.name:index}                            frame_nc[sig]=nc_from                            from_node = nc_from                            # self.autogenerated_nodes[sig]=from_node                            self.solved_nodes[sig]=from_node                            connection = from_node.outputs[link.from_socket.name].connect(node=to_node, socket=link.to_socket.identifier)                            # prGreen(connection)                        continue                    # this actually seems to work. I could use Autogen nodes                    # but maybe this is actually better since it results in fewer nodes.                    # if this never causes any problems, then I will do it in other places                    # HACK Here Be Danger HACK                    to_node.parameters[link.to_socket.name] = index                    del to_node.inputs[link.to_socket.name]                    # so I have tried to implement this as connections and actually this is the best way because otherwise I have                    #  to do something very similar on the input node.                    # HACK                elif link.from_socket.name == "Schema Length":                    # # see, here I can just use the schema node                    _from_name, to_name = get_link_in_out(link)                    to_node = frame_nc.get( (*self.autogen_path_names, to_name+self.index_str()) )                    # this self.index_link is only used here?                    if (self.index_link.from_node):                        connection = self.index_link.from_node.outputs[self.index_link.from_socket].connect(node=to_node, socket=link.to_socket.name)                    # otherwise we can autogen an int input I guess...?                    else:                        raise RuntimeError("I was expecting there to be an incoming connection here for Schema Length")                continue            if isinstance(from_np, SchemaIncomingConnection):                if link.from_socket.name in self.incoming_connections.keys():                    incoming = self.incoming_connections[link.from_socket.name]                    # if incoming is None:                    #     print (link.from_socket.name)                    from_node = incoming.from_node                    _from_name, to_name = get_link_in_out(link)                    to_node = frame_nc.get( (*self.autogen_path_names, to_name+self.index_str()) )                    # try:                    connection = from_node.outputs[incoming.from_socket].connect(node=to_node, socket=link.to_socket.name)                    # prGreen(connection)                    # except KeyError as e:                    #     prRed(f"busted: {from_node}:{incoming.from_socket} --> {to_node}:{link.to_socket.name},{link.to_socket.identifier}")                        # for output in from_node.outputs:                        #     prOrange(output)                        # for sinput in from_node.inputs:                        #     prPurple(sinput)                        # raise e                    init_connections(from_node)                continue            if isinstance(to_np, SchemaOutgoingConnection):                self.held_links.append(link)                continue             if isinstance(from_np, SchemaConstInput):                if link.from_socket.name in self.constant_in.keys():                    incoming = self.constant_in[link.from_socket.name]                    from_node = incoming.from_node                    to_name = get_link_in_out(link)[1]                    to_node = frame_nc.get( (*self.autogen_path_names, to_name+self.index_str()) )                    # print(from_node, incoming.from_socket, "==>", to_node, link.to_socket.identifier)                    # print (to_node.inputs)                    # for k,v in from_node.outputs.items():                    #     print (k,v)                    # print (from_node.outputs[incoming.from_socket])                    to_socket=link.to_socket.name                    from .base_definitions import SchemaGroup                    if isinstance(to_np, SchemaGroup):                        to_socket=link.to_socket.identifier                    connection = from_node.outputs[incoming.from_socket].connect(node=to_node, socket=to_socket)                    init_connections(from_node)                continue             if isinstance(to_np, SchemaArrayInputGet):                from_name, to_name = get_link_in_out(link)                from_nc = frame_nc.get( (*self.autogen_path_names, from_name+self.index_str()))                to_nc = self.schema_nodes.get((*self.tree_path_names, self.node.signature[-1], to_name))                # this only needs to be done once.                if index == 0:                    old_nc = self.all_nodes.get((*self.tree_path_names, self.node.signature[-1], from_name))                    # I am not sure about this!                    existing_link = old_nc.outputs[link.from_socket.name].links[0]                    existing_link.die()                #                connection = from_nc.outputs[link.from_socket.name].connect(node=to_nc, socket=link.to_socket.name)                continue            if isinstance(from_np, SchemaArrayInput):                get_index = index                try:                    incoming = self.array_input_connections[link.from_socket.identifier][get_index]                except IndexError:                    if len(self.array_input_connections[link.from_socket.identifier]) > 0:                        incoming = self.array_input_connections[link.from_socket.identifier][0]                        # prOrange(incoming.from_node.node_type)                        if incoming.from_node.node_type not in ['DUMMY_SCHEMA']:                            raise RuntimeError(wrapRed("You need to make it so Mantis checks if there are enough Array inputs."))                        else: # do nothing                            continue                    else:                        raise RuntimeError(wrapRed("make it so Mantis checks if there are enough Array inputs!"))                to_name = get_link_in_out(link)[1]                to_node = frame_nc.get((*self.autogen_path_names, to_name+self.index_str()))                connection = incoming.from_node.outputs[incoming.from_socket].connect(node=to_node, socket=link.to_socket.name)                init_connections(incoming.from_node)                continue            link_path_names = self.tree_path_names[1:]            # use this line to debug, usually I don't need it            connection = link_node_containers(self.autogen_path_names, link, frame_nc, from_suffix=self.index_str(), to_suffix=self.index_str())        for k,v in frame_nc.items():            self.solved_nodes[k]=v            init_dependencies(v) # it is hard to overstate how important this single line of code is            # for node in v.hierarchy_dependencies:            #     init_connections(node)        # done with the link handling.                # Start Section: This is the place where we solve dependencies and continue        # we need to sort the nodes in solved_nc and prepare whatever can be preepared.        from collections import deque        unprepared= deque()        for nc in frame_nc.values():            if nc.prepared == False:                unprepared.append(nc)                # this is potentially a little inneficient but it isn't a big deal.                # since the only extra preparations I am doing is nodes that don't yet have outgoing connections                # but I may add them in the next step anyways, then I need to prepare them! so this is simpler.        # at this point it should be possible to sort unprepared to avoid the while loop        # but I don't really care. this will work since we have guarenteed solved all the        #  schema_dummy's dependencies.... I hope. lol.        while unprepared: # DANGER.            # raise NotImplementedError            # prRed("this part!")            nc = unprepared.pop()            # print(nc)            if sum([dep.prepared for dep in nc.hierarchy_dependencies]) == len(nc.hierarchy_dependencies):                nc.bPrepare()                if nc.node_type == 'DUMMY_SCHEMA':                    self.solve_nested_schema(nc)            else:                # print (sum([dep.prepared for dep in nc.hierarchy_dependencies]), len(nc.hierarchy_dependencies))                # for dep in nc.hierarchy_dependencies:                #     if not dep.prepared:                #         prOrange(dep)                unprepared.appendleft(nc)                for i in range(len(awaiting_prep_stage)): #why is this a for loop and not a while loop?? # FIXME?            link = awaiting_prep_stage.pop()            to_np = link.to_socket.node; from_np = link.from_socket.node            if isinstance(to_np, SchemaConstOutput):                to_node = self.schema_nodes.get((*self.tree_path_names, self.node.signature[-1], to_np.bl_idname))                expose_when = to_node.evaluate_input('Expose when N==')                if index == expose_when:                    for outgoing in self.constant_out[link.to_socket.name]:                        to_node = outgoing.to_node                        from_name = get_link_in_out(link)[0]                        from_node = frame_nc.get( (*self.autogen_path_names, from_name+self.index_str()) )                        connection = from_node.outputs[link.from_socket.name].connect(node=to_node, socket=outgoing.to_socket)            if isinstance(to_np, SchemaArrayOutput): # if this duplicated code works, dedupe!                to_node = self.schema_nodes.get((*self.tree_path_names, self.node.signature[-1], to_np.bl_idname))                for outgoing in self.array_output_connections[link.to_socket.identifier]:                    # print (type(outgoing))                    from .schema_containers import SchemaIndex                    from_name = get_link_in_out(link)[0]                    from_node = frame_nc.get( (*self.autogen_path_names, from_name+self.index_str()) )                    if not from_node:                        from_node = self.schema_nodes.get( (*self.tree_path_names, self.node.signature[-1], from_np.bl_idname) )                    if not from_node:                        raise RuntimeError()                    to_node = outgoing.to_node                    if isinstance(from_node, SchemaIndex): # I think I need to dedup this stuff                        # print("INDEX")                        from .utilities import gen_nc_input_for_data                        nc_cls = gen_nc_input_for_data(link.from_socket)                        if (nc_cls): #HACK                            sig = ("MANTIS_AUTOGENERATED", *self.tree_path_names[1:], self.index_str(), link.from_socket.name, link.from_socket.identifier)                            nc_from = nc_cls(sig, self.node.base_tree)                            # ugly! maybe even a HACK!                            nc_from.inputs = {}                            from .node_container_common import NodeSocket                            nc_from.outputs = {link.from_socket.name:NodeSocket(name = link.from_socket.name, node=nc_from)}                            from .node_container_common import get_socket_value                            if link.from_socket.name in ['Index']:                                nc_from.parameters = {link.from_socket.name:index}                            else:                                nc_from.parameters = {link.from_socket.name:schema_length}                            frame_nc[sig]=nc_from                            from_node = nc_from                            self.solved_nodes[sig]=from_node                    # I have a feeling that something bad will happen if both of these conditions (above and below) are true                    if to_node.node_type == 'DUMMY_SCHEMA' and to_node.prepared:                        other_stem = ('SCHEMA_AUTOGENERATED', *to_node.signature[1:-1])                        from .utilities import get_node_prototype                        other_schema_np = get_node_prototype(to_node.signature, to_node.base_tree)                        other_schema_tree = other_schema_np.node_tree                        for n in other_schema_tree.nodes:                            if n.bl_idname not in ["SchemaArrayInput", "SchemaArrayInputGet"]:                                continue                            out = n.outputs[outgoing.to_socket]                            for l in out.links:                                other_index_str = lambda : '.'+str(to_node.uuid)+'.'+str(index).zfill(4)                                out_node = self.all_nodes.get((*other_stem, l.to_node.name+other_index_str()))                                connection = from_node.outputs[link.from_socket.name].connect(node=out_node, socket=l.to_socket.name)                    else:                        connection = from_node.outputs[link.from_socket.name].connect(node=to_node, socket=outgoing.to_socket)                                                    if isinstance(from_np, SchemaArrayInputGet): # or isinstance(from_np, SchemaArrayInput) or                 get_index = index                if isinstance(from_np, SchemaArrayInputGet):                    from_node = self.schema_nodes.get((*self.tree_path_names, self.node.signature[-1], from_np.bl_idname))                    from .utilities import cap, wrap                    get_index = from_node.evaluate_input("Index", index)                    oob = from_node.evaluate_input("OoB Behaviour")                    # we must assume that the array has sent the correct number of links                    if oob == 'WRAP':                        get_index = wrap(get_index, len(self.array_input_connections[link.from_socket.identifier])-1, 0)                    if oob == 'HOLD':                        get_index = cap(get_index, len(self.array_input_connections[link.from_socket.identifier])-1)                try:                    incoming = self.array_input_connections[link.from_socket.identifier][get_index]                except IndexError:                    raise RuntimeError(wrapRed("Dummy! You need to make it so Mantis checks if there are enough Array inputs! It should probably have a Get Index!"))                to_name = get_link_in_out(link)[1]                to_node = frame_nc.get((*self.autogen_path_names, to_name+self.index_str()))                connection = incoming.from_node.outputs[incoming.from_socket].connect(node=to_node, socket=link.to_socket.name)                init_connections(incoming.from_node)            # end seciton        return frame_nc            # TODO: figure out why the tree is sorting wrong when using arrays!# despite a lot of ugly hacks, things are going well# current TODO:#  - get nested schema working when nodes in the parent tree depend on them#  - eventually I can clean all this up by re-designing the solver code to solve one iteration at a time instead of all at once#  - get schema-in-group working#  - groups need constants and arrays # maybe the simplest solution is for groups to be schema always# but I don't want to do that# anyways the next milestone is for the spine to be a group or schema output# note that schemas will send out arrays and such. So I don't necessarily want groups to have array in/out# instead, groups are simple# they can contain schema, but schema can't have arrays from the group interface# groups are good for large, abstract components# fundamentally they are similar but groups are cleaner since they don't require dependency solving# anyways... schema with nesting and groups is good enough for now# I don't need it to be stable. I just need to rig my human model with Mantis and iterate from there. Getting it to rig a human character will find and fix most bugs.
 |