Megascan Import script addition for Blender - Solved

5/8/2019 So far, a 48+ people have viewed this thread, but none of tried to integrate the script addition that I have suggested. Is it doable? Have I asked the impossible?
I am using Blender 2.80Beta, and Quixel Megascans Bridge ships with an Import Addon to Blender, that works as intended, except, it doesn’t give the User any indication of what to do, or that it is working at all. I sent in this code, and they put it in their, someday/maybe category. I do not code Python well enough to implement this change, so I am including their init.py script and the additional code that should be part of it. All of the new code is from https://b3d.interplanety.org/en/creating-pop-up-panels-with-user-ui-in-blender-add-on/
The only part, is the actual message that I would like to have displayed.
________________________________ Here is their code.
#init.py

# ##### QUIXEL AB - MEGASCANS LIVELINK FOR BLENDER #####
#
# The Megascans LiveLink plugin for Blender is an add-on that lets
# you instantly import assets with their shader setup with one click only.
#
# Because it relies on some of the latest 2.80 features, this plugin is currently
# only available for Blender 2.80 and forward.
#
# You are free to modify, add features or tweak this add-on as you see fit, and
# don't hesitate to send us some feedback if you've done something cool with it.
#
# ##### QUIXEL AB - MEGASCANS LIVELINK FOR BLENDER #####


# version: 0.5b 

import bpy, threading, os, time, json, socket

globals()['Megascans_DataSet'] = None

debug_info_files = False

bl_info = {
    "name": "Megascans LiveLink",
    "description": "Connects Blender to Quixel Bridge for one-click imports with shader setup and geometry",
    "author": "Quixel",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "File > Import",
    "warning": "", # used for warning icon and text in addons panel
    "wiki_url": "https://docs.quixel.org/bridge/livelinks/blender/info_quickstart.html",
    "tracker_url": "https://docs.quixel.org/bridge/livelinks/blender/info_quickstart#release_notes",
    "support": "COMMUNITY",
    "category": "Import-Export"
}


# MS_Init_ImportProcess is the main asset import class.
# This class is invoked whenever a new asset is set from Bridge.

class MS_Init_ImportProcess():

    def __init__(self):
    # This initialization method create the data structure to process our assets
    # later on in the initImportProcess method. The method loops on all assets
    # that have been sent by Bridge.

        print("Initialized import class...")

        # Check if there's any incoming data
        if globals()['Megascans_DataSet'] != None:
            self.json_Array = json.loads(globals()['Megascans_DataSet'])

            # Start looping over each asset in the self.json_Array list
            for js in self.json_Array:

                self.json_data = js

                self.selectedObjects = []

                self.assetType = self.json_data["type"]
                self.assetPath = self.json_data["path"]
                self.assetID = self.json_data["id"]
                self.isMetal = bool(self.json_data["category"] == "Metal") 

                baseTextures = ["albedo", "displacement", "normal", "roughness",
                                "specular", "normalbump", "ao", "opacity",
         __.py                       "translucency", "gloss", "metalness", "bump", "fuzz"]

                # Create a list of tuples of all the textures maps available.
                # This tuple is composed of (textureFormat, textureMapType, texturePath)
                self.textureList = []
                for obj in self.json_data["components"]:
                    if obj["type"] in baseTextures:
                        self.textureList.append( (obj["format"], obj["type"], obj["path"]) )

                # Create a tuple list of all the 3d meshes  available.
                # This tuple is composed of (meshFormat, meshPath)
                self.geometryList = [(obj["format"], obj["path"]) for obj in self.json_data["meshList"]]

                # Create name of our asset. Multiple conditions are set here
                # in order to make sure the asset actually has a name and that the name
                # is short enough for us to use it. We compose a name with the ID otherwise.
                if "name" in self.json_data.keys():
                    self.assetName = self.json_data["name"].replace(" ", "_")
                else:
                    self.assetName = os.path.basename(self.json_data["path"]).replace(" ", "_")
                if len(self.assetName.split("_")) > 2:
                    self.assetName = "_".join(self.assetName.split("_")[:-1])

                self.materialName = self.assetName + '_' + self.assetID

                # Commented these lines, but you can use this to load the json data of a specific
                # asset and retrieve information like tags, real-world size, scanning location, etc...
                with open(os.path.join( self.assetPath, (self.assetID + ".json" ) ), 'r') as fl_:
                    assetJson =  json.load(fl_)

                # Initialize the import method to start building our shader and import our geometry
                self.initImportProcess()
                print("Imported asset from" + self.assetName + " Quixel Bridge")

            globals()['Megascans_DataSet'] = None


    def initImportProcess(self):
    # this method is used to import the geometry and create the material setup.
    
        if len(self.textureList) >= 1:

            # Import geometry
            if len(self.geometryList) >= 1:
                for obj in self.geometryList:
                    meshPath = obj[1]
                    meshFormat = obj[0]

                    if meshFormat.lower() == "fbx":
                        myOBJ = bpy.ops.import_scene.fbx(filepath=meshPath)
                        # get selected objects
                        obj_objects = [ o for o in bpy.context.scene.objects if o.select_get() ]
                        self.selectedObjects += obj_objects

                    elif meshFormat.lower() == "obj":
                        myOBJ = bpy.ops.import_scene.obj(filepath=meshPath)
                        # get selected objects
                        obj_objects = [ o for o in bpy.context.scene.objects if o.select_get() ]
                        self.selectedObjects += obj_objects

            # Create material
            mat = (bpy.data.materials.get( self.materialName ) or bpy.data.materials.new( self.materialName ))

            mat.use_nodes = True
            nodes = mat.node_tree.nodes

            # iterate through all objects
            for obj in self.selectedObjects:
                # assign material to obj
                obj.active_material = mat

            # Get a list of all available texture maps. item[1] returns the map type (albedo, normal, etc...).
            maps_ = [item[1] for item in self.textureList]
            parentName = "Principled BSDF"
            colorSpaces = ["COLOR", "NONE"]

            mat.node_tree.nodes[parentName].inputs[4].default_value = 1 if self.isMetal else 0 # Metallic value
            mat.node_tree.nodes[parentName].inputs[14].default_value = 1.52 # IOR Value

            y_exp = 310

            # Create the albedo setup.
            if "albedo" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "albedo"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (-720, y_exp)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[0]

                    mat.node_tree.links.new(nodes.get(parentName).inputs[0], texNode.outputs[0])

            # Create the roughness setup.
            if "roughness" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "roughness"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (-720, y_exp)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[1]

                    mat.node_tree.links.new(nodes.get(parentName).inputs[7], texNode.outputs[0])

            # Create the fuzziness setup.
            if "fuzz" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "fuzz"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (-720, y_exp)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[1]

                    mat.node_tree.links.new(nodes.get(parentName).inputs[10], texNode.outputs[0])
                    nodes.get(parentName).inputs[11].default_value = 1

            # Create the metalness setup
            if "metalness" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "metalness"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (-720, y_exp)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[1]

                    mat.node_tree.links.new(nodes.get(parentName).inputs[4], texNode.outputs[0])

            # Create the displacement setup.
            if "displacement" in maps_:

                pass

            # Create the translucency setup.
            if "translucency" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "translucency"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (-720, y_exp)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[0]

                    mat.node_tree.links.new(nodes.get(parentName).inputs[3], texNode.outputs[0])

            # Create the opacity setup
            if "opacity" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "opacity"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (256, 0)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[1]

                    # mat.node_tree.links.new(nodes.get(parentName).inputs[4], texNode.outputs[0])

                    mixNode = nodes.new('ShaderNodeMixShader')
                    mixNode.location = (630, 0)
                    mixNode.inputs[0].default_value = 1
                    mat.node_tree.links.new(mixNode.inputs[0], texNode.outputs[0])

                    transpNode = nodes.new('ShaderNodeBsdfTransparent')
                    transpNode.location = (375, 168)
                    mat.node_tree.links.new(mixNode.inputs[1], transpNode.outputs[0])

                    mat.node_tree.links.new(nodes.get("Principled BSDF").outputs["BSDF"], mixNode.inputs[2])
                    mat.node_tree.links.new(nodes.get("Material Output").inputs["Surface"], mixNode.outputs[0])

                    mat.blend_method = 'CLIP'
                    mat.transparent_shadow_method = 'CLIP'

            # Create the normal map setup for Redshift.
            if "normal" in maps_:

                normalNode = nodes.new('ShaderNodeNormalMap')
                texNode = nodes.new('ShaderNodeTexImage')

                imgPath = [item[2] for item in self.textureList if item[1] == "normal"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode.location = (-720*1.5, y_exp)

                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[1]

                    normalNode.location = (-450, y_exp)

                    mat.node_tree.links.new(nodes.get(parentName).inputs[17], normalNode.outputs[0])
                    texNode.color_space = colorSpaces[1]
                    mat.node_tree.links.new(texNode.outputs[0], normalNode.inputs[1])

                    mat.node_tree.links.new(texNode.outputs[0], normalNode.inputs[1])

class ms_Init(threading.Thread):
    
	#Initialize the thread and assign the method (i.e. importer) to be called when it receives JSON data.
    def __init__(self, importer):
        threading.Thread.__init__(self)
        self.importer = importer

	#Start the thread to start listing to the port.
    def run(self):
        try:
            run_livelink = True
            host, port = 'localhost', 28888
            #Making a socket object.
            socket_ = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            #Binding the socket to host and port number mentioned at the start.
            socket_.bind((host, port))

            #Run until the thread starts receiving data.
            while run_livelink:
                socket_.listen(5)
                #Accept connection request.
                client, addr = socket_.accept()
                data = ""
                buffer_size = 4096*2
                #Receive data from the client. 
                data = client.recv(buffer_size)
                if debug_info_files:
                    open(r'C:\Users\Dell\Documents\socket_data.txt', 'w').write(str(data))
                if data == b'Bye Megascans':
                    if debug_info_files:
                        open(r'C:\Users\Dell\Documents\socket_exception.txt', 'w').write("Why are you not quitting? 1")
                    run_livelink = False
                    break

                #If any data is received over the port.
                if data != "":
                    self.TotalData = b""
                    self.TotalData += data #Append the previously received data to the Total Data.
                    #Keep running until the connection is open and we are receiving data.
                    while run_livelink:
                        #Keep receiving data from client.
                        data = client.recv(4096*2)
                        if debug_info_files:
                            open(r'C:\Users\Dell\Documents\socket_data_1.txt', 'w').write(str(data))
                        if data == b'Bye Megascans':
                            if debug_info_files:
                                open(r'C:\Users\Dell\Documents\socket_exception.txt', 'w').write("Why are you not quitting? 11")
                            run_livelink = False
                            break
                        #if we are getting data keep appending it to the Total data.
                        if data : self.TotalData += data
                        else:
                            #Once the data transmission is over call the importer method and send the collected TotalData.
                            self.importer(self.TotalData)
                            break
        except:
            pass

class thread_checker(threading.Thread):
    
	#Initialize the thread and assign the method (i.e. importer) to be called when it receives JSON data.
    def __init__(self):
        threading.Thread.__init__(self)

	#Start the thread to start listing to the port.
    def run(self):
        try:
            run_checker = True
            while run_checker:
                time.sleep(3)
                for i in threading.enumerate():
                    if debug_info_files:
                        open(r'C:\Users\Dell\Documents\threadses.txt', 'a').write("Name: " + i.getName() + " Is Alive? " + str(i.is_alive()) + "\n")
                    if(i.getName() == "MainThread" and i.is_alive() == False):
                        host, port = 'localhost', 28888
                        s = socket.socket()
                        s.connect((host,port))
                        data = "Bye Megascans"
                        s.send(data.encode())
                        s.close()
                        run_checker = False
                        if debug_info_files:
                            open(r'C:\Users\Dell\Documents\main_thread_dead.txt', 'a').write("Why are you not quitting? 111")
                        break
        except Exception as e:
            if debug_info_files:
                open(r'C:\Users\Dell\Downloads\thread_exception.txt', 'a').write(str(e))
            pass

class MS_Init_LiveLink(bpy.types.Operator):

    bl_idname = "ms_livelink.py"
    bl_label = "Megascans LiveLink"
    socketCount = 0

    def execute(self, context):

        try:
            globals()['Megascans_DataSet'] = None
            self.thread_ = threading.Thread(target = self.socketMonitor)
            self.thread_.start()
            bpy.app.timers.register(self.newDataMonitor)
            return {'FINISHED'}
        except Exception as e:
            print( "Megascans LiveLink Error : ", str(e) )
            return {"FAILED"}

    def newDataMonitor(self):
        if globals()['Megascans_DataSet'] != None:
            MS_Init_ImportProcess()
            globals()['Megascans_DataSet'] = None
        return 1.0


    def socketMonitor(self):
        #Making a thread object
        threadedServer = ms_Init(self.importer)
        #Start the newly created thread.
        threadedServer.start()
        #Making a thread object
        thread_checker_ = thread_checker()
        #Start the newly created thread.
        thread_checker_.start()
        

    def importer (self, recv_data):
        globals()['Megascans_DataSet'] = recv_data

def menu_func_import(self, context):
    self.layout.operator(MS_Init_LiveLink.bl_idname, text="Megascans LiveLink")


def register():
    bpy.utils.register_class(MS_Init_LiveLink)
    bpy.types.TOPBAR_MT_file_import.append(menu_func_import)

def unregister():
    # bpy.utils.unregister_class(MS_Init_LiveLink)
    bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)

