private TES5ScriptHeader CreateHeader(TES4Script script) { string edid = script.ScriptHeader.ScriptName; ITES5Type type = this.esmAnalyzer.GetScriptTypeByScriptNameFromCache(edid); return(TES5ScriptHeaderFactory.GetFromCacheOrConstructByBasicType(edid, type, TES5TypeFactory.TES4Prefix, false)); }
public static void GenerateINFOAddTopicScripts(ESMAnalyzer esmAnalyzer, BuildTracker buildTracker, IBuildTarget tifBuildTarget) { TES5TypeInferencer typeInferencer = new TES5TypeInferencer(esmAnalyzer); TES5ObjectCallFactory objectCallFactory = new TES5ObjectCallFactory(typeInferencer); TES4TopicsToTES5GlobalVariableFinder globalVariableFinder = new TES4TopicsToTES5GlobalVariableFinder(); TES5GlobalVariables globalVariables = esmAnalyzer.GlobalVariables; var builtTIFs = buildTracker.GetBuiltScripts(BuildTargetFactory.TIFName); foreach (TES4Record infoRecord in esmAnalyzer.GetRecords().Where(r => r.RecordType == TES4RecordType.INFO)) { TES4SubrecordData[] names = infoRecord.GetSubrecords("NAME").ToArray(); if (names.Any()) { string fragment0Name = TES5FragmentFactory.GetFragmentName(0); string nameTES5FormIDHex = (infoRecord.FormID + 0x01000000).ToString("x8"); string scriptName = TES5ReferenceFactory.tif_Prefix + "_" + nameTES5FormIDHex; TES5Script? infoTIF = builtTIFs.Where(s => s.Key == scriptName).Select(s => s.Value.Script).FirstOrDefault(); TES5FunctionCodeBlock fragment0; if (infoTIF != null) { fragment0 = infoTIF.BlockList.Blocks.OfType <TES5FunctionCodeBlock>().Where(b => b.BlockName == fragment0Name).First(); } else { TES5ScriptHeader scriptHeader = TES5ScriptHeaderFactory.GetFromCacheOrConstructByBasicType(scriptName, TES5BasicType.T_TOPICINFO, TES5TypeFactory.TES4_Prefix, true); TES5GlobalScope globalScope = new TES5GlobalScope(scriptHeader); TES5FunctionScope functionScope = new TES5FunctionScope(fragment0Name); functionScope.AddParameter(new TES5SignatureParameter("akSpeakerRef", TES5BasicType.T_OBJECTREFERENCE, true)); TES5LocalScope localScope = new TES5LocalScope(functionScope); TES5CodeScope codeScope = TES5CodeScopeFactory.CreateCodeScope(localScope); fragment0 = new TES5FunctionCodeBlock(functionScope, codeScope, TES5VoidType.Instance, false, true); TES5BlockList blockList = new TES5BlockList() { fragment0 }; infoTIF = new TES5Script(globalScope, blockList, true); string outputPath = tifBuildTarget.GetTranspileToPath(scriptName); TES5Target target = new TES5Target(infoTIF, outputPath); buildTracker.RegisterBuiltScript(tifBuildTarget, target); } foreach (TES4SubrecordData name in names) { int formID = infoRecord.ExpandBytesIntoFormID(name); TES4Record addedTopic = esmAnalyzer.GetRecordByFormID(formID); Tuple <int, string>?globalVariable = globalVariableFinder.GetGlobalVariableNullable(addedTopic.FormID); string globalVariableEditorID = globalVariable != null ? globalVariable.Item2 : globalVariableFinder.GetGlobalVariableEditorID(addedTopic.GetEditorID()); Nullable <int> globalVariableTES5FormID = globalVariable != null ? globalVariable.Item1 : (Nullable <int>)null; TES5Property topicAddedProperty = TES5PropertyFactory.ConstructWithTES5FormID(globalVariableEditorID, TES5BasicType.T_GLOBALVARIABLE, globalVariableEditorID, globalVariableTES5FormID); infoTIF.GlobalScope.AddPropertyIfNotExists(topicAddedProperty); TES5Reference topicAddedReference = TES5ReferenceFactory.CreateReferenceToVariableOrProperty(topicAddedProperty); fragment0.AddChunk(objectCallFactory.CreateObjectCall(topicAddedReference, "SetValueInt", new TES5ObjectCallArguments() { new TES5Integer(1) })); } } } }
public static List <TES5GlobalScope> CreateGlobalScopes() { List <TES5GlobalScope> globalScopes = new List <TES5GlobalScope>() { new TES5GlobalScope(TES5ScriptHeaderFactory.GetFromCacheOrConstructByBasicType(TES5BasicType.TES4TimerHelperName, TES5BasicType.T_QUEST, "", false)) }; TES5GlobalScope globalScope = new TES5GlobalScope(TES5ScriptHeaderFactory.GetFromCacheOrConstructByBasicType(TES5BasicType.TES4ContainerName, TES5BasicType.T_QUEST, "", false)); globalScope.AddProperty(TES5PropertyFactory.ConstructWithoutFormID("isInJail", TES5BasicType.T_BOOL, "isInJail")); globalScope.AddProperty(TES5PropertyFactory.ConstructWithoutFormID("isMurderer", TES5BasicType.T_BOOL, "isMurderer")); globalScopes.Add(globalScope); return(globalScopes); }
public TES5GlobalScope Build(string sourcePath, TES5GlobalVariables globalVariables) { string scriptName = Path.GetFileNameWithoutExtension(sourcePath); TES4VariableDeclarationList variableList = fragmentsReferencesBuilder.BuildVariableDeclarationList(sourcePath, scriptName, fragmentType); //Create the header. TES5ScriptHeader scriptHeader = TES5ScriptHeaderFactory.GetFromCacheOrConstructByBasicType(scriptName, scriptType, scriptNamePrefix, true); TES5GlobalScope globalScope = new TES5GlobalScope(scriptHeader); if (variableList != null) { propertyFactory.CreateAndAddProperties(variableList, globalScope, globalVariables); } return(globalScope); }
/* * @todo REFACTOR, it"s really ugly! * @throws ConversionException */ public ITES5Type GetScriptTypeByEDID(string edid) { string edidLower = edid.ToLower(); ITES5Type?value; if (this.edidLowerCache.TryGetValue(edidLower, out value)) { return(value); } TES4Record attachedNameRecord = GetRecordByEDIDAndFollowNAME(edid); Nullable <int> scriptFormid = attachedNameRecord.TryGetSubrecordAsFormID("SCRI"); if (scriptFormid == null) { throw new ConversionException("Cannot resolve script type for " + edid + " - Asked base record has no script bound."); } string scriptRecordEDID = GetEDIDByFormID(scriptFormid.Value); TES5ScriptHeader scriptHeader = TES5ScriptHeaderFactory.GetFromCacheOrConstructByBasicType(scriptRecordEDID, TypeMapper.GetTES5BasicType(attachedNameRecord.RecordType), TES5TypeFactory.TES4Prefix, false); this.edidLowerCache.Add(edidLower, scriptHeader.ScriptType); return(scriptHeader.ScriptType); }
/* * Joins N QF subfragments into one QF fragment that can be properly binded into Skyrim VM * @throws ConversionException */ public TES5Target JoinQFFragments(IBuildTarget target, string resultingFragmentName, List <QuestStageScript> subfragmentsTrees) { int tes4FormID = GetTES4FormID(resultingFragmentName); StageMap stageMap = StageMapBuilder.Build(target, resultingFragmentName, esmAnalyzer, tes4FormID); /* * We need script fragment for objective handling for each stage, so when parsing the script fragments, * we"ll be marking them there, and intersecting this with stage. * This will give us an array of stages which don"t have script fragment, but will need it anyways * for objective handling. */ TES5ScriptHeader resultingScriptHeader = TES5ScriptHeaderFactory.GetFromCacheOrConstructByBasicType(resultingFragmentName, TES5BasicType.T_QUEST, TES5TypeFactory.TES4_Prefix, true); TES5GlobalScope resultingGlobalScope = new TES5GlobalScope(resultingScriptHeader); string[] referenceAliases = ReferenceAliasBuilder.Build(target, resultingFragmentName, esmAnalyzer, tes4FormID).ToArray(); foreach (string propertyName in referenceAliases) { resultingGlobalScope.AddProperty(TES5PropertyFactory.ConstructWithoutFormID(propertyName, TES5BasicType.T_REFERENCEALIAS, propertyName)); } List <QuestStageBlock> questStageBlocks = new List <QuestStageBlock>(); HashSet <int> implementedStages = new HashSet <int>(); HashSet <string> propertiesNamesDeclared = new HashSet <string>(); foreach (var subfragment in subfragmentsTrees) { TES5Target subfragmentsTree = subfragment.Script; TES5Script subfragmentScript = subfragmentsTree.Script; TES5GlobalScope subfragmentGlobalScope = subfragmentScript.GlobalScope; foreach (TES5Property subfragmentProperty in subfragmentGlobalScope.Properties) { /* * Move over the properties to the new global scope */ if (propertiesNamesDeclared.Add(subfragmentProperty.Name)) { resultingGlobalScope.AddProperty(subfragmentProperty); } else { if (subfragmentProperty.IsPlayerRef) { continue; } //WTM: Change: I don't think renaming these properties actually helps anything. /* * string propertyName = GeneratePropertyName(subfragmentScript.ScriptHeader, subfragmentProperty); * subfragmentProperty.Rename(propertyName); * if (!propertiesNamesDeclared.Add(subfragmentProperty.Name)) * { * throw new ConversionException(nameof(propertiesNamesDeclared) + " already contained property " + subfragmentProperty.Name + "."); * } */ //WTM: Change: I'm trying to unify properties and include extended type declarations. TES5Property existingProperty = resultingGlobalScope.GetPropertyByName(subfragmentProperty.Name); if (TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(existingProperty.TES5Type, subfragmentProperty.TES5Type)) { continue; } if (TES5InheritanceGraphAnalyzer.IsExtending(subfragmentProperty.TES5Type, existingProperty.TES5Type)) { existingProperty.TES5Type = subfragmentProperty.TES5Type; continue; } if (TES5InheritanceGraphAnalyzer.IsExtending(existingProperty.TES5Type, subfragmentProperty.TES5Type.NativeType)) { subfragmentProperty.TES5Type.NativeType = existingProperty.TES5Type.NativeType; existingProperty.TES5Type = subfragmentProperty.TES5Type; continue; } throw new ConversionException("Types were not compatible for property " + subfragmentProperty.Name + ": " + subfragmentProperty.TES5Type.Value + " should extend " + existingProperty.TES5Type.Value + " (" + existingProperty.TES5Type.NativeType.Value + ")."); } } List <ITES5CodeBlock> subfragmentBlocks = subfragmentScript.BlockList.Blocks; if (subfragmentBlocks.Count != 1) { throw new ConversionException("Wrong QF fragment, actual function count: " + subfragmentBlocks.Count + ".."); } ITES5CodeBlock subfragmentBlock = subfragmentBlocks[0]; if (subfragmentBlock.FunctionScope.BlockName != TES5FragmentFactory.GetFragmentName(0)) { throw new ConversionException("Wrong QF fragment funcname, actual function name: " + subfragmentBlock.FunctionScope.BlockName + "."); } string newFragmentFunctionName = TES5FragmentFactory.GetFragmentName(subfragment.Stage, subfragment.LogIndex); subfragmentBlock.FunctionScope.Rename(newFragmentFunctionName); List <int>?stageMapOfStage = stageMap.TryGetStageTargetsMap(subfragment.Stage); if (stageMapOfStage != null) { var objectiveCodeChunks = objectiveHandlingFactory.GenerateObjectiveHandling(subfragmentBlock, resultingGlobalScope, stageMapOfStage); foreach (var newCodeChunk in objectiveCodeChunks) { subfragmentBlock.AddChunk(newCodeChunk); } } questStageBlocks.Add(new QuestStageBlock(subfragment.Stage, subfragment.LogIndex, subfragmentBlock)); implementedStages.Add(subfragment.Stage); } /* * Diff to find stages which we still need to mark */ int[] nonDoneStages = stageMap.StageIDs.Where(stageID => !implementedStages.Contains(stageID)).ToArray(); foreach (int nonDoneStage in nonDoneStages) { TES5FunctionCodeBlock fragment = objectiveHandlingFactory.CreateEnclosedFragment(resultingGlobalScope, nonDoneStage, stageMap.GetStageTargetsMap(nonDoneStage)); questStageBlocks.Add(new QuestStageBlock(nonDoneStage, 0, fragment)); } this.mappedTargetsLogService.WriteScriptName(resultingFragmentName); foreach (var kvp in stageMap.MappedTargetsIndex) { var originalTargetIndex = kvp.Key; var mappedTargetIndexes = kvp.Value; this.mappedTargetsLogService.WriteLine(originalTargetIndex, mappedTargetIndexes); } TES5BlockList resultingBlockList = new TES5BlockList(questStageBlocks.OrderBy(b => b.StageID).ThenBy(b => b.LogIndex).Select(b => b.CodeBlock)); TES5Script resultingTree = new TES5Script(resultingGlobalScope, resultingBlockList, true); string outputPath = target.GetTranspileToPath(resultingFragmentName); return(new TES5Target(resultingTree, outputPath)); }