Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
global-json-file: global.json
- run: ./gradlew :buildPlugin --no-daemon
- run: ./gradlew :buildResharperPlugin --no-daemon
- uses: actions/upload-artifact@v4
Expand All @@ -47,5 +47,5 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
global-json-file: global.json
- run: ./gradlew :testDotNet --no-daemon
2 changes: 1 addition & 1 deletion .github/workflows/Deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
global-json-file: global.json
- name: Publish Rider Package
run: ./gradlew :publishPlugin -PBuildConfiguration="Release" -PPluginVersion="${{ github.ref_name }}" -PPublishToken="${{ secrets.PUBLISH_TOKEN }}"
env:
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ packages/
**/NuGetLocks/*

# Example Mod
example-mod/.idea
example-mod/.idea

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions .run/Build Plugin.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
<option name="PROGRAM_PARAMETERS" value="/c gradlew.bat :buildPlugin -x compileDotNet" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="JAVA_HOME" value="$USER_HOME$\.jdks\corretto-17.0.7" />
</envs>
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<method v="2">
<option name="Build Solution" enabled="true" />
Expand Down
4 changes: 2 additions & 2 deletions .run/Build ReSharper Plugin.run.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Build ReSharper Plugin" type="RunNativeExe" factoryName="Native Executable">
<option name="EXE_PATH" value="C:\Windows\System32\cmd.exe" />
<option name="PROGRAM_PARAMETERS" value="/c powershell -ExecutionPolicy ByPass -NoProfile -File buildPlugin.ps1" />
<option name="PROGRAM_PARAMETERS" value="/c gradlew.bat :buildResharperPlugin" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<method v="2" />
</configuration>
</component>
</component>
42 changes: 30 additions & 12 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<Project>

<PropertyGroup>
<SdkVersion>2026.1.*</SdkVersion>
<!-- THE Rider/ReSharper version. Everything else is derived from it: WaveVersion below, and Gradle's ProductVersion
(build.gradle.kts reads this line). Exact NuGet form, e.g. 2026.1.5.2 / 2026.2.0-rc01 / 2026.3.0-eap02.
See docs/rider-version.md. -->
<SdkVersion>2026.1.5.2</SdkVersion>

<Title>Rimworld Development Environment</Title>
<Description>Bring the intelligence of your IDE to Rimworld XML files. Use information backed by Rimworlds DLL file to autocomplete your XML, Ctrl+Click into the C# that your XML gets translated into and see what options you have when adding items in your mods!</Description>
Expand All @@ -22,6 +25,7 @@

<BaseIntermediateOutputPath>obj\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
<DefaultItemExcludes>$(DefaultItemExcludes);obj\**</DefaultItemExcludes>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<OutputPath>bin\$(MSBuildProjectName)\$(Configuration)\</OutputPath>
</PropertyGroup>

Expand All @@ -30,19 +34,20 @@
</PropertyGroup>

<PropertyGroup>
<WaveVersionBase>$(SdkVersion.Substring(2,2))$(SdkVersion.Substring(5,1))</WaveVersionBase>
<WaveVersion>$(WaveVersionBase).0.0$(SdkVersion.Substring(8))</WaveVersion>
<UpperWaveVersion>$(WaveVersionBase).9999.0</UpperWaveVersion>
<!-- 2026.1.5.2 / 2026.3.0-eap02 -> 261 / 263. The Wave package only publishes <wave>.0.0 (no EAP builds). -->
<WaveVersionBase>$([System.Text.RegularExpressions.Regex]::Replace($(SdkVersion), '^\d\d(\d\d)\.(\d+)\..*$', '$1$2'))</WaveVersionBase>
<WaveVersion>$(WaveVersionBase).0.0</WaveVersion>
</PropertyGroup>

<!--
The Harmony project compiles nothing and only exists to fetch 0Harmony.dll, so it doesn't need the SDK.

The SDK's IncludeAssets deliberately omits `compile`, so Annotations/Lifetimes/RdFramework have to be referenced
directly to be usable in code. The SDK pins exact versions of them that don't track SdkVersion (e.g. the 2026.1.5
SDK wants Lifetimes [2026.1.2] and Annotations [2025.2.0]), so these references trip NU1608. Pinning them to match
instead would turn into a hard NU1605 downgrade error whenever a newer SDK is picked up by the floating SdkVersion,
so the warning is suppressed. Rider supplies its own copies at runtime either way.
The SDK's IncludeAssets deliberately omits `compile`, and that flows to its dependencies, so Annotations/Lifetimes/
RdFramework aren't compile references by default. ReferenceSdkCoreLibraries (below) adds the versions the SDK's own
graph resolved, instead of us pinning them: ~150 SDK packages require one exact version of each, which changes with
every SDK line and used to have to be matched by hand.

NU1608: our System.Diagnostics.TraceSource 4.3.0 (net8.0 build) is newer than the exact 4.0.0 one SDK package pins.

NU1701/NU1603 come from JetBrains' own packages inside the SDK graph (.NET Framework-only packages, missing native
package versions) and aren't actionable from here. Package-level NoWarn doesn't reach transitive packages, hence
Expand All @@ -60,9 +65,6 @@
</PropertyGroup>

<ItemGroup Condition="'$(MSBuildProjectName)' != 'ReSharperPlugin.RimworldDev.Harmony'">
<PackageReference Include="JetBrains.Annotations" Version="2025.2.4" />
<PackageReference Include="JetBrains.Lifetimes" Version="$(SdkVersion)" />
<PackageReference Include="JetBrains.RdFramework" Version="$(SdkVersion)" />
<!-- Resolves an NU1107 version conflict between SDK packages. On net10.0 it's part of the framework and gets pruned
(NU1510 if referenced), so it's only needed for the net8.0 ReSharper build. -->
<PackageReference Include="System.Diagnostics.TraceSource" Version="4.3.0" Condition="'$(TargetFramework)' != 'net10.0'" />
Expand All @@ -80,4 +82,20 @@
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

<!--
Compile against exactly the JetBrains.Lifetimes/RdFramework/Annotations the SDK resolved (their runtime assets, which
IncludeAssets keeps). They are the rd/annotations the SDK was built against, so the versions follow SdkVersion
automatically. Private=false: Rider/ReSharper supply these at runtime; this is only for the compiler.
-->
<Target Name="ReferenceSdkCoreLibraries" AfterTargets="ResolvePackageAssets"
Condition="'$(MSBuildProjectName)' != 'ReSharperPlugin.RimworldDev.Harmony'">
<ItemGroup>
<_SdkCoreLibrary Include="@(RuntimeCopyLocalItems)"
Condition="'%(RuntimeCopyLocalItems.Extension)' == '.dll' And ('%(RuntimeCopyLocalItems.NuGetPackageId)' == 'JetBrains.Lifetimes' Or '%(RuntimeCopyLocalItems.NuGetPackageId)' == 'JetBrains.RdFramework' Or '%(RuntimeCopyLocalItems.NuGetPackageId)' == 'JetBrains.Annotations')" />
<Reference Include="@(_SdkCoreLibrary->'%(Filename)')" HintPath="%(_SdkCoreLibrary.FullPath)" Private="false" />
</ItemGroup>
<Error Condition="'@(_SdkCoreLibrary->Count())' != '3'"
Text="Expected JetBrains.Lifetimes, JetBrains.RdFramework and JetBrains.Annotations in the SDK's resolved packages, found: @(_SdkCoreLibrary->'%(NuGetPackageId) %(NuGetPackageVersion)')" />
</Target>

</Project>
44 changes: 41 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ import com.jetbrains.plugin.structure.base.utils.isFile
import org.apache.tools.ant.taskdefs.condition.Os
import org.jetbrains.intellij.platform.gradle.Constants
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import rimworlddev.gradle.RiderVersion
import rimworlddev.gradle.RiderVersionsTask
import rimworlddev.gradle.RunVisualStudioTask

plugins {
id("java")
alias(libs.plugins.kotlinJvm)
id("org.jetbrains.intellij.platform") version "2.15.0" // https://github.com/JetBrains/gradle-intellij-plugin/releases
id("me.filippov.gradle.jvm.wrapper") version "0.16.0"
alias(libs.plugins.intellijPlatform)
alias(libs.plugins.gradleJvmWrapper)
}


Expand All @@ -24,8 +27,43 @@ extra["isWindows"] = isWindows

val DotnetSolution: String by project
val BuildConfiguration: String by project
val ProductVersion: String by project

// The Rider version comes from one place: <SdkVersion> in Directory.Build.props (NuGet form). Read through a provider so
// the configuration cache is invalidated when that file changes. -PProductVersion=... still overrides it.
val SdkVersion: String = providers.fileContents(layout.projectDirectory.file("Directory.Build.props")).asText
.map { props ->
RiderVersion.sdkVersionPattern.find(props)?.groupValues?.get(1)
?: throw GradleException("No <SdkVersion> found in Directory.Build.props")
}
.get()

val ProductVersion: String = providers.gradleProperty("ProductVersion").orNull ?: RiderVersion.mavenVersion(SdkVersion)

// ./gradlew versions [--to <target>] [--usage]: buildSrc/src/main/kotlin/rimworlddev/gradle/RiderVersionsTask.kt
val versions by tasks.registering(RiderVersionsTask::class) {
group = "help"
description = "Lists Rider versions (every build of the current EAP, last three stable lines) or switches with --to.\n\n" +
RiderVersionsTask.USAGE
propsFile.set(layout.projectDirectory.file("Directory.Build.props"))
}

val DotnetPluginId: String by project

// ./gradlew runVisualStudio [--plan] [--clean] [--reinstall] [--usage]: the ReSharper build in an experimental Visual
// Studio instance. Generic task in buildSrc/src/main/kotlin/rimworlddev/gradle/RunVisualStudioTask.kt; everything
// specific to this plugin is set here.
val runVisualStudio by tasks.registering(RunVisualStudioTask::class) {
group = "run"
description = "Runs the ReSharper build of the plugin in an experimental Visual Studio instance (Windows).\n\n" +
RunVisualStudioTask.USAGE
pluginId.set(DotnetPluginId)
projectFile.set(layout.projectDirectory.file("src/dotnet/$DotnetPluginId/$DotnetPluginId.csproj"))
sdkVersion.set(SdkVersion)
rootSuffix.set("RimworldDev")
installerDirectory.set(layout.buildDirectory.dir("installer"))
packageOutputDirectory.set(layout.projectDirectory.dir("output"))
logFile.set(layout.projectDirectory.file("ReSharper.log"))
}
val RiderPluginId: String by project
val PublishToken: String by project
val PluginVersion: String by project
Expand Down
12 changes: 0 additions & 12 deletions buildPlugin.ps1

This file was deleted.

4 changes: 4 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
plugins {
// Compiles against the Gradle API with Gradle's own embedded Kotlin, like the build scripts themselves.
`kotlin-dsl`
}
15 changes: 15 additions & 0 deletions buildSrc/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Build logic for the root build: Kotlin in src/main/kotlin is compiled before the root build scripts are evaluated and is
// on their classpath (see RiderVersionsTask). Same mirrors as the root settings.gradle.kts.
pluginManagement {
repositories {
maven("https://cache-redirector.jetbrains.com/plugins.gradle.org")
maven("https://cache-redirector.jetbrains.com/maven-central")
}
}

dependencyResolutionManagement {
repositories {
maven("https://cache-redirector.jetbrains.com/maven-central")
maven("https://cache-redirector.jetbrains.com/plugins.gradle.org")
}
}
56 changes: 56 additions & 0 deletions buildSrc/src/main/kotlin/rimworlddev/gradle/RiderVersion.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package rimworlddev.gradle

/**
* A JetBrains.Rider.SDK version as NuGet publishes it: 2026.1.5.2, 2026.2.0-rc01, 2026.3.0-eap02.
*
* `<SdkVersion>` in Directory.Build.props is written in this form; the companion holds the mappings to the other
* version formats derived from it (the IntelliJ Platform's Maven version, ReSharper's wave).
*/
data class RiderVersion(val raw: String, val numbers: List<Int>, val preKind: String?, val preNumber: Int) :
Comparable<RiderVersion> {

/** "2026.1" */
val line get() = "${numbers[0]}.${numbers[1]}"
val stable get() = preKind == null

override fun compareTo(other: RiderVersion): Int {
for (i in 0 until maxOf(numbers.size, other.numbers.size)) {
val c = numbers.getOrElse(i) { 0 }.compareTo(other.numbers.getOrElse(i) { 0 })
if (c != 0) return c
}
// A release sorts after its prereleases; an RC after the EAPs.
fun rank(v: RiderVersion) = when (v.preKind) { null -> 2; "rc" -> 1; else -> 0 }
return compareValuesBy(this, other, { rank(it) }, { it.preNumber })
}

companion object {
private val pattern = Regex("""^(\d{4}(?:\.\d+){1,3})(?:-(eap|rc)(\d+))?$""", RegexOption.IGNORE_CASE)

/** `<SdkVersion>…</SdkVersion>` in Directory.Build.props; group 1 is the version. */
val sdkVersionPattern = Regex("""<SdkVersion>\s*([^<\s]+)\s*</SdkVersion>""")

fun parse(raw: String) = pattern.matchEntire(raw)?.let { m ->
RiderVersion(raw, m.groupValues[1].split('.').map(String::toInt),
m.groupValues[2].lowercase().ifEmpty { null }, m.groupValues[3].toIntOrNull() ?: 0)
}

/** "2026.1" -> sortable number, so 2026.10 would sort after 2026.9. */
fun lineKey(line: String) = line.split('.').let { it[0].toInt() * 1000 + it[1].toInt() }

/**
* Rider's Maven artifacts (what the IntelliJ Platform Gradle Plugin downloads) name the same builds differently
* from NuGet: 2026.3.0-eap02 -> 2026.3-EAP2-SNAPSHOT, 2026.2.0-rc01 -> 2026.2-RC1-SNAPSHOT, 2026.2.0 -> 2026.2,
* 2026.1.5.2 -> 2026.1.5.2.
*/
fun mavenVersion(sdkVersion: String): String {
Regex("""^(\d+\.\d+)\.0-(eap|rc)0*(\d+)$""", RegexOption.IGNORE_CASE).matchEntire(sdkVersion)?.let { m ->
return "${m.groupValues[1]}-${m.groupValues[2].uppercase()}${m.groupValues[3]}-SNAPSHOT"
}
Regex("""^(\d+\.\d+)\.0$""").matchEntire(sdkVersion)?.let { return it.groupValues[1] }
return sdkVersion
}

/** Same derivation as WaveVersionBase in Directory.Build.props: 2026.3.0-eap02 -> 263. */
fun waveBase(sdkVersion: String) = Regex("""^\d\d(\d\d)\.(\d+)\..*$""").replace(sdkVersion, "$1$2")
}
}
Loading
Loading