if __name__ == "__main__":
    register()

________________________________ Here is the Messagebox code that it should invoke.
#messagebox.py

import bpy
 
class MessageBox(bpy.types.Operator):
    bl_idname = "message.messagebox"
    bl_label = ""
 
    message = bpy.props.StringProperty(
        name = "message",
        description = "message",
        default = ''
    )
 
    def execute(self, context):
        self.report({'INFO'}, self.message)
        print(self.message)
        return {'FINISHED'}
 
    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self, width = 400)
 
    def draw(self, context):
        self.layout.label(self.message)
        self.layout.label("")
 
# somewhere in the add-on code
 
import messagebox
 
 # here is the message that I want to display, when the addon is involked
msg = 'The Import from Bridge is working correctly. Return to Bridge and Export an Asset, as the Import function is Listening. Your material will show up in the Material Window to be applied to an object/mesh, when you return to Blender.'
bpy.ops.message.messagebox('INVOKE_DEFAULT', message = msg)
 
def register():
    bpy.utils.register_class(MessageBox)
 
def unregister():
    bpy.utils.unregister_class(MessageBox)
 
if __name__ == "__main__":
    register()

I have partially solved the question. Only problem left over, is that the MessageBox will show when you open Blender, if the Megascans Livelink is enabled. A fair reminder, because Blender is going thru the Addons and initializes the plugin. But, it works as intended. It is Open Source, so any further improvements are always welcome.

