Main Form Code: https://pastebin.com/31gjpzm6 < Outdated
Blueprint Input Code W/ Mods: https://pastebin.com/KsF2vAWw < Outdated
Mods from "%AppData%\Roaming\SpaceEngineers\Mods" are extracted to "C:\SETools\unpacked_mods\" into a folder named by an integer which is equal to the number that it was extracted so the first mod is 0 second is 1 and so on.
A typical mod will have its main data file like so "C:\SETools\unpacked_mods\0\data\CubeBlocks.sbc" and the internal data is in XML as well.
CubeBlocks.sbc Mod Info File: https://pastebin.com/UhhGtEhN
So what i want to do is cross-reference the modded subtype id in the blueprint file with the one in all the mod files and check if they match and if they do then grab their Icon which is in DDS format and send it to a picturebox which has already been generated in the Form1 code above. And i want to do this by retrieving the path to a string.
Screenshot: http://imgur.com/a/3bIfN
So my question is how do i go about writing a function to do this without writing an IF function for each mod, basically i want to make a list of vanilla blocktypes and do like an if blockname is = to any item in the list of vanilla blocks then run the check for mods function.
What ive got so far:
Public Sub LoadModDefinitions()
Dim modpath As String = "C:\SETools\unpacked_mods\"
For Each entry In Directory.GetFiles(modpath, "CubeBlocks.sbc") 'For each zipfilename in the given directory extract them to the given folder
Dim filereader As StreamReader = New StreamReader(modpath)
For Each block In entry
ModdedCubeblockDefinitions.Add(filereader.ReadToEnd(modpath))
Next block
Next
End Sub
^ This loads all the modded block information into a list.
And the function in question is the one below how can i search each block of data in the list of modded block data, find out which one contains the input "subtypesearch" & return a specific chunk of that files contents which is a file path between "" and "/icon"
Public Function SearchModdedCubeDefinitions(subtypesearch As String) 'WIP WIP WIP WIP WIP WIP
Dim BlockToSearch As String = subtypesearch
Return Nothing
End Function
And the automatic extracting of the mods files
'Check if program has been ran before and extract all mods if it hasnt
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles Me.Load
Try
'Check if the program directory exists & if not then create it
If Not Directory.Exists("C:\SETools") Then
Try
Directory.CreateDirectory("C:\SETools")
Catch ex As Exception
End Try
End If
'Check if the mod extraction directory exists in the C drive & if not then create it
If Not Directory.Exists("C:\SETools\unpacked_mods") Then
Try
Directory.CreateDirectory("C:\SETools\unpacked_mods")
Catch ex As Exception
End Try
End If
'Check if the file that determins whether or not the program has been run before exists or not & if not then create it
If Not File.Exists("C:\SETools\Activated.txt") Then
Try
File.CreateText("C:\SETools\Activated.txt")
'Unpack all mods
unpackAll(sepath, extractto)
Catch ex As Exception
End Try
End If
Catch ex As Exception
End Try
End Sub
Currently it seems that all the files are being read into the string list with no issue but i have no idea where to even start with the search function. I have a function written already for something i was doing before to search textboxes and was thinking of trying to implement it here but I'm still going to be concerned on how to return the text between the icon tags, i was thinking maybe using regex string splitting but I'm not quite sure any pointers?
Current Search Function
Private Function FindWords(ByVal TextSearched As String, ByVal Paragraph As String) As Integer
Dim location As Integer = 0
Dim occurances As Integer = 0
Do
location = TextSearched.IndexOf(Paragraph, location)
If location <> -1 Then
occurances += 1
location += Paragraph.Length
End If
Loop Until location = -1
Return occurances
End Function
Using serialization to solve the problem
XMLCleaner.vb
Public Class XMLCleaner
Public Function CleanXML(inputfile As String)
Dim originalxml As String = inputfile
Dim outputxml As String = Nothing
'only keep requested xml lines and remove xsi:type from <definition> element
For Each line In originalxml.Split(vbNewLine)
If line.ToString().Contains("<?xml") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<Definitions xmlns:xsi") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<CubeBlocks>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<Definition xsi:type") Then
outputxml += "<Definition>" + vbNewLine
ElseIf line.ToString().Contains("<Definition>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<Id>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("</Id>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<TypeId>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<SubtypeId>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<DisplayName>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<Icon>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<CubeSize>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<BlockPairName>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<BuildTimeSeconds>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<Components>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("<Component Subtype") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("</Components>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("</Definition>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("</CubeBlocks>") Then
outputxml += line.ToString() + vbNewLine
ElseIf line.ToString().Contains("</Definitions>") Then
outputxml += line.ToString() + vbNewLine
End If
Next
Return outputxml
End Function
End Class
This method extracts only the wanted data from the cubeblocks file of every mod to make it serializable by the universal cubeblocks deserializer I made to answer another question I had.
CubeBlocksSerializer.vb
Option Strict Off
Option Explicit On
Imports System.Xml.Serialization
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.7.3081.0"),
System.SerializableAttribute(),
System.Diagnostics.DebuggerStepThroughAttribute(),
System.ComponentModel.DesignerCategoryAttribute("code"),
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True),
System.Xml.Serialization.XmlRootAttribute([Namespace]:="", IsNullable:=False)>
Partial Public Class Definitions
Private cubeBlocksField() As DefinitionsDefinition
<System.Xml.Serialization.XmlArrayItemAttribute("Definition", IsNullable:=False)>
Public Property CubeBlocks() As DefinitionsDefinition()
Get
Return Me.cubeBlocksField
End Get
Set
Me.cubeBlocksField = Value
End Set
End Property
End Class
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.7.3081.0"),
System.SerializableAttribute(),
System.Diagnostics.DebuggerStepThroughAttribute(),
System.ComponentModel.DesignerCategoryAttribute("code"),
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)>
Partial Public Class DefinitionsDefinition
Private idField As DefinitionsDefinitionID
Private displayNameField As String
Private iconField As String
Private cubeSizeField As String
Private componentsField() As DefinitionsDefinitionComponent
Private blockPairNameField As String
Private buildTimeSecondsField As Integer
Public Property Id() As DefinitionsDefinitionID
Get
Return Me.idField
End Get
Set
Me.idField = Value
End Set
End Property
Public Property DisplayName() As String
Get
Return Me.displayNameField
End Get
Set
Me.displayNameField = Value
End Set
End Property
Public Property Icon() As String
Get
Return Me.iconField
End Get
Set
Me.iconField = Value
End Set
End Property
Public Property CubeSize() As String
Get
Return Me.cubeSizeField
End Get
Set
Me.cubeSizeField = Value
End Set
End Property
<System.Xml.Serialization.XmlArrayItemAttribute("Component", IsNullable:=False)>
Public Property Components() As DefinitionsDefinitionComponent()
Get
Return Me.componentsField
End Get
Set
Me.componentsField = Value
End Set
End Property
Public Property BlockPairName() As String
Get
Return Me.blockPairNameField
End Get
Set
Me.blockPairNameField = Value
End Set
End Property
Public Property BuildTimeSeconds() As Integer
Get
Return Me.buildTimeSecondsField
End Get
Set
Me.buildTimeSecondsField = Value
End Set
End Property
End Class
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.7.3081.0"),
System.SerializableAttribute(),
System.Diagnostics.DebuggerStepThroughAttribute(),
System.ComponentModel.DesignerCategoryAttribute("code"),
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)>
Partial Public Class DefinitionsDefinitionID
Private typeIdField As String
Private subtypeIdField As String
Public Property TypeId() As String
Get
Return Me.typeIdField
End Get
Set
Me.typeIdField = Value
End Set
End Property
Public Property SubtypeId() As String
Get
Return Me.subtypeIdField
End Get
Set
Me.subtypeIdField = Value
End Set
End Property
End Class
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.7.3081.0"),
System.SerializableAttribute(),
System.Diagnostics.DebuggerStepThroughAttribute(),
System.ComponentModel.DesignerCategoryAttribute("code"),
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)>
Partial Public Class DefinitionsDefinitionComponent
Private subtypeField As String
Private countField As Integer
Private countFieldSpecified As Boolean
<System.Xml.Serialization.XmlAttributeAttribute()>
Public Property Subtype() As String
Get
Return Me.subtypeField
End Get
Set
Me.subtypeField = Value
End Set
End Property
<System.Xml.Serialization.XmlAttributeAttribute()>
Public Property Count() As Integer
Get
Return Me.countField
End Get
Set
Me.countField = Value
End Set
End Property
<System.Xml.Serialization.XmlIgnoreAttribute()>
Public Property CountSpecified() As Boolean
Get
Return Me.countFieldSpecified
End Get
Set
Me.countFieldSpecified = Value
End Set
End Property
End Class
This class deserializes the cubeblocks file to a dictionary of DefinitionsDefinition class see below.
Main.vb
Public ModBlockDefinitionDictionary As New Dictionary(Of String, DefinitionsDefinition)
Public Sub LoadModDefinitions()
Dim modpath As String = My.Settings.SpaceEngineersWorkingDirectory
Dim id As Integer = 0
Dim Cleaner As New XMLCleaner()
For Each folder In Directory.GetDirectories(modpath)
Dim folder_complete As String = folder.ToString() + "\Data"
For Each file In Directory.GetFiles(folder_complete, "CubeBlocks.sbc") 'For each zipfilename in the given directory extract them to the given folder
Dim moddedxml As String = Cleaner.CleanXML(System.IO.File.ReadAllText(file))
Dim DefinitionData As New Definitions()
Dim xmlSerializer As XmlSerializer = New XmlSerializer(GetType(Definitions))
Try
Dim streamread As New StringReader(moddedxml)
DefinitionData = xmlSerializer.Deserialize(streamread)
Catch ex As Exception
End Try
For Each BlockDefinition In DefinitionData.CubeBlocks()
Try
If Not ModBlockDefinitionDictionary(BlockDefinition.Id.SubtypeId.ToString()) Is Nothing Then
'Block already exists dont add it
Else
ModBlockDefinitionDictionary.Add(BlockDefinition.Id.SubtypeId.ToString(), BlockDefinition)
End If
Catch ex As Exception
End Try
Next
Next
id += 1
Next
End Sub
Then for each mod block you want to check you can fetch that block from the ModBlockDefintionsDictonary using its subtype id as the key.