Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- unit ParseTSBlueprint;
- // I've copied this from the source code at git to know which is the cast for each type of data.
- // Short names
- // property S[const Name: string]: string read GetString write SetString; // returns '' if property doesn't exist, auto type-cast except for array/object
- // property I[const Name: string]: Integer read GetInt write SetInt; // returns 0 if property doesn't exist, auto type-cast except for array/object
- // property L[const Name: string]: Int64 read GetLong write SetLong; // returns 0 if property doesn't exist, auto type-cast except for array/object
- // property U[const Name: string]: UInt64 read GetULong write SetULong; // returns 0 if property doesn't exist, auto type-cast except for array/object
- // property F[const Name: string]: Double read GetFloat write SetFloat; // returns 0 if property doesn't exist, auto type-cast except for array/object
- // property D[const Name: string]: TDateTime read GetDateTime write SetDateTime; // returns 0 if property doesn't exist, auto type-cast except for array/object
- // property DUtc[const Name: string]: TDateTime read GetUtcDateTime write SetUtcDateTime; // returns 0 if property doesn't exist, auto type-cast except for array/object
- // 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
- // property A[const Name: string]: TJsonArray read GetArray write SetArray; // auto creates array on first access
- // property O[const Name: string]: TJsonObject read {$IFDEF BCB}GetObj{$ELSE}GetObject{$ENDIF} write SetObject; // auto creates object on first access
- //00066EB6
- procedure SplitText(const s: String; aList: TStringList);
- begin
- aList.Delimiter := '|';
- aList.StrictDelimiter := True; // Spaces excluded from being a delimiter
- aList.DelimitedText := s;
- end;
- function GetPluginIndex(PluginName: string): integer;
- var
- i, pi : integer;
- begin
- pi := -1;
- for i := Pred(FileCount) downto 0 do
- if SameText(PluginName, GetFileName(FileByIndex(i))) then begin
- pi := i;
- Break;
- end;
- Result := pi;
- end;
- function GetWorkshopRef(PluginIndex: integer; WorkshopID:string): IInterface;
- var
- fid: integer;
- f: IInterface;
- begin
- f := FileByIndex(PluginIndex);
- fid := StrToInt64('$' + IntToHex(GetLoadOrder(f), 2) + WorkshopID);
- Result := RecordByFormID(f, fid, True);
- end;
- procedure AddOrAssign(r: IInterface; container: string; element: string; value: string);
- var
- el: IInterface;
- begin
- if ElementExists(r, container) then begin
- el := ElementByPath(r, container);
- el := ElementAssign(el, HighInteger, nil, False);
- if Assigned(el) then begin
- SetElementEditValues(el, element, value);
- end;
- end
- else begin
- el := Add(r, container, True);
- if Assigned(el) then begin
- SetElementEditValues(ElementByIndex(el, 0), element, value);
- end;
- end;
- end;
- procedure BeginImport(bppath: string; ToFile: IInterface);
- var
- BP, obj: TJsonObject;
- form_id, reftype: string;
- items: TJsonArray;
- j, i, pi: integer;
- f, lr, workshopRef, workshopRefOverride, ws, wscell, ref, refA, refB, temp, powerRadiator, testPR: IInterface;
- sl: TStringList;
- begin
- BP := TJsonObject.Create;
- try
- BP.LoadFromResource(bppath); // parse the blueprint in the path given by the argument (relative to data)
- AddMasterIfMissing(ToFile, GetFileName(FileByIndex(0)));
- pi := GetPluginIndex(BP.O['header'].S['worldspace_plugin']);
- f := FileByIndex(pi);
- workshopRef := GetWorkshopRef(pi, BP.O['workshop'].S['id']);
- wscell := LinksTo(ElementByName(workshopRef, 'Cell'));
- AddMasterIfMissing(ToFile, GetFileName(GetFile(wscell)));
- workshopRefOverride := wbCopyElementToFile(workshopRef, ToFile, False, True);// Override record for workshop ref
- temp := wbCopyElementToFile(ElementByIndex(ChildGroup(wscell), 0), ToFile, True, False);//cell -> temporary
- ws := LinksTo(ElementByName(wscell, 'Worldspace'));
- items := BP.A['items']; // Store the blueprint items array in items.
- i := 0;
- while i < items.Count do begin
- obj := items.O[i];
- pi := GetPluginIndex(obj.S['plugin_name']);
- if pi = -1 then begin
- AddMessage(obj.S['plugin_name'] + ' Plugin Not Found');
- end
- else begin
- form_id := IntToHex(GetLoadOrder(FileByIndex(pi)), 2) + obj.S['FormID'];
- AddMasterIfMissing(ToFile, GetFileName(FileByIndex(pi)));
- testPR := RecordByFormID(FileByIndex(pi), StrToInt64('$' + form_id), False);
- if Signature(testPR) = 'NPC_' then reftype := 'ACHR' else reftype := 'REFR';
- ref := Add(temp, reftype, True);
- SetElementEditValues(ref, 'NAME', form_id);
- SetElementEditValues(ref, 'DATA\Position\X', obj.S['posX']);
- SetElementEditValues(ref, 'DATA\Position\Y', obj.S['posY']);
- SetElementEditValues(ref, 'DATA\Position\Z', obj.S['posZ']);
- SetElementEditValues(ref, 'DATA\Rotation\X', obj.S['rotX']);
- SetElementEditValues(ref, 'DATA\Rotation\Y', obj.S['rotY']);
- SetElementEditValues(ref, 'DATA\Rotation\Z', obj.S['rotZ']);
- if obj.S['Scale'] <> '1.0' then begin
- lr := Add(ref, 'XSCL', True);
- if Assigned(lr) then
- SetEditValue(lr, obj.S['Scale']);
- end;
- lr := Add(ref, 'Linked References', True);
- if Assigned(lr) then begin
- SetElementEditValues(lr, 'XLKR\Keyword/Ref', '00054BA6');
- SetElementEditValues(lr, 'XLKR\Ref', Name(workshopRef));
- end;
- obj.I['RefId'] := GetLoadOrderFormID(ref);
- end;
- Inc(i);
- end;
- // Start Powering Phase While
- i := 0;
- while i < items.Count do begin
- obj := items.O[i];
- if obj.I['RefId'] <> 0 then
- pi := GetPluginIndex(obj.S['plugin_name']);
- // Get Power Radiator
- if not Assigned(powerRadiator) then begin
- form_id := IntToHex(GetLoadOrder(FileByIndex(pi)), 2) + obj.S['FormID'];
- testPR := RecordByFormID(FileByIndex(pi), StrToInt64('$' + form_id), False);
- lr := ElementByPath(testPR, 'PRPS');
- if Assigned(lr) then begin
- sl := TStringList.Create;
- j := 0;
- while j < ElementCount(lr) do begin
- sl.Add(GetElementEditValues(ElementByIndex(lr, j), 'Actor Value'));
- Inc(j);
- end;
- lr := ElementByPath(testPR, 'KWDA');
- if Assigned(lr) then begin
- j := 0;
- while j < ElementCount(lr) do begin
- sl.Add(GetEditValue(ElementByIndex(lr, j)));
- Inc(j);
- end;
- end;
- if sl.IndexOf('PowerRadiation [AVIF:0000032F]') > -1 then
- if sl.IndexOf('WorkshopSwitchActivatorKeyword [KYWD:001690A4]') = -1 then
- powerRadiator := RecordByFormID(ToFile, obj.I['RefId'], True);
- end;
- end;
- refA := RecordByFormID(ToFile, obj.I['RefId'], True);
- // Start if Cables else Objects
- // Start Cables
- if obj.S['ConnectedObjects'] <> '' then begin
- sl := TStringList.Create;
- SplitText(obj.S['ConnectedObjects'], sl);
- // Loop Connected Objects
- j := 0;
- while j < sl.Count do begin
- // Start (Is Connected Object with greater Index)
- if StrToInt(sl[j]) > i then begin
- // Get Connected Object Ref
- refB := RecordByFormID(ToFile, items.O[StrToInt(sl[j])].L['RefId'], True);
- // Create Spline
- ref := Add(temp, 'REFR', True);
- SetElementEditValues(ref, 'NAME', '0001D971');
- SetElementNativeValues(ref, 'DATA\Position\X', StrToFloat(obj.S['posX']) + ((GetElementNativeValues(refB, 'DATA\Position\X') - GetElementNativeValues(refA, 'DATA\Position\X'))/2));
- SetElementNativeValues(ref, 'DATA\Position\Y', StrToFloat(obj.S['posY']) + ((GetElementNativeValues(refB, 'DATA\Position\Y') - GetElementNativeValues(refA, 'DATA\Position\Y'))/2));
- SetElementNativeValues(ref, 'DATA\Position\Z', StrToFloat(obj.S['posZ']) + ((GetElementNativeValues(refB, 'DATA\Position\Z') - GetElementNativeValues(refA, 'DATA\Position\Z'))/2));
- SetElementEditValues(ref, 'DATA\Rotation\X', '0.0');
- SetElementEditValues(ref, 'DATA\Rotation\Y', '0.0');
- SetElementEditValues(ref, 'DATA\Rotation\Z', '0.0');
- // Link Spline ref to workshop
- lr := Add(ref, 'Linked References', True);
- if Assigned(lr) then begin
- SetElementEditValues(lr, 'XLKR\Keyword/Ref', '00054BA6');
- SetElementEditValues(lr, 'XLKR\Ref', Name(workshopRefOverride));
- end;
- // Set Spline Values
- lr := Add(ref, 'XBSD', True);
- if Assigned(lr) then begin
- // Slack
- SetEditValue(ElementByIndex(lr, 0), '0.051149');
- // Thickness
- SetEditValue(ElementByIndex(lr, 1), '1.500000');
- // ? Other point Relative X
- SetNativeValue(ElementByIndex(lr, 2), (GetElementNativeValues(refB, 'DATA\Position\X') - GetElementNativeValues(refA, 'DATA\Position\X'))/2);
- // ? Other point Relative Y
- SetNativeValue(ElementByIndex(lr, 3), (GetElementNativeValues(refB, 'DATA\Position\Y') - GetElementNativeValues(refA, 'DATA\Position\Y'))/2);
- // ? Other point Relative Z
- SetNativeValue(ElementByIndex(lr, 4), (GetElementNativeValues(refB, 'DATA\Position\Z') - GetElementNativeValues(refA, 'DATA\Position\Z'))/2);
- // Detached End
- SetEditValue(ElementByIndex(lr, 5), 'False');
- end;
- // Set Spline Connections
- AddOrAssign(ref, 'Spline Connection', 'Ref', Name(refA));
- AddOrAssign(ref, 'Spline Connection', 'Ref', Name(refB));
- AddOrAssign(refA, 'Spline Connection', 'Ref', Name(ref));
- AddOrAssign(refB, 'Spline Connection', 'Ref', Name(ref));
- // Setup Grid
- if ElementExists(workshopRefOverride, 'Power Grid') then begin
- lr := ElementByPath(workshopRefOverride, 'Power Grid');
- SetElementNativeValues(lr, 'XWPG', GetElementNativeValues(lr, 'XWPG') + 1);
- lr := ElementByPath(lr, 'Connections');
- if Assigned(lr) then begin
- lr := ElementAssign(lr, HighInteger, nil, False);
- if Assigned(lr) then begin
- SetElementEditValues(lr, 'Node 1', Name(refA));
- SetElementEditValues(lr, 'Node 2', Name(refB));
- SetElementEditValues(lr, 'Line', Name(ref));
- end;
- end;
- end
- else begin
- lr := Add(workshopRefOverride, 'Power Grid', True);
- if Assigned(lr) then begin
- SetElementEditValues(lr, 'XWPG', '1');
- lr := Add(lr, 'XWPN', False);
- if Assigned(lr) then begin
- //AddMessage('Signature: ' + Signature(lr));
- SetElementEditValues(lr, 'XWPN\Node 1', Name(refA));
- SetElementEditValues(lr, 'XWPN\Node 2', Name(refB));
- SetElementEditValues(lr, 'XWPN\Line', Name(ref));
- end;
- end;
- end;
- // End (Is Connected Object with greater Index)
- end;
- Inc(j);
- // End Loop Connected Objects
- end;
- // End Cables
- end
- // Start Objects
- else begin
- // Start If assigned radiator
- if Assigned(powerRadiator) then begin
- // Start if powered
- if obj.I['isPowered'] = 1 then begin
- // Start Setup Grid
- // Start Exist
- if ElementExists(workshopRefOverride, 'Power Grid') then begin
- lr := ElementByPath(workshopRefOverride, 'Power Grid');
- SetElementNativeValues(lr, 'XWPG', GetElementNativeValues(lr, 'XWPG') + 1);
- lr := ElementByPath(lr, 'Connections');
- if Assigned(lr) then begin
- lr := ElementAssign(lr, HighInteger, nil, False);
- if Assigned(lr) then begin
- SetElementEditValues(lr, 'Node 1', Name(refA));
- SetElementEditValues(lr, 'Node 2', Name(powerRadiator));
- end;
- end;
- // End Exits
- end
- // Start Not Exist
- else begin
- lr := Add(workshopRefOverride, 'Power Grid', True);
- if Assigned(lr) then begin
- SetElementEditValues(lr, 'XWPG', '1');
- lr := Add(lr, 'XWPN', False);
- if Assigned(lr) then begin
- SetElementEditValues(lr, 'XWPN\Node 1', Name(refA));
- SetElementEditValues(lr, 'XWPN\Node 2', Name(powerRadiator));
- end;
- end;
- // End Not Exits
- // End Setup Grid
- end;
- // End if powered
- end;
- // End If assigned radiator
- end;
- // End Objects
- // End if Cables else Objects
- end;
- Inc(i);
- // End Powering Phase While
- end;
- finally
- BP.Free;
- end;
- end;
- // in the initialization it just shows a dialogue to enter the path of the blueprint
- // and calls BeginImport with the given path
- function Initialize: Integer;
- var
- s: string;
- f: IInterface;
- begin
- s := InputBox('Import TS Blueprint to esp.', 'Blueprint Path:', 'TS/bp.json');
- s := Trim(s);
- if s <> '' then begin
- if ResourceExists(s) then begin
- f := AddNewFile; //Shows a dialog to create a new esp.
- if f <> nil then BeginImport(s, f) else AddMessage('Invalid File Name.');
- end
- else AddMessage('File ' + s + ' could not be found in the Data folder.');
- end
- else AddMessage('You must eneter the path of the blueprint (relative to Data).');
- Result := 1;
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement