2
2
# LICENSE https://creativecommons.org/licenses/by/4.0/ https://creativecommons.org/licenses/by/4.0/legalcode
3
3
# © 2024 https://github.com/Oops19
4
4
#
5
+
6
+
5
7
import random
8
+ import sys
9
+ import threading
10
+ import traceback
11
+ from typing import Dict , Set
6
12
13
+ import services
7
14
from copy_outfits .enums .copy_outfits_age import CopyOutfitsAge
8
15
from copy_outfits .enums .default_head import DefaultHead
9
16
from copy_outfits .enums .pie_menu_action_id import PieMenuActionId
10
17
from copy_outfits .modinfo import ModInfo
11
18
from copy_outfits .persist .skin_store import SkinStore
12
19
from copy_outfits .struct .copy_outfits_sim import CopyOutfitsSim
20
+ from objects import HiddenReasonFlag , ALL_HIDDEN_REASONS
21
+ from sims .sim_info import SimInfo
22
+ from sims4communitylib .services .commands .common_console_command import CommonConsoleCommand
23
+ from sims4communitylib .services .commands .common_console_command_output import CommonConsoleCommandOutput
13
24
from sims4communitylib .services .sim .cas .common_sim_outfit_io import CommonSimOutfitIO
25
+ from sims4communitylib .utils .cas .common_cas_utils import CommonCASUtils
14
26
from sims4communitylib .utils .cas .common_outfit_utils import CommonOutfitUtils
15
27
from sims4communitylib .utils .common_log_registry import CommonLog , CommonLogRegistry
28
+ from sims4communitylib .utils .sims .common_age_utils import CommonAgeUtils
29
+ from sims4communitylib .utils .sims .common_gender_utils import CommonGenderUtils
30
+ from sims4communitylib .utils .sims .common_sim_utils import CommonSimUtils
31
+ from ts4lib .common_enums .body_type import BodyType
16
32
from ts4lib .utils .singleton import Singleton
17
33
18
34
log : CommonLog = CommonLogRegistry .get ().register_log (ModInfo .get_identity (), 'OutfitSkin' )
19
35
log .enable ()
20
36
21
37
22
38
class OutfitSkin (metaclass = Singleton ):
23
- """ Add skins to sims """
39
+ do_init = True
40
+
24
41
def __init__ (self ):
25
- self .config = {
42
+ log .debug (f"{ OutfitSkin .do_init } " )
43
+ if OutfitSkin .do_init is True :
44
+ OutfitSkin .do_init = False
45
+ self .init ()
46
+
47
+ """ Add skins to sims """
48
+ def init (self ):
49
+ log .debug (f"init" )
50
+ try :
51
+ log .debug (f"Thread Dump" )
52
+ for thread in threading .enumerate ():
53
+ log .debug (f"{ thread } " )
54
+ thread_details = traceback .extract_stack (sys ._current_frames ()[thread .ident ])
55
+ for thread_detail in thread_details :
56
+ (filename , number , function , line_text ) = thread_detail
57
+ log .debug (f" { filename } #{ number } '{ line_text } ' in '{ function } ()'" )
58
+ log .debug (f"" )
59
+ except :
60
+ pass
61
+
62
+ self .available_skins : Dict = {
63
+ CopyOutfitsAge .TYAE : {
64
+ True : [], # Female / is_female==True
65
+ False : [], # Male
66
+ },
67
+ CopyOutfitsAge .CHILD : {
68
+ True : [], # Female
69
+ False : [], # Male
70
+ },
71
+ }
72
+ self .supported_skins : Dict = {
26
73
CopyOutfitsAge .TYAE : {
27
74
True : [ # is_female, used in o19_yfHead.package
28
75
# The high-bit must be set for all custom CAS Parts. Otherwise, they will not be found.
76
+ # custom head cas part, custom skin images, description
29
77
(0xFD57E11C9F0D2AFD , 0xA83ABE943B90DD44 , 'ddarkpinkrosa0_Miami_Skin_V1' ),
30
78
(0xE2F29393763FBEFD , 0xE9DF3FAEC660DE19 , 'ddarkpinkrosa0_Miami_Skin_V1' ),
31
79
(0xF2157D9C0F5DBB0C , 0xE1750D34ED49C938 , 'ddarkpinkrosa0_Miami_Skin_V1' ),
@@ -36,7 +84,6 @@ def __init__(self):
36
84
(0x8B269F3A852B0059 , 0xC42933F4CFD6B686 , 'JS_008Skin' ),
37
85
(0x8F30F85CC19644C1 , 0xDABE010DB300612C , 'JS_008Skin' ),
38
86
(0x8D88C11365FFA9EC , 0xA91D148D8D6709B5 , 'JS_008Skin' ),
39
-
40
87
(0xCD27D0CC83CC79CE , 0xA2C37B6FF654696D , '[THISISTHEM] Pamela Anderson Skin' ),
41
88
(0x8111880154582F44 , 0xBF054E412D1C3FF1 , '[THISISTHEM] Selena G. Skin' ),
42
89
(0xD8191C563F223169 , 0x945804D533C7195C , '[THISISTHEM] Salma Hayek Skin' ),
@@ -53,7 +100,6 @@ def __init__(self):
53
100
(0xF5E803E374BAAA88 , 0xC6E085AE73312D6D , '[THISISTHEM] Ashley Skin' ),
54
101
(0xA59BBF6B64B413FF , 0xAD660A57BEC2E456 , '[THISISTHEM] Abény Skin' ),
55
102
(DefaultHead .YF_HEAD_DEFAULT .value , DefaultHead .YF_HEAD_DEFAULT .value , 'TS4 Default' ),
56
-
57
103
],
58
104
False : [ # is_male, used in o19_ymHead.package
59
105
(0xE66AA85AD5A6C480 , 0xA63963459FAC2D01 , '[THISISTHEM] A$AP Rocky Skin' ),
@@ -77,10 +123,35 @@ def __init__(self):
77
123
(0x800298CD9078A60D , 0xA78520CC00C7191C , '[THISISTHEM] Child Skin N24' ),
78
124
(DefaultHead .CU_HEAD_DEFAULT .value , DefaultHead .CU_HEAD_DEFAULT .value , 'TS4 Default' ),
79
125
],
80
-
81
126
},
82
127
}
83
- self .skin_store = SkinStore (self .config )
128
+
129
+ missing_packages : Set = set ()
130
+ for sim_age in [CopyOutfitsAge .CHILD , CopyOutfitsAge .TYAE , ]:
131
+ _ages = {}
132
+ for is_female in [True , False , ]:
133
+ _available_skins = []
134
+ for data in self .supported_skins .get (sim_age ).get (is_female ):
135
+ check_cas_part , use_cas_part , package_name = data
136
+ if CommonCASUtils .is_cas_part_loaded (check_cas_part ):
137
+ if CommonCASUtils .is_cas_part_loaded (use_cas_part ):
138
+ _available_skins .append (use_cas_part )
139
+ else :
140
+ # this should never happen
141
+ log .warn (f"copy_outfits.package missing or broken - { use_cas_part :016X} not found!" )
142
+ else :
143
+ missing_packages .add (package_name )
144
+ log .warn (f"Dropping: { is_female } { sim_age } : { data } " )
145
+ _ages .update ({is_female : _available_skins })
146
+ self .available_skins .update ({sim_age : _ages })
147
+
148
+ if missing_packages :
149
+ log .info (f"Optional packages which are not installed: '{ missing_packages } '. Install some of them to use more skins on mannequins." )
150
+
151
+ log .debug (f".... { self .available_skins } " )
152
+ # Initialize store with the available skins
153
+ self .skin_store = SkinStore (self .available_skins )
154
+ log .debug (f"init-end" )
84
155
85
156
# A78520CC00C7191C
86
157
def apply_skin (self , zim : CopyOutfitsSim ):
@@ -116,6 +187,31 @@ def apply_skin(self, zim: CopyOutfitsSim):
116
187
sim_info ._current_outfit = (outfit_category , outfit_index )
117
188
log .debug (f"Replacing head { current_head } with new { head_skin } ." )
118
189
190
+ def fix_head (self , sim_info : SimInfo ):
191
+ sim_info = CommonSimUtils .get_sim_info (sim_info )
192
+ if not sim_info :
193
+ return
194
+ if CommonAgeUtils .is_child (sim_info ):
195
+ sim_age = CopyOutfitsAge .CHILD
196
+ elif CommonAgeUtils .is_teen_adult_or_elder (sim_info ):
197
+ sim_age = CopyOutfitsAge .TYAE
198
+ else :
199
+ log .info (f"Age not supported." )
200
+ return
201
+ is_female = CommonGenderUtils .is_female (sim_info )
202
+ old_head_id = CommonCASUtils .get_cas_part_id_at_body_type (sim_info , BodyType .HEAD .value )
203
+ # True == CommonCASUtils.is_cas_part_loaded(old_head_id) as the part is 'in use'. A test makes no sense.
204
+ head_ids = OutfitSkin ().available_skins .get (sim_age ).get (is_female )
205
+ head_id = random .choice (head_ids )
206
+
207
+ log .info (f"Fixing '{ sim_info } 's head to { head_id } (from { old_head_id } )." )
208
+ CommonCASUtils .attach_cas_part_to_sim (sim_info , head_id , BodyType .HEAD .value )
209
+
210
+ @staticmethod
211
+ @CommonConsoleCommand (ModInfo .get_identity (), 'o19.co.fix' , 'Fix the head of the active sim.' )
212
+ def cheat_o19_test_print_genetics (output : CommonConsoleCommandOutput ):
213
+ sim_info = CommonSimUtils .get_active_sim_info ()
214
+ OutfitSkin ().fix_head (sim_info )
119
215
120
- # Init SkinStore as soon as possible
216
+ # Init OutfitSkin / SkinStore as soon as possible
121
217
OutfitSkin ()
0 commit comments