UPBGE 0.3 Object exists on screen but not listed and can't be deleted

I’m running into an issue that I hope someone can help me with. I have a demo file to help. essentially I am loading models into my game from external .blends and deleting them when I want to go to the next object.
I can load them in and delete them pretty consistently right up until a point randomly where the object spawns on screen but when I tell Blender to endObject() it refuses and says that it does not exist

It also does not seem to exist when I list all the objects in the game scene, yet it is rendering.

Here’s a demo project:
AssetSelectTest.zip (455.6 KB)

Here’s the script, I apologize for any bad parts, it’s not my wheelhouse:

import bge, bpy
import os
import os.path
import glob
bl = bge.logic
scene = bl.getCurrentScene()
cont = bl.getCurrentController()
own = cont.owner

bl.CurrentObjectIndex = 0
bl.currentobject = []


def AccessoryCycle():
	cont = bl.getCurrentController()
	own = cont.owner
	cycleDirection = own.get("cycleDirection")
	MouseOver = cont.sensors['MouseOver']
	MouseClick = cont.sensors['MouseClick']
	
	if MouseOver.positive and MouseClick.positive:	
		#List current Game objects and all bpy objects in Asset collections ***UPON ERROR THE GAME OBJECT WILL NOT BE LISTED DESPITE BEING RENDERED***
		for existing in bge.logic.getSceneList()['Scene'].objects:
			print ("GAME OBJECT:", existing)
        #Lists BPY objects if of interest
		#for obj in bpy.data.collections['Asset'].all_objects:
		#	print ("BPY OBJECT:", obj.name)
			
		#Destroy objects in bl.currentobject and clear it
		oldobjects = bl.currentobject
		DestroyAsset(oldobjects)
		bl.currentobject.clear

		currentIndex = bl.CurrentObjectIndex
		assetlistpaths = ListAssets()
		
		newAssetPath, newIndex = CycleAsset(cycleDirection, assetlistpaths, currentIndex)
		bl.CurrentObjectIndex = newIndex
		
		#Load Asset and set old game objects to new assets
		bl.currentobject = LoadAsset(newAssetPath)
		
		
def CycleAsset(cycleDirection, assetlistpaths, currentIndex):
	#Get new asset path depending on which Next or Previous - also loop if at end or begining
	assetlistpathslen = len(assetlistpaths)
	newIndex = currentIndex +(cycleDirection)
	if newIndex > assetlistpathslen -1:
		newIndex =	 0
	elif newIndex < 0:
		newIndex = assetlistpathslen -1
	newAssetPath = assetlistpaths[newIndex]
	print ("Reading Asset from", newAssetPath)
	return newAssetPath, newIndex
	
def DestroyAsset(oldobjects):
	for obj in oldobjects:
		gameobject = scene.objects[obj.name]
		gameobject.endObject()
		
def LoadAsset(newAssetPath):
	objectpath = (newAssetPath)
	objectlist = []
	with bpy.data.libraries.load(objectpath, link=False) as (data_from, data_to):
		data_to.objects = data_from.objects
	for obj in data_to.objects:
		bpy.data.collections['Asset'].objects.link(obj)
		gameobj = scene.convertBlenderObject(obj)
		objectlist.append(obj)
	return objectlist

def ListAssets():
	assetlistpaths = []
	gamepath = bpy.path.abspath("//")
	searchpath = os.path.join(gamepath, "Assets")
	assetlistpaths = glob.glob((searchpath)+'*/*.blend', recursive=True)
	return (assetlistpaths)

Here’s an image:

There are a few bad practices in there, like using the obj.name instead of referencing them directly

I’ve fixed those but the problem persists.

No idea how bpy works with it or in general, but with bge you use libload to load blends/assets from blends, and libfree to delete them, you need to keep a list to track what you loaded in then with libfree you check that list and grab the right one out of it to “free”/ delete it.

1 Like

Thanks for the heads up.
This is with 0.3 so the old libload/libfree method isn’t an option unfortunately. But it’s a similar issue.

Z_Blue_Print_Random from the UPBGE Discord gave me some info.
For some reason convertBlenderObject() seemed to be failing at times which resulted in the bpy object appearing but no KX_Object being made along side it. Which would mean there’s nothing for endObject() to remove.
So I was left with a bpy mesh that was rendering that the game engine had no knowledge of
I fixed this via the following:

def DestroyAsset(oldobjects):
	for obj in oldobjects:
		if obj.name in scene.objects:
			gameobject = scene.objects[obj.name]
			gameobject.endObject()
#$Added these lines to clear any bpy meshes after endObject() has run.
	for obj in oldobjects:
		bpy.data.objects.remove(obj, do_unlink=True)

Technically this doesn’t solve the issue of the gameobject not being created properly in the first place but at least it cleans it up properly so I can try again.

I can probably put in some checks to ensure it is made properly in the first place as well as leave this in to ensure it’s cleaned up properly as well.
Not doing so would result in the object not being able to interact with any game engine logic.

if object.invalid:
    #object doesn't exist

Blender objects created with BPY code must be converted to BGE objects before they can be registered by the BGE functions at runtime.

You can do this by doing:

KX_Scene.convertBlenderObject(bpy_object)

Or more commonly seen as:

import bge

self = bge.logic.getCurrentController().owner

self.convertBlenderObject(bpy_object)