mirror of
https://github.com/litruv/PNGTuber-Plus.git
synced 2026-07-24 02:26:02 +10:00
337 lines
9.5 KiB
GDScript
337 lines
9.5 KiB
GDScript
extends Node
|
|
|
|
## WobbleSyncGroupManager - Manages synchronized wobble groups for sprites
|
|
## Follows class-based OOP pattern as requested
|
|
|
|
var syncGroups: Dictionary = {} # groupName: WobbleSyncGroup
|
|
var spriteGroupMembership: Dictionary = {} # spriteId: groupName
|
|
|
|
signal group_created(group_name: String)
|
|
signal group_deleted(group_name: String)
|
|
signal sprite_joined_group(sprite_id: int, group_name: String)
|
|
signal sprite_left_group(sprite_id: int, group_name: String)
|
|
|
|
func _ready():
|
|
# Manager initialization complete
|
|
pass
|
|
|
|
class WobbleSyncGroup:
|
|
var name: String
|
|
var xFrq: float = 0.0
|
|
var xAmp: float = 0.0
|
|
var yFrq: float = 0.0
|
|
var yAmp: float = 0.0
|
|
var rFrq: float = 0.0
|
|
var rAmp: float = 0.0
|
|
var memberSprites: Array = []
|
|
|
|
func _init(group_name: String):
|
|
name = group_name
|
|
|
|
## Set wobble parameters for the entire group
|
|
func setWobbleParameters(x_frq: float, x_amp: float, y_frq: float, y_amp: float, r_frq: float, r_amp: float, manager_ref):
|
|
xFrq = x_frq
|
|
xAmp = x_amp
|
|
yFrq = y_frq
|
|
yAmp = y_amp
|
|
rFrq = r_frq
|
|
rAmp = r_amp
|
|
|
|
# Update all member sprites using the manager reference
|
|
var sprites = manager_ref.get_tree().get_nodes_in_group("saved")
|
|
|
|
var updated_count = 0
|
|
for sprite in sprites:
|
|
if sprite.id in memberSprites:
|
|
# Preserve the sprite's group membership
|
|
var current_group = sprite.wobbleSyncGroup
|
|
sprite.xFrq = xFrq
|
|
sprite.xAmp = xAmp
|
|
sprite.yFrq = yFrq
|
|
sprite.yAmp = yAmp
|
|
sprite.rFrq = rFrq
|
|
sprite.rAmp = rAmp
|
|
# Restore group membership in case it got cleared
|
|
sprite.wobbleSyncGroup = current_group
|
|
updated_count += 1
|
|
|
|
## Add sprite to this group
|
|
func addSprite(sprite_id): # Remove type constraint to handle float IDs
|
|
if sprite_id not in memberSprites:
|
|
memberSprites.append(sprite_id)
|
|
else:
|
|
pass # Sprite already in group
|
|
|
|
## Remove sprite from this group
|
|
func removeSprite(sprite_id): # Remove type constraint
|
|
memberSprites.erase(sprite_id)
|
|
|
|
## Check if group is empty
|
|
func isEmpty() -> bool:
|
|
return memberSprites.size() == 0
|
|
|
|
## Get group data for saving
|
|
func toSaveData() -> Dictionary:
|
|
return {
|
|
"name": name,
|
|
"xFrq": xFrq,
|
|
"xAmp": xAmp,
|
|
"yFrq": yFrq,
|
|
"yAmp": yAmp,
|
|
"rFrq": rFrq,
|
|
"rAmp": rAmp,
|
|
"memberSprites": memberSprites
|
|
}
|
|
|
|
## Load group data from save
|
|
func fromSaveData(data: Dictionary):
|
|
name = data.get("name", "")
|
|
xFrq = data.get("xFrq", 0.0)
|
|
xAmp = data.get("xAmp", 0.0)
|
|
yFrq = data.get("yFrq", 0.0)
|
|
yAmp = data.get("yAmp", 0.0)
|
|
rFrq = data.get("rFrq", 0.0)
|
|
rAmp = data.get("rAmp", 0.0)
|
|
memberSprites = data.get("memberSprites", [])
|
|
|
|
## Create a new wobble sync group
|
|
func createGroup(group_name: String, sprite_id = -1) -> bool: # Remove type constraint
|
|
if group_name.strip_edges() == "" or syncGroups.has(group_name):
|
|
return false
|
|
|
|
var group = WobbleSyncGroup.new(group_name)
|
|
syncGroups[group_name] = group
|
|
|
|
# If a sprite ID is provided, add it and copy its wobble values
|
|
if sprite_id != -1:
|
|
var sprite = getSpriteById(sprite_id)
|
|
if sprite:
|
|
# Store the sprite's raw wobble values directly
|
|
group.setWobbleParameters(sprite.xFrq, sprite.xAmp, sprite.yFrq, sprite.yAmp, sprite.rFrq, sprite.rAmp, self)
|
|
addSpriteToGroup(sprite_id, group_name)
|
|
|
|
group_created.emit(group_name)
|
|
Global.pushUpdate("Created wobble sync group: " + group_name)
|
|
return true
|
|
|
|
## Delete a wobble sync group
|
|
func deleteGroup(group_name: String):
|
|
if not syncGroups.has(group_name):
|
|
return
|
|
|
|
var group = syncGroups[group_name]
|
|
|
|
# Remove all sprites from the group
|
|
for sprite_id in group.memberSprites.duplicate():
|
|
removeSpriteFromGroup(sprite_id, group_name)
|
|
|
|
syncGroups.erase(group_name)
|
|
group_deleted.emit(group_name)
|
|
Global.pushUpdate("Deleted wobble sync group: " + group_name)
|
|
|
|
## Add sprite to a group
|
|
func addSpriteToGroup(sprite_id, group_name: String) -> bool: # Remove type constraint
|
|
|
|
if not syncGroups.has(group_name):
|
|
return false
|
|
|
|
# Remove sprite from any existing group first
|
|
removeSpriteFromAllGroups(sprite_id)
|
|
|
|
var group = syncGroups[group_name]
|
|
group.addSprite(sprite_id)
|
|
spriteGroupMembership[sprite_id] = group_name
|
|
|
|
# Sync the sprite's wobble parameters to the group
|
|
var sprite = getSpriteById(sprite_id)
|
|
if sprite:
|
|
sprite.wobbleSyncGroup = group_name
|
|
sprite.xFrq = group.xFrq
|
|
sprite.xAmp = group.xAmp
|
|
sprite.yFrq = group.yFrq
|
|
sprite.yAmp = group.yAmp
|
|
sprite.rFrq = group.rFrq
|
|
sprite.rAmp = group.rAmp
|
|
|
|
sprite_joined_group.emit(sprite_id, group_name)
|
|
Global.pushUpdate("Added sprite to wobble sync group: " + group_name)
|
|
return true
|
|
|
|
## Remove sprite from a specific group
|
|
func removeSpriteFromGroup(sprite_id, group_name: String): # Remove type constraint
|
|
if not syncGroups.has(group_name):
|
|
return
|
|
|
|
var group = syncGroups[group_name]
|
|
group.removeSprite(sprite_id)
|
|
spriteGroupMembership.erase(sprite_id)
|
|
|
|
# Clear the sprite's sync group reference
|
|
var sprite = getSpriteById(sprite_id)
|
|
if sprite:
|
|
sprite.wobbleSyncGroup = ""
|
|
else:
|
|
pass # Sprite not found
|
|
|
|
sprite_left_group.emit(sprite_id, group_name)
|
|
|
|
# Auto-delete empty groups
|
|
if group.isEmpty():
|
|
deleteGroup(group_name)
|
|
else:
|
|
Global.pushUpdate("Removed sprite from wobble sync group: " + group_name)
|
|
|
|
## Remove sprite from all groups
|
|
func removeSpriteFromAllGroups(sprite_id): # Remove type constraint
|
|
if spriteGroupMembership.has(sprite_id):
|
|
var group_name = spriteGroupMembership[sprite_id]
|
|
removeSpriteFromGroup(sprite_id, group_name)
|
|
else:
|
|
pass # Sprite not in any group
|
|
|
|
## Update wobble parameters for a group
|
|
func updateGroupWobble(group_name: String, x_frq: float, x_amp: float, y_frq: float, y_amp: float, r_frq: float, r_amp: float):
|
|
|
|
if not syncGroups.has(group_name):
|
|
return
|
|
|
|
var group = syncGroups[group_name]
|
|
group.setWobbleParameters(x_frq, x_amp, y_frq, y_amp, r_frq, r_amp, self)
|
|
|
|
## Get sprite's current group name
|
|
func getSpriteGroupName(sprite_id: int) -> String:
|
|
return spriteGroupMembership.get(sprite_id, "")
|
|
|
|
## Get all group names
|
|
func getGroupNames() -> Array:
|
|
return syncGroups.keys()
|
|
|
|
## Test function to manually load wobble sync groups
|
|
func testManualLoad():
|
|
var test_data = {
|
|
"ears": {
|
|
"name": "ears",
|
|
"xFrq": 0.0,
|
|
"xAmp": 0.0,
|
|
"yFrq": 0.019,
|
|
"yAmp": 3.0,
|
|
"rFrq": 0.399,
|
|
"rAmp": 47.0,
|
|
"memberSprites": [3291286625.0]
|
|
}
|
|
}
|
|
await loadSaveData(test_data)
|
|
|
|
## Check if a group exists
|
|
func hasGroup(group_name: String) -> bool:
|
|
return syncGroups.has(group_name)
|
|
|
|
## Get sprite by ID
|
|
func getSpriteById(sprite_id): # Remove type constraint to handle float IDs
|
|
var sprites = get_tree().get_nodes_in_group("saved")
|
|
for sprite in sprites:
|
|
if sprite.id == sprite_id:
|
|
return sprite
|
|
return null
|
|
|
|
## Clean up orphaned sprites (sprites that no longer exist)
|
|
func cleanupOrphanedSprites():
|
|
var existing_sprite_ids = []
|
|
var sprites = get_tree().get_nodes_in_group("saved")
|
|
for sprite in sprites:
|
|
existing_sprite_ids.append(sprite.id)
|
|
|
|
# Check each group for orphaned sprite IDs
|
|
for group_name in syncGroups.keys():
|
|
var group = syncGroups[group_name]
|
|
var orphaned_ids = []
|
|
|
|
for sprite_id in group.memberSprites:
|
|
if sprite_id not in existing_sprite_ids:
|
|
orphaned_ids.append(sprite_id)
|
|
|
|
# Remove orphaned IDs
|
|
for orphaned_id in orphaned_ids:
|
|
group.removeSprite(orphaned_id)
|
|
spriteGroupMembership.erase(orphaned_id)
|
|
|
|
# Delete empty groups
|
|
if group.isEmpty():
|
|
deleteGroup(group_name)
|
|
|
|
## Get save data for all groups
|
|
func getSaveData() -> Dictionary:
|
|
var save_data = {}
|
|
for group_name in syncGroups.keys():
|
|
var group = syncGroups[group_name]
|
|
save_data[group_name] = group.toSaveData()
|
|
return save_data
|
|
|
|
## Load save data for all groups
|
|
func loadSaveData(save_data: Dictionary):
|
|
|
|
# Check if save_data is valid
|
|
if save_data == null or typeof(save_data) != TYPE_DICTIONARY:
|
|
return
|
|
|
|
if save_data.size() == 0:
|
|
return
|
|
|
|
# Clear existing groups
|
|
syncGroups.clear()
|
|
spriteGroupMembership.clear()
|
|
|
|
# Load groups from save data
|
|
var loaded_groups = 0
|
|
for group_name in save_data.keys():
|
|
var group_data = save_data[group_name]
|
|
|
|
if typeof(group_data) == TYPE_DICTIONARY:
|
|
var group = WobbleSyncGroup.new(group_name)
|
|
group.fromSaveData(group_data)
|
|
syncGroups[group_name] = group
|
|
loaded_groups += 1
|
|
|
|
# Update sprite group membership
|
|
for sprite_id in group.memberSprites:
|
|
spriteGroupMembership[sprite_id] = group_name
|
|
else:
|
|
pass # Invalid group data
|
|
|
|
|
|
# If no groups were loaded, clear any orphaned group references on sprites
|
|
if syncGroups.size() == 0:
|
|
var sprites = get_tree().get_nodes_in_group("saved")
|
|
for sprite in sprites:
|
|
if sprite.wobbleSyncGroup != "":
|
|
sprite.wobbleSyncGroup = ""
|
|
else:
|
|
# Apply wobble parameters to sprites with better timing
|
|
await get_tree().process_frame # Wait for sprites to be loaded
|
|
await get_tree().process_frame # Extra frame to ensure everything is ready
|
|
|
|
for group_name in syncGroups.keys():
|
|
var group = syncGroups[group_name]
|
|
for sprite_id in group.memberSprites:
|
|
var sprite = getSpriteById(sprite_id)
|
|
if sprite:
|
|
sprite.wobbleSyncGroup = group_name
|
|
sprite.xFrq = group.xFrq
|
|
sprite.xAmp = group.xAmp
|
|
sprite.yFrq = group.yFrq
|
|
sprite.yAmp = group.yAmp
|
|
sprite.rFrq = group.rFrq
|
|
sprite.rAmp = group.rAmp
|
|
# Force a complete opacity update after modifying sprite properties
|
|
if sprite.has_method("updateOpacity"):
|
|
sprite.updateOpacity()
|
|
if sprite.has_method("updateShaderOpacity"):
|
|
sprite.updateShaderOpacity()
|
|
else:
|
|
pass # Sprite not found
|
|
|
|
|
|
## Called when a sprite is deleted to clean up references
|
|
func onSpriteDeleted(sprite_id): # Remove type constraint
|
|
removeSpriteFromAllGroups(sprite_id)
|