NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

skin_design.py (13638B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\cosmetics\common\ships\skins\live_data\skin_design.py
      2 import datetime
      3 from carbon.common.script.sys.serviceConst import ROLE_QA
      4 from collections import defaultdict
      5 from cosmetics.common.ships.skins.static_data.pattern_blend_mode import PatternBlendMode, NO_SECONDARY_COLOR_BLEND_MODES
      6 from cosmetics.common.ships.skins.static_data.slot_configuration import SlotConfigurationsDataLoader
      7 from cosmetics.common.ships.skins.static_data.skin_tier import ShipSkinTierTable
      8 from cosmetics.common.ships.skins.static_data.slot_name import SlotID
      9 from google.protobuf.timestamp_pb2 import Timestamp
     10 from signals import Signal
     11 
     12 class BaseSkinDesign(object):
     13     SLOT_LAYOUT_CLASS = None
     14     CHARACTER_PROTO = None
     15     SKIN_ATTRIBUTES_PROTO = None
     16     SKIN_TIER_PROTO = None
     17 
     18     def __init__(self, creator_character_id = None, tier_table = None):
     19         self.construct_signals()
     20         self._ship_type_id = None
     21         self._slot_layout = None
     22         self.clear()
     23         self.creator_character_id = creator_character_id
     24         self._tier_table = tier_table if tier_table is not None else ShipSkinTierTable()
     25 
     26     def construct_signals(self):
     27         self.on_name_changed = Signal('on_name_changed')
     28         self.on_line_name_changed = Signal('on_line_name_changed')
     29         self.on_slot_fitting_changed = Signal('on_slot_fitting_changed')
     30         self.on_ship_type_id_changed = Signal('on_ship_type_id_changed')
     31         self.on_tier_level_changed = Signal('on_tier_level_changed')
     32         self.on_component_instance_license_to_use_changed = Signal('on_component_instance_license_to_use_changed')
     33         self.on_pattern_blend_mode_changed = Signal('on_pattern_blend_mode_changed')
     34         self.on_component_attribute_changed = Signal('on_component_attribute_changed')
     35 
     36     @property
     37     def name(self):
     38         return self._name
     39 
     40     @name.setter
     41     def name(self, value):
     42         self._name = u'{}'.format(value) if value else ''
     43         self.on_name_changed(self.name)
     44 
     45     @property
     46     def full_name(self):
     47         return self._name
     48 
     49     @property
     50     def line_name(self):
     51         return self._line_name
     52 
     53     @line_name.setter
     54     def line_name(self, value):
     55         self._line_name = u'{}'.format(value) if value else ''
     56         self.on_line_name_changed(self.line_name)
     57 
     58     @property
     59     def creator_character_id(self):
     60         return self._creator_character_id
     61 
     62     @creator_character_id.setter
     63     def creator_character_id(self, value):
     64         self._creator_character_id = value
     65 
     66     @property
     67     def ship_type_id(self):
     68         return self._ship_type_id
     69 
     70     @ship_type_id.setter
     71     def ship_type_id(self, value):
     72         if self.ship_type_id != value:
     73             self._ship_type_id = value
     74             old_layout = None
     75             if self._slot_layout is not None:
     76                 old_layout = self._slot_layout
     77             self._initialize_slot_layout()
     78             if old_layout is not None:
     79                 self._slot_layout.copy_slots_from_other(old_layout)
     80             self._compute_tier_level()
     81             self.on_ship_type_id_changed(self.ship_type_id)
     82         self._connect_component_instance_signals()
     83         self._apply_type_id_to_components(value)
     84 
     85     def _apply_type_id_to_components(self, value):
     86         pass
     87 
     88     @property
     89     def saved_skin_design_id(self):
     90         return self._saved_skin_design_id
     91 
     92     @saved_skin_design_id.setter
     93     def saved_skin_design_id(self, value):
     94         self._saved_skin_design_id = value
     95 
     96     @property
     97     def design_hex(self):
     98         return self._design_hex
     99 
    100     @design_hex.setter
    101     def design_hex(self, value):
    102         self._design_hex = value
    103 
    104     def copy_ship_type_and_layout(self, ship_type_id, layout):
    105         self._slot_layout = layout
    106         self.ship_type_id = ship_type_id
    107 
    108     @property
    109     def tier_level(self):
    110         return self._tier_level
    111 
    112     @tier_level.setter
    113     def tier_level(self, value):
    114         self._tier_level = value
    115 
    116     @property
    117     def slot_layout(self):
    118         if self._slot_layout is None:
    119             self._initialize_slot_layout()
    120         return self._slot_layout
    121 
    122     @property
    123     def sequenced(self):
    124         return self._sequenced
    125 
    126     @sequenced.setter
    127     def sequenced(self, value):
    128         self._sequenced = value
    129 
    130     @property
    131     def tier_points(self):
    132         return self.compute_current_points_value()
    133 
    134     @property
    135     def tier_thresholds(self):
    136         return self._tier_table.get_thresholds_for_ship_type(self.ship_type_id)
    137 
    138     def compute_current_points_value(self):
    139         total_points = 0
    140         for slot_id, component_instance in self.slot_layout.fitted_slots.iteritems():
    141             if component_instance.get_component_data().points_value:
    142                 if self.slot_layout.pattern_blend_mode in NO_SECONDARY_COLOR_BLEND_MODES and slot_id == SlotID.SECONDARY_PATTERN_MATERIAL:
    143                     pass
    144                 else:
    145                     total_points += component_instance.get_component_data().points_value
    146 
    147         if session and session.role & ROLE_QA:
    148             total_points += self._qa_tier_points
    149         return total_points
    150 
    151     def get_sequence_binder_amounts_required(self, number_of_runs):
    152         amount_by_type_id = defaultdict(int)
    153         for instance in self.slot_layout.fitted_slots.values():
    154             amount_required = instance.sequence_binder_amount_required
    155             if amount_required > 0:
    156                 type_id = instance.sequence_binder_type_id
    157                 amount_by_type_id[type_id] += amount_required * number_of_runs
    158 
    159         return amount_by_type_id
    160 
    161     def fit_slot(self, slot_id, component_id, licence = None):
    162         if component_id:
    163             component_instance = self.create_component_instance(component_id)
    164             component_instance.component_license_to_use = licence
    165             component_instance.on_licence_to_use_changed.connect(self.on_component_instance_license_to_use_changed)
    166             component_instance.on_attribute_changed.connect(self._on_component_instance_attribute_changed)
    167         else:
    168             component_instance = None
    169         self.slot_layout.fit_slot(slot_id, component_instance)
    170         return component_instance
    171 
    172     def swap_slots(self, slot_id_1, slot_id_2):
    173         self.slot_layout.swap_slots(slot_id_1, slot_id_2)
    174 
    175     def unfit_all(self):
    176         self.slot_layout.unfit_all()
    177 
    178     def _on_component_instance_attribute_changed(self, component_instance, attribute_id, value):
    179         slot_id = self.slot_layout.get_slot_id(component_instance)
    180         if slot_id:
    181             self.on_component_attribute_changed(slot_id, attribute_id, value)
    182 
    183     def get_fitted_component_instance(self, slot_id):
    184         return self.slot_layout.slots.get(slot_id, None)
    185 
    186     def has_fitted_components(self):
    187         return bool(self.get_fitted_components())
    188 
    189     def get_fitted_components(self):
    190         return [ component_instance for component_instance in self.slot_layout.slots.itervalues() if component_instance ]
    191 
    192     def _initialize_slot_layout(self):
    193         config = SlotConfigurationsDataLoader.get_for_ship(self._ship_type_id)
    194         if config:
    195             self._slot_layout = self.SLOT_LAYOUT_CLASS(config)
    196             self._slot_layout.on_slot_fitting_changed.connect(self._on_slot_fitting_changed)
    197             self._slot_layout.on_pattern_blend_mode_changed.connect(self._on_pattern_blend_mode_changed)
    198         else:
    199             self._slot_layout = None
    200 
    201     def _on_slot_fitting_changed(self, slot_id, component_instance):
    202         self._compute_tier_level()
    203         self.on_slot_fitting_changed(slot_id, component_instance)
    204 
    205     def _on_pattern_blend_mode_changed(self, value):
    206         self._compute_tier_level()
    207         self.on_pattern_blend_mode_changed(value)
    208 
    209     def clear(self):
    210         self._name = None
    211         self._line_name = None
    212         self._creator_character_id = None
    213         self._tier_level = 1
    214         if self.slot_layout:
    215             for component_instance in self.slot_layout.fitted_slots.values():
    216                 component_instance.on_licence_to_use_changed.disconnect(self.on_component_instance_license_to_use_changed)
    217                 component_instance.on_attribute_changed.disconnect(self._on_component_instance_attribute_changed)
    218 
    219         self._slot_layout = None
    220         self._sequenced = None
    221         self._saved_skin_design_id = None
    222         self._design_hex = None
    223         self._qa_tier_points = 0
    224 
    225     def _compute_tier_level(self):
    226         new_tier_level = self._tier_table.get_tier_level_for_design(self)
    227         if new_tier_level == self.tier_level:
    228             return
    229         self.tier_level = new_tier_level
    230         self.on_tier_level_changed(new_tier_level)
    231 
    232     def __eq__(self, other):
    233         if other is None:
    234             return False
    235         return self.name == other.name and self.line_name == other.line_name and self.creator_character_id == other.creator_character_id and self.ship_type_id == other.ship_type_id and self.slot_layout == other.slot_layout and self.tier_level == other.tier_level
    236 
    237     def __ne__(self, other):
    238         return not self.__eq__(other)
    239 
    240     def __str__(self):
    241         design_str = 'Name: {name}\nLine:\n{line}\nCreated by {char_id} for ship type {ship_type}\nTier level {tier}\n'.format(name=self.name.encode('utf-8'), line=self.line_name.encode('utf-8') if self.line_name is not None else 'No line name', char_id=self.creator_character_id, ship_type=self.ship_type_id, tier=self.tier_level)
    242         design_str += 'Layout:\n %s' % self.slot_layout
    243         return design_str
    244 
    245     def update_from_other(self, other_design, saved_skin_design_id = None):
    246         self.clear()
    247         self.creator_character_id = other_design.creator_character_id
    248         self._name = other_design.name
    249         self._line_name = other_design.line_name
    250         self.slot_layout.copy_slots_from_other(other_design.slot_layout, should_copy_components_to_use=True)
    251         self.ship_type_id = other_design.ship_type_id
    252         self.sequenced = other_design.sequenced
    253         self.saved_skin_design_id = saved_skin_design_id
    254         self.design_hex = other_design.design_hex
    255         self._compute_tier_level()
    256 
    257     def clean_up_skin(self):
    258         if self.slot_layout is None:
    259             return
    260         if self.slot_layout.pattern_blend_mode in NO_SECONDARY_COLOR_BLEND_MODES or self.slot_layout.slots[SlotID.SECONDARY_PATTERN] is None:
    261             self.slot_layout.unfit_slot(SlotID.SECONDARY_PATTERN_MATERIAL, True)
    262 
    263     def _connect_component_instance_signals(self):
    264         for component_instance in self.slot_layout.fitted_slots.values():
    265             component_instance.on_licence_to_use_changed.connect(self.on_component_instance_license_to_use_changed)
    266             component_instance.on_attribute_changed.connect(self._on_component_instance_attribute_changed)
    267 
    268     @classmethod
    269     def copy_from_other(cls, other_design, new_creator_character_id = None, should_copy_components_to_use = False):
    270         if other_design is not None:
    271             if new_creator_character_id is not None:
    272                 design_copy = cls(new_creator_character_id)
    273             else:
    274                 design_copy = cls(other_design.creator_character_id)
    275             design_copy.name = other_design.name
    276             design_copy.line_name = other_design.line_name
    277             design_copy.ship_type_id = other_design.ship_type_id
    278             design_copy.slot_layout.copy_slots_from_other(other_design.slot_layout, should_copy_components_to_use=should_copy_components_to_use)
    279             design_copy.sequenced = other_design.sequenced
    280             design_copy.saved_skin_design_id = other_design.saved_skin_design_id
    281             design_copy.design_hex = other_design.design_hex
    282             design_copy.tier_level = other_design.tier_level
    283             return design_copy
    284 
    285     @classmethod
    286     def build_from_proto(cls, payload):
    287         design = cls(payload.creator.sequential)
    288         design.name = payload.name
    289         design.line_name = payload.line_name if len(payload.line_name) > 0 else None
    290         design.ship_type_id = payload.layout.ship_type.sequential
    291         design.slot_layout.fit_slots_from_proto(payload.layout)
    292         design.tier_level = payload.tier.level
    293         if payload.HasField('first_sequenced'):
    294             design.sequenced = datetime.datetime.fromtimestamp(payload.first_sequenced.seconds)
    295         return design
    296 
    297     @classmethod
    298     def build_proto_from_design(cls, skin_design):
    299         attributes = cls.SKIN_ATTRIBUTES_PROTO()
    300         attributes.name = skin_design.name
    301         attributes.line_name = skin_design.line_name if skin_design.line_name is not None else ''
    302         attributes.creator.CopyFrom(cls.CHARACTER_PROTO(sequential=skin_design.creator_character_id))
    303         attributes.layout.CopyFrom(cls.SLOT_LAYOUT_CLASS.build_proto_from_layout(skin_design.ship_type_id, skin_design.slot_layout))
    304         attributes.tier.CopyFrom(cls.SKIN_TIER_PROTO(level=skin_design.tier_level))
    305         if skin_design.sequenced is None:
    306             attributes.not_sequenced = True
    307         else:
    308             attributes.sequenced = Timestamp().FromDatetime(skin_design.sequenced)
    309         return attributes
    310 
    311     def create_component_instance(self, component_id, **kwargs):
    312         raise NotImplementedError
    313 
    314     @property
    315     def qa_tier_points(self):
    316         if session and session.role & ROLE_QA:
    317             return self._qa_tier_points
    318         return 0
    319 
    320     def set_qa_tier_points(self, value):
    321         if session and session.role & ROLE_QA:
    322             self._qa_tier_points = value
    323             self._compute_tier_level()
    324             self.on_tier_level_changed(self.tier_level)