Advertisement
DieFeM

ParseTSBlueprint radiator persistent

Jun 26th, 2019
213
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pascal 14.54 KB | None | 0 0
  1. unit ParseTSBlueprint;
  2.  
  3. // I've copied this from the source code at git to know which is the cast for each type of data.
  4. // Short names
  5. //    property S[const Name: string]: string read GetString write SetString;        // returns '' if property doesn't exist, auto type-cast except for array/object
  6. //    property I[const Name: string]: Integer read GetInt write SetInt;             // returns 0 if property doesn't exist, auto type-cast except for array/object
  7. //    property L[const Name: string]: Int64 read GetLong write SetLong;             // returns 0 if property doesn't exist, auto type-cast except for array/object
  8. //    property U[const Name: string]: UInt64 read GetULong write SetULong;          // returns 0 if property doesn't exist, auto type-cast except for array/object
  9. //    property F[const Name: string]: Double read GetFloat write SetFloat;          // returns 0 if property doesn't exist, auto type-cast except for array/object
  10. //    property D[const Name: string]: TDateTime read GetDateTime write SetDateTime; // returns 0 if property doesn't exist, auto type-cast except for array/object
  11. //    property DUtc[const Name: string]: TDateTime read GetUtcDateTime write SetUtcDateTime; // returns 0 if property doesn't exist, auto type-cast except for array/object
  12. //    property B[const Name: string]: Boolean read GetBool write SetBool;           // returns false if property doesn't exist, auto type-cast with "<>'true'" and "<>0" except for array/object
  13. //    property A[const Name: string]: TJsonArray read GetArray write SetArray;      // auto creates array on first access
  14. //    property O[const Name: string]: TJsonObject read {$IFDEF BCB}GetObj{$ELSE}GetObject{$ENDIF} write SetObject;   // auto creates object on first access
  15. //00066EB6
  16.  
  17. procedure SplitText(const s: String; aList: TStringList);
  18. begin
  19.   aList.Delimiter := '|';
  20.   aList.StrictDelimiter := True; // Spaces excluded from being a delimiter
  21.   aList.DelimitedText := s;
  22. end;
  23.  
  24. function GetPluginIndex(PluginName: string): integer;
  25. var
  26.   i, pi : integer;
  27. begin
  28.   pi := -1;
  29.   for i := Pred(FileCount) downto 0 do
  30.     if SameText(PluginName, GetFileName(FileByIndex(i))) then begin
  31.       pi := i;
  32.       Break;
  33.     end;
  34.   Result := pi;
  35. end;
  36.  
  37. function GetWorkshopRef(PluginIndex: integer; WorkshopID:string): IInterface;
  38. var
  39.   fid: integer;
  40.   f: IInterface;
  41. begin
  42.   f := FileByIndex(PluginIndex);
  43.   fid := StrToInt64('$' + IntToHex(GetLoadOrder(f), 2) + WorkshopID);
  44.   Result := RecordByFormID(f, fid, True);
  45. end;
  46.  
  47. procedure AddOrAssign(r: IInterface; container: string; element: string; value: string);
  48. var
  49.   el: IInterface;
  50. begin
  51.   if ElementExists(r, container) then begin
  52.     el := ElementByPath(r, container);
  53.     el := ElementAssign(el, HighInteger, nil, False);
  54.     if Assigned(el) then begin
  55.       SetElementEditValues(el, element, value);
  56.     end;
  57.   end
  58.   else begin
  59.     el := Add(r, container, True);
  60.     if Assigned(el) then begin
  61.       SetElementEditValues(ElementByIndex(el, 0), element, value);
  62.     end;
  63.   end;
  64. end;
  65.  
  66. procedure BeginImport(bppath: string; ToFile: IInterface);
  67. var
  68.   BP, obj: TJsonObject;
  69.   form_id, reftype: string;
  70.   items: TJsonArray;
  71.   j, i, pi: integer;
  72.   f, lr, workshopRef, workshopRefOverride, ws, wscell, ref, refA, refB, temp, powerRadiator, testPR: IInterface;
  73.   sl: TStringList;
  74. begin
  75.   BP := TJsonObject.Create;
  76.   try
  77.     BP.LoadFromResource(bppath); // parse the blueprint in the path given by the argument (relative to data)
  78.     AddMasterIfMissing(ToFile, GetFileName(FileByIndex(0)));
  79.     pi := GetPluginIndex(BP.O['header'].S['worldspace_plugin']);
  80.     f := FileByIndex(pi);
  81.     workshopRef := GetWorkshopRef(pi, BP.O['workshop'].S['id']);
  82.     wscell := LinksTo(ElementByName(workshopRef, 'Cell'));
  83.     AddMasterIfMissing(ToFile, GetFileName(GetFile(wscell)));
  84.     workshopRefOverride := wbCopyElementToFile(workshopRef, ToFile, False, True);// Override record for workshop ref
  85.     temp := wbCopyElementToFile(ElementByIndex(ChildGroup(wscell), 0), ToFile, True, False);//cell -> temporary
  86.     ws := LinksTo(ElementByName(wscell, 'Worldspace'));
  87.     items := BP.A['items']; // Store the blueprint items array in items.
  88.     i := 0;
  89.     while i < items.Count do begin
  90.       obj := items.O[i];
  91.       pi := GetPluginIndex(obj.S['plugin_name']);
  92.       if pi = -1 then begin
  93.         AddMessage(obj.S['plugin_name'] + ' Plugin Not Found');
  94.       end
  95.       else begin
  96.           form_id := IntToHex(GetLoadOrder(FileByIndex(pi)), 2) + obj.S['FormID'];
  97.           AddMasterIfMissing(ToFile, GetFileName(FileByIndex(pi)));
  98.          
  99.           testPR := RecordByFormID(FileByIndex(pi), StrToInt64('$' + form_id), False);
  100.           if Signature(testPR) = 'NPC_' then reftype := 'ACHR' else reftype := 'REFR';
  101.          
  102.           ref := Add(temp, reftype, True);
  103.           SetElementEditValues(ref, 'NAME', form_id);
  104.           SetElementEditValues(ref, 'DATA\Position\X', obj.S['posX']);
  105.           SetElementEditValues(ref, 'DATA\Position\Y', obj.S['posY']);
  106.           SetElementEditValues(ref, 'DATA\Position\Z', obj.S['posZ']);
  107.           SetElementEditValues(ref, 'DATA\Rotation\X', obj.S['rotX']);
  108.           SetElementEditValues(ref, 'DATA\Rotation\Y', obj.S['rotY']);
  109.           SetElementEditValues(ref, 'DATA\Rotation\Z', obj.S['rotZ']);
  110.          
  111.           if obj.S['Scale'] <> '1.0' then begin
  112.             lr := Add(ref, 'XSCL', True);
  113.             if Assigned(lr) then
  114.               SetEditValue(lr, obj.S['Scale']);
  115.           end;
  116.          
  117.           lr := Add(ref, 'Linked References', True);
  118.           if Assigned(lr) then begin
  119.             SetElementEditValues(lr, 'XLKR\Keyword/Ref', '00054BA6');
  120.             SetElementEditValues(lr, 'XLKR\Ref', Name(workshopRef));
  121.           end;
  122.          
  123.           obj.I['RefId'] := GetLoadOrderFormID(ref);
  124.       end;
  125.       Inc(i);
  126.     end;
  127.    
  128.     // Start Powering Phase While
  129.     i := 0;
  130.     while i < items.Count do begin
  131.       obj := items.O[i];
  132.      
  133.       if obj.I['RefId'] <> 0 then
  134.         pi := GetPluginIndex(obj.S['plugin_name']);
  135.        
  136.         // Get Power Radiator
  137.         if not Assigned(powerRadiator) then begin
  138.           form_id := IntToHex(GetLoadOrder(FileByIndex(pi)), 2) + obj.S['FormID'];
  139.           testPR := RecordByFormID(FileByIndex(pi), StrToInt64('$' + form_id), False);
  140.           lr := ElementByPath(testPR, 'PRPS');
  141.           if Assigned(lr) then begin
  142.             sl := TStringList.Create;
  143.             j := 0;
  144.             while j < ElementCount(lr) do begin
  145.               sl.Add(GetElementEditValues(ElementByIndex(lr, j), 'Actor Value'));
  146.               Inc(j);
  147.             end;
  148.            
  149.             lr := ElementByPath(testPR, 'KWDA');
  150.             if Assigned(lr) then begin
  151.               j := 0;
  152.               while j < ElementCount(lr) do begin
  153.                 sl.Add(GetEditValue(ElementByIndex(lr, j)));
  154.                 Inc(j);
  155.               end;
  156.             end;
  157.            
  158.             if sl.IndexOf('PowerRadiation [AVIF:0000032F]') > -1 then
  159.               if sl.IndexOf('WorkshopSwitchActivatorKeyword [KYWD:001690A4]') = -1 then
  160.                 powerRadiator := RecordByFormID(ToFile, obj.I['RefId'], True);
  161.           end;
  162.         end;
  163.        
  164.         refA := RecordByFormID(ToFile, obj.I['RefId'], True);
  165.        
  166.         // Start if Cables else Objects
  167.         // Start Cables
  168.         if obj.S['ConnectedObjects'] <> '' then begin
  169.          
  170.           sl := TStringList.Create;
  171.           SplitText(obj.S['ConnectedObjects'], sl);
  172.          
  173.           // Loop Connected Objects
  174.           j := 0;
  175.           while j < sl.Count do begin
  176.             // Start (Is Connected Object with greater Index)
  177.             if StrToInt(sl[j]) > i then begin
  178.               // Get Connected Object Ref
  179.               refB := RecordByFormID(ToFile, items.O[StrToInt(sl[j])].L['RefId'], True);
  180.              
  181.               // Create Spline
  182.               ref := Add(temp, 'REFR', True);
  183.               SetElementEditValues(ref, 'NAME', '0001D971');
  184.               SetElementNativeValues(ref, 'DATA\Position\X', StrToFloat(obj.S['posX']) + ((GetElementNativeValues(refB, 'DATA\Position\X') - GetElementNativeValues(refA, 'DATA\Position\X'))/2));
  185.               SetElementNativeValues(ref, 'DATA\Position\Y', StrToFloat(obj.S['posY']) + ((GetElementNativeValues(refB, 'DATA\Position\Y') - GetElementNativeValues(refA, 'DATA\Position\Y'))/2));
  186.               SetElementNativeValues(ref, 'DATA\Position\Z', StrToFloat(obj.S['posZ']) + ((GetElementNativeValues(refB, 'DATA\Position\Z') - GetElementNativeValues(refA, 'DATA\Position\Z'))/2));
  187.               SetElementEditValues(ref, 'DATA\Rotation\X', '0.0');
  188.               SetElementEditValues(ref, 'DATA\Rotation\Y', '0.0');
  189.               SetElementEditValues(ref, 'DATA\Rotation\Z', '0.0');
  190.              
  191.               // Link Spline ref to workshop
  192.               lr := Add(ref, 'Linked References', True);
  193.               if Assigned(lr) then begin
  194.                 SetElementEditValues(lr, 'XLKR\Keyword/Ref', '00054BA6');
  195.                 SetElementEditValues(lr, 'XLKR\Ref', Name(workshopRefOverride));
  196.               end;
  197.              
  198.               // Set Spline Values
  199.               lr := Add(ref, 'XBSD', True);
  200.               if Assigned(lr) then begin
  201.                 // Slack
  202.                 SetEditValue(ElementByIndex(lr, 0), '0.051149');
  203.                 // Thickness
  204.                 SetEditValue(ElementByIndex(lr, 1), '1.500000');
  205.                 // ? Other point Relative X
  206.                 SetNativeValue(ElementByIndex(lr, 2), (GetElementNativeValues(refB, 'DATA\Position\X') - GetElementNativeValues(refA, 'DATA\Position\X'))/2);
  207.                 // ? Other point Relative Y
  208.                 SetNativeValue(ElementByIndex(lr, 3), (GetElementNativeValues(refB, 'DATA\Position\Y') - GetElementNativeValues(refA, 'DATA\Position\Y'))/2);
  209.                 // ? Other point Relative Z
  210.                 SetNativeValue(ElementByIndex(lr, 4), (GetElementNativeValues(refB, 'DATA\Position\Z') - GetElementNativeValues(refA, 'DATA\Position\Z'))/2);
  211.                 // Detached End
  212.                 SetEditValue(ElementByIndex(lr, 5), 'False');
  213.               end;
  214.              
  215.               // Set Spline Connections
  216.               AddOrAssign(ref, 'Spline Connection', 'Ref', Name(refA));
  217.               AddOrAssign(ref, 'Spline Connection', 'Ref', Name(refB));
  218.               AddOrAssign(refA, 'Spline Connection', 'Ref', Name(ref));
  219.               AddOrAssign(refB, 'Spline Connection', 'Ref', Name(ref));
  220.              
  221.               // Setup Grid
  222.               if ElementExists(workshopRefOverride, 'Power Grid') then begin
  223.                 lr := ElementByPath(workshopRefOverride, 'Power Grid');
  224.                 SetElementNativeValues(lr, 'XWPG', GetElementNativeValues(lr, 'XWPG') + 1);
  225.                 lr := ElementByPath(lr, 'Connections');
  226.                 if Assigned(lr) then begin
  227.                   lr := ElementAssign(lr, HighInteger, nil, False);
  228.                   if Assigned(lr) then begin
  229.                     SetElementEditValues(lr, 'Node 1', Name(refA));
  230.                     SetElementEditValues(lr, 'Node 2', Name(refB));
  231.                     SetElementEditValues(lr, 'Line', Name(ref));
  232.                   end;
  233.                 end;
  234.               end
  235.               else begin
  236.                 lr := Add(workshopRefOverride, 'Power Grid', True);
  237.                 if Assigned(lr) then begin
  238.                   SetElementEditValues(lr, 'XWPG', '1');
  239.                   lr := Add(lr, 'XWPN', False);
  240.                   if Assigned(lr) then begin
  241.                     //AddMessage('Signature: ' + Signature(lr));
  242.                     SetElementEditValues(lr, 'XWPN\Node 1', Name(refA));
  243.                     SetElementEditValues(lr, 'XWPN\Node 2', Name(refB));
  244.                     SetElementEditValues(lr, 'XWPN\Line', Name(ref));
  245.                   end;
  246.                 end;
  247.               end;
  248.            
  249.             // End (Is Connected Object with greater Index)
  250.             end;
  251.             Inc(j);
  252.           // End Loop Connected Objects
  253.           end;
  254.         // End Cables
  255.         end
  256.         // Start Objects
  257.         else begin
  258.           // Start If assigned radiator
  259.           if Assigned(powerRadiator) then begin
  260.             // Start if powered
  261.             if obj.I['isPowered'] = 1 then begin
  262.               // Start Setup Grid
  263.               // Start Exist
  264.               if ElementExists(workshopRefOverride, 'Power Grid') then begin
  265.                 lr := ElementByPath(workshopRefOverride, 'Power Grid');
  266.                 SetElementNativeValues(lr, 'XWPG', GetElementNativeValues(lr, 'XWPG') + 1);
  267.                 lr := ElementByPath(lr, 'Connections');
  268.                 if Assigned(lr) then begin
  269.                   lr := ElementAssign(lr, HighInteger, nil, False);
  270.                   if Assigned(lr) then begin
  271.                     SetElementEditValues(lr, 'Node 1', Name(refA));
  272.                     SetElementEditValues(lr, 'Node 2', Name(powerRadiator));
  273.                   end;
  274.                 end;
  275.               // End Exits
  276.               end
  277.               // Start Not Exist
  278.               else begin
  279.                 lr := Add(workshopRefOverride, 'Power Grid', True);
  280.                 if Assigned(lr) then begin
  281.                   SetElementEditValues(lr, 'XWPG', '1');
  282.                   lr := Add(lr, 'XWPN', False);
  283.                   if Assigned(lr) then begin
  284.                     SetElementEditValues(lr, 'XWPN\Node 1', Name(refA));
  285.                     SetElementEditValues(lr, 'XWPN\Node 2', Name(powerRadiator));
  286.                   end;
  287.                 end;
  288.               // End Not Exits
  289.               // End Setup Grid
  290.               end;
  291.             // End if powered
  292.             end;
  293.           // End If assigned radiator
  294.           end;
  295.         // End Objects
  296.         // End if Cables else Objects
  297.         end;
  298.       Inc(i);
  299.     // End Powering Phase While
  300.     end;
  301.   finally
  302.     BP.Free;
  303.   end;
  304. end;
  305.  
  306. // in the initialization it just shows a dialogue to enter the path of the blueprint
  307. // and calls BeginImport with the given path
  308. function Initialize: Integer;
  309. var
  310.   s: string;
  311.   f: IInterface;
  312. begin
  313.   s := InputBox('Import TS Blueprint to esp.', 'Blueprint Path:', 'TS/bp.json');
  314.   s := Trim(s);
  315.   if s <> '' then begin
  316.     if ResourceExists(s) then begin
  317.       f := AddNewFile; //Shows a dialog to create a new esp.
  318.       if f <> nil then BeginImport(s, f) else AddMessage('Invalid File Name.');
  319.     end
  320.     else AddMessage('File ' + s + ' could not be found in the Data folder.');
  321.   end
  322.   else AddMessage('You must eneter the path of the blueprint (relative to Data).');
  323.   Result := 1;
  324. end;
  325.  
  326. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement