locatorValidation.py (9591B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\evegraphics\validation\validators\locatorValidation.py 2 import ctypes 3 import string 4 import re 5 from evegraphics.validation.commonUtilities import Validate, SceneType 6 from evegraphics.validation.errors import SingleObjectValidationError 7 from evegraphics.validation.validationFunctions import ListIsNotEmpty, ShouldBeGreaterThanOrEqual 8 from evegraphics.validation import resources 9 import geo2 10 from evegraphics.validation.validators import limits 11 import trinity 12 13 @Validate('EveSOFDataHull(owner)/.../List[EveSOFDataHullLocator](locators)') 14 def ValidateTurretLocatorsCount(context, owner, locators): 15 minTurretLocators = limits.GetValue(owner.category, limits.MIN_TURRET_LOCATOR_COUNT) 16 if minTurretLocators is None: 17 return 18 validTurretSetNames = ['locator_turret_', 'locator_atomic_'] 19 locatorsByName = {locator.name:locator for locator in locators} 20 turretLocators = set() 21 for validTurretSetName in validTurretSetNames: 22 for locatorName, locator in locatorsByName.iteritems(): 23 if locatorName.startswith(validTurretSetName): 24 setIdentifier = re.search('%s\\d+' % validTurretSetName, locatorName).group() 25 turretLocators.add(setIdentifier) 26 27 if len(turretLocators) < minTurretLocators: 28 context.Error(locators, 'Too few turret locators, expected to get %d locators, but only found %d: [%s]' % (minTurretLocators, len(turretLocators), ','.join(turretLocators))) 29 30 31 @Validate('EveSOFDataHull(owner)/.../List[EveSOFDataHullLocator](locators)') 32 def ValidateTurretLocatorName(context, owner, locators): 33 minTurretLocators = limits.GetValue(owner.category, limits.MIN_TURRET_LOCATOR_COUNT) 34 if minTurretLocators is None: 35 return 36 validTurretSetNames = ['locator_turret_', 'locator_atomic_'] 37 locatorsByName = {locator.name:locator for locator in locators} 38 locatorSetIdentifiers = {setName:[] for setName in validTurretSetNames} 39 for validTurretSetName in validTurretSetNames: 40 for locatorName, locator in locatorsByName.iteritems(): 41 if locatorName.startswith(validTurretSetName): 42 if not re.match('[a-z]+_[a-z]+_\\d+[a-z]', locatorName): 43 context.Error(locator, 'Incorrectly named turret locator') 44 continue 45 setIndex = int(re.search('\\d+', locatorName.replace(validTurretSetName, '')).group()) 46 setLetter = re.search('[a-z]+', locatorName.replace(validTurretSetName, '')).group() 47 locatorSetIdentifiers[validTurretSetName].append((setIndex, setLetter)) 48 49 for turretSetName, identifiers in locatorSetIdentifiers.iteritems(): 50 if len(identifiers) == 1: 51 context.Error(locators, 'Turret set has only 1 locator. There should be more than 1...') 52 continue 53 identifiers.sort() 54 for index, (turretIndex, turretLetter) in enumerate(identifiers): 55 currentLocatorName = '%s%d%s' % (turretSetName, turretIndex, turretLetter) 56 locator = locatorsByName[currentLocatorName] 57 if index == 0: 58 if turretIndex != 1 or turretLetter != 'a': 59 context.Error(locator, 'Incorrect name should be %s%d%s' % (turretSetName, 1, 'a')) 60 continue 61 lastIndex, lastLetter = identifiers[index - 1] 62 lastLocatorName = '%s%d%s' % (turretSetName, lastIndex, lastLetter) 63 incorrectIndex = turretIndex not in (lastIndex, lastIndex + 1) 64 incorrectLetter = turretIndex == lastIndex and ord(turretLetter) != ord(lastLetter) + 1 65 incorrectStartingLetter = turretIndex == lastIndex + 1 and turretLetter != 'a' 66 if incorrectIndex or incorrectLetter or incorrectStartingLetter: 67 context.Error(locator, "Incorrect name when following this locator '%s'" % lastLocatorName) 68 69 70 @Validate('EveSOFDataHullLocatorSet') 71 def ValidateEveSOFDataHullLocatorSet(context, sofLocatorSet): 72 context.Expect(sofLocatorSet, 'locators', ListIsNotEmpty) 73 74 75 def RemoveSofLocatorSets(owner): 76 77 def inner(): 78 owner.locatorSets.removeAt(-1) 79 80 return ('Remove all locator sets from hull', inner, True) 81 82 83 @Validate('EveSOFDataHull(owner)/.../List[EveSOFDataHullLocatorSet](sofLocatorSets)') 84 def StructureSetsShouldNotHaveLocators(context, owner, sofLocatorSets): 85 if owner.category == 'structure_states' and sofLocatorSets: 86 context.Error(sofLocatorSets, 'Structure state hulls should not have locators', actions=(RemoveSofLocatorSets(owner),)) 87 88 89 @Validate('EveSOFDataHull(owner)/.../List[EveSOFDataHullLocatorSet](sofLocatorSets)') 90 def ValidateListOfEveSOFDataHullLocatorSet(context, owner, sofLocatorSets): 91 damageLocatorsMin = limits.GetValue(owner.category, limits.DAMAGE_LOCATORS_MIN) 92 damageLocatorSet = None 93 for locatorSet in sofLocatorSets: 94 if locatorSet.name == 'damage': 95 damageLocatorSet = locatorSet 96 break 97 98 if damageLocatorSet is None: 99 if owner.category not in ('structure_states', 'placeholder') and damageLocatorsMin > 0: 100 context.AddError(SingleObjectValidationError(sofLocatorSets, "has no locatorset called 'damage'")) 101 elif damageLocatorsMin is not None: 102 context.ExpectValue(damageLocatorSet, len(damageLocatorSet.locators), ShouldBeGreaterThanOrEqual(damageLocatorsMin), message='number of damage locators should be no less than %s (but is %s)' % (damageLocatorsMin, len(damageLocatorSet.locators))) 103 104 105 @Validate('EveSOFDataHull(owner)/.../EveSOFDataHullLocatorSet(sofLocatorSet)') 106 def ValidateLocatorSetBoneIndices(context, owner, sofLocatorSet): 107 granny = resources.GetResource(context, owner.geometryResFilePath, resources.ResourceType.GRANNY) 108 if not granny: 109 return 110 count = len(granny.meshes[0].bonebindings) 111 for locator in sofLocatorSet.locators: 112 if locator.boneIndex >= count: 113 context.Error(locator, 'bone index is not valid') 114 115 116 @Validate('EveSOFDataHull(owner)/.../EveSOFDataHullLocatorSet(locators)') 117 def HullLocatorsAreCloseToGeometry(context, owner, locators): 118 if locators.name not in ('damage', 'explosions'): 119 return 120 granny = resources.GetResource(context, owner.geometryResFilePath, resources.ResourceType.GRANNY) 121 if not granny: 122 return 123 fi = ctypes.cast(granny.GetGrannyFileInfo(), ctypes.c_void_p).value 124 for i, each in enumerate(locators.locators): 125 direction = geo2.QuaternionTransformVector(each.rotation, (0, 1, 0)) 126 pos = geo2.Vec3Add(each.position, geo2.Vec3Scale(direction, 1)) 127 if not trinity.GrannyRayIntersection(fi, pos, geo2.Vec3Scale(direction, -1), -1, -1): 128 context.Error(locators, '%s locators not touching geometry' % locators.name) 129 return 130 131 132 _NAME_PATTERNS = (re.compile('locator_turret_(?P<index>\\d+)\\w?'), 133 re.compile('locator_launcher_(?P<index>\\d+)\\w?'), 134 re.compile('locator_booster_(?P<index>\\d+)'), 135 re.compile('locator_audio_booster'), 136 re.compile('locator_turretm_(?P<index>\\d+)\\w?'), 137 re.compile('locator_moonharvester_(?P<index>\\d+)\\w?'), 138 re.compile('locator_xl_(?P<index>\\d+)\\w?'), 139 re.compile('locator_atomic_(?P<index>\\d+)\\w?')) 140 _HANGAR_NAME_PATTERNS = (re.compile('Traffic_Start_(?P<index>[123])\\w?'), re.compile('Traffic_End_(?P<index>[123])\\w?')) 141 _SEQUENCE_PATTERNS = (re.compile('locator_turret_(?P<index>\\d+)\\w?'), re.compile('locator_launcher_(?P<index>\\d+)\\w?')) 142 143 def _GetLocatorName(pattern): 144 found = pattern.find('(') 145 if found == -1: 146 return pattern 147 return pattern[:found] 148 149 150 @Validate('List[EveLocator2]', SceneType) 151 def ValidateLocatorNamesPrefixes(context, locators): 152 isHangar = context.GetArgument(SceneType) == SceneType.HANGAR 153 namePatterns = _NAME_PATTERNS 154 if isHangar: 155 namePatterns = _NAME_PATTERNS + _HANGAR_NAME_PATTERNS 156 for locator in locators: 157 found = False 158 for i, pattern in enumerate(namePatterns): 159 match = pattern.match(locator.name) 160 if match: 161 found = True 162 break 163 164 if not found: 165 context.Error(locator, 'invalid locator name %s' % locator.name) 166 167 168 @Validate('List[EveLocator2]') 169 def ValidateLocatorNamesFormSequence(context, locators): 170 indices = {} 171 for locator in locators: 172 found = False 173 for i, pattern in enumerate(_SEQUENCE_PATTERNS): 174 match = pattern.match(locator.name) 175 if match: 176 found = True 177 try: 178 idx = int(match.group('index')) 179 except IndexError: 180 break 181 182 indices.setdefault(i, set()).add(idx) 183 break 184 185 if not found: 186 continue 187 188 for k, v in indices.items(): 189 if min(v) != 1 or max(v) != len(v): 190 context.Error(locators, 'locator indices %s in names do not form a sequence 1, 2, ...' % _GetLocatorName(_NAME_PATTERNS[k].pattern)) 191 192 193 @Validate('List[EveLocator2]') 194 def LocatorsHaveDistinctNames(context, locators): 195 for each in locators: 196 occurences = [ x for x in locators if x.name == each.name ] 197 if len(occurences) != 1: 198 context.Error(each, 'duplicate locator name %s' % each.name) 199 200 201 @Validate('/EveShip2/.../List[EveLocator2]') 202 def ShipMustHaveAudioBoosterLocator(context, locators): 203 audio = [ x for x in locators if x.name == 'locator_audio_booster' ] 204 if not audio: 205 context.Error(locators, 'ship must have a locator_audio_booster locator')