Skip to content

Commit 81412d9

Browse files
refactor into C# mod
1 parent 32cebe2 commit 81412d9

File tree

10 files changed

+261
-57
lines changed

10 files changed

+261
-57
lines changed

.github/workflows/ci.yml

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,57 @@
1-
name: Release
1+
name: mycoolmod-ci
22

33
on:
44
push:
55
branches: [ "master" ]
6+
tags: [ "v*" ]
67

78
jobs:
89
build:
910
runs-on: ubuntu-latest
10-
11+
strategy:
12+
matrix:
13+
bepinex-version: [5, 6]
14+
steps:
15+
- name: Checkout source
16+
uses: actions/checkout@v3
17+
- name: Checkout libcs2
18+
uses: actions/checkout@v3
19+
with:
20+
repository: Captain-Of-Coit/libcs2
21+
token: ${{ secrets.GH_PAT }}
22+
path: libcs2/
23+
- name: Install .NET Core
24+
uses: actions/setup-dotnet@v3
25+
with:
26+
dotnet-version: 6.0.x
27+
- name: Install NodeJS
28+
uses: actions/setup-node@v3
29+
with:
30+
node-version: '21.1.0'
31+
- name: Build (BepInEx ${{ matrix.bepinex-version }})
32+
run: make package-unix BEPINEX_VERSION=${{ matrix.bepinex-version }}
33+
- name: Upload Artifact (BepInEx ${{ matrix.bepinex-version }})
34+
uses: actions/upload-artifact@v3
35+
with:
36+
name: built-code-${{ matrix.bepinex-version }}
37+
path: dist/*.dll
38+
publish:
39+
needs: build
40+
if: startsWith(github.ref, 'refs/tags/v')
41+
runs-on: ubuntu-latest
1142
steps:
12-
- uses: actions/checkout@v4
13-
- name: Build project
14-
uses: actions/setup-node@v3
15-
with:
16-
node-version: '21.1.0'
17-
- run: make build
18-
- name: Upload Artifact
19-
uses: actions/upload-artifact@v3
20-
with:
21-
name: release-${{ github.sha }}
22-
path: dist/*.transpiled.js
43+
- name: Checkout source
44+
uses: actions/checkout@v3
45+
- name: Download built artifact
46+
uses: actions/download-artifact@v3
47+
with:
48+
name: built-code-5
49+
path: dist/
50+
- name: Debug
51+
run: ls && ls dist/
52+
- name: Download tcli
53+
run: |
54+
curl -L https://github.com/thunderstore-io/thunderstore-cli/releases/download/0.2.1/tcli-0.2.1-linux-x64.tar.gz -o tcli.tar.gz
55+
tar -xzf tcli.tar.gz
56+
- name: Publish with tcli
57+
run: ./tcli-0.2.1-linux-x64/tcli publish --token=${{ secrets.TS_TOKEN }}

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
dist/
2-
node_modules/
2+
bin/
3+
obj/
4+
ts-build/
5+
node_modules/
6+
.vs/

CityMonitor.csproj

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<!--
4+
Base csproj setup. Change the AssemblyName, RootNamespace and Description to
5+
accurately describe your mod.
6+
7+
Increment the Version property when you release a new version.
8+
-->
9+
10+
<PropertyGroup>
11+
<TargetFramework>netstandard2.1</TargetFramework>
12+
<AssemblyName>CityMonitor</AssemblyName>
13+
<RootNamespace>CityMonitor</RootNamespace>
14+
<Description>A little panel with the most important metrics of your city without having to browse around</Description>
15+
<Version>0.2.0</Version>
16+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
17+
<LangVersion>latest</LangVersion>
18+
<RestoreAdditionalProjectSources>
19+
https://api.nuget.org/v3/index.json;
20+
https://nuget.bepinex.dev/v3/index.json;
21+
https://nuget.samboy.dev/v3/index.json
22+
</RestoreAdditionalProjectSources>
23+
<!-- Copies references we make to 3rd party library for distributions -->
24+
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
25+
<!-- Suppress the version conflict warnings for System.Net.Http and System.IO.Compression -->
26+
<NoWarn>MSB3277</NoWarn>
27+
</PropertyGroup>
28+
29+
<!--
30+
Uncomment this PropertyGroup to let the C# project read DLLs directory from your game directory,
31+
and also allow the build to move the mod DLLs into the plugins directory for you
32+
-->
33+
<PropertyGroup>
34+
<Cities2_Location>C:\Program Files (x86)\Steam\steamapps\common\Cities Skylines II</Cities2_Location>
35+
</PropertyGroup>
36+
37+
<!--
38+
This is all the references to the DLLs directly from your game directory. The Cities2_Location property
39+
above needs to be uncommented for this to work
40+
-->
41+
<ItemGroup>
42+
<Reference Include="$(Cities2_Location)\Cities2_Data\Managed\Colossal.*.dll" Private="False"/>
43+
<Reference Include="$(Cities2_Location)\Cities2_Data\Managed\Game.dll" Private="False"/>
44+
<Reference Include="$(Cities2_Location)\Cities2_Data\Managed\Unity.*.dll" Private="False"/>
45+
</ItemGroup>
46+
47+
<!--
48+
If you want to embed things directly into your mod, instead of shipping multiple files
49+
-->
50+
<ItemGroup>
51+
<EmbeddedResource Include="dist/bundle.js" />
52+
</ItemGroup>
53+
54+
<!--
55+
This ItemGroup is used in CI for the game DLLs.
56+
Make sure you have a private `libcs2` repository with the appropriate DLLs for this to work.
57+
DO NOT make the proprietary DLLs for the game public, as the files are owned by PDX/CO.
58+
-->
59+
<ItemGroup>
60+
<Reference Include="libcs2/Colossal.*.dll" Private="False"/>
61+
<Reference Include="libcs2/Game.dll" Private="False"/>
62+
<Reference Include="libcs2/Unity.*.dll" Private="False"/>
63+
</ItemGroup>
64+
65+
<!--
66+
Everything related to BepInEx and Harmony
67+
-->
68+
<ItemGroup>
69+
<PackageReference Include="BepInEx.PluginInfoProps" Version="2.0.0" />
70+
<PackageReference Include="HarmonyX" Version="2.10.2"></PackageReference>
71+
<PackageReference Include="UnityEngine.Modules" Version="2022.3.7" IncludeAssets="compile" />
72+
<PackageReference Include="HookUILib" Version="0.1.0" />
73+
</ItemGroup>
74+
75+
<!-- Set the default value for BepInExVersion -->
76+
<PropertyGroup>
77+
<BepInExVersion Condition="'$(BepInExVersion)' == ''">5</BepInExVersion>
78+
</PropertyGroup>
79+
80+
<!--
81+
These ItemGroups and PropertyGroups gives you compatibility with both BepInEx 5 and 6.
82+
Mainly for the purposes of being able to distribute your mods on Thunderstore, and
83+
making it easy to upgrade in the future to proper versions.
84+
-->
85+
<ItemGroup Condition="'$(BepInExVersion)' == '6'">
86+
<PackageReference Include="BepInEx.Unity.Mono" Version="6.0.0-be.*" />
87+
</ItemGroup>
88+
89+
<ItemGroup Condition="'$(BepInExVersion)' == '5'">
90+
<PackageReference Include="BepInEx.Core" Version="5.4.21" IncludeAssets="compile"/>
91+
</ItemGroup>
92+
93+
<PropertyGroup Condition="'$(BepInExVersion)' == '6'">
94+
<DefineConstants>$(DefineConstants);BEPINEX_V6</DefineConstants>
95+
</PropertyGroup>
96+
97+
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
98+
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.2"
99+
PrivateAssets="all" />
100+
</ItemGroup>
101+
102+
<!--
103+
This will try to copy the resulting DLLs from builds directly into your game directory,
104+
as long as we're not in CI
105+
-->
106+
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(CI)' != 'true'">
107+
<Exec
108+
Command="if not exist &quot;$(Cities2_Location)\BepInEx\plugins\$(ProjectName)&quot; mkdir &quot;$(Cities2_Location)\BepInEx\plugins\$(ProjectName)&quot;&#xD;&#xA;copy /Y &quot;$(TargetDir)0Harmony.dll&quot; &quot;$(Cities2_Location)\BepInEx\plugins\$(ProjectName)\0Harmony.dll&quot;&#xD;&#xA;copy /Y &quot;$(TargetDir)$(ProjectName).dll&quot; &quot;$(Cities2_Location)\BepInEx\plugins\$(ProjectName)\$(ProjectName).dll&quot;" />
109+
</Target>
110+
</Project>

Makefile

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
all: build
2+
BEPINEX_VERSION = 6
23

3-
install-ui-deps:
4-
@npm ci
4+
clean:
5+
@rm -r dist/
6+
@dotnet clean
57

6-
bundle: install-ui-deps
7-
@node build.mjs
8+
restore:
9+
@dotnet restore
810

9-
build: bundle
10-
@echo Build complete.
11+
build-ui:
12+
@npm install
13+
@npx esbuild ui_src/city_monitor.jsx --bundle --outfile=dist/bundle.js
1114

12-
package-pwsh: build
13-
@powershell -Command "$$version = (Get-Content package.json | ConvertFrom-Json).version; Compress-Archive -Path './dist/city_monitor.transpiled.js' -DestinationPath \"./dist/release-$$version.zip\""
15+
build: clean restore build-ui
16+
@dotnet build /p:BepInExVersion=$(BEPINEX_VERSION)
17+
18+
package-win: build
19+
@-mkdir dist
20+
@cmd /c copy /y "bin\Debug\netstandard2.1\0Harmony.dll" "dist\"
21+
@cmd /c copy /y "bin\Debug\netstandard2.1\CityMonitor.dll" "dist\"
22+
@echo Packaged to dist/
1423

1524
package-unix: build
16-
@version=$$(jq -r '.version' package.json); \
17-
zip ./dist/release-$$version.zip ./dist/city_monitor.transpiled.js
25+
@-mkdir dist
26+
@cp bin/Debug/netstandard2.1/0Harmony.dll dist
27+
@cp bin/Debug/netstandard2.1/CityMonitor.dll dist
28+
@echo Packaged to dist/

Plugin.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System.Linq;
2+
using System.Reflection;
3+
using BepInEx;
4+
using HarmonyLib;
5+
using HookUILib.Core;
6+
using UnityEngine;
7+
8+
#if BEPINEX_V6
9+
using BepInEx.Unity.Mono;
10+
#endif
11+
12+
namespace CityMonitor {
13+
[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)]
14+
public class Plugin : BaseUnityPlugin {
15+
private void Awake() {
16+
Logger.LogInfo($"Plugin {MyPluginInfo.PLUGIN_GUID} is loaded!");
17+
18+
var harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), MyPluginInfo.PLUGIN_GUID + "_Cities2Harmony");
19+
var patchedMethods = harmony.GetPatchedMethods().ToArray();
20+
21+
Logger.LogInfo($"Plugin {MyPluginInfo.PLUGIN_GUID} made patches! Patched methods: " + patchedMethods.Length);
22+
23+
foreach (var patchedMethod in patchedMethods) {
24+
Logger.LogInfo($"Patched method: {patchedMethod.Module.Name}:{patchedMethod.Name}");
25+
}
26+
}
27+
}
28+
public class CityMonitorUI : UIExtension {
29+
public new readonly string extensionID = "example.city_monitor";
30+
public new readonly string extensionContent;
31+
public new readonly ExtensionType extensionType = ExtensionType.Panel;
32+
33+
public CityMonitorUI() {
34+
this.extensionContent = this.LoadEmbeddedResource("CityMonitor.dist.bundle.js");
35+
}
36+
}
37+
}

build.mjs

Lines changed: 0 additions & 11 deletions
This file was deleted.

icon.png

109 KB
Loading

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

thunderstore.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[config]
2+
schemaVersion = "0.0.1"
3+
4+
[package]
5+
namespace = "CaptainOfCoit"
6+
name = "CityMonitor"
7+
versionNumber = "0.2.0"
8+
description = "A little panel with the most important metrics of your city without having to browse around"
9+
websiteUrl = "https://thunderstore.io"
10+
containsNsfwContent = false
11+
12+
[package.dependencies]
13+
BepInEx-BepInExPack = "5.4.2100"
14+
CaptainOfCoit-HookUI = "0.3.1"
15+
16+
[build]
17+
icon = "./icon.png"
18+
readme = "./README.md"
19+
outdir = "./ts-build"
20+
21+
[publish]
22+
repository = "https://thunderstore.io"
23+
communities = [ "cities-skylines-ii", ]
24+
categories = [ "mods" ]

src/city_monitor.jsx renamed to ui_src/city_monitor.jsx

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react'
2-
import {$Meter, $Panel, useEngineData} from 'hookui-framework'
2+
import {$Meter, $Panel, useDataUpdate} from 'hookui-framework'
33

44
const engineEffect = (react, event, setFunc) => {
55
const updateEvent = event + ".update"
@@ -25,33 +25,27 @@ const engineEffect = (react, event, setFunc) => {
2525
}, [])
2626
}
2727

28-
// Used when max value (right) indicates that everything is OK ("Electricity Availability" for example)
29-
const maxGood = 'linear-gradient(to right,rgba(255, 78, 24, 1.000000) 0.000000%, rgba(255, 78, 24, 1.000000) 40.000000%, rgba(255, 131, 27, 1.000000) 40.000000%, rgba(255, 131, 27, 1.000000) 50.000000%, rgba(99, 181, 6, 1.000000) 50.000000%, rgba(99, 181, 6, 1.000000) 60.000000%, rgba(71, 148, 54, 1.000000) 60.000000%, rgba(71, 148, 54, 1.000000) 100.000000%)'
30-
// Used when min value (left) indicates everything is fine ("Fire Hazard" for example)
31-
const minGood = 'linear-gradient(to right,rgba(71, 148, 54, 1.000000) 0.000000%, rgba(99, 181, 6, 1.000000) 66.000000%, rgba(255, 131, 27, 1.000000) 33.000000%, rgba(255, 78, 24, 1.000000) 100.000000%)'
32-
3328
const eventsToListenTo = [
34-
['Electricity', 'electricityInfo.electricityAvailability', maxGood],
35-
['Water Availability', 'waterInfo.waterAvailability', maxGood],
36-
['Sewage', 'waterInfo.sewageAvailability', maxGood],
37-
['Landfill Usage', 'garbageInfo.landfillAvailability', maxGood],
29+
['Electricity', 'electricityInfo.electricityAvailability', "maxGood"],
30+
['Water Availability', 'waterInfo.waterAvailability', "maxGood"],
31+
['Sewage', 'waterInfo.sewageAvailability', "maxGood"],
32+
['Landfill Usage', 'garbageInfo.landfillAvailability', "maxGood"],
3833
// TODO Incineration
39-
['Healthcare Availability', 'healthcareInfo.healthcareAvailability', maxGood],
40-
['Average Health', 'healthcareInfo.averageHealth', maxGood],
41-
['Cemetery Availability', 'healthcareInfo.cemeteryAvailability', maxGood],
34+
['Healthcare Availability', 'healthcareInfo.healthcareAvailability', "maxGood"],
35+
['Average Health', 'healthcareInfo.averageHealth', "maxGood"],
36+
['Cemetery Availability', 'healthcareInfo.cemeteryAvailability', "maxGood"],
4237
// TODO Crematorium
43-
['Fire Hazard', 'fireAndRescueInfo.averageFireHazard', minGood],
44-
['Crime Rate', 'policeInfo.averageCrimeProbability', minGood],
45-
['Jail Availability', 'policeInfo.jailAvailability', maxGood],
46-
['Elementary School Availability', 'educationInfo.elementaryAvailability', maxGood],
47-
['High School Availability', 'educationInfo.highSchoolAvailability', maxGood],
48-
['College Availability', 'educationInfo.collegeAvailability', maxGood],
49-
['University Availability', 'educationInfo.universityAvailability', maxGood],
38+
['Fire Hazard', 'fireAndRescueInfo.averageFireHazard', "minGood"],
39+
['Crime Rate', 'policeInfo.averageCrimeProbability', "minGood"],
40+
['Jail Availability', 'policeInfo.jailAvailability', "maxGood"],
41+
['Elementary School Availability', 'educationInfo.elementaryAvailability', "maxGood"],
42+
['High School Availability', 'educationInfo.highSchoolAvailability', "maxGood"],
43+
['College Availability', 'educationInfo.collegeAvailability', "maxGood"],
44+
['University Availability', 'educationInfo.universityAvailability', "maxGood"],
5045
// TODO Employment Rate
5146
]
5247

5348
const $CityMonitor = ({react}) => {
54-
5549
const meters = eventsToListenTo.map(([label, eventName, gradient]) => {
5650
const [read, set] = react.useState(-1)
5751
engineEffect(react, eventName, set)

0 commit comments

Comments
 (0)