-
Notifications
You must be signed in to change notification settings - Fork 227
Expand file tree
/
Copy pathFabricProjectSettingsWizard.kt
More file actions
407 lines (348 loc) · 15.7 KB
/
Copy pathFabricProjectSettingsWizard.kt
File metadata and controls
407 lines (348 loc) · 15.7 KB
1
2
3
4
5
6
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
/*
* Minecraft Dev for IntelliJ
*
* https://minecraftdev.org
*
* Copyright (c) 2020 minecraft-dev
*
* MIT License
*/
package com.demonwav.mcdev.platform.fabric.creator
import com.demonwav.mcdev.asset.PlatformAssets
import com.demonwav.mcdev.creator.MinecraftModuleWizardStep
import com.demonwav.mcdev.creator.MinecraftProjectCreator
import com.demonwav.mcdev.creator.ValidatedField
import com.demonwav.mcdev.creator.ValidatedFieldType.LIST
import com.demonwav.mcdev.creator.ValidatedFieldType.NON_BLANK
import com.demonwav.mcdev.platform.PlatformType
import com.demonwav.mcdev.platform.fabric.EntryPoint
import com.demonwav.mcdev.platform.fabric.util.FabricConstants
import com.demonwav.mcdev.sideonly.Side
import com.demonwav.mcdev.util.License
import com.demonwav.mcdev.util.SemanticVersion
import com.demonwav.mcdev.util.modUpdateStep
import com.demonwav.mcdev.util.toPackageName
import com.extracraftx.minecraft.templatemakerfabric.data.DataProvider
import com.intellij.openapi.ui.ComboBox
import com.intellij.ui.CollectionComboBoxModel
import com.intellij.ui.ToolbarDecorator
import com.intellij.ui.table.JBTable
import com.intellij.util.ui.EditableModel
import com.intellij.util.ui.table.ComboBoxTableCellEditor
import java.awt.event.ActionListener
import java.awt.event.ComponentAdapter
import java.awt.event.ComponentEvent
import java.util.Collections
import java.util.Locale
import javax.swing.JCheckBox
import javax.swing.JComboBox
import javax.swing.JComponent
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.JProgressBar
import javax.swing.JTextField
import javax.swing.table.AbstractTableModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.swing.Swing
import org.apache.commons.lang.WordUtils
class FabricProjectSettingsWizard(private val creator: MinecraftProjectCreator) : MinecraftModuleWizardStep() {
// Initialize ALL custom fields in createUIComponents, otherwise they are null until after that point!
@ValidatedField(NON_BLANK)
private lateinit var modNameField: JTextField
private lateinit var panel: JPanel
private lateinit var title: JLabel
private lateinit var descriptionField: JTextField
@ValidatedField(LIST)
private lateinit var authorsField: JTextField
private lateinit var websiteField: JTextField
private lateinit var repositoryField: JTextField
private lateinit var minecraftVersionBox: JComboBox<String>
private lateinit var loaderVersionBox: JComboBox<String>
private lateinit var yarnVersionBox: JComboBox<String>
private lateinit var loomVersionBox: JComboBox<String>
private lateinit var licenseBox: JComboBox<License>
private lateinit var useFabricApiCheckbox: JCheckBox
private lateinit var fabricApiBox: JComboBox<String>
private lateinit var environmentBox: JComboBox<String>
private lateinit var mixinsCheckbox: JCheckBox
private lateinit var decompileMcCheckbox: JCheckBox
private lateinit var loadingBar: JProgressBar
private lateinit var minecraftVersionLabel: JLabel
private lateinit var entryPointsTable: JPanel
private lateinit var entryPoints: ArrayList<EntryPoint>
private lateinit var tableModel: EntryPointTableModel
private lateinit var yarnWarning: JLabel
private lateinit var errorLabel: JLabel
private var config: FabricProjectConfig? = null
private var dataProvider: DataProvider? = null
private var currentJob: Job? = null
private var initializedEntryPointsTable = false
private val minecraftBoxActionListener: ActionListener = ActionListener {
yarnVersionBox.selectedItem = null
loaderVersionBox.selectedItem = null
loomVersionBox.selectedItem = null
fabricApiBox.selectedItem = null
updateForm()
}
init {
yarnWarning.isVisible = false
}
fun createUIComponents() {
entryPoints = arrayListOf()
tableModel = EntryPointTableModel(entryPoints)
val entryPointsTable = JBTable(tableModel)
entryPointsTable.setDefaultEditor(EntryPoint.Type::class.java, ComboBoxTableCellEditor.INSTANCE)
fun resizeColumns() {
val model = entryPointsTable.columnModel
val totalWidth = model.totalColumnWidth
model.getColumn(0).preferredWidth = (totalWidth * 0.1).toInt()
model.getColumn(1).preferredWidth = (totalWidth * 0.1).toInt()
model.getColumn(2).preferredWidth = (totalWidth * 0.3).toInt()
model.getColumn(3).preferredWidth = (totalWidth * 0.3).toInt()
model.getColumn(4).preferredWidth = (totalWidth * 0.2).toInt()
}
resizeColumns()
entryPointsTable.addComponentListener(object : ComponentAdapter() {
override fun componentResized(e: ComponentEvent?) {
resizeColumns()
}
})
this.entryPointsTable = ToolbarDecorator.createDecorator(entryPointsTable).createPanel()
licenseBox = ComboBox(CollectionComboBoxModel(enumValues<License>().toList()))
licenseBox.selectedItem = License.MIT
}
override fun getComponent(): JComponent {
return panel
}
override fun updateStep() {
val (conf, buildSystem) = modUpdateStep<FabricProjectConfig>(creator, modNameField) ?: return
config = conf
if (creator.configs.indexOf(conf) != 0) {
modNameField.isEditable = false
}
if (!initializedEntryPointsTable) {
val packageName = "${buildSystem.groupId.toPackageName()}.${buildSystem.artifactId.toPackageName()}"
var className = buildSystem.artifactId.replace('-', ' ').let { WordUtils.capitalize(it) }.replace(" ", "")
if (creator.configs.size > 1) {
className += PlatformType.FABRIC.normalName
}
entryPoints.add(
EntryPoint(
"main",
EntryPoint.Type.CLASS,
"$packageName.$className",
FabricConstants.MOD_INITIALIZER
)
)
entryPoints.add(
EntryPoint(
"client",
EntryPoint.Type.CLASS,
"$packageName.client.${className}Client",
FabricConstants.CLIENT_MOD_INITIALIZER
)
)
tableModel.fireTableDataChanged()
entryPointsTable.revalidate()
initializedEntryPointsTable = true
}
title.icon = PlatformAssets.FABRIC_ICON_2X
title.text = "<html><font size=\"5\">Fabric Settings</font></html>"
minecraftVersionLabel.text = "Minecraft Version"
if (dataProvider != null || currentJob?.isActive == true) {
return
}
currentJob = updateVersions()
}
private val mcVersion: String?
get() = minecraftVersionBox.selectedItem as? String
private val yarnVersion: String?
get() = yarnVersionBox.selectedItem as? String
private val loomVersion: String?
get() = loomVersionBox.selectedItem as? String
private val loaderVersion: String?
get() = loaderVersionBox.selectedItem as? String
private val fabricApiVersion: String?
get() = fabricApiBox.selectedItem as? String
override fun validate(): Boolean {
return super.validate() && !loadingBar.isVisible
}
override fun isStepVisible(): Boolean {
return creator.configs.any { it is FabricProjectConfig }
}
override fun onStepLeaving() {
currentJob?.cancel()
}
fun error() {
errorLabel.isVisible = true
loadingBar.isIndeterminate = false
loadingBar.isVisible = false
}
override fun updateDataModel() {
val conf = config ?: return
conf.pluginName = modNameField.text
conf.description = descriptionField.text
conf.website = websiteField.text
conf.setAuthors(authorsField.text)
conf.modRepo = repositoryField.text
conf.yarnVersion = yarnVersion ?: "$mcVersion+build.1"
val yarnVersionObj = dataProvider?.yarnVersions?.firstOrNull { it.name == yarnVersion }
conf.yarnClassifier = if (yarnVersionObj?.hasV2Mappings == false) {
null
} else {
"v2"
}
conf.mcVersion = mcVersion ?: ""
val normalizedMcVersion = dataProvider?.getNormalizedMinecraftVersion(mcVersion)?.normalized
conf.semanticMcVersion = normalizedMcVersion?.let { SemanticVersion.parse(it) } ?: SemanticVersion.release()
val loaderVer = loaderVersion
if (loaderVer != null) {
conf.loaderVersion = SemanticVersion.parse(loaderVer)
}
val api = if (useFabricApiCheckbox.isSelected) {
dataProvider?.fabricApiVersions?.firstOrNull { it.name == fabricApiVersion }
} else {
null
}
conf.apiVersion = api?.mavenVersion?.let { SemanticVersion.parse(it) }
conf.apiMavenLocation = api?.mavenLocation
conf.gradleVersion = when (dataProvider?.loomVersions?.firstOrNull { it.name == loomVersion }?.gradle) {
4 -> SemanticVersion.release(4, 10, 3)
5 -> SemanticVersion.release(5, 6, 4)
else -> SemanticVersion.release(6, 5, 1)
}
val loomVer = loomVersion
if (loomVer != null) {
conf.loomVersion = SemanticVersion.parse(loomVer)
}
conf.environment = when ((environmentBox.selectedItem as? String)?.toLowerCase(Locale.ROOT)) {
"client" -> Side.CLIENT
"server" -> Side.SERVER
else -> Side.BOTH
}
conf.license = licenseBox.selectedItem as? License
conf.entryPoints = entryPoints.filter { it.valid }
conf.mixins = mixinsCheckbox.isSelected
conf.genSources = decompileMcCheckbox.isSelected
}
private fun updateVersions() = CoroutineScope(Dispatchers.Swing).launch {
loadingBar.isIndeterminate = true
loadingBar.isVisible = true
try {
dataProvider = downloadVersions()
updateForm()
} catch (e: Exception) {
e.printStackTrace()
error()
}
loadingBar.isIndeterminate = false
loadingBar.isVisible = false
currentJob = null
}
private suspend fun downloadVersions(): DataProvider? = coroutineScope {
// prefetch the data
val dataProvider = DataProvider()
val minecraftVersionJob = async(Dispatchers.IO) { runCatching { dataProvider.minecraftVersions }.getOrNull() }
val fabricApiVersionJob = async(Dispatchers.IO) { runCatching { dataProvider.fabricApiVersions }.getOrNull() }
val yarnVersionJob = async(Dispatchers.IO) { runCatching { dataProvider.yarnVersions }.getOrNull() }
val loomVersionJob = async(Dispatchers.IO) { runCatching { dataProvider.loomVersions }.getOrNull() }
val loaderVersionJob = async(Dispatchers.IO) { runCatching { dataProvider.loaderVersions }.getOrNull() }
minecraftVersionJob.await() ?: return@coroutineScope null
fabricApiVersionJob.await() ?: return@coroutineScope null
yarnVersionJob.await() ?: return@coroutineScope null
loomVersionJob.await() ?: return@coroutineScope null
loaderVersionJob.await() ?: return@coroutineScope null
return@coroutineScope dataProvider
}
private fun updateForm() {
val dp = dataProvider ?: return
val mcVer = mcVersion ?: dp.minecraftVersions.firstOrNull { it.stable }?.name
val mcVerObj = dp.minecraftVersions.firstOrNull { it.name == mcVer }
val yarnVer = yarnVersion ?: mcVerObj?.let { mvo ->
dp.getFilteredYarnVersions(mvo).firstOrNull()?.name
}
val yarnVerObj = dp.yarnVersions.firstOrNull { it.name == yarnVer }
val loomVer = loomVersion ?: yarnVerObj?.let { dp.getDefaultLoomVersion(it) }?.name
val loomVerObj = dp.loomVersions.firstOrNull { it.name == loomVer }
val loaderVer = loaderVersion ?: loomVerObj?.let { lvo ->
dp.getFilteredLoaderVersions(lvo).firstOrNull()?.name
}
val fabricVer = fabricApiVersion ?: mcVerObj?.let { mvo ->
dp.getDefaultFabricApiVersion(mvo)
}?.let { dp.sortedFabricApiVersions[it] }?.name
minecraftVersionBox.removeActionListener(minecraftBoxActionListener)
minecraftVersionBox.model = CollectionComboBoxModel(dp.minecraftVersions.map { it.name })
minecraftVersionBox.selectedItem = mcVer
minecraftVersionBox.addActionListener(minecraftBoxActionListener)
yarnVersionBox.model = CollectionComboBoxModel(dp.yarnVersions.map { it.name })
yarnVersionBox.selectedItem = yarnVer
loomVersionBox.model = CollectionComboBoxModel(dp.loomVersions.map { it.name })
loomVersionBox.selectedItem = loomVer
loaderVersionBox.model = CollectionComboBoxModel(dp.loaderVersions.map { it.name })
loaderVersionBox.selectedItem = loaderVer
fabricApiBox.model = CollectionComboBoxModel(dp.fabricApiVersions.map { it.name })
fabricApiBox.selectedItem = fabricVer
useFabricApiCheckbox.isSelected = fabricVer != null
}
class EntryPointTableModel(private val entryPoints: ArrayList<EntryPoint>) : AbstractTableModel(), EditableModel {
override fun getColumnName(col: Int) = when (col) {
0 -> "Category"
1 -> "Type"
2 -> "Class"
3 -> "Interface"
else -> "Method Name"
}
override fun getRowCount() = entryPoints.size
override fun getColumnCount() = 5
override fun getValueAt(row: Int, col: Int): Any? = when (col) {
0 -> entryPoints[row].category
1 -> entryPoints[row].type
2 -> entryPoints[row].className
3 -> entryPoints[row].interfaceName
else -> entryPoints[row].methodName
}
override fun isCellEditable(row: Int, col: Int): Boolean {
return col != 4 || entryPoints.getOrNull(row)?.type == EntryPoint.Type.METHOD
}
override fun setValueAt(value: Any?, row: Int, col: Int) {
when (col) {
0 -> entryPoints[row] = entryPoints[row].copy(category = value.toString())
1 -> entryPoints[row] = entryPoints[row].copy(type = parseEntryPointType(value))
2 -> entryPoints[row] = entryPoints[row].copy(className = value.toString())
3 -> entryPoints[row] = entryPoints[row].copy(interfaceName = value.toString())
4 -> entryPoints[row] = entryPoints[row].copy(methodName = value.toString())
}
fireTableCellUpdated(row, col)
}
private fun parseEntryPointType(value: Any?): EntryPoint.Type {
return when (value) {
is EntryPoint.Type -> value
else -> enumValues<EntryPoint.Type>().firstOrNull {
it.name.equals(value.toString(), ignoreCase = true)
} ?: EntryPoint.Type.CLASS
}
}
override fun removeRow(idx: Int) {
entryPoints.removeAt(idx)
}
override fun exchangeRows(oldIndex: Int, newIndex: Int) {
Collections.swap(entryPoints, oldIndex, newIndex)
}
override fun canExchangeRows(oldIndex: Int, newIndex: Int) = true
override fun addRow() {
entryPoints.add(EntryPoint("", EntryPoint.Type.CLASS, "", "", ""))
}
override fun getColumnClass(col: Int): Class<*> {
return if (col == 1) {
EntryPoint.Type::class.java
} else {
String::class.java
}
}
}
}