# ##### QUIXEL AB - MEGASCANS LIVELINK FOR BLENDER #####
#
# The Megascans LiveLink plugin for Blender is an add-on that lets
# you instantly import assets with their shader setup with one click only.
#
# Because it relies on some of the latest 2.80 features, this plugin is currently
# only available for Blender 2.80 and forward.
#
# You are free to modify, add features or tweak this add-on as you see fit, and
# don't hesitate to send us some feedback if you've done something cool with it.
#
# ##### QUIXEL AB - MEGASCANS LIVELINK FOR BLENDER #####


# version: 0.5b 
# modified: Paul Hartsuyker 2019-05-10 with help from
# https://stackoverflow.com/questions/4485610/python-message-box-without-huge-library-dependency 

import bpy, threading, os, time, json, socket, ctypes
# modified: added ctypes to import above.
globals()['Megascans_DataSet'] = None

debug_info_files = False

bl_info = {
    "name": "Megascans LiveLink",
    "description": "Connects Blender to Quixel Bridge for one-click imports with shader setup and geometry",
    "author": "Quixel",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "File > Import",
    "warning": "", # used for warning icon and text in addons panel
    "wiki_url": "https://docs.quixel.org/bridge/livelinks/blender/info_quickstart.html",
    "tracker_url": "https://docs.quixel.org/bridge/livelinks/blender/info_quickstart#release_notes",
    "support": "COMMUNITY",
    "category": "Import-Export"
}


# MS_Init_ImportProcess is the main asset import class.
# This class is invoked whenever a new asset is set from Bridge.

