Blender Game Engien (2.78a+) Junk remover Script:

pretty simple just allows for the easy removal of junk before you want to save runtimes or publish your game etc.

you should make a new save before running this script as it WILL remove any documentation and it will delete all textblocks with out game-engine-users aka anything not linked up or active to a controller block, or filter2d logic block.

import bpy
import os
import re

def process_text_block(text_block):
    comment_pattern = r'#[^\n]*'
    docstring_pattern = r'""".*?"""|\'\'\'.*?\'\'\''
    print_pattern = r'print\(.*?\)'
    new_lines = []
    for line in text_block.lines:
        line.body = re.sub(comment_pattern, '', line.body)
        line.body = re.sub(docstring_pattern, '', line.body, flags=re.DOTALL)
        line.body = re.sub(print_pattern, 'pass', line.body)
        line.body = line.body.replace("pass)","pass")
        line.body = line.body.replace("pass(","pass")
        line.body = line.body.replace("pass,","pass")        
        new_lines.append(line.body)
    text_block.clear()
    text_block.write("\n".join(new_lines))

os.system("cls")
GameUsers = set()
AllBpyTextNames = set(T.name for T in bpy.data.texts)
for Scene in bpy.data.scenes: 
    for obj in Scene.objects:
        if obj.game:
            for sensor in obj.game.sensors:
                if sensor.active:
                    for controller in sensor.controllers:
                        if controller.active and controller.type == 'PYTHON' and controller.text:
                            TxtContains = list(controller.text.lines)
                            for Line in TxtContains:
                                if "import" in Line.body or "from" in Line.body:
                                    if Line.body.split()[1]+'.py' in AllBpyTextNames:
                                        GameUsers.add(Line.body.split()[1]+'.py')
                            GameUsers.add(controller.text.name)
                            for actuator in controller.actuators:
                                if actuator.active and actuator.type == "FILTER_2D" and actuator.glsl_shader:
                                    GameUsers.add(actuator.glsl_shader.name)

ScriptsName = bpy.context.space_data.text.name
for text in bpy.data.texts:
    if text.name not in GameUsers and text.name != ScriptsName:
        bpy.data.texts.remove(bpy.data.texts[text.name], do_unlink=True)

for text in bpy.data.texts:
    if '.glsl' not in text.name and text.name != ScriptsName:
        process_text_block(text)

#for 2.78a+
#Find Game-Users, delete files that are non Game-Users and modify files to remove
#documentation and print statements. 
#▼ this is a workable method,
import bpy
import os
import re
os.system("cls")
GameUsers = []

AllBpyTextNames = [];
for T in bpy.data.texts:
    AllBpyTextNames.append(T.name)
print(AllBpyTextNames)
# Iterate over all objects in the current scene
for Scene in bpy.data.scenes: 
    for obj in Scene.objects:
        # Check if the object has a game engine logic
        if obj.game:
            # Iterate over all sensors in the object's game engine logic
            for sensor in obj.game.sensors:
                # Check if the sensor is active
                if sensor.active:
                    # Iterate over all controllers linked to the active sensor
                    for controller in sensor.controllers:
                        SkipCheck = False;
                        # Check if the controller is active
                        if controller.active:
                            # If the controller is a Python controller and has a text block assigned
                            if controller.type == 'PYTHON' and controller.text:
                                SkipCheck = True;
                                TxtContains = list(controller.text.lines); 

                                for Line in TxtContains:
                                    if "import" in Line.body or "from" in Line.body:
                                        if Line.body.split()[1]+'.py' in AllBpyTextNames: #to avoid adding stuff like "bge.py" or "math.py"
                                            GameUsers.append(Line.body.split()[1]+'.py')#I think I did this right.
                                    for CA in controller.actuators:
                                        #print(CA.name in Line.body)
                                        if CA.name in Line.body:
                                            SkipCheck = False;

                                print([controller.text.name, controller])
                                GameUsers.append(controller.text.name)
                            #and make it check if its a python-controller that is linked to a actuator
                            #then if it doesn't contain the actuator in the text it will skip this check:
                            if SkipCheck == True:
                                # Iterate over all actuators linked to the active controller
                                for actuator in controller.actuators:
                                    # Check if the actuator is active
                                    if actuator.active:
                                        # If the actuator is of type "FILTER_2D" and has a GLSL shader
                                        if actuator.type == "FILTER_2D" and actuator.glsl_shader:
                                            print([actuator.glsl_shader.name, actuator])
                                            GameUsers.append(actuator.glsl_shader.name)

print("GameUsers",GameUsers)
TextNames = []
TextGamesUsers = {}
texts = bpy.data.texts
for text in texts:
    TextNames.append(text.name)

print("TextNames",TextNames)
for I in GameUsers:
    print('i',I,GameUsers.count(I))
    TextGamesUsers[I] = GameUsers.count(I)
for text in texts:
    if text.name not in TextGamesUsers:
        TextGamesUsers[text.name] = 0;

os.system("cls")
ScriptsName = bpy.context.space_data.text.name;
print("Self Name :: ScriptsName",ScriptsName)
for NamedGameUsers in TextGamesUsers:
    
    if TextGamesUsers[NamedGameUsers] == 0:
        if not (NamedGameUsers == ScriptsName):
            #We need to be *very* careful here:
            bpy.data.texts.remove(bpy.data.texts[NamedGameUsers],do_unlink=True)
            print(NamedGameUsers)

#Everything else needs to be processed like so:
#Removes documentation and print statements. 

# Define the function to process a file
def process_text_block(text_block):
    # Regular expression patterns for comments, docstrings and print statements
    comment_pattern = r'#[^\n]*'
    docstring_pattern = r'""".*?"""|\'\'\'.*?\'\'\''
    print_pattern = r'print\(.*?\)'

    new_lines = []
    for line in text_block.lines:
        # Remove comments and docstrings
        line.body = re.sub(comment_pattern, '', line.body)
        line.body = re.sub(docstring_pattern, '', line.body, flags=re.DOTALL)

        # Replace print statements with pass
        line.body = re.sub(print_pattern, 'pass', line.body) #<- this doesn't always work sometimes leaving a ')' behind after a pass statement where a print statement originally was.
        line.body = line.body.replace("pass)","pass");
        line.body = line.body.replace("pass(","pass");
        line.body = line.body.replace("pass,","pass");        
        new_lines.append(line.body)

    # Replace the text block's lines with the new lines
    text_block.clear()
    text_block.write("\n".join(new_lines))

# Process all the remaining text blocks
for text in bpy.data.texts:
    if '.glsl' not in text.name and text.name != ScriptsName:
        print(text.name)
        # Process the text block
        process_text_block(text)

a non optimized version of the original ^ in case it has problems.

1 Like