Forum Discussion
Greetings fellow AHQ visitors.
The root cause of the error is something that needs to be fixed on EA's end; there is a bit of a flaw in the logic of the Python code resulting in the Sim refusing to do the interaction/causing an exception.
For some background on the problem, the livestream interactions have a special tuning option which allows for the icon for the interaction in the queue to be specially overridden to the icon of the Sim's career. The problem with this is that the code assumes that the career that is referenced actually exists -- which is not the case, necessarily.
What happened in these cases is that the livestream interactions, which are base game, reference the High School Years teen streaming career. Because these interactions are base game but reference something not from the base game, errors can occur.
Example of the XML below spoiler number 1. Spoiler demonstrates the computer_Livestream_IncredibleSports interaction and how it references the career_Teen_StreamerSideHustle career in a place where it is not safe to do so.
<?xml version="1.0" encoding="utf-8"?> <I c="SuperInteraction" i="interaction" m="interactions.base.super_interaction" n="computer_Livestream_IncredibleSports" s="33432"> <V n="_affordance_key_override_for_autonomy" t="enabled"> <T n="enabled">Computer_Fun</T> </V> <V n="_icon" t="career_icon_override"> <U n="career_icon_override"> <T n="career_reference">273911<!--career_Teen_StreamerSideHustle--></T> <L n="participant_type"> <E>Actor</E> </L> </U> </V>
On the Python side of things, it is clear this is sort of an oversight. The code defaults to showing the Sim doing the interaction (or one of them, if there are multiple to consider) if the Sim does not have the listed career, so it is clear that that is the intended behaviour. Up until now, it may simply not have been the case where this code was used in such a way that a career is referenced in a place where it's possible the career doesn't exist (which is to say, an interaction, for example, references a career from another pack).
The code, from interactions.util.tunable_icon can be seen below in spoiler 2.
class TunableCareerIconOverrideIconFactory(TunableFactory): @staticmethod def factory(resolver, participant_type, career_reference, balloon_target_override=None, **kwargs): if resolver is None: logger.callstack('Attempting to use a None resolver in an icon.', level=LEVEL_ERROR, owner='yecao') return EMPTY_ICON_INFO_DATA if balloon_target_override is not None: return IconInfoData(obj_instance=balloon_target_override) participant = resolver.get_participant(participant_type) if participant is None or not participant.is_sim: logger.callstack('Unable to retrieve participant for Career.', level=LEVEL_ERROR, owner='yecao') return EMPTY_ICON_INFO_DATA career_tracker = participant.career_tracker if career_tracker is None: logger.callstack('Unable to find a Career Tracker for the participant: {}', participant, level=LEVEL_ERROR, owner='yecao') return EMPTY_ICON_INFO_DATA for current_career in career_tracker.careers.values(): if current_career.guid64 == career_reference.guid64 and current_career.icon_override is not None: localized_full_name = LocalizationHelperTuning.get_sim_full_name(participant) return IconInfoData(icon_resource=current_career.icon_override, obj_name=localized_full_name) icon_targets = resolver.get_participants(participant_type) if icon_targets: chosen_object = random.choice(icon_targets) else: chosen_object = None return IconInfoData(obj_instance=chosen_object) FACTORY_TYPE = factory def __init__(self, **kwargs): super().__init__(participant_type=TunableEnumFlags(description='\n The Participant who owns the career.\n ', enum_type=ParticipantTypeSingle, default=ParticipantType.Actor), career_reference=TunablePackSafeReference(description='\n The Career to override the icon.\n ', manager=services.get_instance_manager(sims4.resources.Types.CAREER)), **kwargs)
An easy way to re-write the code to work as how it seems is intended could be as such, shown in the 3rd spoiler.
class TunableCareerIconOverrideIconFactory(TunableFactory): @staticmethod def factory(resolver, participant_type, career_reference, balloon_target_override=None, **kwargs): if resolver is None: logger.callstack('Attempting to use a None resolver in an icon.', level=LEVEL_ERROR, owner='yecao') return EMPTY_ICON_INFO_DATA if balloon_target_override is not None: return IconInfoData(obj_instance=balloon_target_override) participant = resolver.get_participant(participant_type) if participant is None or not participant.is_sim: logger.callstack('Unable to retrieve participant for Career.', level=LEVEL_ERROR, owner='yecao') return EMPTY_ICON_INFO_DATA career_tracker = participant.career_tracker if career_tracker is None: logger.callstack('Unable to find a Career Tracker for the participant: {}', participant, level=LEVEL_ERROR, owner='yecao') return EMPTY_ICON_INFO_DATA # here is the change -- test if the career reference exists first before testing against it if career_reference is not None: for current_career in career_tracker.careers.values(): if current_career.guid64 == career_reference.guid64 and current_career.icon_override is not None: localized_full_name = LocalizationHelperTuning.get_sim_full_name(participant) return IconInfoData(icon_resource=current_career.icon_override, obj_name=localized_full_name) icon_targets = resolver.get_participants(participant_type) if icon_targets: chosen_object = random.choice(icon_targets) else: chosen_object = None return IconInfoData(obj_instance=chosen_object) FACTORY_TYPE = factory def __init__(self, **kwargs): super().__init__(participant_type=TunableEnumFlags(description='\n The Participant who owns the career.\n ', enum_type=ParticipantTypeSingle, default=ParticipantType.Actor), career_reference=TunablePackSafeReference(description='\n The Career to override the icon.\n ', manager=services.get_instance_manager(sims4.resources.Types.CAREER)), **kwargs)
At the end of the day, it's ultimately up to the dev team to fix the Python code to allow for it to be pack-safe, since whether or not it was intended to be in the first place, it clearly is being used in such a way now.
Finally, an example of the exception, in case one has not been uploaded here, is as follows, behind the 4th spoiler:
[cjiang] Error invoking TunableCareerIconOverrideIconFactoryWrapper.factory (AttributeError: 'NoneType' object has no attribute 'guid64') Traceback (most recent call last): File "T:\InGame\Gameplay\Scripts\Server\areaserver.py", line 117, in wrapped File "T:\InGame\Gameplay\Scripts\Server\areaserver.py", line 113, in finally_wrap File "T:\InGame\Gameplay\Scripts\Core\sims4\utils.py", line 157, in wrapper File "T:\InGame\Gameplay\Scripts\Core\sims4\utils.py", line 175, in wrapper File "T:\InGame\Gameplay\Scripts\Server\areaserver.py", line 365, in c_api_client_connect File "T:\InGame\Gameplay\Scripts\Server\zone.py", line 595, in do_zone_spin_up File "T:\InGame\Gameplay\Scripts\Server\zone_spin_up_service.py", line 1593, in update File "T:\InGame\Gameplay\Scripts\Server\zone_spin_up_service.py", line 567, in on_enter File "T:\InGame\Gameplay\Scripts\Server\sims\sim_info_manager.py", line 777, in restore_sim_si_state File "T:\InGame\Gameplay\Scripts\Server\interactions\si_restore.py", line 90, in restore_sim_si_state File "T:\InGame\Gameplay\Scripts\Server\interactions\si_restore.py", line 56, in _run_startup_interactions File "T:\InGame\Gameplay\Scripts\Server\interactions\si_restore.py", line 118, in _load_staged_interactions File "T:\InGame\Gameplay\Scripts\Server\sims\sim.py", line 4198, in load_staged_interactions File "T:\InGame\Gameplay\Scripts\Server\interactions\si_state.py", line 1283, in load_staged_interactions File "T:\InGame\Gameplay\Scripts\Server\interactions\si_state.py", line 1358, in _load_and_push_interaction File "T:\InGame\Gameplay\Scripts\Server\sims\sim.py", line 3919, in push_super_affordance File "T:\InGame\Gameplay\Scripts\Server\interactions\aop.py", line 236, in test_and_execute File "T:\InGame\Gameplay\Scripts\Server\interactions\aop.py", line 224, in execute File "T:\InGame\Gameplay\Scripts\Server\interactions\aop.py", line 212, in execute_interaction File "T:\InGame\Gameplay\Scripts\Server\interactions\interaction_queue.py", line 1344, in append File "T:\InGame\Gameplay\Scripts\Server\interactions\base\super_interaction.py", line 4262, in on_added_to_queue File "T:\InGame\Gameplay\Scripts\Server\interactions\base\interaction.py", line 7191, in on_added_to_queue File "T:\InGame\Gameplay\Scripts\Server\sims\ui_manager.py", line 175, in add_queued_interaction File "T:\InGame\Gameplay\Scripts\Server\sims\ui_manager.py", line 635, in _add_interaction File "T:\InGame\Gameplay\Scripts\Server\interactions\base\interaction.py", line 4946, in get_icon_info File "T:\InGame\Gameplay\Scripts\Server\interactions\base\interaction.py", line 4977, in _get_icon File "T:\InGame\Gameplay\Scripts\Core\sims4\tuning\tunable.py", line 525, in __call__ File "T:\InGame\Gameplay\Scripts\Server\interactions\utils\tunable_icon.py", line 242, in factory AttributeError: 'NoneType' object has no attribute 'guid64'rtim=0 ClientInfo isn't here
About The Sims 4 Bug Reports - Archive
Recent Discussions
- 55 minutes ago
- 56 minutes ago
- 8 hours ago
- 24 hours ago