├── .gitattributes
├── .gitignore
├── Analysis
├── AIAnalyzer.vb
├── AnalyzerManager.vb
├── ArtAnalyzer.vb
├── CrashAnalyzer.vb
├── CrashItem.vb
├── INIAnalyzeInfo.vb
├── INIAnalyzeResult.vb
├── INIAnalyzer.vb
├── Ra2IniAnalyzer.vb
└── RulesAnalyzer.vb
├── Collections
└── IndexedList.vb
├── Colorize
├── CodeColorBase.vb
├── CodeColorBlock.vb
└── CodeColors.vb
├── Document
├── DocumentCategories.vb
├── DocumentLoadOptions.vb
├── IniBlock.vb
├── IniCommentBlock.vb
├── IniCommentSyntax.vb
├── IniCommentSyntaxTrivia.vb
├── IniControlCharacterSyntaxTrivia.vb
├── IniDocument.vb
├── IniKeyValuePairSyntax.vb
├── IniMainKeySyntax.vb
├── IniNewlineSyntaxTrivia.vb
├── IniRecordBlock.vb
├── IniRecordSyntax.vb
├── IniSyntax.vb
├── IniSyntaxTrivia.vb
├── IniWhitespaceSyntaxTrivia.vb
├── IniWordSyntaxTrivia.vb
├── IniWrongSyntax.vb
└── IniWrongSyntaxTrivia.vb
├── Entities
├── EntityInferContext.vb
├── IniFileItem.vb
├── NamedIniAnalyzer.vb
└── VBProjectWriter.vb
├── Help
├── AIHelpProvider.vb
├── ArtHelpProvider.vb
├── EmptyHelpProvider.vb
├── HelpDataProvider.vb
├── HelpProvider.vb
├── HelpProviderManager.vb
├── IHelpProvider.vb
├── IniNamespace.vb
├── IniNamespaceFile.vb
├── IniNamespaceItem.vb
└── RulesHelpProvider.vb
├── Imaging
├── IRegisterable.vb
├── IniImagingAnalizer.vb
├── IniTreeNode.vb
├── KeyTreeNode.vb
├── MainKeyTreeNode.vb
├── MainKeyTreeNodeWriter.vb
├── RegisterTreeNode.vb
├── SubValueTreeNode.vb
├── Synchronization.vb
└── ValueTreeNode.vb
├── Input
├── CodeSnippet.vb
├── ImeBase.vb
├── IniValueMainKeyRenamer.vb
├── QuickFix.vb
├── QuickFixSuggestion.vb
└── RenameOptions.vb
├── Linq
└── StringExtension.vb
├── My Project
└── AssemblyInfo.vb
├── Primitives
└── Percentage.vb
├── Ra2CodeAnalysis.vbproj
├── Tools
└── SymbolFinder.vb
├── Utility
├── DataGridDisplayNameAttribute.vb
├── DocumentExtensions.vb
├── ExpressionCalculator.vb
├── Parallel.vb
├── ParameterizedProperty.vb
├── ResetableDelayTask.vb
├── TextExtensions.vb
├── ValueConverter.vb
└── WritableKeyValuePair.vb
└── ViewModels
├── AnalizeSourceViewModel.vb
├── CodeGenerateLogViewModel.vb
├── CodeSnippetGroup.vb
├── CodeSnippetsViewModel.vb
├── DocumentsViewModel.vb
├── FindSymbolResult.vb
├── IniFilesViewModel.vb
├── ProjectGenerateViewModel.vb
├── ProjectSetupViewModel.vb
├── SingleInstance.vb
└── WidenIniAnalysisInfo.vb
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.vb diff=visualbasic
7 |
8 | # Standard to msysgit
9 | *.doc diff=astextplain
10 | *.DOC diff=astextplain
11 | *.docx diff=astextplain
12 | *.DOCX diff=astextplain
13 | *.dot diff=astextplain
14 | *.DOT diff=astextplain
15 | *.pdf diff=astextplain
16 | *.PDF diff=astextplain
17 | *.rtf diff=astextplain
18 | *.RTF diff=astextplain
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # Build results
11 | [Dd]ebug/
12 | [Dd]ebugPublic/
13 | [Rr]elease/
14 | [Rr]eleases/
15 | x64/
16 | x86/
17 | build/
18 | bld/
19 | [Bb]in/
20 | [Oo]bj/
21 |
22 | # Roslyn cache directories
23 | *.ide/
24 |
25 | # MSTest test Results
26 | [Tt]est[Rr]esult*/
27 | [Bb]uild[Ll]og.*
28 |
29 | #NUNIT
30 | *.VisualState.xml
31 | TestResult.xml
32 |
33 | # Build Results of an ATL Project
34 | [Dd]ebugPS/
35 | [Rr]eleasePS/
36 | dlldata.c
37 |
38 | *_i.c
39 | *_p.c
40 | *_i.h
41 | *.ilk
42 | *.meta
43 | *.obj
44 | *.pch
45 | *.pdb
46 | *.pgc
47 | *.pgd
48 | *.rsp
49 | *.sbr
50 | *.tlb
51 | *.tli
52 | *.tlh
53 | *.tmp
54 | *.tmp_proj
55 | *.log
56 | *.vspscc
57 | *.vssscc
58 | .builds
59 | *.pidb
60 | *.svclog
61 | *.scc
62 |
63 | # Chutzpah Test files
64 | _Chutzpah*
65 |
66 | # Visual C++ cache files
67 | ipch/
68 | *.aps
69 | *.ncb
70 | *.opensdf
71 | *.sdf
72 | *.cachefile
73 |
74 | # Visual Studio profiler
75 | *.psess
76 | *.vsp
77 | *.vspx
78 |
79 | # TFS 2012 Local Workspace
80 | $tf/
81 |
82 | # Guidance Automation Toolkit
83 | *.gpState
84 |
85 | # ReSharper is a .NET coding add-in
86 | _ReSharper*/
87 | *.[Rr]e[Ss]harper
88 | *.DotSettings.user
89 |
90 | # JustCode is a .NET coding addin-in
91 | .JustCode
92 |
93 | # TeamCity is a build add-in
94 | _TeamCity*
95 |
96 | # DotCover is a Code Coverage Tool
97 | *.dotCover
98 |
99 | # NCrunch
100 | _NCrunch_*
101 | .*crunch*.local.xml
102 |
103 | # MightyMoose
104 | *.mm.*
105 | AutoTest.Net/
106 |
107 | # Web workbench (sass)
108 | .sass-cache/
109 |
110 | # Installshield output folder
111 | [Ee]xpress/
112 |
113 | # DocProject is a documentation generator add-in
114 | DocProject/buildhelp/
115 | DocProject/Help/*.HxT
116 | DocProject/Help/*.HxC
117 | DocProject/Help/*.hhc
118 | DocProject/Help/*.hhk
119 | DocProject/Help/*.hhp
120 | DocProject/Help/Html2
121 | DocProject/Help/html
122 |
123 | # Click-Once directory
124 | publish/
125 |
126 | # Publish Web Output
127 | *.[Pp]ublish.xml
128 | *.azurePubxml
129 | # TODO: Comment the next line if you want to checkin your web deploy settings
130 | # but database connection strings (with potential passwords) will be unencrypted
131 | *.pubxml
132 | *.publishproj
133 |
134 | # NuGet Packages
135 | *.nupkg
136 | # The packages folder can be ignored because of Package Restore
137 | **/packages/*
138 | # except build/, which is used as an MSBuild target.
139 | !**/packages/build/
140 | # If using the old MSBuild-Integrated Package Restore, uncomment this:
141 | #!**/packages/repositories.config
142 |
143 | # Windows Azure Build Output
144 | csx/
145 | *.build.csdef
146 |
147 | # Windows Store app package directory
148 | AppPackages/
149 |
150 | # Others
151 | sql/
152 | *.Cache
153 | ClientBin/
154 | [Ss]tyle[Cc]op.*
155 | ~$*
156 | *~
157 | *.dbmdl
158 | *.dbproj.schemaview
159 | *.pfx
160 | *.publishsettings
161 | node_modules/
162 |
163 | # RIA/Silverlight projects
164 | Generated_Code/
165 |
166 | # Backup & report files from converting an old project file
167 | # to a newer Visual Studio version. Backup files are not needed,
168 | # because we have git ;-)
169 | _UpgradeReport_Files/
170 | Backup*/
171 | UpgradeLog*.XML
172 | UpgradeLog*.htm
173 |
174 | # SQL Server files
175 | *.mdf
176 | *.ldf
177 |
178 | # Business Intelligence projects
179 | *.rdl.data
180 | *.bim.layout
181 | *.bim_*.settings
182 |
183 | # Microsoft Fakes
184 | FakesAssemblies/
185 |
186 | # =========================
187 | # Operating System Files
188 | # =========================
189 |
190 | # OSX
191 | # =========================
192 |
193 | .DS_Store
194 | .AppleDouble
195 | .LSOverride
196 |
197 | # Thumbnails
198 | ._*
199 |
200 | # Files that might appear on external disk
201 | .Spotlight-V100
202 | .Trashes
203 |
204 | # Directories potentially created on remote AFP share
205 | .AppleDB
206 | .AppleDesktop
207 | Network Trash Folder
208 | Temporary Items
209 | .apdisk
210 |
211 | # Windows
212 | # =========================
213 |
214 | # Windows image file caches
215 | Thumbs.db
216 | ehthumbs.db
217 |
218 | # Folder config file
219 | Desktop.ini
220 |
221 | # Recycle Bin used on file shares
222 | $RECYCLE.BIN/
223 |
224 | # Windows Installer files
225 | *.cab
226 | *.msi
227 | *.msm
228 | *.msp
229 |
230 | # Windows shortcuts
231 | *.lnk
232 |
--------------------------------------------------------------------------------
/Analysis/AIAnalyzer.vb:
--------------------------------------------------------------------------------
1 | Imports Nukepayload2.Ra2CodeAnalysis.AnalysisHelper
2 | Public Class AIAnalyzer
3 | Inherits Ra2IniAnalyzer
4 | Dim rules As RulesAnalyzer
5 | Sub New(INIText As StreamReader, rules As RulesAnalyzer)
6 | MyBase.New(INIText)
7 | Me.rules = rules
8 | End Sub
9 | Sub New(INIText As String, rules As RulesAnalyzer)
10 | MyBase.New(INIText)
11 | Me.rules = rules
12 | End Sub
13 |
14 | Public Overrides ReadOnly Property Name As String = "AI"
15 |
16 | Public Overrides Function Check() As INIAnalyzeResult
17 | Dim AdvResult As New INIAnalyzeResult
18 | SyncLock Result
19 | AdvResult = AdvResult.Concat(Result)
20 | End SyncLock
21 | Try
22 | Dim RulesUnitsCache As New List(Of String)
23 | RulesUnitsCache.AddRange(From i In rules.Values("InfantryTypes") Select i.Value.Item1)
24 | RulesUnitsCache.AddRange(From v In rules.Values("VehicleTypes") Select v.Value.Item1)
25 | RulesUnitsCache.AddRange(From a In rules.Values("AircraftTypes") Select a.Value.Item1)
26 | For Each Record In Values
27 | If Record.Key = "AITriggerTypes" Then
28 | For Each r In Record.Value
29 | Dim vals = r.Value.Item1.Split(","c)
30 | If vals.Count <> 18 Then
31 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "AI触发参数数量错误,可导致运行时AccessViolation异常", r.Value.Item1, "AITriggerTypes"))
32 | Else
33 | ValueRegistryCheck("TeamTypes", "AI触发使用了未注册的作战小队1,可导致运行时AccessViolation异常", "AITriggerTypes", vals(1), r.Value.Item2, AdvResult.Fault, Me)
34 | If Not vals(2).Trim.StartsWith("<") Then
35 | ValueRegistryCheck("Countries", "AI触发使用了未注册的国家,可导致运行时AccessViolation异常", "AITriggerTypes", vals(2), r.Value.Item2, AdvResult.Fault, rules)
36 | End If
37 | TypeCheck(vals, {3, 4, 10, 11, 12, 13, 15, 16, 17}, Function(s) s.Trim.IsUInteger, "AI触发参数第{0}个的类型错误,应为正整数,可导致AI行为异常", AdvResult.Message, r.Value.Item2, "AITriggerTypes")
38 | If Not vals(5).Trim.StartsWith("<") Then
39 | If Not SpecialBuildings.Contains(vals(5)) AndAlso Not RulesUnitsCache.Contains(vals(5)) Then
40 | ValueRegistryCheck("BuildingTypes", "AI触发使用了未注册的建筑/单位,可导致运行时AccessViolation异常", "AITriggerTypes", vals(5), r.Value.Item2, AdvResult.Fault, rules)
41 | End If
42 | End If
43 | TypeCheck(vals, {6}, Function(s) s.IsUInteger AndAlso s.Length = 64, "AI触发参数第{0}个的类型错误, 应为长度为64的数字, 可导致运行时AccessViolation异常", AdvResult.Fault, r.Value.Item2, "AITriggerTypes")
44 | TypeCheck(vals, {7, 8, 9}, Function(s) s.Trim.IsUFraction, "AI触发参数第{0}个的类型错误, 应为展开写的正小数, 可导致AI行为异常", AdvResult.Message, r.Value.Item2, "AITriggerTypes")
45 | If Not vals(14).Trim.StartsWith("<") Then
46 | ValueRegistryCheck("TeamTypes", "AI触发使用了未注册的作战小队2, 可导致运行时AccessViolation异常", "AITriggerTypes", vals(14), r.Value.Item2, AdvResult.Fault, Me)
47 | End If
48 | End If
49 | Next
50 | ElseIf Record.Key = "TaskForces"
51 | For Each r In Record.Value
52 | If Values.ContainsKey(r.Value.Item1) Then
53 | For Each vs In Values(r.Value.Item1)
54 | If vs.Key.IsUInteger Then
55 | Try
56 | Dim tmp = CUInt(vs.Key)
57 | Catch ex As OverflowException
58 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "特遣小队成员ID严重超出规定范围, 可能导致AI行为混乱或崩溃", r.Value.Item1, Record.Key))
59 | Continue For
60 | End Try
61 | If CUInt(vs.Key) > 6 Then
62 | AdvResult.Warning.Add(New INIAnalyzeInfo(r.Value.Item2, "特遣小队成员ID大于6, 此成员会被忽略", r.Value.Item1, Record.Key))
63 | Else
64 | Dim team = vs.Value.Item1.Split(","c)
65 | If team.Count <> 2 Then
66 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "特遣小队成员格式无效, 应为数量, 单位, 可能导致运行时AccessViolation异常", r.Value.Item1, Record.Key))
67 | ElseIf team(0).IsUInteger Then
68 | If Not RulesUnitsCache.Contains(team(1)) Then
69 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "特遣小队成员单位未注册, 可能导致运行时AccessViolation异常", r.Value.Item1, Record.Key))
70 | End If
71 | Else
72 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "特遣小队成员数量格式无效, 应为正整数, 可能导致运行时AccessViolation异常", r.Value.Item1, Record.Key))
73 | End If
74 | End If
75 | End If
76 | Next
77 | Else
78 | AdvResult.Warning.Add(New INIAnalyzeInfo(r.Value.Item2, "特遣注册了, 但是没有定义, 此注册会被忽略", r.Value.Item1, Record.Key))
79 | End If
80 | Next
81 | ElseIf Record.Key = "ScriptTypes"
82 | For Each r In Record.Value
83 | If Values.ContainsKey(r.Value.Item1) Then
84 | Dim Has490 As Boolean = False
85 | For Each vs In Values(r.Value.Item1)
86 | If vs.Key.IsUInteger Then
87 | Dim s = vs.Value.Item1.Split(","c)
88 | If s.Count = 2 Then
89 | If s(0).Trim = "49" AndAlso s(1).Trim = "0" Then
90 | Has490 = True
91 | ElseIf s(0).Trim = "16"
92 | AdvResult.Warning.Add(New INIAnalyzeInfo(r.Value.Item2, "AI.ini的脚本中使用指令16(巡逻路径点),可能导致AI行为异常", r.Value.Item1, "ScriptTypes"))
93 | End If
94 | Else
95 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "脚本内容的两个值格式错误,可能导致运行时AccessViolation异常", r.Value.Item1, "ScriptTypes"))
96 | End If
97 | End If
98 | Next
99 | If Not Has490 Then
100 | AdvResult.Warning.Add(New INIAnalyzeInfo(r.Value.Item2, "脚本没有49,0,可能导致AI行为异常", r.Value.Item1, "ScriptTypes"))
101 | End If
102 | Else
103 | AdvResult.Warning.Add(New INIAnalyzeInfo(r.Value.Item2, "脚本注册了,但是没有定义,此注册会被忽略", r.Value.Item1, "ScriptTypes"))
104 | End If
105 | Next
106 | Else
107 | For Each r In Record.Value
108 | Select Case r.Key
109 | Case "TaskForce"
110 | ValueRegistryCheck("TaskForces", "特遣小队未注册", Record.Key, r, AdvResult.Fault)
111 | Case "Script"
112 | MainKeyRegistryCheck("TeamTypes", "作战小队未注册", Record.Key, r, AdvResult.Fault)
113 | ValueRegistryCheck("ScriptTypes", "脚本未注册", Record.Key, r, AdvResult.Fault)
114 | End Select
115 | Next
116 | End If
117 | Next
118 | Catch ex As KeyNotFoundException
119 | AdvResult.Fault.Add(New INIAnalyzeInfo(0, "关键的主键或键未找到,可能在运行时发生AccessViolation异常", "(未收集)", "(未收集)"))
120 | End Try
121 |
122 | Return AdvResult
123 | End Function
124 | End Class
125 |
--------------------------------------------------------------------------------
/Analysis/AnalyzerManager.vb:
--------------------------------------------------------------------------------
1 | Imports System.Threading
2 |
3 | Public Class AnalyzerManager
4 | WithEvents DataSource As AnalizeSourceViewModel
5 | Public ReadOnly Property Rules As RulesAnalyzer
6 | Public ReadOnly Property Art As ArtAnalyzer
7 | Public ReadOnly Property AI As AIAnalyzer
8 | Public ReadOnly Property Ra2 As INIAnalyzer
9 | Public ReadOnly Property Updating As Boolean
10 | Dim _UpdateDelay As New TimeSpan(0, 0, 1)
11 | Public Property UpdateDelay As TimeSpan
12 | Get
13 | Return _UpdateDelay
14 | End Get
15 | Set(value As TimeSpan)
16 | _UpdateDelay = value
17 | DelayTimer.Change(1, DelayTime)
18 | DelayTimer.Change(-1, DelayTime)
19 | End Set
20 | End Property
21 | Private ReadOnly Property DelayTime As Integer
22 | Get
23 | Return CInt(_UpdateDelay.TotalMilliseconds)
24 | End Get
25 | End Property
26 | Dim Update As TimerCallback = Async Sub(state) Await UpdateNowAsync()
27 | Dim DelayTimer As New Timer(Update, Nothing, Timeout.Infinite, DelayTime)
28 | Public Sub DelayedUpdateAnalizeDataRequest()
29 | DelayTimer.Change(DelayTime, DelayTime)
30 | End Sub
31 | '''
32 | ''' 强制检查分析结果的更新。如果正在更新则会不进行更新并返回False。
33 | '''
34 | ''' 是否成功更新(没遇到正在更新的情况)
35 | Public Async Function UpdateNowAsync() As Task(Of Boolean)
36 | If _Updating Then
37 | Return False
38 | Else
39 | _Updating = True
40 | Await Task.WhenAll(EnsureRulesUpdatedAsync(), EnsureArtUpdatedAsync(), EnsureAIUpdatedAsync(), EnsureRa2UpdatedAsync())
41 | UpdateDelay = UpdateDelay
42 | _Updating = False
43 | Return True
44 | End If
45 | End Function
46 | Sub New(DataSource As AnalizeSourceViewModel)
47 | With DataSource
48 | Rules = New RulesAnalyzer(.RulesText)
49 | Art = New ArtAnalyzer(.ArtText, Rules)
50 | AI = New AIAnalyzer(.AIText, Rules)
51 | Ra2 = New INIAnalyzer(.Ra2Text)
52 | End With
53 | Me.DataSource = DataSource
54 | End Sub
55 | Public Async Function EnsureRulesUpdatedAsync() As Task
56 | If DataSource.IsRulesInvalid Then
57 | Await Rules.ReloadAsync(DataSource.RulesText)
58 | DataSource.IsRulesInvalid = False
59 | End If
60 | End Function
61 | Public Async Function EnsureArtUpdatedAsync() As Task
62 | If DataSource.IsArtInvalid Then
63 | Await Art.ReloadAsync(DataSource.ArtText)
64 | DataSource.IsArtInvalid = False
65 | End If
66 | End Function
67 | Public Async Function EnsureAIUpdatedAsync() As Task
68 | If DataSource.IsAIInvalid Then
69 | Await AI.ReloadAsync(DataSource.AIText)
70 | DataSource.IsAIInvalid = False
71 | End If
72 | End Function
73 | Public Async Function EnsureRa2UpdatedAsync() As Task
74 | If DataSource.IsRa2Invalid Then
75 | Await Ra2.ReloadAsync(DataSource.Ra2Text)
76 | DataSource.IsRa2Invalid = False
77 | End If
78 | End Function
79 |
80 | Private Sub DataSource_DataChanged() Handles DataSource.DataChanged
81 | DelayedUpdateAnalizeDataRequest()
82 | End Sub
83 | End Class
--------------------------------------------------------------------------------
/Analysis/ArtAnalyzer.vb:
--------------------------------------------------------------------------------
1 | Imports Nukepayload2.Ra2CodeAnalysis.AnalysisHelper
2 |
3 | Public Class ArtAnalyzer
4 | Inherits Ra2IniAnalyzer
5 | Public Overrides ReadOnly Property Name As String = "Art"
6 | Dim rules As RulesAnalyzer
7 | Sub New(INIText As StreamReader, rules As RulesAnalyzer)
8 | MyBase.New(INIText)
9 | Me.rules = rules
10 | End Sub
11 | Sub New(INIText As String, rules As RulesAnalyzer)
12 | MyBase.New(INIText)
13 | Me.rules = rules
14 | End Sub
15 | Public Overrides Function Check() As INIAnalyzeResult
16 | Dim AdvResult As New INIAnalyzeResult
17 | SyncLock Result
18 | AdvResult = AdvResult.Concat(Result)
19 | End SyncLock
20 | Try
21 |
22 | For Each Record In Values
23 | For Each r In Record.Value
24 | Select Case r.Key
25 | Case "Sequence"
26 | If Not Values.ContainsKey(r.Value.Item1) Then
27 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "使用了不存在的动作序列,可导致运行时AccessViolation异常。", r.Value.Item1, Record.Key))
28 | End If
29 | Case "Trailer", "Next"
30 | ValueRegistryCheck("Animations", "使用了未注册的动画,动画不会生效。", Record.Key, r.Value.Item1, r.Value.Item2, AdvResult.Warning, rules, "VoxelAnims")
31 | Case "ExpireAnim", "Spawns"
32 | EachValueRegistryCheck(r, AdvResult.Warning, r.Key, "使用了未注册的动画,动画不会生效。", "Animations", rules, "VoxelAnims")
33 | Case "ToOverlay"
34 | ValueRegistryCheck("OverlayTypes", "使用了未注册的覆盖物,可导致运行时AccessViolation异常。", Record.Key, r.Value.Item1, r.Value.Item2, AdvResult.Fault, rules)
35 | Case "TiberiumSpawnType"
36 | ValueRegistryCheck("OverlayTypes", "使用了未注册的覆盖物,可导致运行时AccessViolation异常。", Record.Key, r.Value.Item1, r.Value.Item2, AdvResult.Fault, rules)
37 | If r.Value.Item1.Length <= 2 OrElse Not r.Value.Item1.Substring(r.Value.Item1.Length - 2).IsUInteger Then
38 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "产生的覆盖物名的结尾不是两位数字,可导致运行时AccessViolation异常。", r.Value.Item1, Record.Key))
39 | End If
40 | Case "Warhead"
41 | If Not rules.Values.Keys.Contains(r.Value.Item1) Then
42 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "使用了不存在的弹头,可导致运行时AccessViolation异常。", r.Value.Item1, Record.Key))
43 | End If
44 | Case "SpawnsParticle"
45 | ValueRegistryCheck("Particles", "使用了未注册的粒子动画,可导致运行时AccessViolation异常。", Record.Key, r.Value.Item1, r.Value.Item2, AdvResult.Fault, rules)
46 | End Select
47 | Next
48 | Next
49 | Catch ex As KeyNotFoundException
50 | AdvResult.Fault.Add(New INIAnalyzeInfo(0, "关键的主键或键未找到,可能在运行时发生AccessViolation异常", "(未收集)", "(未收集)"))
51 | End Try
52 | Return AdvResult
53 | End Function
54 | End Class
55 |
--------------------------------------------------------------------------------
/Analysis/CrashAnalyzer.vb:
--------------------------------------------------------------------------------
1 | Public Class CrashAnalyzer
2 | Enum TSPlatformVersions
3 | TiberianSun203
4 | FireStrom
5 | Ra2Original
6 | Ra21006
7 | YuriOriginal
8 | Yuri1001
9 | End Enum
10 | Sub New(Version As TSPlatformVersions)
11 | If Version < TSPlatformVersions.YuriOriginal Then
12 | Throw New NotSupportedException($"不支持{Version}的游戏平台")
13 | End If
14 | End Sub
15 | Public Function FindEIP(Except As String) As String
16 | Dim reg As New Text.RegularExpressions.Regex("(?<=Eip:)[0-9A-F]{8}")
17 | If reg.IsMatch(Except) Then
18 | Return reg.Match(Except).Value
19 | Else
20 | Return Nothing
21 | End If
22 | End Function
23 | Public Function TryGetDetail(Except As String) As CrashItem
24 | Dim cureip = FindEIP(Except)
25 | If cureip IsNot Nothing Then
26 | Return TryGetHelpText(cureip)
27 | Else
28 | Return Nothing
29 | End If
30 | End Function
31 | Private Function TryGetHelpText(UpperEIPText As String) As CrashItem
32 | If EIPTable.ContainsKey(UpperEIPText) Then
33 | Dim s = EIPTable(UpperEIPText)
34 | Return New CrashItem(UpperEIPText, s(0), s(1))
35 | Else
36 | Return Nothing
37 | End If
38 | End Function
39 |
40 | Dim EIPTable As New Dictionary(Of String, String()) From {
41 | {"004145BD", {"Art", "An AircraftType has a corrupted HVA.
42 | Shows the file type as ""unknown"" in the XCC Mixer. Also an AircraftType has image tag missing or no artmd section.
43 | This could also be caused from an aircraft with no name under AircraftTypes or the name is in the wrong section."}},
44 | {"004157E3", {"Weapon", "An AircraftType used as spy plane has no Primary weapon."}},
45 | {"00417D05", {"Weapon", "An AircraftType has fired a weapon which has Suicide=yes set."}},
46 | {"004242DB", {"Animation", "Using a TrailerAnim on an Animation but not setting a TrailerSeperation (or setting TrailerSeperation=0). This is because the default TrailerSeperation is zero, and that number is used as a divisor."}},
47 | {"00424A14", {"Animation", "An Animation with MakeInfantry=X set was played, where X was greater than the number of list entries in AnimToInfantry or less than 0."}},
48 | {"0042E7AF", {"AI", "A Construction Yard does not have AIBuildThis=yes set and the owning side's AI was present in the game."}},
49 | {"00441C28", {"Misc", "You have set [AudioVisual]→ShakeScreen= to zero."}},
50 | {"004593BB", {"Misc", "See Tank Bunker / Sell Unit IEs"}},
51 | {"0045EC90", {"Misc", "Multiple reasons, depending on the stack dump in the except:
52 | If 00506115 appears near the top of the stack dump - some country (present in the game at the moment, controlled by AI) cannot build anything from [General]→Shipyard=."}},
53 | {"0045ED69", {"Misc", "The [General]→PadAircraft= list is empty."}},
54 | {"0045ED71", {"Misc", "The first AircraftType in the [General]→PadAircraft= list doesn't have at least one BuildingType listed as its Dock."}},
55 | {"0046650D", {"Weapon", "A unit's shrapnel weapon does not exist (see broken-reference causes, below)."}},
56 | {"00471CA4", {"Weapon", "A unit's initial primary (Primary or Weapon1) weapon's Warhead does not have MindControl=yes set, but a weapon in some other weapon slot does. Triggered by one of the following events:
57 | Unit was selected by the user and the user moused-over a potential target.
58 | Unit was considering potential targets on its own (e.g. the unit was about to fire automatically at a nearby enemy unit).
59 | An IFV or urban combat building gains a mind-control weapon via passenger entry or garrison."}},
60 | {"00482096", {"Unit crates", "Your [AI]→BuildRefinery= is either invalid, missing or blank thereby the game can't find the harvesters for deciding the unit."}},
61 | {"004895C7", {"Warhead", "You have a warhead with a CellSpread greater than 11."}},
62 | {"004D5108", {"Weapon", "A unit's secondary weapon does not exist (see broken-reference causes, below), or the weapon's Warhead tag is missing or set to blank. Examples:
63 | The offending weapon is the unit's Secondary weapon, and the unit just finished constructing.
64 | The offending weapon is the unit's EliteSecondary weapon, and the unit just got promoted to Elite status."}},
65 | {"004F8CCD", {"AI", "[AI]→BuildConst= lists less than 3 BuildingTypes and your last [listed] Construction Yard was destroyed or sold while you were on low power, or you went into low power without owning any Construction Yards."}},
66 | {"004F65BF", {"Misc", "Some House cannot build anything from [General]→BaseUnit= ."}},
67 | {"00505E41", {"Misc", "An AI-controlled House which, due to rules(md).ini configuration, is unable to construct a base, received a Construction Yard thus triggering the AI base planning routine. Triggered by the following events:
68 | If a player's MCV was mind-controlled by an enemy, that player is killed, and the MCV is then released from mind-control to the neutral side. The only workaround is to make MCVs immune to mind-control (this is done in the UMP).
69 | A neutral Engineer (there's an official multiplayer map that has neutral Psychic Sensors which, on rare occasions, can leave an Engineer as a survivor) captures a Construction Yard.
70 | More detail: The AI base planning logic kicks in at the moment a player receives a Construction Yard and generates a plan of what buildings to build, in what order. However, the game makes an assumption that any country that can actually start base construction will be able to build at least 3 different BuildingTypes. When that assumption fails (a Construction Yard is received by the civilian house, who cannot build anything), everything goes haywire. For more info on how base planning logic works, refer to the AI Base Planning System article.
71 | Interestingly, the civilian house acquiring a Construction Yard via relinquished mind-control (in the same way as for an MCV) does not cause an IE. Clearly this effect was not taken into consideration when mind-control was added to the engine and the AI base planning routine is only called when a Construction Yard is captured or is first created."}},
72 | {"0050CD20", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - An InfantryType With Engineer=yes exists On the map. AIIonCannonEngineerValue needs restoring."}},
73 | {"0050CD44", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - An InfantryType with VehicleThief=yes exists on the map. AIIonCannonThiefValue needs restoring."}},
74 | {"0050CD79", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - A BuildingType With Factory=BuildingType exists On the map. AIIonCannonConYardValue needs restoring."}},
75 | {"0050CDA2", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - A BuildingType with Factory=UnitType and Naval=no exists on the map. AIIonCannonWarFactoryValue needs restoring."}},
76 | {"0050CDCC", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - A BuildingType With a positive Power value exists On the map. AIIonCannonPowerValue needs restoring."}},
77 | {"0050CDF0", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - A BuildingType with IsBaseDefense=yes exists on the map. AIIonCannonBaseDefenseValue needs restoring."}},
78 | {"0050CE14", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - A BuildingType With IsPlug=yes exists On the map. AIIonCannonPlugValue needs restoring."}},
79 | {"0050CE38", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - A BuildingType with IsTemple=yes exists on the map. AIIonCannonTempleValue needs restoring."}},
80 | {"0050CE5C", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - A BuildingType With HoverPad=yes exists On the map. AIIonCannonHelipadValue needs restoring."}},
81 | {"0050CEA2", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - A BuildingType listed in [AI] → BuildTech exists on the map. AIIonCannonTechCenterValue needs restoring."}},
82 | {"0050CECC", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - A VehicleType With Harvester=yes exists On the map. AIIonCannonHarvesterValue needs restoring."}},
83 | {"0050CF15", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - A VehicleType with a positive Passengers value exists on the map. AIIonCannonAPCValue needs restoring."}},
84 | {"0050CF2A", {"AI", "The AI is trying to pick a target for the Nuclear Missile or Weather Storm superweapon but is lacking target weighting values for a certain object that exists on the map. You need to uncomment/restore one of the [General]→AIIonCannonXValue= lines. - A VehicleType which DeploysInto a BuildingType listed in [AI] → BuildConst exists on the map. AIIonCannonMCVValue needs restoring."}},
85 | {"00518369", {"Warhead", "An InfantryType Is taking damage from a non-existant warhead."}}, '{"0053A15B", {"Unknown", "map error"}},
86 | {"0054AF0E", {"Object", "A unit's Secondary points to a non-existent weapon."}},
87 | {"00567B43", {"Object", "An Object has a negative sight."}},
88 | {"0056D388", {"Object", "An InfantryType or VehicleType does not have a valid movement zone."}},
89 | {"005D7387", {"Misc", "Not having at least one valid InfantryType with AllowedToStartInMultiplayer=yes (default) for each house."}},
90 | {"005DA453", {"Network", "A crash occurred with the network code around an object called FirewallHelper."}},
91 | {"005F4F88", {"Animation", "An Animation has TiberiumSpawnType=SOME_OVERLAY and SOME_OVERLAY is one of the three last entries in [OverlayTypes].Link to original report"}},
92 | {"005F5155", {"Misc", "You tried to construct a BuildingType with HasSpotlight=yes. Yuri's Revenge 1.001 doesn't support this, only patched versions do."}},
93 | {"0062B662", {"Animation", "Having an animation with SpawnsParticle which does not point to a valid ParticleSystem (see broken-reference causes, below)."}},
94 | {"0062DCD2", {"Misc", "An overlay type with Explodes=yes set has been destroyed, random dice roll determined that the particle specified in BarrelParticle should be displayed, but that flag is blank OR you're firing a weapon with UseSparkParticles=yes/UseFireParticles=yes/IsRailgun=yes without a valid AttachedParticleSystem= set."}},
95 | {"0064003C", {"Misc", "If you have a buildable Construction Yard, start its construction, and then cancel it, an IE will occur. Construction Yards should not be buildable - they should only be deployed from vehicles."}},
96 | {"006407A6", {"Misc", "You've made a MapShot ""Not ScreenShot"" that was saved as Map****.yrm and is in your Directory. Game is trying to load map during initial startup. Remove these MapShots from the directory to prevent this from happening."}},
97 | {"0065B73F", {"Weapon", "You have a Weapon whose RadLevel is less than [Radiation]→RadLightDelay=. (Cause: Integer division is performed on those two values, which yields zero in this case, and then another value is divided by the result - division by zero.)"}},
98 | {"0069ACC6", {"Map", "A PKT file's [MultiMaps] section declares a map which doesn't have its own section to define the parameters, or lacks the CD entry in the section."}},
99 | {"00697F29", {"Misc", "The game can't find a valid gamemode. Your mpmodesmd.ini is corrupted."}},
100 | {"006AEBB8", {"Misc", "Your ra2md.ini file lists a combination of game mode/map which the game cannot satisfy. This can happen if the range of valid combinations changes between one game session and the next (i.e. because you changed what maps were valid for which game modes in your mod, or you activated a different mod to the one that was active previously).
101 | LaunchBase works around this by saving and restoring the game's configuration on a per-mod basis."}},
102 | {"006B7D30", {"Object", "An object has a weapon with Spawner=yes, but it doesn't have Spawns=yes. The latter part is what tells the game to initialize the Spawn Manager for this unit when it's instantiated, the former part tells the game to try and access the Spawn Manager (and it doesn't check if it's been initialized properly)."}},
103 | {"006B7718", {"Object", "A Spawned=yes attempted to fly over the map border instead of landing, thus crashing the game. A known reason for this issue is Selectable=no on AircraftTypes that use aircraft Locomotor."}},
104 | {"006EA6AE", {"AI/Map", "You coerced the game into creating an instance of a TeamType that is not defined, either through Map Triggers or through AI Script Actions."}},
105 | {"006F1FC6", {"AI programming", "A TeamType has been defined without assigning it a TaskForce, or a TeamType is being referenced without being defined at all."}},
106 | {"006F352E", {"Weapon", "A unit has an ElitePrimary weapon specified which does not exist (see broken-reference causes, below), or the weapon's Warhead tag is missing or set to blank, and that unit just got promoted to Elite status."}},
107 | {"006F72EF", {"Weapon", "A unit has an ElitePrimary weapon specified which does not exist (see broken-reference causes, below), or the weapon's Warhead tag is missing or set to blank, and that unit just got promoted to Elite status."}},
108 | {"006F40A2", {"Weapon", "Started construction of a unit whose Primary weapon does not exist (see broken-reference causes, below), or the weapon's Warhead tag is missing or set to blank."}},
109 | {"0070031E", {"Weapon", "A unit has a weapon specified which does not exist in the INI (see broken-reference causes, below), or the weapon's Warhead tag is missing or set to blank. (Common reason - that unit just got promoted to Elite status and one of the Elite weapons is misdefined.)"}},
110 | {"00702330", {"Anim", "A building has missing or non-existing DebrisTypes. Like DebrisTypes=CRYSTAL1."}},
111 | {"007120F7", {"Misc", "You have a BuildingType (which is click-repairable) with Strength=0 or Strength below [General]→RepairStep=."}},
112 | {"0071AF4D", {"Warhead", "Detonating a Temporal=yes warhead under one of the following conditions:
113 | Firing weapon was a shrapnel weapon.
114 | Firing weapon was an urban combat weapon (fired from an occupied building).
115 | Warhead has a non-zero CellSpread set."}},
116 | {"0071B173", {"Warhead", "Firing a death weapon using a Temporal=yes warhead."}},
117 | {"00442832", {"Warhead", "Using Sparky=yes warhead without three valid animations defined in [AudioVisual]→OnFire=. Crash happens when damaging a building into yellow or red health."}},
118 | {"0071C661", {"Warhead", "Using Sparky=yes warhead without two valid animations defined in [AudioVisual]→TreeFire=. Crash happens when damaging a wooden terrain object."}},
119 | {"0072652D", {"Map", "There is a trigger in the map that wants to change a house's non-existant object to another house."}},
120 | {"00684E55", {"Map", "There is a trigger which requires a house, either because its events, actions or attached triggers require a house. The house on the trigger is not set."}},
121 | {"007387EB", {"Art", "[AudioVisual]→ShakeScreen= is missing or set to zero."}},
122 | {"0073B0C9", {"Misc", "The concept known as ""Infantry Linking"" can result in an IE, occuring when the linked infantry was modified in a subsequent game mode override file or a map and a human player scrolls their battlefield view to a place on the map where an AI-owned War Factory is located. Don't do Infantry Linking."}},
123 | {"0073C762", {"Art", "The artmd.ini entry specified by a Voxel-using VehicleType's Image tag is missing - the game defaults to Voxel=no in this case and attempts to load and draw a non-existant SHP."}},
124 | {"00756B2D", {"Art", "The specified ShadowIndex on a voxel VehicleType adresses a section that does not exist."}},
125 | {"00772A98", {"Weapon", "A unit has an ElitePrimary weapon specified which does not exist (see broken-reference causes, below), or the weapon's Warhead tag is missing or set to blank, and that unit just got promoted to Elite status.
126 | Also reported to be due to ""firing a weapon that has no projectile"".
127 | This needs testing - missing projectile may be an alternative reason to all 'missing weapon' IEs."}},
128 | {"007C9B92", {"Malformed input", "Multiple reasons, depending on the stack dump in the except:
129 | If 006DD5D2 or 006DD009 appear near the top of the stack dump - Map contains a malformed Map Action, while parsing it, a number was expected, something else or end-of-line was found instead. Map Actions expect well-formed input.
130 | If 00843EEC appears in the stack - RefinerySmokeOffsetThree is not set to a valid value."}},
131 | {"007CAF66", {"Malformed input", "Multiple reasons, depending on the stack dump in the except:
132 | If 0075DE19 appears near the top of the stack dump - A Warhead whose Verses could not be processed. EBP value says how many values remained to be parsed when an error occurred - (11 - EBP) is the 0-based index of the problematic value."}},
133 | {"007CFD30", {"Misc - memory management", "If line 20 of the stack dump includes 61108B, and line 23 includes 610CA0, you are likely trying to use RockPatch's ""Place Urban Areas"" feature without applying the necessary snowmd.ini fix. Please check the RockPatch Help for more info."}},
134 | {"0051BB7D", {"Warhead", "A unit was being erased by a chrono weapon but the object that started the erase process no longer exists. When a unit is being erased, an instance of the TemporalClass is linked to it. This class references the object that is doing the erasing. If the object breaks the link under 'normal' circumstances (e.g. the firer is destroyed or moved) then the attack order is cancelled and the TemporalClass is removed. In some rare cases the link to the firer's TemporalClass is not removed and therefore points to garbage memory.
135 | Examples of how the IE may occur:
136 | Ore harvester with a chrono weapon started an attack but then transformed whilst unloading ore at a refinery before the target was destroyed. Don't give ore harvesters chrono weapons.
137 | A vehicle was being erased but then got picked up by a carryall. This is very difficult to replicate - it has only been reported once.
138 | The IE occurs when the unit would have been erased."}},
139 | {"00520FC8", {"Warhead", "A building was being erased by a chrono weapon after infantry recieved the order to occupy it. When the building is erased before the infantry reaches it, an IE occurs. This is because the TemporalClass removes the building without marking it as dead, thus the occupying infantry is not informed its destination is gone. The IE occurs when the infantry unit updates its position. There is another TemporalClass related bug similar to this one – EIP address 00521BB6, which lies inside the same function, can be seen near the top on a stack of this exception."}},
140 | {"90900004", {"Misc", "Generic exception, for example, raised when you are missing the snowmd.ini median fix."}},
141 | {"FEEEFEEE", {"Misc", "Multiple reasons, depending on the stack dump in the except:
142 | If the stack dump starts with 006B771E then it's a variant of 006B7718."}}}
143 |
144 | End Class
145 |
--------------------------------------------------------------------------------
/Analysis/CrashItem.vb:
--------------------------------------------------------------------------------
1 | Public Class CrashItem
2 | Public EIP, Category, Description As String
3 | Sub New(EIP As String, Category As String, Desc As String)
4 | Me.EIP = EIP
5 | Me.Category = Category
6 | Description = Desc
7 | End Sub
8 | End Class
--------------------------------------------------------------------------------
/Analysis/INIAnalyzeInfo.vb:
--------------------------------------------------------------------------------
1 | Public Class INIAnalyzeInfo
2 |
3 | Public ReadOnly Property LineNumber As Integer
4 |
5 | Public ReadOnly Property Description As String
6 |
7 | Public ReadOnly Property LineText As String
8 |
9 | Public ReadOnly Property MainKey As String
10 | Sub New(Ln As Integer, Desc As String, Text As String, MK As String)
11 | LineNumber = Ln
12 | Description = Desc
13 | LineText = Text
14 | MainKey = MK
15 | End Sub
16 | End Class
--------------------------------------------------------------------------------
/Analysis/INIAnalyzeResult.vb:
--------------------------------------------------------------------------------
1 |
2 | Public Class INIAnalyzeResult
3 | Public ReadOnly Property Message As New List(Of INIAnalyzeInfo)
4 | Public ReadOnly Property Warning As New List(Of INIAnalyzeInfo)
5 | Public ReadOnly Property Fault As New List(Of INIAnalyzeInfo)
6 |
7 | Sub New()
8 |
9 | End Sub
10 | Sub New(Msg As List(Of INIAnalyzeInfo), Warn As List(Of INIAnalyzeInfo), Fau As List(Of INIAnalyzeInfo))
11 | Message = Msg
12 | Warning = Warn
13 | Fault = Fau
14 | End Sub
15 | '''
16 | ''' 返回被合并的两个结果
17 | '''
18 | Public Function Concat(AnotherResult As INIAnalyzeResult) As INIAnalyzeResult
19 | Dim tmp As New INIAnalyzeResult(Message, Warning, Fault)
20 | tmp.Message.AddRange(AnotherResult.Message)
21 | tmp.Warning.AddRange(AnotherResult.Warning)
22 | tmp.Fault.AddRange(AnotherResult.Fault)
23 | Return tmp
24 | End Function
25 | End Class
--------------------------------------------------------------------------------
/Analysis/INIAnalyzer.vb:
--------------------------------------------------------------------------------
1 | '''
2 | ''' 对未拓展的Ini进行分析
3 | '''
4 | Public Class INIAnalyzer
5 | '''
6 | ''' 不加载任何信息。只能在关于类型的情况使用
7 | '''
8 | Sub New()
9 |
10 | End Sub
11 | Public Overridable Function Check() As INIAnalyzeResult
12 | Return Result
13 | End Function
14 | Public Overridable ReadOnly Property Result As New INIAnalyzeResult
15 | '''
16 | ''' 主键,键和值。如果主键重复注册则合并,如果键重复注册则进入ConflictValues。
17 | '''
18 | '''
19 | Public ReadOnly Property Values As New Dictionary(Of String, Dictionary(Of String, Tuple(Of String, Integer)))
20 | '''
21 | ''' 重复注册的值的多余的部分
22 | '''
23 | '''
24 | Public ReadOnly Property ConflictValues As New Dictionary(Of String, List(Of KeyValuePair(Of String, String)))
25 | Protected Sub LineProc(tx As String, ln As Integer, ByRef curMK As String)
26 | If tx.Contains(";") Then
27 | tx = tx.Substring(0, tx.IndexOf(";"c)).Trim
28 | End If
29 | If Not String.IsNullOrEmpty(tx) Then
30 | If tx.StartsWith("[") Then
31 | If tx.Length = 1 Then
32 | Result.Fault.Add(New INIAnalyzeInfo(ln, "语法错误:空的主键", tx, curMK))
33 | Return
34 | End If
35 | curMK = tx.Substring(1, tx.Length - 2).Trim
36 | If String.IsNullOrWhiteSpace(curMK) Then
37 | Result.Fault.Add(New INIAnalyzeInfo(ln, "语法错误:空的主键", tx, curMK))
38 | End If
39 | If Not Values.ContainsKey(curMK) Then
40 | Values.Add(curMK, New Dictionary(Of String, Tuple(Of String, Integer)))
41 | End If
42 | ElseIf tx.Contains("=")
43 | If Values.ContainsKey(curMK) Then
44 | Dim spl As Integer = tx.IndexOf("="c)
45 | Dim left = tx.Substring(0, spl).Trim
46 | Dim rig = tx.Substring(spl + 1, tx.Length - 1 - spl).Trim
47 | If String.IsNullOrEmpty(left) Then
48 | Result.Warning.Add(New INIAnalyzeInfo(ln, "空的左值(键),此记录会被忽略", tx, curMK))
49 | Else
50 | If Values(curMK).ContainsKey(left) Then
51 | Result.Warning.Add(New INIAnalyzeInfo(ln, "重复注册,此记录会被忽略", tx, curMK))
52 | If ConflictValues.ContainsKey(curMK) Then
53 | ConflictValues(curMK).Add(New KeyValuePair(Of String, String)(left, rig))
54 | Else
55 | ConflictValues.Add(curMK, New List(Of KeyValuePair(Of String, String)))
56 | End If
57 | Else
58 | Values(curMK).Add(left, New Tuple(Of String, Integer)(rig, ln))
59 | End If
60 | End If
61 | Else
62 | Result.Warning.Add(New INIAnalyzeInfo(ln, "内容无效:记录应包括在主键内", tx, "(没有主键)"))
63 | End If
64 | Else
65 | Result.Warning.Add(New INIAnalyzeInfo(ln, "内容无效:注释应该以;开头", tx, curMK))
66 | End If
67 | End If
68 | End Sub
69 | Public Async Function ReloadAsync(IniText As String) As Task
70 | Await Task.Run(Sub() Reload(IniText))
71 | End Function
72 | Public Sub Reload(IniText As String)
73 | Values.Clear()
74 | ConflictValues.Clear()
75 | Result.Fault.Clear()
76 | Result.Message.Clear()
77 | Result.Warning.Clear()
78 | Load(IniText)
79 | End Sub
80 | Protected Overridable Sub Load(IniText As String)
81 | Dim curMK As String = String.Empty
82 | Dim txs = IniText.Split(CChar(vbLf))
83 | SyncLock New Object
84 | For ln As Integer = 0 To txs.Length - 1
85 | Dim tx = txs(ln).Trim
86 | LineProc(tx, ln, curMK)
87 | Next
88 | End SyncLock
89 | End Sub
90 | Sub New(INIText As String)
91 | INIText = If(INIText, "")
92 | Load(INIText)
93 | Debug.WriteLine(Me.GetType.Name & " Initialized.")
94 | End Sub
95 | Sub New(INIText As StreamReader)
96 | Dim curMK As String = String.Empty
97 | Dim ln As Integer = 0
98 | SyncLock New Object
99 | Do While Not INIText.EndOfStream
100 | Dim tx = INIText.ReadLine.Trim
101 | LineProc(tx, ln, curMK)
102 | ln += 1
103 | Loop
104 | End SyncLock
105 | End Sub
106 | '''
107 | ''' 把分析的INI重新写出来,这样能去除重复注册,删除所有注释。
108 | '''
109 | '''
110 | Public Overrides Function ToString() As String
111 | Dim sb As New Text.StringBuilder
112 | sb.AppendLine(";由Nukepayload2.Ra2CodeAnalysis生成")
113 | SyncLock Me 'Protect Values
114 | For Each ks In Values.Keys
115 | sb.AppendLine()
116 | sb.AppendLine("[" & ks & "]")
117 | For Each vs In Values(ks)
118 | sb.AppendLine(vs.Key & "=" & vs.Value.Item1)
119 | Next
120 | Next
121 | End SyncLock
122 | Return sb.ToString
123 | End Function
124 | End Class
125 |
--------------------------------------------------------------------------------
/Analysis/Ra2IniAnalyzer.vb:
--------------------------------------------------------------------------------
1 | '''
2 | ''' 包含专门分析Ra2/Ts/Fs/Yr平台的Ini的函数
3 | '''
4 | Public MustInherit Class Ra2IniAnalyzer
5 | Inherits INIAnalyzer
6 | Public MustOverride ReadOnly Property Name As String
7 | Public MustOverride Overrides Function Check() As INIAnalyzeResult
8 | Sub New(INIText As StreamReader)
9 | MyBase.New(INIText)
10 | End Sub
11 | Sub New(INIText As String)
12 | MyBase.New(INIText)
13 | End Sub
14 | Protected Sub TypeCheck(Arr As IEnumerable(Of String), ids As IEnumerable(Of Integer), chk As Func(Of String, Boolean), errtxt As String, lst As IList(Of INIAnalyzeInfo), Linenum As Integer, MKName As String)
15 | For Each n In ids
16 | If Not chk.Invoke(Arr(n)) Then
17 | lst.Add(New INIAnalyzeInfo(Linenum, String.Format(errtxt, n), Arr(n), MKName))
18 | End If
19 | Next
20 | End Sub
21 | Protected Sub ValueRegistryCheck(RegistryMainKeyName As String, FailText As String, MainKeyOfCheck As String, Value As String, LineNumber As Integer, lst As IList(Of INIAnalyzeInfo), ExternalValuesSource As INIAnalyzer, Optional SecondaryMainKey As String = Nothing)
22 | If 0 = Aggregate c In From v In ExternalValuesSource.Values(RegistryMainKeyName) Where v.Value.Item1 = Value Into Count Then
23 | If String.IsNullOrEmpty(SecondaryMainKey) Then
24 | lst.Add(New INIAnalyzeInfo(LineNumber, FailText, Value, MainKeyOfCheck))
25 | Else
26 | ValueRegistryCheck(SecondaryMainKey, FailText, MainKeyOfCheck, Value, LineNumber, lst, ExternalValuesSource)
27 | End If
28 | End If
29 | End Sub
30 | '''
31 | ''' 值不包含在指定的主键的值则添加指定的列表
32 | '''
33 | ''' 主键的名字
34 | ''' 如果要添加错误,指定错误的文本
35 | ''' 正在扫描的记录
36 | ''' 目标列表
37 | Protected Sub ValueRegistryCheck(MainKeyName As String, FailText As String, MainKeyOfCheck As String, Record As KeyValuePair(Of String, Tuple(Of String, Integer)), lst As IList(Of INIAnalyzeInfo), Optional SecondaryMainKey As String = Nothing)
38 | ValueRegistryCheck(MainKeyName, FailText, MainKeyOfCheck, Record.Value.Item1, Record.Value.Item2, lst, Me, SecondaryMainKey)
39 | End Sub
40 | '''
41 | ''' 主键不包含在指定的主键的值则添加指定的列表
42 | '''
43 | ''' 主键的名字
44 | ''' 如果要添加错误,指定错误的文本
45 | ''' 正在扫描的记录
46 | ''' 目标列表
47 | Protected Sub MainKeyRegistryCheck(MainKeyName As String, FailText As String, MainKeyOfCheckingKV As String, Record As KeyValuePair(Of String, Tuple(Of String, Integer)), lst As IList(Of INIAnalyzeInfo), Optional SecodaryMainKeyName As String = Nothing)
48 | Dim Value = Record.Value
49 | If 0 = Aggregate c In From v In Values(MainKeyName) Where v.Value.Item1 = MainKeyOfCheckingKV Into Count Then
50 | If String.IsNullOrEmpty(SecodaryMainKeyName) Then
51 | lst.Add(New INIAnalyzeInfo(Value.Item2, FailText, Value.Item1, MainKeyOfCheckingKV))
52 | Else
53 | MainKeyRegistryCheck(SecodaryMainKeyName, FailText, MainKeyOfCheckingKV, Record, lst)
54 | End If
55 | End If
56 | End Sub
57 | '''
58 | ''' 对用逗号分隔开的所有值进行注册检查
59 | '''
60 | ''' 要检查的键值对
61 | ''' 要写入的记录
62 | ''' 注册用的主键
63 | ''' 失败时的文本
64 | ''' 被检查的键值对的主键
65 | ''' 备用的注册用的主键
66 | Protected Sub EachValueRegistryCheck(r As KeyValuePair(Of String, Tuple(Of String, Integer)), ls As List(Of INIAnalyzeInfo), MK As String, Tx As String, FindMKey As String, Optional SecondaryMainKey As String = Nothing)
67 | For Each val In r.Value.Item1.Split(","c)
68 | If String.IsNullOrEmpty(val) Then
69 | ls.Add(New INIAnalyzeInfo(r.Value.Item2, "语法错误:','前后应为数值", r.Value.Item1, MK))
70 | Else
71 | ValueRegistryCheck(FindMKey, Tx, MK, New KeyValuePair(Of String, Tuple(Of String, Integer))(r.Key, New Tuple(Of String, Integer)(val, r.Value.Item2)), ls, SecondaryMainKey)
72 | End If
73 | Next
74 | End Sub
75 | Protected Sub EachValueRegistryCheck(r As KeyValuePair(Of String, Tuple(Of String, Integer)), ls As List(Of INIAnalyzeInfo), MK As String, Tx As String, FindMKey As String, ExternalValuesSource As INIAnalyzer, Optional SecondaryMainKey As String = Nothing)
76 | For Each val In r.Value.Item1.Split(","c)
77 | If String.IsNullOrEmpty(val) Then
78 | ls.Add(New INIAnalyzeInfo(r.Value.Item2, "语法错误:','前后应为数值", r.Value.Item1, MK))
79 | Else
80 | ValueRegistryCheck(FindMKey, Tx, MK, val, r.Value.Item2, ls, ExternalValuesSource, SecondaryMainKey)
81 | End If
82 | Next
83 | End Sub
84 | Public Shared ReadOnly Property SpecialBuildings As ICollection(Of String)
85 | Get
86 | Return {"BARRACKS", "RADAR", "TECH", "PROC", "POWER", "FACTORY"}
87 | End Get
88 | End Property
89 | Public Shared ReadOnly SpecialTags As ICollection(Of String) = {"", ""}
90 | End Class
91 |
--------------------------------------------------------------------------------
/Analysis/RulesAnalyzer.vb:
--------------------------------------------------------------------------------
1 | Imports Nukepayload2.Ra2CodeAnalysis.AnalysisHelper
2 |
3 | '''
4 | ''' 分析Rules.ini或它的等效ini
5 | '''
6 | Public Class RulesAnalyzer
7 | Inherits Ra2IniAnalyzer
8 |
9 | Public Overrides ReadOnly Property Name As String = "Rules"
10 |
11 | '''
12 | ''' 分析结果,包括基类提供的语法检查
13 | '''
14 | '''
15 | Public Overrides Function Check() As INIAnalyzeResult
16 | Return CheckInternal()
17 | End Function
18 | Sub New(INIText As StreamReader)
19 | MyBase.New(INIText)
20 | End Sub
21 | Sub New(INIText As String)
22 | MyBase.New(INIText)
23 | End Sub
24 | Public Shared Function IsWeaponKey(Key As String) As Boolean
25 | Return {"OccupyWeapon", "EliteOccupyWeapon", "Primary", "Secondary", "ElitePrimary", "EliteSecondary", "DeathWeapon"}.Contains(Key) OrElse Key.StartsWith("Weapon") OrElse Key.StartsWith("EliteWeapon")
26 | End Function
27 | Protected Function CheckInternal() As INIAnalyzeResult
28 | Dim AdvResult As New INIAnalyzeResult
29 | SyncLock Result
30 | AdvResult = AdvResult.Concat(Result)
31 | End SyncLock
32 | Dim UsedWeapons As New List(Of String)
33 | Dim LoadWeapons As New List(Of Tuple(Of String, Tuple(Of String, Integer)))
34 |
35 | Try
36 | Dim DeadBodies, MetallicDebris As IEnumerable(Of String)
37 |
38 | DeadBodies = From d In Values("General")("DeadBodies").Item1.Split(","c) Select d.Trim
39 | MetallicDebris = From d In Values("General")("MetallicDebris").Item1.Split(","c) Select d.Trim
40 | For Each Record In Values
41 | For Each r In Record.Value
42 | Dim wpchk As Action = Sub()
43 | If Values.ContainsKey(r.Value.Item1) Then
44 | UsedWeapons.Add(r.Value.Item1)
45 | ElseIf r.Value.Item1.ToLower <> "none" Then
46 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "武器未定义,可导致单位无法开火或建造时发生AccessViolation", r.Value.Item1, Record.Key))
47 | End If
48 | End Sub
49 | Select Case r.Key
50 | Case "SuperWeapon", "SuperWeapon2" 'SW
51 | ValueRegistryCheck("SuperWeaponTypes", "超级武器未注册或注册失败,可能导致运行时AccessViolation异常", Record.Key, r, AdvResult.Fault)
52 | Case "Warhead" 'WH
53 | ValueRegistryCheck("Warheads", "弹头未注册或注册失败.", Record.Key, r, AdvResult.Message)
54 | Case "DeadBodies"
55 | If DeadBodies.ContainsEachTrim(r.Value.Item1.Split(","c)) Then
56 | Exit Select
57 | End If
58 | EachValueRegistryCheck(r, AdvResult.Warning, Record.Key, "尸体动画未正确注册,可能导致尸体消失", "Animations", "VoxelAnims")
59 | Case "DebrisAnim", "DebrisAnims"
60 | If MetallicDebris.ContainsEachTrim(r.Value.Item1.Split(","c)) Then
61 | Exit Select
62 | End If
63 | EachValueRegistryCheck(r, AdvResult.Message, Record.Key, "碎片动画未正确注册.", "Animations", "VoxelAnims")
64 | Case "AnimList", "Anim", "MetallicDebris", "ExpireAnim", "TrailerAnim", "Explosion"
65 | EachValueRegistryCheck(r, AdvResult.Message, Record.Key, "一般的动画未注册或注册失败.", "Animations", "VoxelAnims")
66 | Case "Next"
67 | ValueRegistryCheck("Animations", "关键动画未注册或注册失败,可导致运行时AccessViolation异常", Record.Key, New KeyValuePair(Of String, Tuple(Of String, Integer))(r.Key, New Tuple(Of String, Integer)(r.Value.Item1, r.Value.Item2)), AdvResult.Fault)
68 | Case "Owner", "RequiredHouses", "FactoryOwners", "ForbiddenHouses"
69 | EachValueRegistryCheck(r, AdvResult.Warning, Record.Key, "国家未正确注册,可能导致建造结果不是预期的", "Countries")
70 | Case "Category" 'Unit
71 | Select Case r.Value.Item1
72 | Case "AirLift", "AirPower", "AirSupport"
73 | MainKeyRegistryCheck("AircraftTypes", "Category错误或战机未正确注册,可能导致无法正常建造或运行时AccessViolation异常", Record.Key, r, AdvResult.Fault, "VehicleTypes")
74 | Case "VIP", "Soldier", "Civilian"
75 | MainKeyRegistryCheck("InfantryTypes", "Category错误或步兵未正确注册,可能导致无法正常建造或运行时AccessViolation异常", Record.Key, r, AdvResult.Fault)
76 | Case Else
77 | MainKeyRegistryCheck("VehicleTypes", "Category错误或战车未正确注册,可能导致无法正常建造或运行时AccessViolation异常", Record.Key, r, AdvResult.Fault)
78 | End Select
79 | Case "Prerequisite", "Prerequisite2"
80 | If SpecialBuildings.ContainsEachTrim(r.Value.Item1.Split(","c)) Then
81 | Exit Select
82 | End If
83 | EachValueRegistryCheck(r, AdvResult.Warning, Record.Key, "建筑未正确注册,可能导致建造结果不是预期的", "BuildingTypes")
84 | Case "BuildCat" 'Building
85 | MainKeyRegistryCheck("BuildingTypes", "建筑或覆盖物建筑未注册或注册失败,可能导致建筑无法建造或运行时AccessViolation异常", Record.Key, r, AdvResult.Fault, "OverlayTypes")
86 | Case "TiberiumSpawnType" 'Overlay
87 | ValueRegistryCheck("OverlayTypes", "覆盖物未注册或注册失败,可能导致覆盖物无法产生或运行时AccessViolation异常", Record.Key, r, AdvResult.Fault)
88 | Case "OccupyWeapon", "EliteOccupyWeapon", "Primary", "Secondary", "ElitePrimary", "EliteSecondary", "DeathWeapon"
89 | wpchk()
90 | Case "Verses"
91 | Dim spl = r.Value.Item1.Split(","c)
92 | If 0 = Aggregate c In From s In spl Where Not s.Contains("%") Into Count Then
93 | If spl.Count <> 11 Then
94 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "弹头百分比数量错误,可能导致运行时AccessViolation异常", r.Value.Item1, Record.Key))
95 | End If
96 | Else
97 | AdvResult.Fault.Add(New INIAnalyzeInfo(r.Value.Item2, "弹头百分比有语法错误,可能导致运行时AccessViolation异常", r.Value.Item1, Record.Key))
98 | End If
99 | Case "ShrapnelWeapon", "AirburstWeapon"
100 | LoadWeapons.Add(New Tuple(Of String, Tuple(Of String, Integer))(Record.Key, r.Value))
101 | Case "HoldsWhat"
102 | MainKeyRegistryCheck("ParticleSystems", "粒子系统未注册或注册失败,可能导致运行时AccessViolation异常", Record.Key, r, AdvResult.Fault)
103 | ValueRegistryCheck("Particles", "粒子未注册或注册失败,可能导致运行时AccessViolation异常", Record.Key, r, AdvResult.Fault)
104 | Case Else
105 | If (r.Key.StartsWith("EliteWeapon") AndAlso r.Key.Length > 11 AndAlso r.Key.Substring(11).IsUInteger) OrElse (r.Key.StartsWith("Weapon") AndAlso r.Key.Length > 6 AndAlso r.Key.Substring(6).IsUInteger) Then
106 | wpchk()
107 | End If
108 | End Select
109 | Next
110 | Next
111 |
112 | Debug.WriteLine("Generic Check complete.Weapon check begins")
113 | Dim wp = From u In UsedWeapons Distinct
114 | Dim lo = From l In LoadWeapons Distinct
115 | For Each wea In lo
116 | If Not wp.Contains(wea.Item2.Item1) Then
117 | AdvResult.Fault.Add(New INIAnalyzeInfo(wea.Item2.Item2, "武器未挂载,可能导致运行时AccessViolation异常", wea.Item2.Item1, wea.Item1))
118 | End If
119 | Next
120 | For Each w In wp
121 | If Values.ContainsKey(w) Then
122 | Dim wpref = Values(w)
123 | If wpref.Count > 0 Then
124 | Dim fir = wpref.First
125 | For Each BasicKey In {"Damage", "Projectile", "Warhead", "Report", "ROF", "Speed", "Range"}
126 | Dim Rec = If({"Projectile", "Warhead"}.Contains(BasicKey), AdvResult.Fault, AdvResult.Warning)
127 | If wpref.ContainsKey(BasicKey) Then
128 | If String.IsNullOrWhiteSpace(wpref(BasicKey).Item1) Then
129 | AdvResult.Fault.Add(New INIAnalyzeInfo(fir.Value.Item2, $"武器的{BasicKey}值为空,可能导致运行时AccessViolation异常", BasicKey, w))
130 | End If
131 | Select Case BasicKey
132 | Case "Warhead", "Projectile"
133 | If Not Values.ContainsKey(w) AndAlso w.ToLower <> "none" Then
134 | AdvResult.Fault.Add(New INIAnalyzeInfo(fir.Value.Item2, $"武器的{BasicKey}值不存在于rules中,可能导致运行时AccessViolation异常", BasicKey, w))
135 | End If
136 | End Select
137 | Else
138 | Rec.Add(New INIAnalyzeInfo(fir.Value.Item2, $"武器没有{BasicKey},可能导致运行时AccessViolation异常", BasicKey, w))
139 | End If
140 | Next
141 | Else
142 | AdvResult.Fault.Add(New INIAnalyzeInfo(0, $"武器{w}为空,可能导致运行时AccessViolation异常", w, w))
143 | End If
144 | Else
145 | AdvResult.Fault.Add(New INIAnalyzeInfo(0, $"Internal Check Error: 没有武器{w},注册信息,但是当作已经注册的武器", w, w))
146 | End If
147 | Next
148 | Catch ex As KeyNotFoundException
149 | AdvResult.Fault.Add(New INIAnalyzeInfo(0, "关键的键或主键没有找到,可导致运行时AccessViolation异常", "(未收集)", "(无)"))
150 | End Try
151 |
152 | Debug.WriteLine("Mission Accomplished")
153 | Return AdvResult
154 | End Function
155 |
156 | End Class
157 |
--------------------------------------------------------------------------------
/Collections/IndexedList.vb:
--------------------------------------------------------------------------------
1 | '''
2 | ''' 对列表某一成员建立唯一索引的列表。它与的区别是:不通过 TKey 查找 TValue。
3 | '''
4 | Public Class IndexedList(Of TIndex, TValue)
5 | '''
6 | ''' 对列表某一成员建立唯一索引的列表
7 | '''
8 | ''' 获取需要索引的成员
9 | ''' 索引是否是聚簇的
10 | Sub New(getIndex As Func(Of TValue, TIndex), clustered As Boolean)
11 | Me.getIndex = getIndex
12 | Index = If(clustered, DirectCast(New SortedSet(Of TIndex), ISet(Of TIndex)), New HashSet(Of TIndex))
13 | End Sub
14 |
15 | Dim getIndex As Func(Of TValue, TIndex)
16 | Public ReadOnly Property Index As ISet(Of TIndex)
17 | Public ReadOnly Property Values As New List(Of TValue)
18 | '''
19 | ''' 添加项目
20 | '''
21 | Public Sub Add(item As TValue)
22 | Values.Add(item)
23 | Index.Add(getIndex(item))
24 | End Sub
25 | '''
26 | ''' 删除项目
27 | '''
28 | Public Sub Remove(item As TValue)
29 | Values.Remove(item)
30 | Index.Remove(getIndex(item))
31 | End Sub
32 | '''
33 | ''' 确定被索引的成员是否包含指定项目。对于聚簇索引,使用折半查找。对于非聚簇索引,使用哈希查找。
34 | '''
35 | Public Function Contains(key As TIndex) As Boolean
36 | Return Index.Contains(key)
37 | End Function
38 | End Class
--------------------------------------------------------------------------------
/Colorize/CodeColorBase.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text.RegularExpressions
2 |
3 | Public MustInherit Class CodeColorBase(Of Brush)
4 | Dim KWLst As IEnumerable(Of String) = {"(?<=\s)As(?=\s)",
5 | "(?<=<)(bool|float|object|int|string)(?=>)",
6 | "(?<=(As|Of)\s+)(Boolean|Integer|Single|String|Object)",
7 | "(bool|float|const|struct|object|int|string|class)(?=\s)",
8 | "(Dim|Const|Structure|Of|Class)(?=\s)",
9 | "(?<==\s*)(Nothing|null|True|true|False|false)"}
10 | Dim SecKWLst As IList(Of String) = {"^\w+(?=\(Of)", 'VB样式的泛型左侧
11 | "\w+(?=<)", 'c#样式的泛型左侧
12 | "(?<=<)\w+(?=>)", 'c#样式的泛型右侧
13 | "(?<=:)\w+(?=\s+[^=]+;)", 'c#样式的单变量声明
14 | "(?<=(As|Of)\s+)\w+", 'VB样式的单变量声明+泛型右
15 | "(?<=\w\.)\w+(?=(\s|;))" '最右侧的成员
16 | }
17 | Dim Comment As New Regex("^[^用].*$", RegexOptions.Multiline)
18 | Protected MustOverride Sub SetColor(Color As Brush, Index As Integer, Length As Integer)
19 | Protected MustOverride Sub ClearEffects()
20 | Protected Overridable Sub EndColorInternal()
21 |
22 | End Sub
23 | Public MustOverride Sub Color()
24 | Protected Sub ColorInternal(Code As String, Instructions As Brush, Types As Brush, Comments As Brush)
25 | ClearEffects()
26 | Dim ProcessedIns As New List(Of Integer)
27 | For Each b In KWLst
28 | Dim reg As New Regex(b)
29 | For Each m As Match In reg.Matches(Code)
30 | ProcessedIns.Add(m.Index)
31 | SetColor(Instructions, m.Index, m.Length)
32 | Next
33 | Next
34 | For Each g In SecKWLst
35 | Dim reg As New Regex(g)
36 | For Each m As Match In reg.Matches(Code)
37 | If Not ProcessedIns.Contains(m.Index) Then
38 | SetColor(Types, m.Index, m.Length)
39 | End If
40 | Next
41 | Next
42 | For Each m As Match In Comment.Matches(Code)
43 | SetColor(Comments, m.Index, m.Length)
44 | Next
45 | EndColorInternal()
46 | End Sub
47 | End Class
48 |
--------------------------------------------------------------------------------
/Colorize/CodeColorBlock.vb:
--------------------------------------------------------------------------------
1 | Public Class CodeColorBlock(Of TColor)
2 | Public StartIndex As Integer
3 | Public Length As Integer
4 | Public Color As TColor
5 | Sub New(Index As Integer, Length As Integer, Color As TColor)
6 | StartIndex = Index
7 | Me.Length = Length
8 | Me.Color = Color
9 | End Sub
10 | End Class
11 |
--------------------------------------------------------------------------------
/Colorize/CodeColors.vb:
--------------------------------------------------------------------------------
1 | Public Class CodeColors
2 |
3 | Public Shared ReadOnly Property AliceBlue As Integer
4 | Get
5 | Return &HFFF0F8FF
6 | End Get
7 | End Property
8 |
9 | Public Shared ReadOnly Property AntiqueWhite As Integer
10 | Get
11 | Return &HFFFAEBD7
12 | End Get
13 | End Property
14 |
15 | Public Shared ReadOnly Property Aqua As Integer
16 | Get
17 | Return &HFF00FFFF
18 | End Get
19 | End Property
20 |
21 | Public Shared ReadOnly Property Aquamarine As Integer
22 | Get
23 | Return &HFF7FFFD4
24 | End Get
25 | End Property
26 |
27 | Public Shared ReadOnly Property Azure As Integer
28 | Get
29 | Return &HFFF0FFFF
30 | End Get
31 | End Property
32 |
33 | Public Shared ReadOnly Property Beige As Integer
34 | Get
35 | Return &HFFF5F5DC
36 | End Get
37 | End Property
38 |
39 | Public Shared ReadOnly Property Bisque As Integer
40 | Get
41 | Return &HFFFFE4C4
42 | End Get
43 | End Property
44 |
45 | Public Shared ReadOnly Property Black As Integer
46 | Get
47 | Return &HFF000000
48 | End Get
49 | End Property
50 |
51 | Public Shared ReadOnly Property BlanchedAlmond As Integer
52 | Get
53 | Return &HFFFFEBCD
54 | End Get
55 | End Property
56 |
57 | Public Shared ReadOnly Property Blue As Integer
58 | Get
59 | Return &HFF0000FF
60 | End Get
61 | End Property
62 |
63 | Public Shared ReadOnly Property BlueViolet As Integer
64 | Get
65 | Return &HFF8A2BE2
66 | End Get
67 | End Property
68 |
69 | Public Shared ReadOnly Property Brown As Integer
70 | Get
71 | Return &HFFA52A2A
72 | End Get
73 | End Property
74 |
75 | Public Shared ReadOnly Property BurlyWood As Integer
76 | Get
77 | Return &HFFDEB887
78 | End Get
79 | End Property
80 |
81 | Public Shared ReadOnly Property CadetBlue As Integer
82 | Get
83 | Return &HFF5F9EA0
84 | End Get
85 | End Property
86 |
87 | Public Shared ReadOnly Property Chartreuse As Integer
88 | Get
89 | Return &HFF7FFF00
90 | End Get
91 | End Property
92 |
93 | Public Shared ReadOnly Property Chocolate As Integer
94 | Get
95 | Return &HFFD2691E
96 | End Get
97 | End Property
98 |
99 | Public Shared ReadOnly Property Coral As Integer
100 | Get
101 | Return &HFFFF7F50
102 | End Get
103 | End Property
104 |
105 | Public Shared ReadOnly Property CornflowerBlue As Integer
106 | Get
107 | Return &HFF6495ED
108 | End Get
109 | End Property
110 |
111 | Public Shared ReadOnly Property Cornsilk As Integer
112 | Get
113 | Return &HFFFFF8DC
114 | End Get
115 | End Property
116 |
117 | Public Shared ReadOnly Property Crimson As Integer
118 | Get
119 | Return &HFFDC143C
120 | End Get
121 | End Property
122 |
123 | Public Shared ReadOnly Property Cyan As Integer
124 | Get
125 | Return &HFF00FFFF
126 | End Get
127 | End Property
128 |
129 | Public Shared ReadOnly Property DarkBlue As Integer
130 | Get
131 | Return &HFF00008B
132 | End Get
133 | End Property
134 |
135 | Public Shared ReadOnly Property DarkCyan As Integer
136 | Get
137 | Return &HFF008B8B
138 | End Get
139 | End Property
140 |
141 | Public Shared ReadOnly Property DarkGoldenrod As Integer
142 | Get
143 | Return &HFFB8860B
144 | End Get
145 | End Property
146 |
147 | Public Shared ReadOnly Property DarkGray As Integer
148 | Get
149 | Return &HFFA9A9A9
150 | End Get
151 | End Property
152 |
153 | Public Shared ReadOnly Property DarkGreen As Integer
154 | Get
155 | Return &HFF006400
156 | End Get
157 | End Property
158 |
159 | Public Shared ReadOnly Property DarkKhaki As Integer
160 | Get
161 | Return &HFFBDB76B
162 | End Get
163 | End Property
164 |
165 | Public Shared ReadOnly Property DarkMagenta As Integer
166 | Get
167 | Return &HFF8B008B
168 | End Get
169 | End Property
170 |
171 | Public Shared ReadOnly Property DarkOliveGreen As Integer
172 | Get
173 | Return &HFF556B2F
174 | End Get
175 | End Property
176 |
177 | Public Shared ReadOnly Property DarkOrange As Integer
178 | Get
179 | Return &HFFFF8C00
180 | End Get
181 | End Property
182 |
183 | Public Shared ReadOnly Property DarkOrchid As Integer
184 | Get
185 | Return &HFF9932CC
186 | End Get
187 | End Property
188 |
189 | Public Shared ReadOnly Property DarkRed As Integer
190 | Get
191 | Return &HFF8B0000
192 | End Get
193 | End Property
194 |
195 | Public Shared ReadOnly Property DarkSalmon As Integer
196 | Get
197 | Return &HFFE9967A
198 | End Get
199 | End Property
200 |
201 | Public Shared ReadOnly Property DarkSeaGreen As Integer
202 | Get
203 | Return &HFF8FBC8F
204 | End Get
205 | End Property
206 |
207 | Public Shared ReadOnly Property DarkSlateBlue As Integer
208 | Get
209 | Return &HFF483D8B
210 | End Get
211 | End Property
212 |
213 | Public Shared ReadOnly Property DarkSlateGray As Integer
214 | Get
215 | Return &HFF2F4F4F
216 | End Get
217 | End Property
218 |
219 | Public Shared ReadOnly Property DarkTurquoise As Integer
220 | Get
221 | Return &HFF00CED1
222 | End Get
223 | End Property
224 |
225 | Public Shared ReadOnly Property DarkViolet As Integer
226 | Get
227 | Return &HFF9400D3
228 | End Get
229 | End Property
230 |
231 | Public Shared ReadOnly Property DeepPink As Integer
232 | Get
233 | Return &HFFFF1493
234 | End Get
235 | End Property
236 |
237 | Public Shared ReadOnly Property DeepSkyBlue As Integer
238 | Get
239 | Return &HFF00BFFF
240 | End Get
241 | End Property
242 |
243 | Public Shared ReadOnly Property DimGray As Integer
244 | Get
245 | Return &HFF696969
246 | End Get
247 | End Property
248 |
249 | Public Shared ReadOnly Property DodgerBlue As Integer
250 | Get
251 | Return &HFF1E90FF
252 | End Get
253 | End Property
254 |
255 | Public Shared ReadOnly Property Firebrick As Integer
256 | Get
257 | Return &HFFB22222
258 | End Get
259 | End Property
260 |
261 | Public Shared ReadOnly Property FloralWhite As Integer
262 | Get
263 | Return &HFFFFFAF0
264 | End Get
265 | End Property
266 |
267 | Public Shared ReadOnly Property ForestGreen As Integer
268 | Get
269 | Return &HFF228B22
270 | End Get
271 | End Property
272 |
273 | Public Shared ReadOnly Property Fuchsia As Integer
274 | Get
275 | Return &HFFFF00FF
276 | End Get
277 | End Property
278 |
279 | Public Shared ReadOnly Property Gainsboro As Integer
280 | Get
281 | Return &HFFDCDCDC
282 | End Get
283 | End Property
284 |
285 | Public Shared ReadOnly Property GhostWhite As Integer
286 | Get
287 | Return &HFFF8F8FF
288 | End Get
289 | End Property
290 |
291 | Public Shared ReadOnly Property Gold As Integer
292 | Get
293 | Return &HFFFFD700
294 | End Get
295 | End Property
296 |
297 | Public Shared ReadOnly Property Goldenrod As Integer
298 | Get
299 | Return &HFFDAA520
300 | End Get
301 | End Property
302 |
303 | Public Shared ReadOnly Property Gray As Integer
304 | Get
305 | Return &HFF808080
306 | End Get
307 | End Property
308 |
309 | Public Shared ReadOnly Property Green As Integer
310 | Get
311 | Return &HFF008000
312 | End Get
313 | End Property
314 |
315 | Public Shared ReadOnly Property GreenYellow As Integer
316 | Get
317 | Return &HFFADFF2F
318 | End Get
319 | End Property
320 |
321 | Public Shared ReadOnly Property Honeydew As Integer
322 | Get
323 | Return &HFFF0FFF0
324 | End Get
325 | End Property
326 |
327 | Public Shared ReadOnly Property HotPink As Integer
328 | Get
329 | Return &HFFFF69B4
330 | End Get
331 | End Property
332 |
333 | Public Shared ReadOnly Property IndianRed As Integer
334 | Get
335 | Return &HFFCD5C5C
336 | End Get
337 | End Property
338 |
339 | Public Shared ReadOnly Property Indigo As Integer
340 | Get
341 | Return &HFF4B0082
342 | End Get
343 | End Property
344 |
345 | Public Shared ReadOnly Property Ivory As Integer
346 | Get
347 | Return &HFFFFFFF0
348 | End Get
349 | End Property
350 |
351 | Public Shared ReadOnly Property Khaki As Integer
352 | Get
353 | Return &HFFF0E68C
354 | End Get
355 | End Property
356 |
357 | Public Shared ReadOnly Property Lavender As Integer
358 | Get
359 | Return &HFFE6E6FA
360 | End Get
361 | End Property
362 |
363 | Public Shared ReadOnly Property LavenderBlush As Integer
364 | Get
365 | Return &HFFFFF0F5
366 | End Get
367 | End Property
368 |
369 | Public Shared ReadOnly Property LawnGreen As Integer
370 | Get
371 | Return &HFF7CFC00
372 | End Get
373 | End Property
374 |
375 | Public Shared ReadOnly Property LemonChiffon As Integer
376 | Get
377 | Return &HFFFFFACD
378 | End Get
379 | End Property
380 |
381 | Public Shared ReadOnly Property LightBlue As Integer
382 | Get
383 | Return &HFFADD8E6
384 | End Get
385 | End Property
386 |
387 | Public Shared ReadOnly Property LightCoral As Integer
388 | Get
389 | Return &HFFF08080
390 | End Get
391 | End Property
392 |
393 | Public Shared ReadOnly Property LightCyan As Integer
394 | Get
395 | Return &HFFE0FFFF
396 | End Get
397 | End Property
398 |
399 | Public Shared ReadOnly Property LightGoldenrodYellow As Integer
400 | Get
401 | Return &HFFFAFAD2
402 | End Get
403 | End Property
404 |
405 | Public Shared ReadOnly Property LightGray As Integer
406 | Get
407 | Return &HFFD3D3D3
408 | End Get
409 | End Property
410 |
411 | Public Shared ReadOnly Property LightGreen As Integer
412 | Get
413 | Return &HFF90EE90
414 | End Get
415 | End Property
416 |
417 | Public Shared ReadOnly Property LightPink As Integer
418 | Get
419 | Return &HFFFFB6C1
420 | End Get
421 | End Property
422 |
423 | Public Shared ReadOnly Property LightSalmon As Integer
424 | Get
425 | Return &HFFFFA07A
426 | End Get
427 | End Property
428 |
429 | Public Shared ReadOnly Property LightSeaGreen As Integer
430 | Get
431 | Return &HFF20B2AA
432 | End Get
433 | End Property
434 |
435 | Public Shared ReadOnly Property LightSkyBlue As Integer
436 | Get
437 | Return &HFF87CEFA
438 | End Get
439 | End Property
440 |
441 | Public Shared ReadOnly Property LightSlateGray As Integer
442 | Get
443 | Return &HFF778899
444 | End Get
445 | End Property
446 |
447 | Public Shared ReadOnly Property LightSteelBlue As Integer
448 | Get
449 | Return &HFFB0C4DE
450 | End Get
451 | End Property
452 |
453 | Public Shared ReadOnly Property LightYellow As Integer
454 | Get
455 | Return &HFFFFFFE0
456 | End Get
457 | End Property
458 |
459 | Public Shared ReadOnly Property Lime As Integer
460 | Get
461 | Return &HFF00FF00
462 | End Get
463 | End Property
464 |
465 | Public Shared ReadOnly Property LimeGreen As Integer
466 | Get
467 | Return &HFF32CD32
468 | End Get
469 | End Property
470 |
471 | Public Shared ReadOnly Property Linen As Integer
472 | Get
473 | Return &HFFFAF0E6
474 | End Get
475 | End Property
476 |
477 | Public Shared ReadOnly Property Magenta As Integer
478 | Get
479 | Return &HFFFF00FF
480 | End Get
481 | End Property
482 |
483 | Public Shared ReadOnly Property Maroon As Integer
484 | Get
485 | Return &HFF800000
486 | End Get
487 | End Property
488 |
489 | Public Shared ReadOnly Property MediumAquamarine As Integer
490 | Get
491 | Return &HFF66CDAA
492 | End Get
493 | End Property
494 |
495 | Public Shared ReadOnly Property MediumBlue As Integer
496 | Get
497 | Return &HFF0000CD
498 | End Get
499 | End Property
500 |
501 | Public Shared ReadOnly Property MediumOrchid As Integer
502 | Get
503 | Return &HFFBA55D3
504 | End Get
505 | End Property
506 |
507 | Public Shared ReadOnly Property MediumPurple As Integer
508 | Get
509 | Return &HFF9370DB
510 | End Get
511 | End Property
512 |
513 | Public Shared ReadOnly Property MediumSeaGreen As Integer
514 | Get
515 | Return &HFF3CB371
516 | End Get
517 | End Property
518 |
519 | Public Shared ReadOnly Property MediumSlateBlue As Integer
520 | Get
521 | Return &HFF7B68EE
522 | End Get
523 | End Property
524 |
525 | Public Shared ReadOnly Property MediumSpringGreen As Integer
526 | Get
527 | Return &HFF00FA9A
528 | End Get
529 | End Property
530 |
531 | Public Shared ReadOnly Property MediumTurquoise As Integer
532 | Get
533 | Return &HFF48D1CC
534 | End Get
535 | End Property
536 |
537 | Public Shared ReadOnly Property MediumVioletRed As Integer
538 | Get
539 | Return &HFFC71585
540 | End Get
541 | End Property
542 |
543 | Public Shared ReadOnly Property MidnightBlue As Integer
544 | Get
545 | Return &HFF191970
546 | End Get
547 | End Property
548 |
549 | Public Shared ReadOnly Property MintCream As Integer
550 | Get
551 | Return &HFFF5FFFA
552 | End Get
553 | End Property
554 |
555 | Public Shared ReadOnly Property MistyRose As Integer
556 | Get
557 | Return &HFFFFE4E1
558 | End Get
559 | End Property
560 |
561 | Public Shared ReadOnly Property Moccasin As Integer
562 | Get
563 | Return &HFFFFE4B5
564 | End Get
565 | End Property
566 |
567 | Public Shared ReadOnly Property NavajoWhite As Integer
568 | Get
569 | Return &HFFFFDEAD
570 | End Get
571 | End Property
572 |
573 | Public Shared ReadOnly Property Navy As Integer
574 | Get
575 | Return &HFF000080
576 | End Get
577 | End Property
578 |
579 | Public Shared ReadOnly Property OldLace As Integer
580 | Get
581 | Return &HFFFDF5E6
582 | End Get
583 | End Property
584 |
585 | Public Shared ReadOnly Property Olive As Integer
586 | Get
587 | Return &HFF808000
588 | End Get
589 | End Property
590 |
591 | Public Shared ReadOnly Property OliveDrab As Integer
592 | Get
593 | Return &HFF6B8E23
594 | End Get
595 | End Property
596 |
597 | Public Shared ReadOnly Property Orange As Integer
598 | Get
599 | Return &HFFFFA500
600 | End Get
601 | End Property
602 |
603 | Public Shared ReadOnly Property OrangeRed As Integer
604 | Get
605 | Return &HFFFF4500
606 | End Get
607 | End Property
608 |
609 | Public Shared ReadOnly Property Orchid As Integer
610 | Get
611 | Return &HFFDA70D6
612 | End Get
613 | End Property
614 |
615 | Public Shared ReadOnly Property PaleGoldenrod As Integer
616 | Get
617 | Return &HFFEEE8AA
618 | End Get
619 | End Property
620 |
621 | Public Shared ReadOnly Property PaleGreen As Integer
622 | Get
623 | Return &HFF98FB98
624 | End Get
625 | End Property
626 |
627 | Public Shared ReadOnly Property PaleTurquoise As Integer
628 | Get
629 | Return &HFFAFEEEE
630 | End Get
631 | End Property
632 |
633 | Public Shared ReadOnly Property PaleVioletRed As Integer
634 | Get
635 | Return &HFFDB7093
636 | End Get
637 | End Property
638 |
639 | Public Shared ReadOnly Property PapayaWhip As Integer
640 | Get
641 | Return &HFFFFEFD5
642 | End Get
643 | End Property
644 |
645 | Public Shared ReadOnly Property PeachPuff As Integer
646 | Get
647 | Return &HFFFFDAB9
648 | End Get
649 | End Property
650 |
651 | Public Shared ReadOnly Property Peru As Integer
652 | Get
653 | Return &HFFCD853F
654 | End Get
655 | End Property
656 |
657 | Public Shared ReadOnly Property Pink As Integer
658 | Get
659 | Return &HFFFFC0CB
660 | End Get
661 | End Property
662 |
663 | Public Shared ReadOnly Property Plum As Integer
664 | Get
665 | Return &HFFDDA0DD
666 | End Get
667 | End Property
668 |
669 | Public Shared ReadOnly Property PowderBlue As Integer
670 | Get
671 | Return &HFFB0E0E6
672 | End Get
673 | End Property
674 |
675 | Public Shared ReadOnly Property Purple As Integer
676 | Get
677 | Return &HFF800080
678 | End Get
679 | End Property
680 |
681 | Public Shared ReadOnly Property Red As Integer
682 | Get
683 | Return &HFFFF0000
684 | End Get
685 | End Property
686 |
687 | Public Shared ReadOnly Property RosyBrown As Integer
688 | Get
689 | Return &HFFBC8F8F
690 | End Get
691 | End Property
692 |
693 | Public Shared ReadOnly Property RoyalBlue As Integer
694 | Get
695 | Return &HFF4169E1
696 | End Get
697 | End Property
698 |
699 | Public Shared ReadOnly Property SaddleBrown As Integer
700 | Get
701 | Return &HFF8B4513
702 | End Get
703 | End Property
704 |
705 | Public Shared ReadOnly Property Salmon As Integer
706 | Get
707 | Return &HFFFA8072
708 | End Get
709 | End Property
710 |
711 | Public Shared ReadOnly Property SandyBrown As Integer
712 | Get
713 | Return &HFFF4A460
714 | End Get
715 | End Property
716 |
717 | Public Shared ReadOnly Property SeaGreen As Integer
718 | Get
719 | Return &HFF2E8B57
720 | End Get
721 | End Property
722 |
723 | Public Shared ReadOnly Property SeaShell As Integer
724 | Get
725 | Return &HFFFFF5EE
726 | End Get
727 | End Property
728 |
729 | Public Shared ReadOnly Property Sienna As Integer
730 | Get
731 | Return &HFFA0522D
732 | End Get
733 | End Property
734 |
735 | Public Shared ReadOnly Property Silver As Integer
736 | Get
737 | Return &HFFC0C0C0
738 | End Get
739 | End Property
740 |
741 | Public Shared ReadOnly Property SkyBlue As Integer
742 | Get
743 | Return &HFF87CEEB
744 | End Get
745 | End Property
746 |
747 | Public Shared ReadOnly Property SlateBlue As Integer
748 | Get
749 | Return &HFF6A5ACD
750 | End Get
751 | End Property
752 |
753 | Public Shared ReadOnly Property SlateGray As Integer
754 | Get
755 | Return &HFF708090
756 | End Get
757 | End Property
758 |
759 | Public Shared ReadOnly Property Snow As Integer
760 | Get
761 | Return &HFFFFFAFA
762 | End Get
763 | End Property
764 |
765 | Public Shared ReadOnly Property SpringGreen As Integer
766 | Get
767 | Return &HFF00FF7F
768 | End Get
769 | End Property
770 |
771 | Public Shared ReadOnly Property SteelBlue As Integer
772 | Get
773 | Return &HFF4682B4
774 | End Get
775 | End Property
776 |
777 | Public Shared ReadOnly Property Tan As Integer
778 | Get
779 | Return &HFFD2B48C
780 | End Get
781 | End Property
782 |
783 | Public Shared ReadOnly Property Teal As Integer
784 | Get
785 | Return &HFF008080
786 | End Get
787 | End Property
788 |
789 | Public Shared ReadOnly Property Thistle As Integer
790 | Get
791 | Return &HFFD8BFD8
792 | End Get
793 | End Property
794 |
795 | Public Shared ReadOnly Property Tomato As Integer
796 | Get
797 | Return &HFFFF6347
798 | End Get
799 | End Property
800 |
801 | Public Shared ReadOnly Property Transparent As Integer
802 | Get
803 | Return &HFFFFFF
804 | End Get
805 | End Property
806 |
807 | Public Shared ReadOnly Property Turquoise As Integer
808 | Get
809 | Return &HFF40E0D0
810 | End Get
811 | End Property
812 |
813 | Public Shared ReadOnly Property Violet As Integer
814 | Get
815 | Return &HFFEE82EE
816 | End Get
817 | End Property
818 |
819 | Public Shared ReadOnly Property Wheat As Integer
820 | Get
821 | Return &HFFF5DEB3
822 | End Get
823 | End Property
824 |
825 | Public Shared ReadOnly Property White As Integer
826 | Get
827 | Return -1
828 | End Get
829 | End Property
830 |
831 | Public Shared ReadOnly Property WhiteSmoke As Integer
832 | Get
833 | Return &HFFF5F5F5
834 | End Get
835 | End Property
836 |
837 | Public Shared ReadOnly Property Yellow As Integer
838 | Get
839 | Return &HFFFFFF00
840 | End Get
841 | End Property
842 |
843 | Public Shared ReadOnly Property YellowGreen As Integer
844 | Get
845 | Return &HFF9ACD32
846 | End Get
847 | End Property
848 |
849 | End Class
850 |
--------------------------------------------------------------------------------
/Document/DocumentCategories.vb:
--------------------------------------------------------------------------------
1 | Public Class DocumentCategories
2 | Public Const Rules = "Rules"
3 | Public Const Art = "Art"
4 | Public Const AI = "AI"
5 | Public Const Ra2 = "Ra2"
6 | End Class
7 |
--------------------------------------------------------------------------------
/Document/DocumentLoadOptions.vb:
--------------------------------------------------------------------------------
1 | Public Enum DocumentLoadOptions
2 | Store
3 | SeparateBlocksOnly
4 | FullAnalysis
5 | End Enum
6 |
--------------------------------------------------------------------------------
/Document/IniBlock.vb:
--------------------------------------------------------------------------------
1 | Namespace Document
2 | Public MustInherit Class IniBlock
3 | Public Property StartIndex As Integer
4 | Protected _Text$ = ""
5 | Public MustOverride Property Text As String
6 | Public ReadOnly Property Children As New List(Of IniSyntax)
7 | Sub New(Text$, StartIndex%)
8 | Me.Text = Text
9 | Me.StartIndex = StartIndex
10 | End Sub
11 | End Class
12 | End Namespace
--------------------------------------------------------------------------------
/Document/IniCommentBlock.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Namespace Document
4 | Public Class IniCommentBlock
5 | Inherits IniBlock
6 | Sub New(Text As String, StartIndex%)
7 | MyBase.New(Text, StartIndex)
8 | End Sub
9 |
10 | Public Overrides Property Text As String
11 | Get
12 | If CurrentLoadOption = DocumentLoadOptions.SeparateBlocksOnly Then
13 | Return _Text
14 | Else
15 | Return Children.JoinText(Function(s) s.Text)
16 | End If
17 | End Get
18 | Set
19 | If CurrentLoadOption = DocumentLoadOptions.SeparateBlocksOnly Then
20 | _Text = Value
21 | Children.Clear()
22 | Else
23 | If Children.Count = 0 Then
24 | Children.Add(New IniCommentSyntax(Value, 0))
25 | Else
26 | Children.Item(0).Text = Value
27 | End If
28 | End If
29 | End Set
30 | End Property
31 | End Class
32 |
33 | End Namespace
34 |
--------------------------------------------------------------------------------
/Document/IniCommentSyntax.vb:
--------------------------------------------------------------------------------
1 | Namespace Document
2 | Public Class IniCommentSyntax
3 | Inherits IniSyntax
4 | Sub New(Text As String, StartIndex%)
5 | MyBase.New(Text, StartIndex)
6 | End Sub
7 |
8 | Public Overrides Property Text As String
9 | Get
10 | Return Children.JoinText(Function(s) s.Text)
11 | End Get
12 | Set
13 | Select Case Children.Count
14 | Case 0
15 | Children.Add(New IniCommentSyntaxTrivia(Value, 0))
16 | Case 1
17 | If Value.EndsWith(vbCrLf) Then
18 | Value = Value.Substring(0, Value.Length - 2)
19 | Children(0).Text = Value
20 | Children.Add(New IniNewlineSyntaxTrivia(Value.Length))
21 | Else
22 | Children(0).Text = Value
23 | End If
24 | Case Else
25 | If Value.EndsWith(vbCrLf) Then
26 | Value = Value.Substring(0, Value.Length - 2)
27 | Children(0).Text = Value
28 | Else
29 | Children.RemoveAt(1)
30 | Children(0).Text = Value
31 | End If
32 | End Select
33 | End Set
34 | End Property
35 | End Class
36 | End Namespace
37 |
--------------------------------------------------------------------------------
/Document/IniCommentSyntaxTrivia.vb:
--------------------------------------------------------------------------------
1 | Namespace Document
2 | Public Class IniCommentSyntaxTrivia
3 | Inherits IniSyntaxTrivia
4 | Public Overrides ReadOnly Property ColorARGB As Integer = CodeColors.ForestGreen
5 | Sub New(Text As String, StartIndex%)
6 | MyBase.New(Text, StartIndex)
7 | End Sub
8 | End Class
9 | End Namespace
10 |
--------------------------------------------------------------------------------
/Document/IniControlCharacterSyntaxTrivia.vb:
--------------------------------------------------------------------------------
1 | Namespace Document
2 | Public Class IniControlCharacterSyntaxTrivia
3 | Inherits IniSyntaxTrivia
4 |
5 | Public Overrides ReadOnly Property ColorARGB As Integer = CodeColors.DarkRed
6 | Sub New(Text As String, StartIndex%)
7 | MyBase.New(Text, StartIndex)
8 | End Sub
9 | End Class
10 | End Namespace
11 |
--------------------------------------------------------------------------------
/Document/IniDocument.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Namespace Document
4 | Friend Module LoadSetting
5 | Public CurrentLoadOption As DocumentLoadOptions
6 | End Module
7 | '''
8 | ''' 表示完整的Ini文档信息, 以便使用 Linq 对它进行分析。
9 | '''
10 | Public Class IniDocument(Of TObservable As {IList(Of IniBlock), New})
11 | Public Property Children As New TObservable
12 | Dim _Text$ = ""
13 | Sub New()
14 | CurrentLoadOption = DocumentLoadOptions.FullAnalysis
15 | End Sub
16 | Sub New(Text$, Optional LoadOption As DocumentLoadOptions = DocumentLoadOptions.FullAnalysis)
17 | Me.Text = Text
18 | CurrentLoadOption = LoadOption
19 | End Sub
20 | Public Overridable Property Text As String
21 | Get
22 | Select Case CurrentLoadOption
23 | Case DocumentLoadOptions.Store
24 | Return _Text
25 | Case Else
26 | Return Children.JoinLine(Function(s) s.Text)
27 | End Select
28 | End Get
29 | Set(value As String)
30 | Select Case CurrentLoadOption
31 | Case DocumentLoadOptions.Store
32 | _Text = value
33 | Children.Clear()
34 | Case Else
35 | ReloadBlocks(value)
36 | End Select
37 | End Set
38 | End Property
39 | Protected Function GetNewBlocks(Value$) As TObservable
40 | Dim NewBlocks As New TObservable
41 | Dim ln = Value.Split({vbCrLf}, StringSplitOptions.None)
42 | Dim StartIndexCounter = 0
43 | If ln.Length >= 1 Then
44 | Dim CurBlk As New StringBuilder
45 | Dim LastComment = Not ln(0).Trim.StartsWith("[")
46 | Dim BlockIsComment = LastComment
47 | CurBlk.AppendLine(ln(0))
48 | For i = 1 To ln.Length - 1
49 | Dim lt = ln(i).Trim
50 | Dim CurIsRecordStart = lt.StartsWith("[")
51 | Dim CurComment = Not (CurIsRecordStart OrElse lt.Split(";"c)(0).Contains("="))
52 | If BlockIsComment Then
53 | If Not CurComment Then
54 | If CurBlk.Length > 0 Then CurBlk.Remove(CurBlk.Length - 2, 2)
55 | NewBlocks.Add(New IniCommentBlock(CurBlk.ToString, StartIndexCounter))
56 | StartIndexCounter += CurBlk.Length
57 | CurBlk.Clear()
58 | BlockIsComment = False
59 | End If
60 | CurBlk.AppendLine(ln(i))
61 | Else
62 | If CurComment Then
63 | Dim j%
64 | For j = i + 1 To ln.Length - 1
65 | Dim ltp = ln(j).TrimStart
66 | Dim PeekIsRecordStart = ltp.StartsWith("[")
67 | Dim PeekIsRecord = ltp.Split(";"c)(0).Contains("=")
68 | If PeekIsRecordStart Then
69 | If CurBlk.Length > 0 Then CurBlk.Remove(CurBlk.Length - 2, 2)
70 | NewBlocks.Add(New IniRecordBlock(CurBlk.ToString, StartIndexCounter))
71 | StartIndexCounter += CurBlk.Length
72 | CurBlk.Clear()
73 | CurBlk.AppendLine(ln(i))
74 | BlockIsComment = True
75 | Exit For
76 | ElseIf PeekIsRecord Then
77 | CurBlk.AppendLine(ln(i))
78 | Exit For
79 | End If
80 | Next
81 | If j = ln.Length Then
82 | CurBlk.AppendLine(ln(i))
83 | End If
84 | Else
85 | CurBlk.AppendLine(ln(i))
86 | End If
87 | End If
88 | Next
89 | If CurBlk.Length > 0 Then
90 | CurBlk.Remove(CurBlk.Length - 2, 2)
91 | StartIndexCounter += CurBlk.Length
92 | NewBlocks.Add(New IniRecordBlock(CurBlk.ToString, StartIndexCounter))
93 | End If
94 | End If
95 | Return NewBlocks
96 | End Function
97 | Public Sub ReloadBlocks(Value$)
98 | Dim Blk = GetNewBlocks(Value)
99 | Children.ReloadContent(Blk, Function(s) s.Text)
100 | End Sub
101 | End Class
102 | End Namespace
103 |
--------------------------------------------------------------------------------
/Document/IniKeyValuePairSyntax.vb:
--------------------------------------------------------------------------------
1 | Namespace Document
2 | Public Class IniKeyValuePairSyntax
3 | Inherits IniRecordSyntax
4 | Sub New(Text As String, StartIndex%)
5 | MyBase.New(Text, StartIndex)
6 | End Sub
7 | End Class
8 | End Namespace
9 |
--------------------------------------------------------------------------------
/Document/IniMainKeySyntax.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Namespace Document
4 | Public Class IniMainKeySyntax
5 | Inherits IniRecordSyntax
6 | Sub New(Text As String, StartIndex%)
7 | MyBase.New(Text, StartIndex)
8 | End Sub
9 | End Class
10 | End Namespace
11 |
--------------------------------------------------------------------------------
/Document/IniNewlineSyntaxTrivia.vb:
--------------------------------------------------------------------------------
1 | Namespace Document
2 | Public Class IniNewlineSyntaxTrivia
3 | Inherits IniSyntaxTrivia
4 |
5 | Public Overrides ReadOnly Property ColorARGB As Integer = CodeColors.Black
6 | Sub New(StartIndex%)
7 | MyBase.New(vbCrLf, StartIndex)
8 | End Sub
9 | End Class
10 | End Namespace
11 |
--------------------------------------------------------------------------------
/Document/IniRecordBlock.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Namespace Document
4 | Public Class IniRecordBlock
5 | Inherits IniBlock
6 |
7 | Sub New(Text As String, StartIndex%)
8 | MyBase.New(Text, StartIndex)
9 | End Sub
10 |
11 | Public Overrides Property Text As String
12 | Get
13 | If CurrentLoadOption = DocumentLoadOptions.SeparateBlocksOnly Then
14 | Return _Text
15 | Else
16 | Return Children.JoinText(Function(s) s.Text)
17 | End If
18 | End Get
19 | Set
20 | If CurrentLoadOption = DocumentLoadOptions.SeparateBlocksOnly Then
21 | _Text = Value
22 | Children.Clear()
23 | Else
24 | Dim Children As New List(Of IniSyntax)
25 | Dim NewBlocks = Value.Split({vbCrLf}, StringSplitOptions.None)
26 | Dim Position% = 0
27 | If NewBlocks.Count > 0 Then
28 | Dim FirstBlk = NewBlocks(0)
29 | Dim MainKeyPart = FirstBlk.ExceptComments
30 | Dim TrimedMKPart = MainKeyPart.Trim
31 | If NewBlocks.Count > 1 Then
32 | FirstBlk &= vbCrLf
33 | End If
34 | If TrimedMKPart.StartsWith("[") AndAlso TrimedMKPart.EndsWith("]") Then
35 | Children.Add(New IniMainKeySyntax(FirstBlk, 0))
36 | Else
37 | Children.Add(New IniWrongSyntax(FirstBlk, 0, "主键没有']'"))
38 | End If
39 | Position += FirstBlk.Length
40 | For i = 1 To NewBlocks.Length - 1
41 | Dim CurBlk = NewBlocks(i)
42 | Dim MainPart = CurBlk.ExceptComments
43 | If i < NewBlocks.Length - 1 Then
44 | CurBlk &= vbCrLf
45 | End If
46 | If MainPart.Contains("=") Then
47 | Children.Add(New IniKeyValuePairSyntax(CurBlk, Position))
48 | ElseIf MainPart.TrimStart.StartsWith(";")
49 | Children.Add(New IniCommentSyntax(CurBlk, Position))
50 | Else
51 | Children.Add(New IniWrongSyntax(CurBlk, Position, "注释没有;"))
52 | End If
53 | Position += CurBlk.Length
54 | Next
55 | End If
56 | Me.Children.ReloadContent(Children, Function(s) s.Text)
57 | End If
58 | End Set
59 | End Property
60 | End Class
61 | End Namespace
62 |
--------------------------------------------------------------------------------
/Document/IniRecordSyntax.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Namespace Document
4 | Public Class IniRecordSyntax
5 | Inherits IniSyntax
6 | Sub New(Text As String, StartIndex%)
7 | MyBase.New(Text, StartIndex)
8 | End Sub
9 |
10 | Public Overrides Property Text As String
11 | Get
12 | Return Children.JoinText(Function(s) s.Text)
13 | End Get
14 | Set
15 | Dim IsWhiteSpace = False
16 | Dim sb As New StringBuilder
17 | Dim i%
18 | Dim NonComment = Value.ExceptComments
19 | Dim Comment = If(NonComment.Length = Value.Length, "", Value.Substring(NonComment.Length))
20 | For i = 0 To NonComment.Length - 2
21 | Dim ch = NonComment(i)
22 | If Char.IsSymbol(ch) OrElse Char.IsPunctuation(ch) Then
23 | If sb.Length > 0 Then
24 | If IsWhiteSpace Then
25 | Children.Add(New IniWhitepaceSyntaxTrivia(sb.ToString, i - sb.Length))
26 | Else
27 | Children.Add(New IniWordSyntaxTrivia(sb.ToString, i - sb.Length))
28 | End If
29 | sb.Clear()
30 | End If
31 | Children.Add(New IniControlCharacterSyntaxTrivia(ch.ToString, i))
32 | ElseIf ch = vbCr
33 | ElseIf ch = vbLf
34 | Children.Add(New IniNewlineSyntaxTrivia(i - 1))
35 | ElseIf Char.IsWhiteSpace(ch)
36 | If sb.Length > 0 AndAlso Not IsWhiteSpace Then
37 | Children.Add(New IniWordSyntaxTrivia(sb.ToString, i - sb.Length))
38 | sb.Clear()
39 | End If
40 | IsWhiteSpace = True
41 | sb.Append(ch)
42 | Else
43 | If sb.Length > 0 AndAlso IsWhiteSpace Then
44 | Children.Add(New IniWhitepaceSyntaxTrivia(sb.ToString, i - sb.Length))
45 | sb.Clear()
46 | End If
47 | sb.Append(ch)
48 | IsWhiteSpace = False
49 | End If
50 | Next
51 | i = NonComment.Length - 1
52 | If Not String.IsNullOrWhiteSpace(NonComment(i)) Then
53 | sb.Append(NonComment(i))
54 | End If
55 | If sb.Length > 0 Then
56 | If IsWhiteSpace Then
57 | Children.Add(New IniWhitepaceSyntaxTrivia(sb.ToString, i - sb.Length))
58 | sb.Clear()
59 | Else
60 | Children.Add(New IniWordSyntaxTrivia(sb.ToString, i - sb.Length))
61 | sb.Clear()
62 | End If
63 | End If
64 | If i > 0 AndAlso Value(i) = vbLf Then
65 | Children.Add(New IniNewlineSyntaxTrivia(i - 1))
66 | End If
67 | If Not String.IsNullOrEmpty(Comment) Then
68 | Children.Add(New IniCommentSyntaxTrivia(Comment, NonComment.Length))
69 | End If
70 | End Set
71 | End Property
72 | End Class
73 | End Namespace
74 |
--------------------------------------------------------------------------------
/Document/IniSyntax.vb:
--------------------------------------------------------------------------------
1 | Namespace Document
2 | Public MustInherit Class IniSyntax
3 | Public Property StartIndex As Integer
4 | Public MustOverride Property Text As String
5 | Public ReadOnly Property Children As New List(Of IniSyntaxTrivia)
6 | Sub New(Text$, StartIndex%)
7 | Me.Text = Text
8 | Me.StartIndex = StartIndex
9 | End Sub
10 | End Class
11 | End Namespace
12 |
--------------------------------------------------------------------------------
/Document/IniSyntaxTrivia.vb:
--------------------------------------------------------------------------------
1 | Namespace Document
2 | Public MustInherit Class IniSyntaxTrivia
3 | Public Property StartIndex As Integer
4 | Public Property Text As String
5 | Public MustOverride ReadOnly Property ColorARGB As Integer
6 | Sub New(Text$, StartIndex%)
7 | Me.Text = Text
8 | Me.StartIndex = StartIndex
9 | End Sub
10 | End Class
11 | End Namespace
12 |
--------------------------------------------------------------------------------
/Document/IniWhitespaceSyntaxTrivia.vb:
--------------------------------------------------------------------------------
1 | Namespace Document
2 | Public Class IniWhitepaceSyntaxTrivia
3 | Inherits IniSyntaxTrivia
4 |
5 | Public Overrides ReadOnly Property ColorARGB As Integer = CodeColors.Black
6 | Sub New(Text As String, StartIndex%)
7 | MyBase.New(Text, StartIndex)
8 | End Sub
9 | End Class
10 | End Namespace
11 |
--------------------------------------------------------------------------------
/Document/IniWordSyntaxTrivia.vb:
--------------------------------------------------------------------------------
1 | Namespace Document
2 | Public Class IniWordSyntaxTrivia
3 | Inherits IniSyntaxTrivia
4 | Public Overrides ReadOnly Property ColorARGB As Integer = CodeColors.Black
5 | Sub New(Text As String, StartIndex%)
6 | MyBase.New(Text, StartIndex)
7 | End Sub
8 | End Class
9 | End Namespace
10 |
--------------------------------------------------------------------------------
/Document/IniWrongSyntax.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Namespace Document
4 | Public Class IniWrongSyntax
5 | Inherits IniSyntax
6 | Public ReadOnly Property Description$
7 |
8 | Public Overrides Property Text As String
9 | Get
10 | Return Children.JoinText(Function(s) s.Text)
11 | End Get
12 | Set
13 | If Children.Count = 0 Then
14 | Children.Add(New IniWrongSyntaxTrivia(Value, 0))
15 | Else
16 | Children(0).Text = Value
17 | End If
18 | End Set
19 | End Property
20 |
21 | Sub New(Text As String, StartIndex%, Description$)
22 | MyBase.New(Text, StartIndex)
23 | Me.Description = Description
24 | End Sub
25 | End Class
26 | End Namespace
27 |
--------------------------------------------------------------------------------
/Document/IniWrongSyntaxTrivia.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Namespace Document
4 | Public Class IniWrongSyntaxTrivia
5 | Inherits IniSyntaxTrivia
6 | Sub New(Text As String, StartIndex%)
7 | MyBase.New(Text, StartIndex)
8 | End Sub
9 | Public Overrides ReadOnly Property ColorARGB As Integer = CodeColors.Red
10 | End Class
11 | End Namespace
12 |
13 |
--------------------------------------------------------------------------------
/Entities/EntityInferContext.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 | Imports Nukepayload2.CodeAnalysis
3 | Imports Nukepayload2.Ra2CodeAnalysis.AnalysisHelper
4 |
5 | Public Class EntityInferContext
6 | Sub New(analyzer As NamedIniAnalyzer, helpProvider As HelpProvider, namespaceBuilder As IndentStringBuilder)
7 | NamedAnalyzer = analyzer
8 | Me.NamespaceBuilder = New VBNamespaceBuilder(namespaceBuilder, analyzer.FileNameWithoutExt)
9 | Me.HelpProvider = helpProvider
10 | ProcessData()
11 | End Sub
12 |
13 | Protected Sub ProcessData()
14 | FillDataHead()
15 | InferNewInterface()
16 | InferPossibleBaseClass()
17 | CleanInterface()
18 | MergePossibleBaseClass()
19 | CleanClass()
20 | CorrectMemberName()
21 | End Sub
22 | '''
23 | ''' 清除与基类重复的声明,同时更新类型推断和数据
24 | '''
25 | Private Sub CleanClass()
26 | For Each cls In ClassIndex.Values
27 | Dim baseClass = cls.InheritsClass
28 | Dim curProperties = cls.Properties
29 | If baseClass IsNot Nothing Then
30 | Dim baseProperties = baseClass.Properties
31 | If cls.ImplementInterfaces.Count > 0 Then
32 | For Each impl In cls.ImplementInterfaces
33 | baseClass.ImplementInterfaces.Add(impl)
34 | For Each prop In impl.Properties
35 | baseClass.Properties(prop.Key).ImplementsInterface.Add(impl)
36 | Next
37 | Next
38 | cls.ImplementInterfaces.Clear()
39 | End If
40 | For Each prop In baseProperties
41 | Dim curKey = prop.Key
42 | If curProperties.ContainsKey(curKey) Then
43 | Dim curProp = curProperties(curKey)
44 | Dim basicInformation = curProp.BasicInformation
45 | Dim typeNameOverride = basicInformation.TypeNameOverride
46 | '纠正类型推断
47 | If typeNameOverride IsNot Nothing Then
48 | baseProperties(curKey).BasicInformation.TypeNameOverride = typeNameOverride
49 | Dim initExpr = Aggregate tp In cls.BasePropertyInitialization
50 | Where tp.PropertyBasicInformation.Name = basicInformation.Name
51 | Into FirstOrDefault
52 | If initExpr IsNot Nothing Then
53 | Dim init = initExpr.InitialValue
54 | If init.StartsWith("""") AndAlso init.EndsWith("""") Then
55 | initExpr.InitialValue = init.Substring(1, init.Length - 2)
56 | If initExpr.InitialValue.Contains(",") Then
57 | initExpr.PropertyBasicInformation.IsQueryable = True
58 | ElseIf ClassIndex.ContainsKey(initExpr.InitialValue) Then
59 | Dim refCls = ClassIndex(initExpr.InitialValue)
60 | If refCls Is cls Then
61 | initExpr.InitialValue = init
62 | initExpr.PropertyBasicInformation.TypeNameOverride = Nothing
63 | Else
64 | initExpr.PropertyBasicInformation.TypeNameOverride = refCls
65 | End If
66 | End If
67 | Else
68 | initExpr.InitialValue = $"{NamespaceBuilder.Name}Context.{initExpr.PropertyBasicInformation.RuntimeTypeName}.Find({init})"
69 | End If
70 | End If
71 | End If
72 | '删除多余的属性定义
73 | curProperties.Remove(curKey)
74 | Else
75 | If prop.Value.IsPrimaryKey Then
76 | Dim baseProp = prop.Value
77 | cls.BasePropertyInitialization.Add(New VBPropertyAssignmentDeclaration(baseProp.BasicInformation, SurroundInitExpr(cls.Name, "String")))
78 | End If
79 | End If
80 | Next
81 | Else
82 | Dim vals = NamedAnalyzer.Analyzer.Values
83 | If vals.ContainsKey(cls.Name) Then
84 | Dim clsData = vals(cls.Name)
85 | For Each curProp In curProperties
86 | Dim data = clsData(curProp.Key)
87 | curProp.Value.InitialValue = SurroundInitExpr(data.Item1, curProp.Value.BasicInformation.RuntimeTypeName)
88 | Next
89 | End If
90 | End If
91 | Next
92 | End Sub
93 |
94 | Private Sub CorrectMemberName()
95 | For Each itf In InterfaceIndex.Values
96 | itf.Name = RenameForVBName(itf.Name)
97 | Dim newProps As New Dictionary(Of String, VBPropertyDeclarationSilm)
98 | For Each prop In itf.Properties.Values
99 | prop.Name = RenameForVBName(prop.Name)
100 | newProps.Add(prop.Name, prop)
101 | Next
102 | itf.Properties = newProps
103 | Next
104 | For Each cls In ClassIndex.Values
105 | cls.Name = RenameForVBName(cls.Name)
106 | Dim newProps As New Dictionary(Of String, VBPropertyDeclaration)
107 | For Each prop In cls.Properties.Values
108 | prop.BasicInformation.Name = RenameForVBName(prop.BasicInformation.Name)
109 | newProps.Add(prop.BasicInformation.Name, prop)
110 | Next
111 | cls.Properties = newProps
112 | Next
113 |
114 | End Sub
115 |
116 | Private Shared Function RenameForVBName(name As String) As String
117 | If Not String.IsNullOrEmpty(name) Then
118 | If Char.IsNumber(name(0)) Then
119 | name = "_" + name
120 | End If
121 | name = name.Replace("-"c, "_"c).Replace(" "c, "_")
122 | End If
123 | If VBKeyWordTranslator.KeywordTable.ContainsKey(name) Then
124 | name = "[" + name + "]"
125 | End If
126 | Return name
127 | End Function
128 |
129 | Private Sub MergePossibleBaseClass()
130 | For Each curCls In ClassIndex.Values
131 | Dim implementInterfaces = curCls.ImplementInterfaces
132 | If implementInterfaces.Count > 0 Then
133 | Dim firstInterface = implementInterfaces.First
134 | Dim firstClass = firstInterface.PossibleBaseClass
135 | If implementInterfaces.Count > 1 Then
136 | For Each impl In implementInterfaces.Skip(1)
137 | Dim mergeClass = impl.PossibleBaseClass
138 | Dim firstProperties = firstClass.Properties
139 | For Each newProp In From p In mergeClass.Properties Where Not firstProperties.ContainsKey(p.Key)
140 | Dim prop = newProp.Value
141 | prop.ImplementsInterface.Add(firstInterface)
142 | firstProperties.Add(newProp.Key, prop)
143 | Next
144 | impl.PossibleBaseClass = firstClass
145 | Next
146 | End If
147 | curCls.InheritsClass = firstClass
148 | End If
149 | Next
150 | End Sub
151 | '''
152 | ''' 通过值提取接口
153 | '''
154 | Private Sub InferNewInterface()
155 | For Each cls In ClassData
156 | Dim cdata = cls.Item2
157 | For Each kv In cdata
158 | Dim key = kv.Key
159 | Dim values = kv.Value.Item1
160 | Dim itf As VBInterfaceBuilder = Nothing
161 | Dim valueArray = values.Split(","c)
162 | For Each value In valueArray
163 | value = value.Trim
164 | If ClassIndex.ContainsKey(value) Then
165 | Dim refCls = ClassIndex(value)
166 | If InterfaceIndex.ContainsKey("I" + key) Then
167 | itf = InterfaceIndex("I" + key)
168 | Else
169 | itf = New VBInterfaceBuilder(NamespaceBuilder, key, Indent)
170 | AddInterface(itf)
171 | If Not refCls.ImplementInterfaces.Contains(itf) Then
172 | ImplementInterface(refCls, itf)
173 | End If
174 | End If
175 | FillInterfaceImplInformation(refCls, itf)
176 | End If
177 | Next
178 | Dim helptext = TrimHelp(HelpProvider.GetHelpText(key))
179 | cls.Item1.Properties.Add(key, New VBPropertyDeclaration(NamespaceBuilder.BaseStringBuilder, helptext, helptext.Contains("<已"), New VBPropertyDeclarationSilm(key, HelpProvider.TempAnalizeUsage(values)) With {.TypeNameOverride = itf, .IsQueryable = valueArray.Length > 1}, Nothing, False))
180 | Next
181 | Next
182 | End Sub
183 |
184 | Private Shared Function TrimHelp(helptext As String) As String
185 | If helptext IsNot Nothing AndAlso helptext.Contains("用法") Then helptext = helptext.Substring(0, helptext.IndexOf("用法"))
186 | Return helptext
187 | End Function
188 |
189 | Private Sub ImplementInterface(curCls As VBClassBuilder, itf As VBInterfaceBuilder)
190 | If Aggregate i In curCls.ImplementInterfaces Select i.Name = itf.Name Into Any Then
191 | Return
192 | End If
193 | curCls.ImplementInterfaces.Add(itf)
194 | InterfaceImplementationIndex(itf).Add(curCls)
195 | End Sub
196 |
197 | '''
198 | ''' 删除接口中冗余的部分
199 | '''
200 | Private Sub CleanInterface()
201 | For Each curItf In InterfaceIndex.Values
202 | For Each curImpl In InterfaceImplementationIndex(curItf)
203 | Dim dels = Aggregate prop In curItf.Properties.Values Where Not curImpl.Properties.ContainsKey(prop.Name) Into ToArray
204 | For i = dels.Count - 1 To 0 Step -1
205 | Dim curDel = dels(i)
206 | If curItf.Properties.ContainsKey(curDel.Name) Then
207 | curItf.Properties.Remove(curDel.Name)
208 | End If
209 | curItf.PossibleBaseClass.Properties(curDel.Name).ImplementsInterface.Clear()
210 | Next
211 | Next
212 | Next
213 | End Sub
214 |
215 | '''
216 | ''' 在类添加实现的接口, 向接口和可能的基类填充初步推断了类型的数据, 向数据类填充数据。
217 | '''
218 | Private Sub InferPossibleBaseClass()
219 | For Each itf In InterfaceData
220 | Dim curItf = itf.Item1
221 | Dim implList = InterfaceImplementationIndex(curItf)
222 | Dim curBase = curItf.PossibleBaseClass
223 | ClassIndex.Add(curBase.Name, curBase)
224 | '可能的基类的主键
225 | Dim itfName = curItf.Name
226 | Dim pkSilm As New VBPropertyDeclarationSilm(itfName + "Id", "String")
227 | Dim pk As New VBPropertyDeclaration(NamespaceBuilder.BaseStringBuilder, $"用于在Ini中索引{itfName}数据", False, pkSilm, Nothing, True)
228 | curBase.Properties.Add(pkSilm.Name, pk)
229 | If itf.Item2 Is Nothing Then Continue For
230 | '查阅接口记录注册了哪些类
231 | For Each clsName In From l In itf.Item2 Select l.Value.Item1
232 | If ClassIndex.ContainsKey(clsName) Then
233 | Dim curCls = ClassIndex(clsName)
234 | If Not Aggregate i In curCls.ImplementInterfaces Where i.Name = curItf.Name Into Any Then
235 | '让数据类实现接口
236 | ImplementInterface(curCls, curItf)
237 | '从数据类提取信息
238 | FillInterfaceImplInformation(curCls, curItf)
239 | End If
240 | End If
241 | Next
242 | Next
243 | End Sub
244 |
245 | Private Sub FillInterfaceImplInformation(registeredClass As VBClassBuilder, curItf As VBInterfaceBuilder)
246 | Dim curBase = curItf.PossibleBaseClass
247 | For Each line In NamedAnalyzer.Analyzer.Values(registeredClass.Name)
248 | Dim key = line.Key
249 | If Not curBase.Properties.ContainsKey(key) Then
250 | Dim declSilm = New VBPropertyDeclarationSilm(key, HelpProvider.TempAnalizeUsage(line.Value.Item1))
251 | Dim helpText = TrimHelp(HelpProvider.GetHelpText(key))
252 | '向数据类增加初始值
253 | Dim initValue = line.Value.Item1
254 | Dim typeName = declSilm.TypeName
255 | initValue = SurroundInitExpr(initValue, typeName)
256 | registeredClass.BasePropertyInitialization.Add(New VBPropertyAssignmentDeclaration(declSilm, initValue))
257 | '向接口添加冗余的临时属性
258 | curItf.Properties.Add(key, declSilm)
259 | '向可能的基类添加属性
260 | Dim decl As New VBPropertyDeclaration(NamespaceBuilder.BaseStringBuilder, helpText, helpText.Contains("<已"), declSilm, Nothing, False)
261 | curBase.Properties.Add(key, decl)
262 | End If
263 | Next
264 | End Sub
265 |
266 | Private Shared Function SurroundInitExpr(initValue As String, typeName As String) As String
267 | Const enumerStr As String = "IEnumerable"
268 | If typeName.StartsWith(enumerStr) Then
269 | Const ofStr As String = "(Of "
270 | Dim ofIdx = typeName.IndexOf(ofStr)
271 | If ofIdx > 0 AndAlso typeName.EndsWith(")") Then
272 | Dim innerTypeName = typeName.Substring(ofIdx + ofStr.Length, typeName.Length - enumerStr.Length - ofStr.Length - 1)
273 | If innerTypeName.Length > 0 Then
274 | Dim sb As New StringBuilder("{")
275 | For Each value In initValue.Split(","c)
276 | sb.Append(SurroundInitExpr(value, innerTypeName)).Append(", ")
277 | Next
278 | sb.Remove(sb.Length - 2, 2).Append("}")
279 | Return sb.ToString
280 | End If
281 | End If
282 | Return $"{{{initValue}}}"
283 | End If
284 | Select Case typeName
285 | Case "String"
286 | Return """" + initValue + """"
287 | Case "Guid"
288 | Return $"New {typeName}(""{initValue}"")"
289 | Case "Percentage", "BigInteger"
290 | Return $"{typeName}.Parse(""{initValue}"")"
291 | Case "Single"
292 | Return initValue & "F"
293 | Case "Long"
294 | Return initValue & "L"
295 | Case "ULong"
296 | Return initValue & "UL"
297 | Case "Decimal"
298 | Return initValue & "D"
299 | Case Else
300 | Return initValue
301 | End Select
302 | End Function
303 |
304 | '''
305 | ''' 将ini数据整理, 仅填充头部数据和索引, 不填充属性
306 | '''
307 | Private Sub FillDataHead()
308 | For Each k In NamedAnalyzer.Analyzer.Values
309 | If k.Value.All(Function(rec) rec.Key.IsInteger) Then
310 | Dim itfb As New VBInterfaceBuilder(NamespaceBuilder, k.Key, Indent)
311 | AddInterface(itfb, k)
312 | Else
313 | Dim clsb = New VBClassBuilder(NamespaceBuilder, k.Key, Indent)
314 | ClassData.Add(New Tuple(Of VBClassBuilder, Dictionary(Of String, Tuple(Of String, Integer)))(clsb, k.Value))
315 | ClassIndex.Add(k.Key, clsb)
316 | End If
317 | Next
318 | End Sub
319 |
320 | Private Sub AddInterface(itfb As VBInterfaceBuilder, Optional data As KeyValuePair(Of String, Dictionary(Of String, Tuple(Of String, Integer))) = Nothing)
321 | InterfaceIndex.Add(itfb.Name, itfb)
322 | InterfaceImplementationIndex.Add(itfb, New List(Of VBClassBuilder))
323 | InterfaceData.Add(New Tuple(Of VBInterfaceBuilder, Dictionary(Of String, Tuple(Of String, Integer)))(itfb, data.Value))
324 | End Sub
325 |
326 | Public ReadOnly Property HelpProvider As HelpProvider
327 | Public ReadOnly Property NamespaceBuilder As VBNamespaceBuilder
328 | Public ReadOnly Property Text As New StringBuilder
329 | Public ReadOnly Property Indent As New StrongBox(Of Integer)(0)
330 | Public ReadOnly Property NamedAnalyzer As NamedIniAnalyzer
331 | Public ReadOnly Property InterfaceData As New List(Of Tuple(Of VBInterfaceBuilder, Dictionary(Of String, Tuple(Of String, Integer))))
332 | Public ReadOnly Property InterfaceIndex As New Dictionary(Of String, VBInterfaceBuilder)
333 | Public ReadOnly Property InterfaceImplementationIndex As New Dictionary(Of VBInterfaceBuilder, List(Of VBClassBuilder))
334 | Public ReadOnly Property ClassData As New List(Of Tuple(Of VBClassBuilder, Dictionary(Of String, Tuple(Of String, Integer))))
335 | Public ReadOnly Property ClassIndex As New Dictionary(Of String, VBClassBuilder)
336 | '''
337 | ''' 从另一个实体信息推断上下文完善推断
338 | '''
339 | Public Sub Infer(another As EntityInferContext)
340 | Throw New NotImplementedException
341 | End Sub
342 | End Class
--------------------------------------------------------------------------------
/Entities/IniFileItem.vb:
--------------------------------------------------------------------------------
1 | Public Class IniFileItem
2 | Sub New(filePath As String)
3 | Me.FilePath = filePath
4 | FileName = Path.GetFileNameWithoutExtension(filePath)
5 | End Sub
6 |
7 | Public Property FilePath As String
8 | Public Property FileName As String
9 | Public Property CachedContent As String
10 | Public Property CachedAnalyzer As NamedIniAnalyzer
11 | End Class
12 |
--------------------------------------------------------------------------------
/Entities/NamedIniAnalyzer.vb:
--------------------------------------------------------------------------------
1 | Public Class NamedIniAnalyzer
2 | Sub New(fileNameWithoutExt As String, analyzer As INIAnalyzer)
3 | Me.FileNameWithoutExt = fileNameWithoutExt
4 | Me.Analyzer = analyzer
5 | End Sub
6 |
7 | Public Property FileNameWithoutExt As String
8 | Public Property Analyzer As INIAnalyzer
9 | End Class
10 |
--------------------------------------------------------------------------------
/Entities/VBProjectWriter.vb:
--------------------------------------------------------------------------------
1 | Imports System.Reflection
2 | Imports System.Text
3 | Imports Nukepayload2.CodeAnalysis
4 | Imports Nukepayload2.CodeAnalysis.Linq
5 |
6 | Public Module VBProjectWriterExtension
7 |
8 |
9 | Public Function GenerateVBFileFromIni(d As NamedIniAnalyzer) As GeneratedCodeFile
10 | Dim hlp As HelpProvider = New EmptyHelpProvider
11 | Select Case d.FileNameWithoutExt.ToLower
12 | Case "rules", "rulesmd"
13 | hlp = New RulesHelpProvider
14 | Case "art", "artmd"
15 | hlp = New ArtHelpProvider
16 | Case "ai", "aimd"
17 | hlp = New AIHelpProvider
18 | End Select
19 | Dim sb As New IndentStringBuilder
20 | Dim entityContext As New EntityInferContext(d, hlp, sb)
21 | Dim ns As New VBNamespaceBuilder(sb, d.FileNameWithoutExt)
22 | ns.BeginBlock()
23 | For Each itf In entityContext.InterfaceIndex.Values
24 | itf.BeginBlock()
25 | itf.EndBlock()
26 | Next
27 | For Each cls In entityContext.ClassIndex.Values
28 | cls.BeginBlock()
29 | cls.EndBlock()
30 | Next
31 | ns.EndBlock()
32 | Return New GeneratedCodeFile(d.FileNameWithoutExt + ".vb", sb.ToString)
33 | End Function
34 | End Module
--------------------------------------------------------------------------------
/Help/AIHelpProvider.vb:
--------------------------------------------------------------------------------
1 |
2 | Public Class AIHelpProvider
3 | Inherits HelpProvider
4 |
5 | Public Overrides Function GetHelpText(code As String) As String
6 | Return GetHelpTextWithUsage(code, AIHelp, AITypes)
7 | End Function
8 |
9 | Public Shared AIHelp As New Dictionary(Of String, String) From {{"VeteranLevel", "<已过时> 地图文件中指定此小队出现在地图时的兵种等级"},
10 | {"MindControlDecision", "<不明确> 遭心灵控制后的动作,0自动,1加入控制者作战小队,2送入部队回收厂,3送入生化反应炉,4搜索敌人,5什么也不做"},
11 | {"Loadable", "<不明确> 可装载"},
12 | {"Full", "<不明确> <已过时> 创建小队成员的时候,如果小队中有运载工具,其他成员是否应该位于运载工具的内部"},
13 | {"Annoyance", "<不明确> 烦恼效果,作用不明"},
14 | {"GuardSlower", "<不明确> 降低反应速度,作用不明"},
15 | {"Recruiter", "强制重组优先级较低的小队的成员,如果它们是可以重组的"},
16 | {"Autocreate", "<不明确> 自动建造"},
17 | {"Prebuild", "<不明确> 预先建造,作用不明"},
18 | {"Reinforce", "<不明确> <已过时> 增援部队"},
19 | {"Droppod", "<已过时> 地图文件中指定使用空降进入战区"},
20 | {"UseTransportOrigin", "<不明确> 使用原始的运载工具"},
21 | {"Whiner", "<不明确> 哀叫效果,作用不明"},
22 | {"LooseRecruit", "<不明确> 解散新兵,作用不明"},
23 | {"Aggressive", "侵略性的,电脑在防御达到一定数量之后再开始建造该小队"},
24 | {"Suicide", "自毁式攻击,受到攻击不允许还击"},
25 | {"Priority", "优先级"},
26 | {"Max", "同一作战方至多允许同时存在的该类型小队个数"},
27 | {"TechLevel", "<不明确> <已过时> 科技等级,疑似无效"},
28 | {"OnTransOnly", "<不明确> 只能运输,作用不明"},
29 | {"AvoidThreats", "规避威胁,小队成员在移动的过程中将会试图规避途中可能遭遇的敌方单位"},
30 | {"IonImmune", "<已过时> 离子风暴发生时仍然建造"},
31 | {"TransportsReturnOnUnload", "运载工具卸载后返回基地"},
32 | {"AreTeamMembersRecruitable", "小队成员是否允许重组"},
33 | {"IsBaseDefense", "基地防御小队"},
34 | {"OnlyTargetHouseEnemy", "<不明确> 只攻击敌方单位,作用不明"},
35 | {"Script", "指定脚本"}, {"House", "指定国家"}, {"TaskForce", "指定特遣小队"},
36 | {"Group", "指定分组,对阵营使用的AI触发一般填-1"}, {"Name", "此主键的注释"}
37 | }
38 |
39 | Private Shared AITypes As New Dictionary(Of String, String) From {{"Name", "String"},
40 | {"Group", "Integer"},
41 | {"VeteranLevel", "Boolean"},
42 | {"MindControlDecision", "Integer"},
43 | {"Loadable", "Boolean"},
44 | {"Full", "Boolean"},
45 | {"Annoyance", "Boolean"},
46 | {"GuardSlower", "Boolean"},
47 | {"House", "String"},
48 | {"Recruiter", "Boolean"},
49 | {"Autocreate", "Boolean"},
50 | {"Prebuild", "Boolean"},
51 | {"Reinforce", "Boolean"},
52 | {"Droppod", "Boolean"},
53 | {"UseTransportOrigin", "Boolean"},
54 | {"Whiner", "Boolean"},
55 | {"LooseRecruit", "Boolean"},
56 | {"Aggressive", "Boolean"},
57 | {"Suicide", "Boolean"},
58 | {"Priority", "Integer"},
59 | {"Max", "Integer"},
60 | {"TechLevel", "Integer"},
61 | {"OnTransOnly", "Boolean"},
62 | {"AvoidThreats", "Boolean"},
63 | {"IonImmune", "Boolean"},
64 | {"TransportsReturnOnUnload", "Boolean"},
65 | {"AreTeamMembersRecruitable", "Boolean"},
66 | {"IsBaseDefense", "Boolean"},
67 | {"OnlyTargetHouseEnemy", "Boolean"},
68 | {"Script", "String"},
69 | {"TaskForce", "String"}
70 | }
71 | End Class
--------------------------------------------------------------------------------
/Help/EmptyHelpProvider.vb:
--------------------------------------------------------------------------------
1 | Public Class EmptyHelpProvider
2 | Inherits HelpProvider
3 |
4 | Public Overrides Function GetHelpText(code As String) As String
5 | Return String.Empty
6 | End Function
7 | End Class
8 |
--------------------------------------------------------------------------------
/Help/HelpDataProvider.vb:
--------------------------------------------------------------------------------
1 | Imports Nukepayload2.Ra2CodeAnalysis.AnalysisHelper
2 |
3 | Public Class HelpDataProvider
4 |
5 | Protected Function GetHelpTextFromDic(code As String, dic As Dictionary(Of String, String)) As String
6 | If String.IsNullOrEmpty(code) Then Return "(空)"
7 | If dic.ContainsKey(code) Then
8 | Return dic(code)
9 | Else
10 | Return ""
11 | End If
12 | End Function
13 |
14 | Dim vbcs As New Dictionary(Of String, String) From {{"String", "string"}, {"Integer", "int"},
15 | {"Single", "float"}, {"Boolean", "bool"}, {"Structure", "struct"}, {"Object", "object"}}
16 | '''
17 | ''' 格式化用法为vb代码和c#代码
18 | '''
19 | ''' 用于推断基本类型的代码
20 | ''' 推断出的类型
21 | '''
22 | Public Function FormatUsage(Code As String, tp As String, Optional DisableTypeJudgeFormat As Boolean = True) As String
23 | Dim cs As String
24 | If vbcs.ContainsKey(tp) Then
25 | cs = vbcs(tp)
26 | Else
27 | cs = tp.Replace("(Of ", "<").Replace(")", ">")
28 | For Each k In vbcs.Keys
29 | cs = cs.Replace(k, vbcs(k))
30 | Next
31 | End If
32 | If String.IsNullOrEmpty(Code) Then
33 | Return String.Empty
34 | End If
35 | If Not DisableTypeJudgeFormat Then
36 | If tp.Contains("IEnumerable(Of") Then
37 | Return "表示多个可枚举的" & tp.Substring(15, tp.Length - 16) & vbCrLf & "用法1:Dim As " & tp & vbCrLf & "用法2:" & cs & " ;"
38 | End If
39 | End If
40 | If Code.IsInteger Then
41 | Return "整数常量" & vbCrLf & "用法1:Structure System.Int32" & vbCrLf & "用法2:struct System.Int32;"
42 | ElseIf Code.IsNumeric Then
43 | Return "小数常量" & vbCrLf & "用法1:Structure System.Single" & vbCrLf & "用法2:struct System.Single;"
44 | ElseIf Code.Replace("%", "").IsNumeric Then
45 | Return "百分数常量" & vbCrLf & "用法1:Structure Nukepayload2.CodeAnalysis.Percentage" & vbCrLf & "用法2:struct Nukepayload2.CodeAnalysis.Percentage;"
46 | ElseIf Code.Chars(0).IsNumeric Then
47 | Code = "_" & Code
48 | ElseIf Code.Contains(".") Then
49 | Code = Code.Replace("."c, "_"c)
50 | ElseIf {"yes", "no"}.Contains(Code.ToLowerInvariant) Then
51 | Return "布尔值常量" & vbCrLf & "用法1:Const " & Code & " As " & tp & " = " & If(Code.ToLowerInvariant = "yes", "True", "False") & vbCrLf & "用法2:const " & cs & " " & Code & " = " & If(Code.ToLowerInvariant = "yes", "true", "false") & ";"
52 | ElseIf {"true", "false"}.Contains(Code.ToLowerInvariant) Then
53 | Return "表示布尔值" & vbCrLf & "用法1:Structure System.Boolean" & vbCrLf & "用法2:struct System.Boolean;"
54 | ElseIf Code.ToLowerInvariant = "none" Then
55 | Return "表示空值或空引用" & vbCrLf & "用法1:Const " & Code & " As Object = Nothing" & vbCrLf & "用法2:const object " & Code & " = null;"
56 | End If
57 | Return vbCrLf & "用法1:Dim " & Code & " As " & tp & vbCrLf & "用法2:" & cs & " " & Code & ";"
58 | End Function
59 |
60 | Protected Function GetHelpTextWithUsage(code As String, text As Dictionary(Of String, String), usage As Dictionary(Of String, String)) As String
61 | If String.IsNullOrEmpty(code) Then Return "(空)"
62 | Dim tx = GetHelpTextFromDic(code, text)
63 | If usage.ContainsKey(code) Then
64 | If String.IsNullOrEmpty(tx) Then
65 | tx = "确定的用法:"
66 | End If
67 | tx &= FormatUsage(code, usage(code))
68 | End If
69 | Return tx
70 | End Function
71 |
72 | Public Function TempAnalizeFormatUsage(Key As String, Value As String) As String
73 | Return FormatUsage(Key, TempAnalizeUsage(Value))
74 | End Function
75 | Public Function GetRulesUsageForIme(Word As String, Helper As RulesHelpProvider, ini As RulesAnalyzer) As String
76 | Dim hlp = Helper.GetHelpText(Word)
77 | If String.IsNullOrEmpty(hlp) Then
78 | hlp = DeepAnalizeFormatUsage(Word, Word, ini)
79 | End If
80 | Return hlp
81 | End Function
82 | Public Function GetUsageForIme(Word As String, Helper As IHelpProvider, ini As INIAnalyzer) As String
83 | Dim hlp = Helper.GetHelpText(Word)
84 | If String.IsNullOrEmpty(hlp) Then
85 | hlp = DeepAnalizeFormatUsage(Word, Word, ini)
86 | End If
87 | Return hlp
88 | End Function
89 | Public Function DeepAnalizeType(Value As String, ini As INIAnalyzer) As String
90 | Dim tp = TempAnalizeUsage(Value)
91 | If tp = "String" Then
92 | For Each mkv In ini.Values
93 | If mkv.Key = "AITriggerTypes" Then
94 | If ini.Values(mkv.Key).ContainsKey(Value) Then
95 | Return mkv.Key
96 | End If
97 | Else
98 | For Each kv In mkv.Value
99 | For Each Name In {"Warhead", "Sequence"}
100 | If kv.Key = Name AndAlso Value = kv.Value.Item1 Then
101 | Return Name
102 | End If
103 | Next
104 | Next
105 | For Each kv In mkv.Value
106 | If Not kv.Key.IsNumeric Then
107 | Exit For
108 | End If
109 | If kv.Value.Item1 = Value Then
110 | Return mkv.Key
111 | End If
112 | Next
113 | End If
114 | Next
115 | End If
116 | Return tp
117 | End Function
118 | Public Function DeepAnalizeFormatUsage(Key As String, Value As String, ini As INIAnalyzer) As String
119 | Return FormatUsage(Value, DeepAnalizeType(Value, ini))
120 | End Function
121 |
122 | Public Function DeepAnalizeType(Value As String, ini As INIAnalyzer, textcomp As Boolean, Optional CsOverloadTemp As Object = Nothing) As String
123 | Return String.Empty
124 | End Function
125 | Public Function DeepAnalizeType(Value As String, ini As RulesAnalyzer, Optional CsOverloadTemp As Object = Nothing) As String
126 | Dim tp = TempAnalizeUsage(Value)
127 | If tp = "String" Then
128 | For Each mkv In ini.Values
129 | For Each kv In mkv.Value
130 | For Each v In kv.Value.Item1.Split(","c)
131 | If v.Trim = Value Then
132 | If kv.Key.IsNumeric Then
133 | Return mkv.Key
134 | ElseIf RulesAnalyzer.IsWeaponKey(kv.Key) Then
135 | Return "Weapon"
136 | Else
137 | For Each Name In {"Warhead", "Projectile", "MetallicDebris", "DeadBodies"}
138 | If kv.Key = Name AndAlso Value = kv.Value.Item1 Then
139 | Return Name
140 | End If
141 | Next
142 | End If
143 | End If
144 | Next
145 | Next
146 | Next
147 | End If
148 | Return tp
149 | End Function
150 |
151 | Public Function DeepAnalizeFormatUsage(Key As String, Value As String, ini As RulesAnalyzer, textcomp As Boolean, Optional CsOverloadTemp As Object = Nothing) As String
152 | Return String.Empty
153 | End Function
154 | Public Function DeepAnalizeFormatUsage(Key As String, Value As String, ini As RulesAnalyzer, Optional CsOverloadTemp As Object = Nothing) As String
155 | Return FormatUsage(Value, DeepAnalizeType(Value, ini))
156 | End Function
157 | Public Function TempAnalizeUsage(Value As String) As String
158 | Dim rig = Value
159 | If String.IsNullOrEmpty(rig) OrElse rig.ToLower = "none" Then
160 | Return "Object"
161 | End If
162 | If rig.Contains(",") Then
163 | Dim spa = rig.Split(","c)
164 | Dim sp = spa.First.Trim
165 | If sp.IsInteger Then
166 | For Each tp In spa.Skip(1)
167 | If Not tp.Trim.IsInteger Then Return "IEnumerable(Of String)"
168 | Next
169 | Return $"IEnumerable(Of {FilterIntegerTypes(sp)})"
170 | ElseIf sp.IsFraction Then
171 | For Each tp In spa.Skip(1)
172 | If Not tp.Trim.IsFraction Then Return "IEnumerable(Of String)"
173 | Next
174 | Return $"IEnumerable(Of {FilterFractionTypes(sp)})"
175 | ElseIf sp.Replace("%", "").IsInteger Then
176 | Return "IEnumerable(Of Percentage)"
177 | Else
178 | Return "IEnumerable(Of String)"
179 | End If
180 | Else
181 | If rig.IsInteger Then
182 | Return FilterIntegerTypes(rig)
183 | ElseIf rig.IsFraction Then
184 | Return FilterFractionTypes(rig)
185 | ElseIf {"true", "false", "yes", "no"}.Contains(rig.ToLowerInvariant) Then
186 | Return "Boolean"
187 | ElseIf rig.Replace("%", "").IsInteger Then
188 | Return "Percentage"
189 | ElseIf rig.StartsWith("{") AndAlso rig.EndsWith("}") AndAlso rig.Contains("-") Then
190 | Return "Guid"
191 | Else
192 | Return "String"
193 | End If
194 | End If
195 | End Function
196 |
197 | Private Shared Function FilterFractionTypes(rig As String) As String
198 | Dim sng = 0F, dbl = 0#, dec = 0D
199 | If Single.TryParse(rig, sng) AndAlso Double.TryParse(rig, dbl) AndAlso Decimal.TryParse(rig, dec) Then
200 | Dim sdbl = dbl.ToString
201 | If sdbl = sng.ToString Then
202 | Return "Single"
203 | ElseIf dec.ToString = sdbl Then
204 | Return "Double"
205 | Else
206 | Return "Decimal"
207 | End If
208 | Else
209 | Return "String"
210 | End If
211 | End Function
212 |
213 | Private Shared Function FilterIntegerTypes(rig As String) As String
214 | If Integer.TryParse(rig, 0) Then
215 | Return "Integer"
216 | ElseIf Long.TryParse(rig, 0) Then
217 | Return "Long"
218 | ElseIf ULong.TryParse(rig, 0) Then
219 | Return "ULong"
220 | Else
221 | Return "String"
222 | End If
223 | End Function
224 | End Class
225 |
--------------------------------------------------------------------------------
/Help/HelpProvider.vb:
--------------------------------------------------------------------------------
1 | Public MustInherit Class HelpProvider
2 | Inherits HelpDataProvider
3 | Implements IHelpProvider
4 |
5 | Public MustOverride Function GetHelpText(code As String) As String Implements IHelpProvider.GetHelpText
6 | End Class
7 |
--------------------------------------------------------------------------------
/Help/HelpProviderManager.vb:
--------------------------------------------------------------------------------
1 | Public Class HelpProviderManager
2 | Public ReadOnly Property Rules As New RulesHelpProvider()
3 | Public ReadOnly Property Art As New ArtHelpProvider()
4 | Public ReadOnly Property AI As New AIHelpProvider()
5 | End Class
6 |
--------------------------------------------------------------------------------
/Help/IHelpProvider.vb:
--------------------------------------------------------------------------------
1 |
2 | Public Interface IHelpProvider
3 | Function GetHelpText(code As String) As String
4 | End Interface
--------------------------------------------------------------------------------
/Help/IniNamespace.vb:
--------------------------------------------------------------------------------
1 | Imports Nukepayload2.Ra2CodeAnalysis.Imaging
2 | '''
3 | ''' inins功能支持。像xmlns那样。这样可以提供类型检查和IME支持。
4 | '''
5 | Public Class IniNamespace
6 | Public Items As New List(Of IniNamespaceItem)
7 | Public Const Rules = "http://schemas.nukepayload2.com/ra2codeanalysis/rules"
8 | Public Const AI = "http://schemas.nukepayload2.com/ra2codeanalysis/ai"
9 | Public Const Art = "http://schemas.nukepayload2.com/ra2codeanalysis/art"
10 |
11 | Sub New(INITree As IEnumerable(Of MainKeyTreeNode), ini As INIAnalyzer, HelpProvider As IHelpProvider)
12 | Dim hd As New HelpDataProvider
13 | Dim KeyNames As New List(Of String)
14 | For Each mk In INITree
15 | For Each kv In mk.KeyValues
16 | Dim tp = hd.DeepAnalizeType(kv.Value.Text, ini)
17 | Items.Add(New IniNamespaceItem(kv.Key.Text, HelpProvider.GetHelpText(kv.Key.Text), tp))
18 | KeyNames.Add(kv.Key.Text)
19 | Next
20 | Next
21 | End Sub
22 | End Class
23 |
--------------------------------------------------------------------------------
/Help/IniNamespaceFile.vb:
--------------------------------------------------------------------------------
1 | Public Structure IniNamespaceFile
2 | Dim TypeID As String
3 | Dim Version As Integer
4 | Dim Author As String
5 | Dim SubIniNsCount As Integer
6 | Dim SubIniNsDatas As IniNamespace()
7 |
8 | End Structure
--------------------------------------------------------------------------------
/Help/IniNamespaceItem.vb:
--------------------------------------------------------------------------------
1 | Public Class IniNamespaceItem
2 | Public KeyName As String
3 | Public Usage As List(Of DescTypePair)
4 | Sub New(Key As String, Desc As String, TpName As String)
5 | KeyName = Key
6 | Usage = New List(Of DescTypePair) From {New DescTypePair(Desc, TpName)}
7 | End Sub
8 | End Class
9 | Public Class DescTypePair
10 | Public Description As String
11 | Public TypeName As String
12 | Sub New(Desc As String, TpName As String)
13 | Description = Desc
14 | TypeName = TpName
15 | End Sub
16 | End Class
--------------------------------------------------------------------------------
/Imaging/IRegisterable.vb:
--------------------------------------------------------------------------------
1 |
2 | Namespace Imaging
3 | '''
4 | ''' 能被注册到主键或键
5 | '''
6 | Public Interface IRegisterable
7 | ReadOnly Property Text As String
8 | ReadOnly Property RegisteredIn As IEnumerable(Of RegisterTreeNode)
9 | Sub RegisterToInternal(Node As RegisterTreeNode)
10 | Sub UnRegisterFromInternal(Node As RegisterTreeNode)
11 | End Interface
12 |
13 | End Namespace
--------------------------------------------------------------------------------
/Imaging/IniImagingAnalizer.vb:
--------------------------------------------------------------------------------
1 | Imports System.Reflection
2 | Imports System.Text
3 | Imports Nukepayload2.Ra2CodeAnalysis.AnalysisHelper
4 |
5 | Namespace Imaging
6 | '''
7 | ''' 用于产生分析图的ini分析器。Values保存着撤销全部更改的结果。
8 | '''
9 | Public Class IniImagingAnalizer
10 | Inherits INIAnalyzer
11 | Sub New(IniText As String)
12 | MyBase.New(IniText)
13 | End Sub
14 | Protected TreeRoot As List(Of MainKeyTreeNode)
15 | '''
16 | ''' 注意:修改Root会导致分析结果无效
17 | '''
18 | '''
19 | Public ReadOnly Property Root As List(Of MainKeyTreeNode) = TreeRoot
20 |
21 | '''
22 | ''' 将ini分析结果保存为String
23 | '''
24 | '''
25 | Public Overrides Function ToString() As String
26 | Return Root.GetText(Me.GetType)
27 | End Function
28 |
29 | Protected Overrides Sub Load(IniText As String)
30 | MyBase.Load(IniText)
31 | TreeRoot = New List(Of MainKeyTreeNode)
32 | For Each mk In Values.Keys
33 | Dim CurBranch As New MainKeyTreeNode(mk)
34 | TreeRoot.Add(CurBranch)
35 | For Each kv In Values(mk)
36 | Dim va = New ValueTreeNode(kv.Value.Item1)
37 | Dim Rec As New KeyValuePair(Of KeyTreeNode, ValueTreeNode)(New KeyTreeNode(kv.Key, va), va)
38 | CurBranch.KeyValues.Add(Rec)
39 | If Rec.Key.IsRegisterKey Then
40 | For Each v In Rec.Value.Values
41 | CurBranch.Register(v)
42 | Next
43 | End If
44 | Next
45 | Next
46 | For Each r In TreeRoot
47 | For i As Integer = r.RegisteredValues.Count - 1 To 0 Step -1
48 | Dim v = r.RegisteredValues(i)
49 | For Each r1 In TreeRoot
50 | If r1.Text = v.Text Then
51 | r.Register(r1)
52 | Exit For
53 | End If
54 | Next
55 | Next
56 | Next
57 | End Sub
58 | End Class
59 |
60 | End Namespace
61 |
--------------------------------------------------------------------------------
/Imaging/IniTreeNode.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 | Namespace Imaging
3 | '''
4 | ''' INI树节点
5 | '''
6 | Public MustInherit Class IniTreeNode
7 | ReadOnly Property Text As String
8 | Sub New(Text As String)
9 | Me.Text = Text
10 | End Sub
11 | Friend Sub RenameInternal(Name As String)
12 | _Text = Name
13 | End Sub
14 | Public Sub Rename(Root As IEnumerable(Of MainKeyTreeNode), NewName As String)
15 | For Each MK In Root
16 | For Each kv In MK.KeyValues.Keys
17 | Dim Vals As New StringBuilder
18 | Dim vs = MK.KeyValues(kv).Values
19 | Dim co = vs.Count
20 | For i As Integer = 0 To co - 2
21 | Dim v = vs(i)
22 | Dim nam2 = If(Text = v.Text, NewName, v.Text)
23 | v.RenameInternal(nam2)
24 | Vals.Append(nam2)
25 | Vals.Append(","c)
26 | Next
27 | Dim Last = vs(co - 1).Text
28 | Dim nam = If(Text = Last, NewName, Last)
29 | vs.Last.RenameInternal(nam)
30 | Vals.Append(nam)
31 | MK.KeyValues(kv).RenameInternal(Vals.ToString)
32 | Next
33 | Next
34 | RenameInternal(NewName)
35 | End Sub
36 | End Class
37 | End Namespace
--------------------------------------------------------------------------------
/Imaging/KeyTreeNode.vb:
--------------------------------------------------------------------------------
1 |
2 | Imports Nukepayload2.Ra2CodeAnalysis.AnalysisHelper
3 |
4 | Namespace Imaging
5 | '''
6 | ''' 键
7 | '''
8 | Public Class KeyTreeNode
9 | Inherits RegisterTreeNode
10 | Public Property ValueNode As ValueTreeNode
11 | Public ReadOnly Property IsRegisterKey As Boolean
12 | Get
13 | Return Text.IsUInteger
14 | End Get
15 | End Property
16 | Sub New(Text As String, ValueNode As ValueTreeNode)
17 | MyBase.New(Text)
18 | Me.ValueNode = ValueNode
19 | End Sub
20 |
21 | Public Overrides Sub RegisterAndModify(Item As IRegisterable)
22 | Register(Item)
23 | If Not (From v In ValueNode.Values Select v.Text).Contains(Item.Text) Then
24 | ValueNode.AddValue(New SubValueTreeNode(Item.Text))
25 | End If
26 | End Sub
27 |
28 | Public Overrides Sub UnRegisterAndModify(Item As IRegisterable)
29 | UnRegister(Item)
30 | If (From v In ValueNode.Values Select v.Text).Contains(Item.Text) Then
31 | ValueNode.RemoveValue(New SubValueTreeNode(Item.Text))
32 | End If
33 | End Sub
34 | End Class
35 |
36 | End Namespace
--------------------------------------------------------------------------------
/Imaging/MainKeyTreeNode.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Namespace Imaging
4 | '''
5 | ''' 主键
6 | '''
7 | Public Class MainKeyTreeNode
8 | Inherits RegisterTreeNode
9 | Implements IRegisterable
10 | '''
11 | ''' 把当前主键的信息转换回ini文本
12 | '''
13 | '''
14 | Public Overrides Function ToString() As String
15 | With New StringBuilder
16 | .Append("["c)
17 | .Append(Text)
18 | .AppendLine("]"c)
19 | For Each kv In KeyValues
20 | .Append(kv.Key.Text)
21 | .Append("="c)
22 | .AppendLine(kv.Value.Text)
23 | Next
24 | Return .ToString
25 | End With
26 | End Function
27 | ReadOnly Property KeyValues As IDictionary(Of KeyTreeNode, ValueTreeNode) =
28 | New Dictionary(Of KeyTreeNode, ValueTreeNode)
29 | Protected RegIn As New List(Of RegisterTreeNode)
30 | Public ReadOnly Property RegisteredIn As IEnumerable(Of RegisterTreeNode) = RegIn Implements IRegisterable.RegisteredIn
31 |
32 | Private ReadOnly Property IRegisterable_Text As String Implements IRegisterable.Text
33 | Get
34 | Return Text
35 | End Get
36 | End Property
37 |
38 | Sub New(Text As String)
39 | MyBase.New(Text)
40 | End Sub
41 |
42 | Friend Sub RegisterToInternal(Node As RegisterTreeNode) Implements IRegisterable.RegisterToInternal
43 | RegIn.Add(Node)
44 | End Sub
45 |
46 | Friend Sub UnRegisterFromInternal(Node As RegisterTreeNode) Implements IRegisterable.UnRegisterFromInternal
47 | RegIn.Remove(Node)
48 | End Sub
49 |
50 | Public Overrides Sub RegisterAndModify(Item As IRegisterable)
51 | If Not IsRegistered(Item) Then
52 | Register(Item)
53 | Dim keys = From k In KeyValues Select k.Key.Text
54 | For i As Integer = 1 To Integer.MaxValue
55 | If Not keys.Contains(i.ToString) Then
56 | Dim v = New ValueTreeNode(Item.Text)
57 | KeyValues.Add(New KeyTreeNode(i.ToString, v), v)
58 | Return
59 | End If
60 | Next
61 | Throw New InvalidOperationException("注册已满")
62 | End If
63 | End Sub
64 |
65 | Public Overrides Sub UnRegisterAndModify(Item As IRegisterable)
66 | If IsRegistered(Item) Then
67 | UnRegister(Item)
68 | For Each kv In KeyValues
69 | If kv.Value.Text = Item.Text Then
70 | KeyValues.Remove(kv)
71 | Return
72 | End If
73 | Next
74 | End If
75 | End Sub
76 | End Class
77 | End Namespace
--------------------------------------------------------------------------------
/Imaging/MainKeyTreeNodeWriter.vb:
--------------------------------------------------------------------------------
1 |
2 | Imports System.Text
3 |
4 | Namespace Imaging
5 | Public Class MainKeyTreeNodeWriter
6 | Dim mkt As MainKeyTreeNode
7 | Protected Sub Load(ReadonlyTree As MainKeyTreeNode)
8 | mkt = ReadonlyTree
9 | Name = mkt.Text
10 | For Each itm In mkt.KeyValues
11 | KeyValues.Add(New WritableKeyValuePair(itm.Key.Text, itm.Value.Text))
12 | Next
13 | End Sub
14 | Sub New(ReadonlyTree As MainKeyTreeNode)
15 | Load(ReadonlyTree)
16 | End Sub
17 | Property Name As String
18 | Get
19 | Return mkt.Text
20 | End Get
21 | Set(value As String)
22 | mkt.RenameInternal(value)
23 | End Set
24 | End Property
25 | Property KeyValues As New List(Of WritableKeyValuePair)
26 | Public Sub Rename(Root As IEnumerable(Of MainKeyTreeNode), NewName As String)
27 | mkt.Rename(Root, NewName)
28 | End Sub
29 | Public Sub SaveWithoutRename()
30 | mkt.KeyValues.Clear()
31 | For Each kv In KeyValues
32 | Dim va = New ValueTreeNode(kv.Value)
33 | mkt.KeyValues.Add(New KeyValuePair(Of KeyTreeNode, ValueTreeNode)(New KeyTreeNode(kv.Key, va), va))
34 | Next
35 | End Sub
36 | End Class
37 | End Namespace
38 |
--------------------------------------------------------------------------------
/Imaging/RegisterTreeNode.vb:
--------------------------------------------------------------------------------
1 |
2 | Namespace Imaging
3 | '''
4 | ''' 主键和键是能注册其它节点的
5 | '''
6 | Public MustInherit Class RegisterTreeNode
7 | Inherits IniTreeNode
8 | Protected RegValues As New List(Of IRegisterable)
9 | Public ReadOnly Property RegisteredValues As IEnumerable(Of IRegisterable) = RegValues
10 | Public MustOverride Sub RegisterAndModify(Item As IRegisterable)
11 | Public MustOverride Sub UnRegisterAndModify(Item As IRegisterable)
12 | Protected Function IsRegistered(Item As IRegisterable) As Boolean
13 | Return (From r In Item.RegisteredIn Select r.Text).Contains(Text)
14 | End Function
15 | Public Sub Register(Item As IRegisterable)
16 | If Not IsRegistered(Item) Then
17 | RegValues.Add(Item)
18 | Item.RegisterToInternal(Me)
19 | End If
20 | End Sub
21 | Public Sub UnRegister(Item As IRegisterable)
22 | RegValues.Remove(Item)
23 | Item.UnRegisterFromInternal(Me)
24 | End Sub
25 | Sub New(Text As String)
26 | MyBase.New(Text)
27 | End Sub
28 | End Class
29 | End Namespace
--------------------------------------------------------------------------------
/Imaging/SubValueTreeNode.vb:
--------------------------------------------------------------------------------
1 |
2 | Namespace Imaging
3 | '''
4 | ''' 值列表
5 | '''
6 | Public Class SubValueTreeNode
7 | Inherits IniTreeNode
8 | Implements IRegisterable
9 | Protected RegIn As New List(Of RegisterTreeNode)
10 | Public ReadOnly Property RegisteredIn As IEnumerable(Of RegisterTreeNode) = RegIn Implements IRegisterable.RegisteredIn
11 |
12 | Private ReadOnly Property IRegisterable_Text As String Implements IRegisterable.Text
13 | Get
14 | Return Text
15 | End Get
16 | End Property
17 |
18 |
19 | Friend Sub RegisterToInternal(Node As RegisterTreeNode) Implements IRegisterable.RegisterToInternal
20 | RegIn.Add(Node)
21 | End Sub
22 | Sub New(Text As String)
23 | MyBase.New(Text)
24 | End Sub
25 |
26 | Friend Sub UnRegisterFromInternal(Node As RegisterTreeNode) Implements IRegisterable.UnRegisterFromInternal
27 | RegIn.Remove(Node)
28 | End Sub
29 | End Class
30 | End Namespace
--------------------------------------------------------------------------------
/Imaging/Synchronization.vb:
--------------------------------------------------------------------------------
1 | Namespace Synchronization
2 | Public Module Events
3 | Public Event ReloadAllDataFromRecord()
4 | Public Sub ReloadAllDataFromRecordRequest()
5 | RaiseEvent ReloadAllDataFromRecord()
6 | End Sub
7 | End Module
8 | End Namespace
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Imaging/ValueTreeNode.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Namespace Imaging
4 |
5 | '''
6 | ''' 值
7 | '''
8 | Public Class ValueTreeNode
9 | Inherits IniTreeNode
10 | Protected Vals As New List(Of SubValueTreeNode)
11 | ReadOnly Property Values As IEnumerable(Of SubValueTreeNode) = Vals
12 | Public Sub AddValue(Item As SubValueTreeNode)
13 | RenameInternal(Text & "," & Item.Text)
14 | Vals.Add(Item)
15 | End Sub
16 | Public Sub RemoveValue(Item As SubValueTreeNode)
17 | Vals.Remove(Item)
18 | Dim sb As New StringBuilder
19 | For Each v In Vals
20 | sb.Append(v.Text)
21 | sb.Append(","c)
22 | Next
23 | sb.Remove(sb.Length - 2, 1)
24 | End Sub
25 | Sub New(Text As String)
26 | MyBase.New(Text)
27 | For Each txs In Text.Split(","c)
28 | Vals.Add(New SubValueTreeNode(txs.Trim))
29 | Next
30 | End Sub
31 | End Class
32 |
33 | End Namespace
--------------------------------------------------------------------------------
/Input/CodeSnippet.vb:
--------------------------------------------------------------------------------
1 | Public Class CodeSnippet
2 | Public ReadOnly Property Shortcut As String
3 | Public ReadOnly Property Text As String
4 | Public ReadOnly Property Description As String
5 | Sub New(Shortcut As String, Text As String, Description As String)
6 | Me.Shortcut = Shortcut
7 | Me.Text = Text
8 | Me.Description = Description
9 | End Sub
10 | End Class
11 |
--------------------------------------------------------------------------------
/Input/ImeBase.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 | Imports Nukepayload2.Ra2CodeAnalysis.AnalysisHelper
3 |
4 | Public Class ImeItem
5 | Public Property Word As String
6 | Sub New(Wrd As String)
7 | Word = Wrd
8 | End Sub
9 | End Class
10 | Public MustInherit Class ImeBase
11 | Protected MustOverride ReadOnly Property SelectPosition As Integer
12 | MustOverride Property ImeListBinding As IEnumerable
13 | MustOverride Property ListVisible As Boolean
14 | Protected MustOverride Property TextInBox As String
15 | Protected MustOverride Sub SelectAndSetText(Start As Integer, Length As Integer, Text As String)
16 |
17 | Dim LeftVals As New List(Of String)
18 | Dim RightVals As New List(Of String)
19 | Dim MainKeys As New List(Of String)
20 |
21 | Public Sub AutoCompleteFast(CompleteText As String)
22 | Dim StartPos As Integer = 0
23 | Dim Selected = SelectText(False, StartPos)
24 | SelectAndSetText(StartPos, Selected.Length, CompleteText)
25 | End Sub
26 | Dim LockViewList As New Object
27 | Public Async Sub ViewList()
28 | ImeListBinding = Nothing
29 | Dim tmp As New List(Of ImeItem)
30 | Dim Left As Boolean = False
31 | Dim sea = GenerateSearch(Left)
32 | Await Task.Run(
33 | Sub()
34 | SyncLock LockViewList
35 | Dim ls = If(Left, LeftVals, RightVals)
36 | Dim Que = From i In ls Where i.ToLowerInvariant.StartsWith(sea.ToLowerInvariant) Order By i
37 | If Left Then
38 | For Each it In Que '使用Like触发测试版vbc的bug
39 | If Not it.IsUInteger Then
40 | tmp.Add(New ImeItem(it & "="))
41 | End If
42 | Next
43 | Else
44 | For Each it In Que '使用Like触发测试版vbc的bug
45 | If Not it.IsUInteger Then
46 | tmp.Add(New ImeItem(it))
47 | End If
48 | Next
49 | End If
50 | End SyncLock
51 | End Sub)
52 | Dim OldItems = TryCast(ImeListBinding, List(Of ImeItem))
53 | If OldItems IsNot Nothing AndAlso OldItems.Count = tmp.Count Then
54 | For i = 0 To OldItems.Count - 1
55 | If OldItems(i).Word <> tmp(i).Word Then
56 | OldItems(i) = tmp(i)
57 | End If
58 | Next
59 | Else
60 | ImeListBinding = tmp
61 | End If
62 | ListVisible = True
63 | End Sub
64 | Protected Function SelectText(ByRef IsLeft As Boolean, ByRef StartPos As Integer) As String
65 | StartPos = Me.SelectPosition
66 | IsLeft = True
67 | Dim tx = TextInBox
68 | If String.IsNullOrEmpty(tx) Then
69 | Return String.Empty
70 | End If
71 | If StartPos > tx.Length Then
72 | Throw New ArgumentOutOfRangeException("Position", "位置位于字符串外侧")
73 | End If
74 | If StartPos = 0 Then
75 | Return String.Empty
76 | Else
77 | Dim wrd As New List(Of Char)
78 | Do Until StartPos = 0
79 | StartPos -= 1
80 | Dim ch = tx.Chars(StartPos)
81 | If ch = "=" OrElse ch = "," Then IsLeft = False
82 | If ch.IsRegisterableChar Then
83 | wrd.Add(ch)
84 | ElseIf ch <> " " Then
85 | Exit Do
86 | End If
87 | Loop
88 | wrd.Reverse()
89 | Return New String(wrd.ToArray)
90 | End If
91 | End Function
92 | Protected Function GenerateSearch(ByRef IsLeft As Boolean) As String
93 | Return SelectText(IsLeft, 0)
94 | End Function
95 | Dim Lock As New Object
96 | Protected Sub ReloadSync(Ini As INIAnalyzer)
97 | MainKeys.Clear()
98 | LeftVals.Clear()
99 | RightVals.Clear()
100 | SyncLock Lock
101 | For Each mk In Ini.Values
102 | If Not MainKeys.Contains(mk.Key) Then
103 | MainKeys.Add(mk.Key)
104 | End If
105 | For Each kv In mk.Value
106 | If Not LeftVals.Contains(kv.Key) Then
107 | LeftVals.Add(kv.Key)
108 | End If
109 | For Each v In kv.Value.Item1.Split(","c)
110 | v = v.Trim
111 | If Not RightVals.Contains(v) AndAlso Not String.IsNullOrWhiteSpace(v) Then
112 | RightVals.Add(v)
113 | End If
114 | Next
115 | Next
116 | Next
117 | End SyncLock
118 | End Sub
119 | Public Async Function Reload(Ini As INIAnalyzer) As Task
120 | Await Task.Run(Sub() ReloadSync(Ini))
121 | End Function
122 | Sub New(Ini As INIAnalyzer)
123 | ReloadSync(Ini)
124 | End Sub
125 | End Class
126 |
--------------------------------------------------------------------------------
/Input/IniValueMainKeyRenamer.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Public Class IniValueMainKeyRenamer
4 | Sub New()
5 |
6 | End Sub
7 | Public Async Function RenameAsync(MatchItem As String, Replacement As String, RenameOption As RenameOptions, DataSource As IEnumerable(Of ParameterizedProperty(Of String))) As Task
8 | If CBool(RenameOption And RenameOptions.MainKey) Then
9 | Await ForEachAsync(DataSource,
10 | Sub(prop)
11 | Dim ini = prop.Value
12 | If MatchItem.StartsWith("<") AndAlso MatchItem.EndsWith(">") Then
13 | prop.Value = prop.Value.Replace(MatchItem, Replacement)
14 | Return
15 | End If
16 | Dim txs = ini.Split({vbCrLf}, StringSplitOptions.None)
17 | Dim sb As New StringBuilder
18 | For Each tx In txs
19 | Dim Original = tx
20 | If tx.Contains(";") Then
21 | tx = tx.Substring(0, tx.IndexOf(";"c)).Trim
22 | End If
23 | If tx.Contains("[") Then
24 | sb.Append(Original.Substring(0, Original.IndexOf("["c) + 1))
25 | If tx.Length > 1 Then
26 | Dim MK = tx.Substring(1, tx.Length - 2).Trim
27 | If MK = MatchItem Then
28 | MK = Replacement
29 | End If
30 | sb.Append(MK).AppendLine(Original.Substring(Original.IndexOf("]"c)))
31 | End If
32 | Else
33 | sb.AppendLine(Original)
34 | End If
35 | Next
36 | prop.Value = sb.ToString
37 | End Sub)
38 | End If
39 | If CBool(RenameOption And RenameOptions.Value) Then
40 | Await ForEachAsync(DataSource,
41 | Sub(prop)
42 | Dim ini = prop.Value
43 | Dim txs = ini.Split({vbCrLf}, StringSplitOptions.None)
44 | Dim sb As New StringBuilder
45 | For Each tx In txs
46 | Dim Original = tx
47 | If tx.Contains(";") Then
48 | tx = tx.Substring(0, tx.IndexOf(";"c)).Trim
49 | End If
50 | If tx.Contains("=") Then
51 | Dim txEq = tx.Split("="c)
52 | sb.Append(txEq(0)).Append("=")
53 | Dim txRights = txEq(1).Split(","c)
54 | Dim newRights = Aggregate s In txRights Select If(s = MatchItem, Replacement, s) Into ToArray
55 | For i = 0 To newRights.Length - 2
56 | sb.Append(newRights(i)).Append(",")
57 | Next
58 | sb.AppendLine(newRights.Last)
59 | Else
60 | sb.AppendLine(Original)
61 | End If
62 | Next
63 | prop.Value = sb.ToString
64 | End Sub)
65 | End If
66 | End Function
67 | End Class
--------------------------------------------------------------------------------
/Input/QuickFix.vb:
--------------------------------------------------------------------------------
1 | Imports Nukepayload2.Ra2CodeAnalysis.AnalysisHelper
2 | Imports Nukepayload2.Ra2CodeAnalysis.Document
3 | '''
4 | ''' 修正ini文档的常见错误
5 | '''
6 | Public Class QuickFix
7 |
8 | End Class
9 |
--------------------------------------------------------------------------------
/Input/QuickFixSuggestion.vb:
--------------------------------------------------------------------------------
1 | Public MustInherit Class QuickFixSuggestion
2 | Public Message As String
3 | Public Fix As [Delegate]
4 | Public PreviewAddedText As String
5 | Public PreviewRemovedText As String
6 | End Class
7 |
--------------------------------------------------------------------------------
/Input/RenameOptions.vb:
--------------------------------------------------------------------------------
1 | Public Enum RenameOptions
2 | None
3 | MainKey
4 | Value
5 | Both
6 | End Enum
7 |
--------------------------------------------------------------------------------
/Linq/StringExtension.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Namespace Linq
4 | Public Module StringAggregation
5 | '''
6 | ''' 带缩进和 Windows 格式 换行的合并
7 | '''
8 |
9 | Public Function Join(source As IEnumerable(Of String), space As Func(Of String, Integer)) As String
10 | Dim sb As New StringBuilder
11 | For Each blk In source
12 | sb.Append(" "c, space(blk)).AppendLine(blk)
13 | Next
14 | sb.Remove(sb.Length - 2, 2)
15 | Return sb.ToString
16 | End Function
17 | '''
18 | ''' 带单字符分隔符的合并
19 | '''
20 |
21 | Public Function Join(source As IEnumerable(Of String), separator As Func(Of String, String)) As String
22 | Dim sb As New StringBuilder
23 | For Each blk In source
24 | sb.Append(blk).Append(separator(blk))
25 | Next
26 | Dim len = separator(String.Empty).Length
27 | If len > 0 Then sb.Remove(sb.Length - len, len)
28 | Return sb.ToString
29 | End Function
30 | End Module
31 | End Namespace
32 |
--------------------------------------------------------------------------------
/My Project/AssemblyInfo.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Resources
3 | Imports System.Reflection
4 |
5 | ' 有关程序集的常规信息通过以下特性集
6 | ' 控制。更改这些特性值可修改
7 | ' 与程序集关联的信息。
8 |
9 | ' 检查程序集特性的值
10 |
11 |
12 |
13 | ' 程序集的版本信息由以下四个值组成:
14 | '
15 | ' 主版本
16 | ' 次版本
17 | ' 生成号
18 | ' 修订号
19 | '
20 | ' 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
21 | ' 方法是按如下所示使用“*”:
22 | '
23 |
--------------------------------------------------------------------------------
/Primitives/Percentage.vb:
--------------------------------------------------------------------------------
1 | '''
2 | ''' 表示单精度的百分比
3 | '''
4 | Public Structure Percentage
5 | Implements IEquatable(Of Percentage), IComparable(Of Percentage), IFormattable
6 |
7 | Dim SingleValue As Single
8 |
9 | Sub New(singleValue As Single)
10 | Me.SingleValue = singleValue
11 | End Sub
12 |
13 | Public Shared Function Parse(text As String) As Percentage
14 | Dim perc As New Percentage
15 | If TryParse(text, perc) Then
16 | Return perc
17 | End If
18 | If String.IsNullOrEmpty(text) Then
19 | text = "空字符串"
20 | End If
21 | Throw New InvalidCastException($"无法将 {text} 转换为 {NameOf(Percentage)} 类型")
22 | End Function
23 |
24 | Public Shared Function TryParse(text As String, ByRef value As Percentage) As Boolean
25 | If text IsNot Nothing AndAlso text.Length > 1 AndAlso text.EndsWith("%") Then
26 | Dim numberPart = text.Substring(0, text.Length - 1)
27 | Dim sng = 0F
28 | If Single.TryParse(numberPart, sng) Then
29 | value.SingleValue = sng
30 | Return True
31 | End If
32 | End If
33 | Return False
34 | End Function
35 | Public Function CompareTo(other As Percentage) As Integer Implements IComparable(Of Percentage).CompareTo
36 | Return SingleValue.CompareTo(other.SingleValue)
37 | End Function
38 |
39 | Public Overloads Function Equals(other As Percentage) As Boolean Implements IEquatable(Of Percentage).Equals
40 | Return SingleValue = other.SingleValue
41 | End Function
42 |
43 | Public Overrides Function Equals(obj As Object) As Boolean
44 | If TypeOf obj Is Percentage Then
45 | Return SingleValue = DirectCast(obj, Percentage).SingleValue
46 | End If
47 | Return False
48 | End Function
49 | Public Overrides Function GetHashCode() As Integer
50 | Return SingleValue.GetHashCode()
51 | End Function
52 | Public Overrides Function ToString() As String
53 | Return (SingleValue * 100).ToString("#") & "%"
54 | End Function
55 | Public Overloads Function ToString(format As String, formatProvider As IFormatProvider) As String Implements IFormattable.ToString
56 | Return (SingleValue * 100).ToString(format, formatProvider) & "%"
57 | End Function
58 |
59 | Public Shared Operator =(left As Percentage, right As Percentage) As Boolean
60 | Return left.SingleValue = right.SingleValue
61 | End Operator
62 |
63 | Public Shared Operator <>(left As Percentage, right As Percentage) As Boolean
64 | Return left.SingleValue <> right.SingleValue
65 | End Operator
66 |
67 | Public Shared Operator >(left As Percentage, right As Percentage) As Boolean
68 | Return left.SingleValue > right.SingleValue
69 | End Operator
70 |
71 | Public Shared Operator <(left As Percentage, right As Percentage) As Boolean
72 | Return left.SingleValue < right.SingleValue
73 | End Operator
74 |
75 | Public Shared Operator >=(left As Percentage, right As Percentage) As Boolean
76 | Return left.SingleValue >= right.SingleValue
77 | End Operator
78 |
79 | Public Shared Operator <=(left As Percentage, right As Percentage) As Boolean
80 | Return left.SingleValue <= right.SingleValue
81 | End Operator
82 |
83 | End Structure
84 | Module Constants
85 | Public Const Yes As Boolean = True
86 | Public Const No As Boolean = False
87 | Public Const None As Object = Nothing
88 | End Module
--------------------------------------------------------------------------------
/Ra2CodeAnalysis.vbproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard1.4
5 | Nukepayload2.Ra2CodeAnalysis
6 | Nukepayload2.Ra2CodeAnalysis
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | {11d14cb7-c9fe-4044-aba0-9be40efbc301}
40 | Nukepayload2.CodeAnalysis
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Tools/SymbolFinder.vb:
--------------------------------------------------------------------------------
1 | Imports Nukepayload2.Ra2CodeAnalysis.AnalysisHelper
2 |
3 | Public Class SymbolFinder
4 | Public Async Function Find(MatchText As String, Rules As RulesAnalyzer, Art As ArtAnalyzer, AI As AIAnalyzer) As Task(Of IEnumerable(Of FindSymbolResult))
5 | Dim Results = Await ForEachAsync(Of Ra2IniAnalyzer, IEnumerable(Of FindSymbolResult))({Rules, Art, AI},
6 | Function(ini)
7 | Dim ls As New List(Of FindSymbolResult)
8 | For Each mk In ini.Values
9 | If MatchText = mk.Key Then
10 | Dim ln = mk.Value.FirstOrDefault.Value.Item2
11 | If ln = 0 Then ln = 1
12 | ls.Add(New FindSymbolResult(ini.Name, mk.Key, ln - 1, mk.Key, "定义"))
13 | End If
14 | For Each kv In mk.Value
15 | For Each v In kv.Value.Item1.Split(","c)
16 | If v.Trim = MatchText Then
17 | Dim Comment As String
18 | If kv.Key.IsNumeric() Then
19 | Comment = "注册"
20 | Else
21 | Comment = "引用"
22 | End If
23 | ls.Add(New FindSymbolResult(ini.Name, v, kv.Value.Item2, v, Comment))
24 | End If
25 | Next
26 | Next
27 | Next
28 | Return ls
29 | End Function)
30 | Dim Heads = Results.First
31 | For i = 1 To 2
32 | Heads = Heads.Concat(Results(i))
33 | Next
34 | Return Heads
35 | End Function
36 | End Class
37 |
--------------------------------------------------------------------------------
/Utility/DataGridDisplayNameAttribute.vb:
--------------------------------------------------------------------------------
1 | Imports System.Reflection
2 |
3 |
4 | Public NotInheritable Class DataGridDisplayNameAttribute
5 | Inherits Attribute
6 | Public ReadOnly Name As String
7 | Public Shared Function GetValueDicFromType(tp As Type) As Dictionary(Of String, String)
8 | Dim NameDic As New Dictionary(Of String, String)
9 | For Each m As MemberInfo In tp.GetRuntimeProperties
10 | Dim Attrib = m.GetCustomAttribute(Of DataGridDisplayNameAttribute)
11 | If Attrib IsNot Nothing Then
12 | NameDic.Add(m.Name, DirectCast(Attrib, DataGridDisplayNameAttribute).Name)
13 | Else
14 | NameDic.Add(m.Name, m.Name)
15 | End If
16 | Next
17 | Return NameDic
18 | End Function
19 | Sub New(Name As String)
20 | MyBase.New
21 | Me.Name = Name
22 | End Sub
23 | End Class
24 |
--------------------------------------------------------------------------------
/Utility/DocumentExtensions.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Public Module DocumentExtensions
4 | '''
5 | ''' 去除Ini注释;后面的的内容
6 | '''
7 |
8 | Public Function ExceptComments(Source$) As String
9 | Return If(Source.Contains(";"), Source.Substring(0, Source.IndexOf(";"c)), Source)
10 | End Function
11 | '''
12 | ''' 把每个内容按换行符分割存入字符串
13 | '''
14 |
15 | Public Function JoinLine(Of T)(Source As IEnumerable(Of T), GetText As Func(Of T, String)) As String
16 | Dim sb As New StringBuilder
17 | For Each blk In Source
18 | sb.AppendLine(GetText(blk))
19 | Next
20 | Return sb.ToString
21 | End Function
22 | '''
23 | ''' 把每个内容无分割存入字符串
24 | '''
25 |
26 | Public Function JoinText(Of T)(Source As IEnumerable(Of T), GetText As Func(Of T, String)) As String
27 | Dim sb As New StringBuilder
28 | For Each blk In Source
29 | sb.Append(GetText(blk))
30 | Next
31 | Return sb.ToString
32 | End Function
33 | '''
34 | ''' 如果数目一样则改写,不一样就删掉重新添加。
35 | '''
36 | '''
37 | '''
38 | '''
39 | '''
40 |
41 | Public Sub ReloadContent(Of T)(Dest As IList(Of T), Source As IList(Of T), GetText As Func(Of T, String))
42 | If Source.Count = Dest.Count Then
43 | For i = 0 To Source.Count - 1
44 | If GetText(Dest(i)) <> GetText(Source(i)) Then
45 | Dest(i) = Source(i)
46 | End If
47 | Next
48 | Else
49 | Dest.Clear()
50 | For Each b In Source
51 | Dest.Add(b)
52 | Next
53 | End If
54 | End Sub
55 | End Module
56 |
--------------------------------------------------------------------------------
/Utility/ExpressionCalculator.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 |
3 | Namespace AnalysisHelper
4 | '''
5 | ''' 用于计算ini中的数值
6 | '''
7 | Public Class ExpressionCalculator
8 | Protected Numbers As New Stack(Of Decimal)
9 | Protected Operators As New Stack(Of String)
10 | Protected ReadOnly Ops As New Dictionary(Of String, Func(Of Decimal, Decimal, Decimal)) From {
11 | {"+", Function(a, b) a + b},
12 | {"-", Function(a, b) a - b},
13 | {"*", Function(a, b) a * b},
14 | {"x", Function(a, b) a * b},
15 | {"/", Function(a, b) a / b},
16 | {"\", Function(a, b) CLng(a) \ CLng(b)},
17 | {"÷", Function(a, b) a / b},
18 | {"^", Function(a, b) CDec(a ^ b)},
19 | {"mod", Function(a, b) a Mod b},
20 | {"%", Function(a, b) a Mod b},
21 | {"not", Function(a, b) Not CLng(b)},
22 | {"!", Function(a, b) Not CLng(b)},
23 | {"and", Function(a, b) CLng(a) And CLng(b)},
24 | {"or", Function(a, b) CLng(a) Or CLng(b)},
25 | {"xor", Function(a, b) CLng(a) Xor CLng(b)},
26 | {"<<", Function(a, b) CLng(a) << CInt(b)},
27 | {">>", Function(a, b) CLng(a) >> CInt(b)},
28 | {"<<<", Function(a, b) CLng(a) << CInt(b)},
29 | {">>>", Function(a, b) CLng(a).BitToUInt64 >> CInt(b)},
30 | {"sal", Function(a, b) CLng(a) << CInt(b)},
31 | {"shl", Function(a, b) CLng(a) << CInt(b)},
32 | {"sar", Function(a, b) CLng(a) >> CInt(b)},
33 | {"shr", Function(a, b) CLng(a).BitToUInt64 >> CInt(b)},
34 | {"ror", Function(a, b)
35 | Dim num As ULong = CLng(a).BitToUInt64, Count As Integer = CInt(b)
36 | Count = Count Mod 64
37 | Dim lo = num >> Count
38 | Dim hi = num << 64 - Count
39 | Return BitToInt64(hi Or lo)
40 | End Function},
41 | {"rol", Function(a, b)
42 | Dim num As ULong = CLng(a).BitToUInt64, Count As Integer = CInt(b)
43 | Count = Count Mod 64
44 | Dim lo = num >> 64 - Count
45 | Dim hi = num << Count
46 | Return BitToInt64(hi Or lo)
47 | End Function}
48 | }
49 | Public ReadOnly Property SupportedOperators As ICollection(Of String)
50 | Get
51 | Return Ops.Keys
52 | End Get
53 | End Property
54 | Protected Overridable Function CalculateBlock(Num2 As Decimal, Num1 As Decimal, OpCode As String) As Decimal
55 | If OpCode.Length > 1 Then OpCode = OpCode.ToLowerInvariant
56 | If Not Ops.ContainsKey(OpCode) Then
57 | Throw New ArgumentException(String.Format("运算符{0}不支持", OpCode))
58 | End If
59 | Return Ops(OpCode).Invoke(Num1, Num2)
60 | End Function
61 | Protected Function Seperate(chrs As IEnumerable(Of Char)) As IEnumerable(Of String)
62 | Dim Expression = New String(chrs.ToArray)
63 | Dim Result As New List(Of String)
64 | If chrs.CountOf("("c) <> chrs.CountOf(")"c) Then
65 | Throw New ArgumentException("表达式中的(的数量不等于)的数量")
66 | End If
67 | For pos As Integer = 0 To chrs.Count - 1
68 | If IsNumeric(chrs(pos)) OrElse (chrs(pos) = "-"c AndAlso (pos = 0 OrElse Not chrs(pos - 1).IsNumeric)) Then
69 | Dim LastStr As New StringBuilder
70 | Do
71 | LastStr.Append(chrs(pos))
72 | pos += 1
73 | Loop While IsNumeric(chrs(pos)) OrElse chrs(pos) = "."
74 | pos -= 1
75 | Result.Add(LastStr.ToString)
76 | Else
77 | If chrs(pos) = "(" OrElse chrs(pos) = ")" Then
78 | Result.Add(chrs(pos))
79 | Else
80 | Dim p As Integer = 0
81 | Dim pm As Integer
82 | Dim LongStr As String = ""
83 | Dim ssb As New StringBuilder
84 | Do
85 | ssb.Append(chrs(pos + p))
86 | If Ops.Keys.Contains(ssb.ToString) Then
87 | LongStr = ssb.ToString
88 | pm = p
89 | End If
90 | p += 1
91 | If pos + p >= chrs.Count - 1 Then
92 | Exit Do
93 | End If
94 | Loop Until IsNumeric(chrs(pos + p))
95 | Result.Add(LongStr)
96 | pos += pm
97 | End If
98 | End If
99 | Next
100 | Return Result
101 | End Function
102 |
103 | Private Function GetPriority(s As String) As Integer
104 | Select Case s
105 | Case "("
106 | Return 0
107 | Case "<<", ">>", "shr", "shl", "rol", "ror", "<<<", ">>>", "sar", "sal"
108 | Return 1
109 | Case "xor", "or", "and"
110 | Return 2
111 | Case "+", "-"
112 | Return 3
113 | Case "mod", "%"
114 | Return 4
115 | Case "\"
116 | Return 5
117 | Case "*", "x", "/", "÷"
118 | Return 6
119 | Case "^"
120 | Return 7
121 | Case ")"
122 | Return 8
123 | Case Else
124 | Throw New ArgumentException("不支持的运算符" & s)
125 | End Select
126 | End Function
127 | Public Function Eval(Expression As String) As Decimal
128 | Numbers.Clear()
129 | Operators.Clear()
130 | Dim Seped = Seperate(Expression.Replace("(", "(").Replace(")", ")").Replace(" ", "").ToCharArray)
131 | For i As Integer = 0 To Seped.Count - 1
132 | Dim current = Seped(i)
133 | If current.IsNumeric Then
134 | Numbers.Push(CDec(current))
135 | Else
136 | If current <> ")" Then
137 | If current <> "(" AndAlso Operators.Count > 0 Then
138 | Do While GetPriority(Operators.Peek) >= GetPriority(current)
139 | Numbers.Push(CalculateBlock(Numbers.Pop, Numbers.Pop, Operators.Pop))
140 | If Operators.Count = 0 Then Exit Do
141 | If Operators.Peek = "(" Then Exit Do
142 | Loop
143 | End If
144 | Operators.Push(current)
145 | ElseIf GetPriority(Operators.Peek) < GetPriority(current) Then
146 | If Operators.Peek <> "(" Then
147 | Do Until Operators.Peek = "("
148 | Numbers.Push(CalculateBlock(Numbers.Pop, Numbers.Pop, Operators.Pop))
149 | Loop
150 | End If
151 | Operators.Pop()
152 | Else
153 | Numbers.Push(CalculateBlock(Numbers.Pop, Numbers.Pop, Operators.Pop))
154 | End If
155 | End If
156 | Next
157 | Do While Operators.Count > 0
158 | Numbers.Push(CalculateBlock(Numbers.Pop, Numbers.Pop, Operators.Pop))
159 | Loop
160 | If Numbers.Count = 1 Then
161 | Return Numbers.First
162 | Else
163 | Throw New ArgumentException("不能省略*或x运算符")
164 | Dim tmp As Decimal = 1
165 | For Each n In Numbers
166 | tmp *= n
167 | Next
168 | Return tmp
169 | End If
170 | End Function
171 | Public Function EvalAsync(Expression As String) As Task(Of Decimal)
172 | Return New Task(Of Decimal)(Function() Eval(Expression))
173 | End Function
174 | End Class
175 | End Namespace
--------------------------------------------------------------------------------
/Utility/Parallel.vb:
--------------------------------------------------------------------------------
1 | Public Module AsyncParallel
2 | Public Async Function ForEachAsync(Of T)(DataSource As IEnumerable(Of T), Proc As Action(Of T)) As Task
3 | Await Task.WhenAll(From d In DataSource Select Task.Run(Sub() Proc(d)))
4 | End Function
5 | Public Async Function ForEachAsync(Of T, TResult)(DataSource As IEnumerable(Of T), Proc As Func(Of T, TResult)) As Task(Of TResult())
6 | Return Await Task.WhenAll(From d In DataSource Select Task.Run(Function() Proc(d)))
7 | End Function
8 | End Module
9 |
--------------------------------------------------------------------------------
/Utility/ParameterizedProperty.vb:
--------------------------------------------------------------------------------
1 | '''
2 | ''' 用于传递属性和为值获取和设置提供通知
3 | '''
4 | '''
5 | Public Class ParameterizedProperty(Of T)
6 | Public ReadOnly Property Getter As Func(Of T)
7 | Public ReadOnly Property Setter As Action(Of T)
8 | Public ReadOnly Property IsReadOnly As Boolean
9 | Get
10 | Return Getter IsNot Nothing AndAlso Setter Is Nothing
11 | End Get
12 | End Property
13 | Public ReadOnly Property IsWriteOnly As Boolean
14 | Get
15 | Return Getter Is Nothing AndAlso Setter IsNot Nothing
16 | End Get
17 | End Property
18 | Public Property Value As T
19 | Get
20 | Return Getter().Invoke
21 | End Get
22 | Set
23 | Setter.Invoke(Value)
24 | End Set
25 | End Property
26 | Public Shared Narrowing Operator CType(Prop As ParameterizedProperty(Of T)) As T
27 | Return Prop.Value
28 | End Operator
29 | Sub New(Getter As Func(Of T), Setter As Action(Of T))
30 | Me.Getter = Getter
31 | Me.Setter = Setter
32 | End Sub
33 | End Class
34 |
--------------------------------------------------------------------------------
/Utility/ResetableDelayTask.vb:
--------------------------------------------------------------------------------
1 | Imports System.Threading
2 |
3 | Public Class ResetableDelayTask
4 | Dim DelayMilsec As Integer
5 | Public ReadOnly Property IsStopped As Boolean = False
6 | Dim CurrentDelay As Integer = 0
7 | Public Sub Reset()
8 | SyncLock Me
9 | CurrentDelay = 0
10 | End SyncLock
11 | End Sub
12 | Public Async Function Run(ac As Action) As Task
13 | If IsStopped Then
14 | Reset()
15 | Return
16 | End If
17 | SyncLock Me
18 | _IsStopped = True
19 | End SyncLock
20 | Do While CurrentDelay < DelayMilsec
21 | Await Task.Delay(16)
22 | If Not IsStopped Then Return
23 | Interlocked.Add(CurrentDelay, 16)
24 | Loop
25 | Await Task.Run(ac)
26 | SyncLock Me
27 | _IsStopped = False
28 | End SyncLock
29 | End Function
30 |
31 | Sub New(DelayTime As TimeSpan)
32 | DelayMilsec = CInt(DelayTime.TotalMilliseconds)
33 | End Sub
34 | End Class
35 |
--------------------------------------------------------------------------------
/Utility/TextExtensions.vb:
--------------------------------------------------------------------------------
1 | Imports System.Reflection
2 | Imports System.Text
3 | Imports System.Text.RegularExpressions
4 | Imports Nukepayload2.Ra2CodeAnalysis.Imaging
5 | Imports Ra2CodeAnalysis.Imaging
6 |
7 | Namespace AnalysisHelper
8 | Public Module Extensions
9 |
10 | Public Function GetText(Root As IEnumerable(Of Imaging.MainKeyTreeNode), Generator As Type) As String
11 | Dim sb As New StringBuilder(";<生成的代码(生成器:=" + If(Generator?.FullName, "null") + ",版本:=" + If(Generator.GetTypeInfo.Assembly.GetCustomAttribute(Of AssemblyFileVersionAttribute)?.Version, "null").ToString + ")>" & vbCrLf)
12 | For Each s In Root
13 | sb.AppendLine(s.ToString)
14 | Next
15 | Return sb.ToString
16 | End Function
17 |
18 | Public Function IsComment(Text As String, Index As Integer) As Boolean
19 | Dim StartPos As Integer = Index
20 | If String.IsNullOrEmpty(Text) Then
21 | Return True
22 | End If
23 | If StartPos > Text.Length Then
24 | Throw New ArgumentOutOfRangeException("Position", "位置位于字符串外侧")
25 | End If
26 | If StartPos = 0 Then
27 | Return False
28 | Else
29 | Do Until StartPos = 0
30 | StartPos -= 1
31 | Dim ch = Text.Chars(StartPos)
32 | If ch = ";"c Then
33 | Return True
34 | Else
35 | If ch = vbCr OrElse ch = vbLf Then
36 | Exit Do
37 | End If
38 | End If
39 | Loop
40 | Return False
41 | End If
42 | End Function
43 |
44 | Public Function FindOne(Of T As IniTreeNode)(RT As IEnumerable(Of T), ObjName As String) As T
45 | For Each mk In RT
46 | If mk.Text = ObjName Then Return mk
47 | Next
48 | Return Nothing
49 | End Function
50 |
51 | Public Function SelectLine(Text As String, index As Integer) As String
52 | If index = -1 Then
53 | Return String.Empty
54 | End If
55 | Dim StartPos As Integer = index
56 | If String.IsNullOrEmpty(Text) Then
57 | Return String.Empty
58 | End If
59 | If StartPos > Text.Length Then
60 | Throw New ArgumentOutOfRangeException("Position", "位置位于字符串外侧")
61 | End If
62 | Dim wrd As New List(Of Char)
63 | Do Until StartPos = 0
64 | StartPos -= 1
65 | Dim ch = Text.Chars(StartPos)
66 | If ch <> vbCr AndAlso ch <> vbLf Then
67 | wrd.Add(ch)
68 | Else
69 | Exit Do
70 | End If
71 | Loop
72 | wrd.Reverse()
73 | Dim LeftPart As New String(wrd.ToArray)
74 | Dim RightPart As New StringBuilder
75 | Do Until index >= Text.Length
76 | Dim ch = Text.Chars(index)
77 | If ch <> vbCr AndAlso ch <> vbLf Then
78 | RightPart.Append(ch)
79 | Else
80 | Exit Do
81 | End If
82 | index += 1
83 | Loop
84 | Return LeftPart + RightPart.ToString
85 | End Function
86 |
87 | Public Function IsValidValueChar(Text As Char) As Boolean
88 | Return Not {ChrW(10), ChrW(13), "="c, ";"c}.Contains(Text)
89 | End Function
90 |
91 | Public Function IsValidSingleWordValueChar(Text As Char) As Boolean
92 | Return Char.IsLetterOrDigit(Text) OrElse Text = "{"c OrElse Text = "}"c
93 | End Function
94 |
95 | Public Function IsValidTemplatedWordValueChar(Text As Char) As Boolean
96 | Return Char.IsLetterOrDigit(Text) OrElse Text = "<"c OrElse Text = ">"c OrElse Text = "_"c OrElse Text = "-"c
97 | End Function
98 |
99 | Public Function SelectWord(Text As String, index As Integer, Optional Filter As Func(Of Char, Boolean) = Nothing) As String
100 | If Filter Is Nothing Then
101 | Filter = AddressOf IsValidValueChar
102 | End If
103 | Dim StartPos As Integer = index
104 | If String.IsNullOrEmpty(Text) Then
105 | Return String.Empty
106 | End If
107 | If StartPos > Text.Length Then
108 | Throw New ArgumentOutOfRangeException("Position", "位置位于字符串外侧")
109 | End If
110 | If StartPos = 0 Then
111 | Return String.Empty
112 | Else
113 | Dim wrd As New List(Of Char)
114 | Dim Terminating = False
115 | Do Until StartPos = 0
116 | StartPos -= 1
117 | Dim ch = Text.Chars(StartPos)
118 | If Filter(ch) AndAlso Not Terminating Then
119 | If ch = "<" Then Terminating = True
120 | wrd.Add(ch)
121 | Else
122 | Exit Do
123 | End If
124 | Loop
125 | Terminating = False
126 | wrd.Reverse()
127 | Dim LeftPart As New String(wrd.ToArray)
128 | Dim RightPart As New StringBuilder
129 | Do Until index >= Text.Length
130 | Dim ch = Text.Chars(index)
131 | If Filter(ch) AndAlso Not Terminating Then
132 | If ch = ">" Then Terminating = True
133 | RightPart.Append(ch)
134 | Else
135 | Exit Do
136 | End If
137 | index += 1
138 | Loop
139 | Return LeftPart.Trim + RightPart.ToString.Trim
140 | End If
141 | End Function
142 | '''
143 | ''' 判断是否是\w,_,%和.
144 | '''
145 | '''
146 | '''
147 |
148 | Function IsRegisterableChar(ch As Char) As Boolean
149 | Return New Regex("(\w|_|\.|%|-)").IsMatch(ch)
150 | End Function
151 |
152 | Function BitToInt64(n As ULong) As Long
153 | Return BitConverter.ToInt64(BitConverter.GetBytes(n), 0)
154 | End Function
155 |
156 | Function BitToUInt64(n As Long) As ULong
157 | Return BitConverter.ToUInt64(BitConverter.GetBytes(n), 0)
158 | End Function
159 |
160 | Function BitToInt32(n As UInteger) As Integer
161 | Return BitConverter.ToInt32(BitConverter.GetBytes(n), 0)
162 | End Function
163 |
164 | Function BitToUInt32(n As Integer) As UInteger
165 | Return BitConverter.ToUInt32(BitConverter.GetBytes(n), 0)
166 | End Function
167 |
168 | Function CountOf(Of T)(txt As IEnumerable(Of T), chr As T) As Integer
169 | Return Aggregate co In From ch In txt Where ch.Equals(chr) Into Count
170 | End Function
171 |
172 | Function CountOf(txt As String, chr As Char) As Integer
173 | Return Aggregate co In From ch In txt.ToCharArray Where ch = chr Into Count
174 | End Function
175 |
176 | Function IsNumeric(t As Char) As Boolean
177 | Return t >= "0"c AndAlso t <= "9"c
178 | End Function
179 |
180 | Function IsInteger(txt As String) As Boolean
181 | If txt.StartsWith("-") OrElse txt.StartsWith("+") Then txt = txt.Substring(1)
182 | If txt.Length = 0 Then Return False
183 | Return txt.Length = Aggregate c In From t In txt.ToCharArray Take While t >= "0"c AndAlso t <= "9"c Into Count
184 | End Function
185 |
186 | Function IsFraction(txt As String) As Boolean
187 | If txt.StartsWith("-") OrElse txt.StartsWith("+") Then txt = txt.Substring(1)
188 | If txt.CountOf("."c) <> 1 Then Return False
189 | Return txt.Length = Aggregate c In From t In txt.ToCharArray Take While t >= "0"c AndAlso t <= "9"c OrElse t = "." Into Count
190 | End Function
191 |
192 | Function IsUInteger(txt As String) As Boolean
193 | If txt.Length = 0 Then Return False
194 | Return txt.Length = Aggregate c In From t In txt.ToCharArray Take While t >= "0"c AndAlso t <= "9"c Into Count
195 | End Function
196 |
197 | Function IsUFraction(txt As String) As Boolean
198 | If txt.CountOf("."c) <> 1 Then Return False
199 | Return txt.Length = Aggregate c In From t In txt.ToCharArray Take While t >= "0"c AndAlso t <= "9"c OrElse t = "." Into Count
200 | End Function
201 |
202 | Function IsNumeric(txt As String) As Boolean
203 | If txt.StartsWith("-") OrElse txt.StartsWith("+") Then txt = txt.Substring(1)
204 | If txt.Length = 0 Then Return False
205 | Return txt.Length = Aggregate c In From t In txt.ToCharArray Take While t >= "0"c AndAlso t <= "9"c OrElse t = "." Into Count
206 | End Function
207 |
208 | Function ContainsEachTrim(Main As IEnumerable(Of String), Second As IEnumerable(Of String)) As Boolean
209 | For Each s In Second
210 | If Main.Contains(s.Trim) Then
211 | Return True
212 | End If
213 | Next
214 | Return False
215 | End Function
216 | End Module
217 | End Namespace
218 |
--------------------------------------------------------------------------------
/Utility/ValueConverter.vb:
--------------------------------------------------------------------------------
1 | Public Module ValueConverter
2 |
3 | Public Function ToYesNo(Value As Boolean) As String
4 | Return If(Value, "yes", "no")
5 | End Function
6 | End Module
7 |
--------------------------------------------------------------------------------
/Utility/WritableKeyValuePair.vb:
--------------------------------------------------------------------------------
1 | Public Class WritableKeyValuePair
2 | Public Property Key As String
3 | Public Property Value As String
4 | Sub New(K As String, V As String)
5 | Key = K
6 | Value = V
7 | End Sub
8 | End Class
9 |
--------------------------------------------------------------------------------
/ViewModels/AnalizeSourceViewModel.vb:
--------------------------------------------------------------------------------
1 | Public Class AnalizeSourceViewModel
2 | Public Event DataChanged(DocumentCategory$, NewData$)
3 | Dim _RulesText$ = "", _ArtText$ = "", _AIText$ = "", _Ra2Text$ = ""
4 | Public Property RulesText$
5 | Get
6 | Return _RulesText
7 | End Get
8 | Set
9 | _RulesText = Value.Replace(vbCr, "").Replace(vbLf, vbCrLf)
10 | IsRulesInvalid = True
11 | RaiseEvent DataChanged("Rules", Value)
12 | End Set
13 | End Property
14 | Public Property Ra2Text$
15 | Get
16 | Return _Ra2Text
17 | End Get
18 | Set
19 | _Ra2Text = Value.Replace(vbCr, "").Replace(vbLf, vbCrLf)
20 | IsRa2Invalid = True
21 | RaiseEvent DataChanged("Ra2", Value)
22 | End Set
23 | End Property
24 | Public Property ArtText$
25 | Get
26 | Return _ArtText
27 | End Get
28 | Set
29 | _ArtText = Value.Replace(vbCr, "").Replace(vbLf, vbCrLf)
30 | IsArtInvalid = True
31 | RaiseEvent DataChanged("Art", Value)
32 | End Set
33 | End Property
34 | Public Property AIText$
35 | Get
36 | Return _AIText
37 | End Get
38 | Set
39 | _AIText = Value.Replace(vbCr, "").Replace(vbLf, vbCrLf)
40 | IsAIInvalid = True
41 | RaiseEvent DataChanged("AI", Value)
42 | End Set
43 | End Property
44 | Public Property IsRulesInvalid As Boolean = True
45 | Public Property IsArtInvalid As Boolean = True
46 | Public Property IsAIInvalid As Boolean = True
47 | Public Property IsRa2Invalid As Boolean = True
48 | Sub New()
49 |
50 | End Sub
51 | Sub New(RulesText$, ArtText$, AIText$, Ra2Text$)
52 | Me.RulesText = RulesText
53 | Me.Ra2Text = Ra2Text
54 | Me.ArtText = ArtText
55 | Me.AIText = AIText
56 | End Sub
57 | End Class
58 |
--------------------------------------------------------------------------------
/ViewModels/CodeGenerateLogViewModel.vb:
--------------------------------------------------------------------------------
1 | Imports System.Collections.ObjectModel
2 | Public Class CodeGenerateLogViewModel
3 | Inherits SingleInstance(Of CodeGenerateLogViewModel)
4 | Public Property IniDiagnostics As New ObservableCollection(Of WidenIniAnalysisInfo)
5 | Public Property GenerateLog As New ObservableCollection(Of String)
6 | End Class
7 |
--------------------------------------------------------------------------------
/ViewModels/CodeSnippetGroup.vb:
--------------------------------------------------------------------------------
1 | Public Class CodeSnippetGroup
2 | Public ReadOnly Property Name$
3 | Public ReadOnly Property Group As IList(Of CodeSnippet)
4 | Sub New(Name$, Group As IList(Of CodeSnippet))
5 | Me.Name = Name
6 | Me.Group = Group
7 | End Sub
8 | End Class
9 |
--------------------------------------------------------------------------------
/ViewModels/DocumentsViewModel.vb:
--------------------------------------------------------------------------------
1 | Namespace Document
2 | Public MustInherit Class DocumentsViewModel(Of TObservable As {IList(Of IniBlock), New})
3 | Public ReadOnly Property RulesDocument As IniDocument(Of TObservable)
4 | Public ReadOnly Property ArtDocument As IniDocument(Of TObservable)
5 | Public ReadOnly Property AIDocument As IniDocument(Of TObservable)
6 | Public ReadOnly Property Ra2Document As IniDocument(Of TObservable)
7 | Public ReadOnly Property Help As New HelpProviderManager
8 | Public ReadOnly Property HelpUtil As New HelpDataProvider
9 | WithEvents ViewSource As AnalizeSourceViewModel
10 | Sub New(ViewSource As AnalizeSourceViewModel)
11 | Me.ViewSource = ViewSource
12 | RulesDocument = New IniDocument(Of TObservable)(ViewSource.RulesText)
13 | ArtDocument = New IniDocument(Of TObservable)(ViewSource.ArtText)
14 | AIDocument = New IniDocument(Of TObservable)(ViewSource.AIText)
15 | Ra2Document = New IniDocument(Of TObservable)(ViewSource.Ra2Text)
16 | End Sub
17 |
18 | Private Sub ViewSource_DataChanged(DocumentCategory As String, NewData As String) Handles ViewSource.DataChanged
19 | Select Case DocumentCategory
20 | Case DocumentCategories.Rules
21 | RulesDocument.Text = NewData
22 | Case DocumentCategories.AI
23 | AIDocument.Text = NewData
24 | Case DocumentCategories.Art
25 | ArtDocument.Text = NewData
26 | Case DocumentCategories.Ra2
27 | Ra2Document.Text = NewData
28 | End Select
29 | End Sub
30 | End Class
31 | End Namespace
32 |
--------------------------------------------------------------------------------
/ViewModels/FindSymbolResult.vb:
--------------------------------------------------------------------------------
1 | Public Class FindSymbolResult
2 | Public ReadOnly Property FileName$
3 | Public ReadOnly Property MainKey$
4 | Public ReadOnly Property LineNumber%
5 | Public ReadOnly Property Text$
6 | Public ReadOnly Property Remark$
7 | Sub New(FileName$, MainKey$, LineNumber%, Text$, Remark$)
8 | Me.FileName = FileName
9 | Me.MainKey = MainKey
10 | Me.LineNumber = LineNumber
11 | Me.Text = Text
12 | Me.Remark = Remark
13 | End Sub
14 | End Class
15 |
--------------------------------------------------------------------------------
/ViewModels/IniFilesViewModel.vb:
--------------------------------------------------------------------------------
1 | Imports System.Collections.ObjectModel
2 | Imports Nukepayload2.Ra2CodeAnalysis
3 |
4 | Public Class IniFilesViewModel
5 | Inherits SingleInstance(Of IniFilesViewModel)
6 | Public Property IniFileItems As New ObservableCollection(Of IniFileItem)
7 | End Class
8 |
--------------------------------------------------------------------------------
/ViewModels/ProjectGenerateViewModel.vb:
--------------------------------------------------------------------------------
1 | Public Class ProjectGenerateViewModel
2 |
3 | End Class
4 |
--------------------------------------------------------------------------------
/ViewModels/ProjectSetupViewModel.vb:
--------------------------------------------------------------------------------
1 | Imports Nukepayload2.CodeAnalysis
2 |
3 | Public Class ProjectSetupViewModel
4 | Inherits SingleInstance(Of ProjectSetupViewModel)
5 | Public Property ProjectBasicInformation As New ProjectBasicInformation
6 | End Class
7 |
--------------------------------------------------------------------------------
/ViewModels/SingleInstance.vb:
--------------------------------------------------------------------------------
1 | Public Class SingleInstance(Of T As SingleInstance(Of T))
2 | Public Shared ReadOnly Property Instance As T
3 | Sub New()
4 | _Instance = CType(Me, T)
5 | End Sub
6 | End Class
7 |
--------------------------------------------------------------------------------
/ViewModels/WidenIniAnalysisInfo.vb:
--------------------------------------------------------------------------------
1 | Imports System.Text
2 | Public Enum ErrorFilters
3 | None
4 | Message
5 | Warning
6 | MessageWarning
7 | Fault
8 | MessageFault
9 | WarningFault
10 | All
11 | End Enum
12 | Public Enum SeverityLevels
13 | Message
14 | Warning
15 | [Error]
16 | End Enum
17 |
18 | Public Class WidenIniAnalysisInfo
19 | Public Enum FileNames
20 | Rules
21 | Art
22 | AI
23 | Ra2
24 | End Enum
25 | Public Shared Function GetWidenIniAnalysisInfo(Result As INIAnalyzeResult, FileName As String, Optional AggOpt As Integer = ErrorFilters.All) As IEnumerable(Of WidenIniAnalysisInfo)
26 | Dim tmp As New List(Of WidenIniAnalysisInfo)
27 | If CBool(AggOpt And ErrorFilters.Message) Then
28 | For Each tp In Result.Message
29 | tmp.Add(New WidenIniAnalysisInfo(SeverityLevels.Message, tp.LineNumber, tp.Description, tp.LineText, tp.MainKey, FileName))
30 | Next
31 | End If
32 | If CBool(AggOpt And ErrorFilters.Warning) Then
33 | For Each tp In Result.Warning
34 | tmp.Add(New WidenIniAnalysisInfo(SeverityLevels.Warning, tp.LineNumber, tp.Description, tp.LineText, tp.MainKey, FileName))
35 | Next
36 | End If
37 | If CBool(AggOpt And ErrorFilters.Fault) Then
38 | For Each tp In Result.Fault
39 | tmp.Add(New WidenIniAnalysisInfo(SeverityLevels.Error, tp.LineNumber, tp.Description, tp.LineText, tp.MainKey, FileName))
40 | Next
41 | End If
42 | Return tmp
43 | End Function
44 |
45 | Public ReadOnly Property InfoType As SeverityLevels
46 |
47 | Public ReadOnly Property LineNumber As Integer
48 |
49 | Public ReadOnly Property Description As String
50 |
51 | Public ReadOnly Property Text As String
52 |
53 | Public ReadOnly Property MainKey As String
54 |
55 | Public ReadOnly Property FileName As String
56 | Sub New(InfoType As SeverityLevels, LineNumber As Integer, Description As String, Text As String, MainKey As String, FileName As String)
57 | Me.InfoType = InfoType
58 | Me.LineNumber = LineNumber
59 | Me.Description = Description
60 | Me.Text = Text
61 | Me.MainKey = MainKey
62 | Me.FileName = FileName
63 | End Sub
64 | End Class
65 |
--------------------------------------------------------------------------------