class MS_Init_ImportProcess():

    def __init__(self):
    # This initialization method create the data structure to process our assets
    # later on in the initImportProcess method. The method loops on all assets
    # that have been sent by Bridge.

        print("Initialized import class...")

        # Check if there's any incoming data
        if globals()['Megascans_DataSet'] != None:
            self.json_Array = json.loads(globals()['Megascans_DataSet'])

            # Start looping over each asset in the self.json_Array list
            for js in self.json_Array:

                self.json_data = js

                self.selectedObjects = []

                self.assetType = self.json_data["type"]
                self.assetPath = self.json_data["path"]
                self.assetID = self.json_data["id"]
                self.isMetal = bool(self.json_data["category"] == "Metal") 

                baseTextures = ["albedo", "displacement", "normal", "roughness",
                                "specular", "normalbump", "ao", "opacity",
                                "translucency", "gloss", "metalness", "bump", "fuzz"]

                # Create a list of tuples of all the textures maps available.
                # This tuple is composed of (textureFormat, textureMapType, texturePath)
                self.textureList = []
                for obj in self.json_data["components"]:
                    if obj["type"] in baseTextures:
                        self.textureList.append( (obj["format"], obj["type"], obj["path"]) )

                # Create a tuple list of all the 3d meshes  available.
                # This tuple is composed of (meshFormat, meshPath)
                self.geometryList = [(obj["format"], obj["path"]) for obj in self.json_data["meshList"]]

                # Create name of our asset. Multiple conditions are set here
                # in order to make sure the asset actually has a name and that the name
                # is short enough for us to use it. We compose a name with the ID otherwise.
                if "name" in self.json_data.keys():
                    self.assetName = self.json_data["name"].replace(" ", "_")
                else:
                    self.assetName = os.path.basename(self.json_data["path"]).replace(" ", "_")
                if len(self.assetName.split("_")) > 2:
                    self.assetName = "_".join(self.assetName.split("_")[:-1])

                self.materialName = self.assetName + '_' + self.assetID

                # Commented these lines, but you can use this to load the json data of a specific
                # asset and retrieve information like tags, real-world size, scanning location, etc...
                with open(os.path.join( self.assetPath, (self.assetID + ".json" ) ), 'r') as fl_:
                    assetJson =  json.load(fl_)

                # Initialize the import method to start building our shader and import our geometry
                self.initImportProcess()
                print("Imported asset from" + self.assetName + " Quixel Bridge")

            globals()['Megascans_DataSet'] = None


    def initImportProcess(self):
    # this method is used to import the geometry and create the material setup.
    
        if len(self.textureList) >= 1:

            # Import geometry
            if len(self.geometryList) >= 1:
                for obj in self.geometryList:
                    meshPath = obj[1]
                    meshFormat = obj[0]

                    if meshFormat.lower() == "fbx":
                        myOBJ = bpy.ops.import_scene.fbx(filepath=meshPath)
                        # get selected objects
                        obj_objects = [ o for o in bpy.context.scene.objects if o.select_get() ]
                        self.selectedObjects += obj_objects

                    elif meshFormat.lower() == "obj":
                        myOBJ = bpy.ops.import_scene.obj(filepath=meshPath)
                        # get selected objects
                        obj_objects = [ o for o in bpy.context.scene.objects if o.select_get() ]
                        self.selectedObjects += obj_objects

            # Create material
            mat = (bpy.data.materials.get( self.materialName ) or bpy.data.materials.new( self.materialName ))

            mat.use_nodes = True
            nodes = mat.node_tree.nodes

            # iterate through all objects
            for obj in self.selectedObjects:
                # assign material to obj
                obj.active_material = mat

            # Get a list of all available texture maps. item[1] returns the map type (albedo, normal, etc...).
            maps_ = [item[1] for item in self.textureList]
            parentName = "Principled BSDF"
            colorSpaces = ["COLOR", "NONE"]

            mat.node_tree.nodes[parentName].inputs[4].default_value = 1 if self.isMetal else 0 # Metallic value
            mat.node_tree.nodes[parentName].inputs[14].default_value = 1.52 # IOR Value

            y_exp = 310

            # Create the albedo setup.
            if "albedo" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "albedo"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (-720, y_exp)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[0]

                    mat.node_tree.links.new(nodes.get(parentName).inputs[0], texNode.outputs[0])

            # Create the roughness setup.
            if "roughness" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "roughness"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (-720, y_exp)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[1]

                    mat.node_tree.links.new(nodes.get(parentName).inputs[7], texNode.outputs[0])

            # Create the fuzziness setup.
            if "fuzz" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "fuzz"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (-720, y_exp)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[1]

                    mat.node_tree.links.new(nodes.get(parentName).inputs[10], texNode.outputs[0])
                    nodes.get(parentName).inputs[11].default_value = 1

            # Create the metalness setup
            if "metalness" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "metalness"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (-720, y_exp)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[1]

                    mat.node_tree.links.new(nodes.get(parentName).inputs[4], texNode.outputs[0])

            # Create the displacement setup.
            if "displacement" in maps_:

                pass

            # Create the translucency setup.
            if "translucency" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "translucency"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (-720, y_exp)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[0]

                    mat.node_tree.links.new(nodes.get(parentName).inputs[3], texNode.outputs[0])

            # Create the opacity setup
            if "opacity" in maps_:

                imgPath = [item[2] for item in self.textureList if item[1] == "opacity"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode = nodes.new('ShaderNodeTexImage')
                    y_exp += -320
                    texNode.location = (256, 0)
                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[1]

                    # mat.node_tree.links.new(nodes.get(parentName).inputs[4], texNode.outputs[0])

                    mixNode = nodes.new('ShaderNodeMixShader')
                    mixNode.location = (630, 0)
                    mixNode.inputs[0].default_value = 1
                    mat.node_tree.links.new(mixNode.inputs[0], texNode.outputs[0])

                    transpNode = nodes.new('ShaderNodeBsdfTransparent')
                    transpNode.location = (375, 168)
                    mat.node_tree.links.new(mixNode.inputs[1], transpNode.outputs[0])

                    mat.node_tree.links.new(nodes.get("Principled BSDF").outputs["BSDF"], mixNode.inputs[2])
                    mat.node_tree.links.new(nodes.get("Material Output").inputs["Surface"], mixNode.outputs[0])

                    mat.blend_method = 'CLIP'
                    mat.transparent_shadow_method = 'CLIP'

            # Create the normal map setup for Redshift.
            if "normal" in maps_:

                normalNode = nodes.new('ShaderNodeNormalMap')
                texNode = nodes.new('ShaderNodeTexImage')

                imgPath = [item[2] for item in self.textureList if item[1] == "normal"]
                if len(imgPath) >= 1:
                    imgPath = imgPath[0].replace("\\", "/")

                    texNode.location = (-720*1.5, y_exp)

                    texNode.image = bpy.data.images.load(imgPath)
                    texNode.show_texture = True
                    texNode.color_space = colorSpaces[1]

                    normalNode.location = (-450, y_exp)

                    mat.node_tree.links.new(nodes.get(parentName).inputs[17], normalNode.outputs[0])
                    texNode.color_space = colorSpaces[1]
                    mat.node_tree.links.new(texNode.outputs[0], normalNode.inputs[1])

                    mat.node_tree.links.new(texNode.outputs[0], normalNode.inputs[1])

class ms_Init(threading.Thread):
    
	#Initialize the thread and assign the method (i.e. importer) to be called when it receives JSON data.
    def __init__(self, importer):
        threading.Thread.__init__(self)
        self.importer = importer

	#Start the thread to start listing to the port.
    def run(self):
        try:
            run_livelink = True
            host, port = 'localhost', 28888
            #Making a socket object.
            socket_ = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            #Binding the socket to host and port number mentioned at the start.
            socket_.bind((host, port))

            #Run until the thread starts receiving data.
            while run_livelink:
                socket_.listen(5)
                #Accept connection request.
                client, addr = socket_.accept()
                data = ""
                buffer_size = 4096*2
                #Receive data from the client. 
                data = client.recv(buffer_size)
                if debug_info_files:
                    open(r'C:\Users\Dell\Documents\socket_data.txt', 'w').write(str(data))
                if data == b'Bye Megascans':
                    if debug_info_files:
                        open(r'C:\Users\Dell\Documents\socket_exception.txt', 'w').write("Why are you not quitting? 1")
                    run_livelink = False
                    break

                #If any data is received over the port.
                if data != "":
                    self.TotalData = b""
                    self.TotalData += data #Append the previously received data to the Total Data.
                    #Keep running until the connection is open and we are receiving data.
                    while run_livelink:
                        #Keep receiving data from client.
                        data = client.recv(4096*2)
                        if debug_info_files:
                            open(r'C:\Users\Dell\Documents\socket_data_1.txt', 'w').write(str(data))
                        if data == b'Bye Megascans':
                            if debug_info_files:
                                open(r'C:\Users\Dell\Documents\socket_exception.txt', 'w').write("Why are you not quitting? 11")
                            run_livelink = False
                            break
                        #if we are getting data keep appending it to the Total data.
                        if data : self.TotalData += data
                        else:
                            #Once the data transmission is over call the importer method and send the collected TotalData.
                            self.importer(self.TotalData)
                            break
        except:
            pass

class thread_checker(threading.Thread):
    
	#Initialize the thread and assign the method (i.e. importer) to be called when it receives JSON data.
    def __init__(self):
        threading.Thread.__init__(self)

	#Start the thread to start listing to the port.
    def run(self):
        try:
            run_checker = True
            while run_checker:
                time.sleep(3)
                for i in threading.enumerate():
                    if debug_info_files:
                        open(r'C:\Users\Dell\Documents\threadses.txt', 'a').write("Name: " + i.getName() + " Is Alive? " + str(i.is_alive()) + "\n")
                    if(i.getName() == "MainThread" and i.is_alive() == False):
                        host, port = 'localhost', 28888
                        s = socket.socket()
                        s.connect((host,port))
                        data = "Bye Megascans"
                        s.send(data.encode())
                        s.close()
                        run_checker = False
                        if debug_info_files:
                            open(r'C:\Users\Dell\Documents\main_thread_dead.txt', 'a').write("Why are you not quitting? 111")
                        break
        except Exception as e:
            if debug_info_files:
                open(r'C:\Users\Dell\Downloads\thread_exception.txt', 'a').write(str(e))
            pass

class MS_Init_LiveLink(bpy.types.Operator):

    bl_idname = "ms_livelink.py"
    bl_label = "Megascans LiveLink"
    socketCount = 0

    def execute(self, context):

        try:
            globals()['Megascans_DataSet'] = None
            self.thread_ = threading.Thread(target = self.socketMonitor)
            self.thread_.start()
            bpy.app.timers.register(self.newDataMonitor)
            return {'FINISHED'}
        except Exception as e:
            print( "Megascans LiveLink Error : ", str(e) )
            return {"FAILED"}

    def newDataMonitor(self):
        if globals()['Megascans_DataSet'] != None:
            MS_Init_ImportProcess()
            globals()['Megascans_DataSet'] = None
        return 1.0


    def socketMonitor(self):
        #Making a thread object
        threadedServer = ms_Init(self.importer)
        #Start the newly created thread.
        threadedServer.start()
        #Making a thread object
        thread_checker_ = thread_checker()
        #Start the newly created thread.
        thread_checker_.start()
        

    def importer (self, recv_data):
        globals()['Megascans_DataSet'] = recv_data

def menu_func_import(self, context):
    self.layout.operator(MS_Init_LiveLink.bl_idname, text="Megascans LiveLink")


def register():
    bpy.utils.register_class(MS_Init_LiveLink)
    bpy.types.TOPBAR_MT_file_import.append(menu_func_import)

def unregister():
    # bpy.utils.unregister_class(MS_Init_LiveLink)
    bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
# modified: with the section below. It will remind you each time Blender opens new, if enabled
ctypes.windll.user32.MessageBoxW(0, "The Import from Bridge is working correctly. Return to Bridge and Export an Asset, as the Import function is Listening. Your material will show up in the Material Window to be applied to an object/mesh, when you return to Blender.", "Megascan LiveLink Active", 1)
# modified: ends here

if __name__ == "__main__":
    register()