8ef5bfbe21
- Implemented TechnicianHiring class to register and manage extra technician employees. - Defined a struct TechDef to encapsulate technician properties such as ID, name, description, salary, and required reputation. - Added methods for initializing technicians, handling hiring and firing events, and restoring technicians on load. - Included logging for tracking registration, hiring, firing, and restoration processes.
270 lines
10 KiB
PowerShell
270 lines
10 KiB
PowerShell
#Requires -Version 7
|
|
<#
|
|
.SYNOPSIS
|
|
Builds all framework, plugin, and mod projects, then packages each into a
|
|
Steamworks-compatible Workshop project folder under <GameRoot>/workshop.
|
|
|
|
.DESCRIPTION
|
|
Each Workshop project gets:
|
|
<project>/content/<target path>/<assembly>.dll
|
|
<project>/metadata.json (title, description, tags, visibility)
|
|
|
|
The content/ folder mirrors the game directory structure:
|
|
- Framework DLL: content/Mods/
|
|
- Plugin DLLs: content/greg/Plugins/
|
|
- Standalone mods: content/Mods/
|
|
|
|
After running, use the WorkshopUploader UI or CLI to publish each folder.
|
|
|
|
.EXAMPLE
|
|
pwsh -File scripts/Deploy-Release-ToWorkshop.ps1
|
|
.EXAMPLE
|
|
pwsh -File scripts/Deploy-Release-ToWorkshop.ps1 -GameDir 'D:\Games\Data Center'
|
|
#>
|
|
param(
|
|
[string]$GameDir = $env:DATA_CENTER_GAME_DIR,
|
|
[ValidateSet('Release', 'Debug')]
|
|
[string]$Configuration = 'Release'
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot '..')
|
|
. (Join-Path $PSScriptRoot 'Resolve-WorkshopUploaderMonorepoDir.ps1')
|
|
$WuDir = Resolve-WorkshopUploaderMonorepoDir $RepoRoot
|
|
|
|
#region Resolve game directory
|
|
if ([string]::IsNullOrWhiteSpace($GameDir)) {
|
|
$findScript = Join-Path $RepoRoot 'scripts\Find-DataCenterPath.ps1'
|
|
if (Test-Path -LiteralPath $findScript) {
|
|
$GameDir = (& pwsh -NoProfile -ExecutionPolicy Bypass -File $findScript | Select-Object -Last 1).Trim()
|
|
}
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($GameDir) -or -not (Test-Path -LiteralPath $GameDir)) {
|
|
throw "Data Center game folder not found. Pass -GameDir or set DATA_CENTER_GAME_DIR."
|
|
}
|
|
$WorkshopRoot = Join-Path $GameDir 'workshop'
|
|
Write-Host "[workshop] WorkshopRoot = $WorkshopRoot"
|
|
#endregion
|
|
|
|
#region Build all projects
|
|
$AllProjects = @(
|
|
'framework\gregCore.csproj',
|
|
'plugins\greg.Plugin.AssetExporter\greg.Plugin.AssetExporter.csproj',
|
|
'plugins\greg.Plugin.WebUIBridge\greg.Plugin.WebUIBridge.csproj',
|
|
'plugins\greg.Plugin.PlayerModels\greg.Plugin.PlayerModels.csproj',
|
|
'mods\greg.ConsoleInputGuard\greg.ConsoleInputGuard.csproj',
|
|
'mods\greg.Mod.GregifyEmployees\greg.GregifyEmployees.csproj',
|
|
'mods\greg.Mod.HexLabelMod\greg.HexLabelMod.csproj'
|
|
)
|
|
|
|
foreach ($rel in $AllProjects) {
|
|
$proj = Join-Path $RepoRoot $rel
|
|
Write-Host "[workshop] Building $proj"
|
|
& dotnet build $proj -c $Configuration
|
|
if ($LASTEXITCODE -ne 0) { throw "Build failed: $proj" }
|
|
}
|
|
#endregion
|
|
|
|
$tfm = 'net6.0'
|
|
|
|
function New-WorkshopProject {
|
|
param(
|
|
[string]$Name,
|
|
[string]$DllSource,
|
|
[string]$ContentSubPath,
|
|
[string]$Title,
|
|
[string]$Description,
|
|
[string[]]$Tags
|
|
)
|
|
|
|
$projectDir = Join-Path $WorkshopRoot $Name
|
|
$contentDir = Join-Path $projectDir "content\$ContentSubPath"
|
|
New-Item -ItemType Directory -Path $contentDir -Force | Out-Null
|
|
|
|
$dllName = [System.IO.Path]::GetFileName($DllSource)
|
|
Copy-Item -LiteralPath $DllSource -Destination (Join-Path $contentDir $dllName) -Force
|
|
Write-Host "[workshop] $DllSource -> $contentDir\$dllName"
|
|
|
|
$meta = @{
|
|
publishedFileId = 0
|
|
title = $Title
|
|
description = $Description
|
|
visibility = 'Private'
|
|
previewImageRelativePath = 'preview.png'
|
|
tags = $Tags
|
|
} | ConvertTo-Json -Depth 3
|
|
|
|
$metaPath = Join-Path $projectDir 'metadata.json'
|
|
if (-not (Test-Path -LiteralPath $metaPath)) {
|
|
Set-Content -LiteralPath $metaPath -Value $meta -Encoding utf8NoBOM
|
|
Write-Host "[workshop] Created $metaPath"
|
|
} else {
|
|
Write-Host "[workshop] Skipped $metaPath (already exists)"
|
|
}
|
|
}
|
|
|
|
#region Package framework
|
|
$fwDll = Join-Path $RepoRoot "framework\bin\$Configuration\$tfm\gregCore.dll"
|
|
$hooksJson = Join-Path $RepoRoot "assets\greg_hooks.json"
|
|
if (-not (Test-Path -LiteralPath $fwDll)) { throw "Missing: $fwDll" }
|
|
New-WorkshopProject `
|
|
-Name 'gregCore' `
|
|
-DllSource $fwDll `
|
|
-ContentSubPath 'Mods' `
|
|
-Title 'gregCore' `
|
|
-Description 'Core modding framework for Data Center. Required by all greg-based mods and plugins.' `
|
|
-Tags @('modded', 'melonloader', 'framework', 'greg')
|
|
|
|
$fwProjDir = Join-Path $WorkshopRoot 'gregCore'
|
|
$fwContentDir = Join-Path $fwProjDir 'content\Mods'
|
|
Copy-Item -LiteralPath $hooksJson -Destination (Join-Path $fwContentDir 'greg_hooks.json') -Force
|
|
Write-Host "[workshop] Copied greg_hooks.json to $fwContentDir"
|
|
#endregion
|
|
|
|
#region Package plugins
|
|
$plugins = @(
|
|
@{ Id = 'greg.Plugin.AssetExporter'; Folder = 'plugins\greg.Plugin.AssetExporter'; Desc = 'Asset export utilities for Data Center modding.' },
|
|
@{ Id = 'greg.Plugin.WebUIBridge'; Folder = 'plugins\greg.Plugin.WebUIBridge'; Desc = 'Web UI bridge plugin for in-game browser-based interfaces.' },
|
|
@{ Id = 'greg.Plugin.PlayerModels'; Folder = 'plugins\greg.Plugin.PlayerModels'; Desc = 'Custom player models plugin for Data Center.' }
|
|
)
|
|
|
|
foreach ($p in $plugins) {
|
|
$dll = Join-Path $RepoRoot "$($p.Folder)\bin\$Configuration\$tfm\$($p.Id).dll"
|
|
if (-not (Test-Path -LiteralPath $dll)) { throw "Missing: $dll" }
|
|
New-WorkshopProject `
|
|
-Name $p.Id `
|
|
-DllSource $dll `
|
|
-ContentSubPath 'greg\Plugins' `
|
|
-Title $p.Id `
|
|
-Description $p.Desc `
|
|
-Tags @('modded', 'greg', 'plugin')
|
|
}
|
|
#endregion
|
|
|
|
#region Package mods
|
|
$mods = @(
|
|
@{ Name = 'greg.ConsoleInputGuard'; Folder = 'mods\greg.ConsoleInputGuard'; Assembly = 'greg.ConsoleInputGuard'; Desc = 'Console input guard mod for Data Center.' },
|
|
@{ Name = 'greg.GregifyEmployees'; Folder = 'mods\greg.Mod.GregifyEmployees'; Assembly = 'greg.GregifyEmployees'; Desc = 'Gregify Employees gameplay mod.' },
|
|
@{ Name = 'greg.HexLabelMod'; Folder = 'mods\greg.Mod.HexLabelMod'; Assembly = 'greg.HexLabelMod'; Desc = 'Hex label display mod for Data Center.' }
|
|
)
|
|
|
|
foreach ($m in $mods) {
|
|
$dll = Join-Path $RepoRoot "$($m.Folder)\bin\$Configuration\$tfm\$($m.Assembly).dll"
|
|
if (-not (Test-Path -LiteralPath $dll)) { throw "Missing: $dll" }
|
|
New-WorkshopProject `
|
|
-Name $m.Name `
|
|
-DllSource $dll `
|
|
-ContentSubPath 'Mods' `
|
|
-Title $m.Name `
|
|
-Description $m.Desc `
|
|
-Tags @('modded', 'melonloader', 'mod')
|
|
}
|
|
#endregion
|
|
|
|
#region Package Gregtools Modmanager (WorkshopUploader self-contained)
|
|
$wuProj = Join-Path $RepoRoot "$WuDir\WorkshopUploader.csproj"
|
|
Write-Host "[workshop] Publishing $wuProj (self-contained, trimmed)"
|
|
& dotnet publish $wuProj -c $Configuration
|
|
if ($LASTEXITCODE -ne 0) { throw "WorkshopUploader publish failed" }
|
|
|
|
$wuPublish = Join-Path $RepoRoot "$WuDir\bin\$Configuration\net9.0-windows10.0.19041.0\win10-x64\publish"
|
|
if (-not (Test-Path -LiteralPath $wuPublish)) { throw "Missing: $wuPublish" }
|
|
|
|
$mmProject = Join-Path $WorkshopRoot 'Gregtools Modmanager'
|
|
$mmContent = Join-Path $mmProject 'content'
|
|
New-Item -ItemType Directory -Path $mmContent -Force | Out-Null
|
|
Copy-Item -Path (Join-Path $wuPublish '*') -Destination $mmContent -Recurse -Force
|
|
|
|
#region Strip unnecessary files from Workshop content
|
|
$beforeSize = (Get-ChildItem $mmContent -Recurse -File | Measure-Object Length -Sum).Sum
|
|
Write-Host "[workshop] Pre-cleanup size: $([math]::Round($beforeSize / 1MB, 1)) MB"
|
|
|
|
# Debug / diagnostics DLLs not needed at runtime
|
|
$debugDlls = @(
|
|
'mscordaccore.dll',
|
|
'mscordaccore_amd64_amd64_*.dll',
|
|
'mscordbi.dll',
|
|
'Microsoft.DiaSymReader.Native.amd64.dll',
|
|
'clrgcexp.dll'
|
|
)
|
|
foreach ($pattern in $debugDlls) {
|
|
Get-ChildItem $mmContent -Filter $pattern | ForEach-Object {
|
|
Write-Host "[workshop] Removing debug: $($_.Name)"
|
|
Remove-Item $_.FullName -Force
|
|
}
|
|
}
|
|
|
|
# Features the app doesn't use
|
|
$unusedDlls = @(
|
|
'msquic.dll',
|
|
'Microsoft.Windows.AI.*.dll',
|
|
'Microsoft.Windows.Widgets.dll',
|
|
'Microsoft.Security.Authentication.OAuth.dll',
|
|
'Microsoft.Windows.Media.Capture.dll'
|
|
)
|
|
foreach ($pattern in $unusedDlls) {
|
|
Get-ChildItem $mmContent -Filter $pattern | ForEach-Object {
|
|
Write-Host "[workshop] Removing unused: $($_.Name)"
|
|
Remove-Item $_.FullName -Force
|
|
}
|
|
}
|
|
|
|
# Unused .winmd metadata files (keep only UI/Graphics/Runtime essentials)
|
|
$keepWinmd = @(
|
|
'Microsoft.UI.Xaml.winmd',
|
|
'Microsoft.UI.winmd',
|
|
'Microsoft.UI.Text.winmd',
|
|
'Microsoft.Graphics.winmd',
|
|
'Microsoft.Windows.ApplicationModel.WindowsAppRuntime.winmd',
|
|
'Microsoft.Windows.ApplicationModel.DynamicDependency.winmd',
|
|
'Microsoft.Windows.AppLifecycle.winmd',
|
|
'Microsoft.Windows.ApplicationModel.Resources.winmd',
|
|
'Microsoft.Windows.System.Power.winmd'
|
|
)
|
|
Get-ChildItem $mmContent -Filter '*.winmd' | Where-Object { $_.Name -notin $keepWinmd } | ForEach-Object {
|
|
Write-Host "[workshop] Removing winmd: $($_.Name)"
|
|
Remove-Item $_.FullName -Force
|
|
}
|
|
|
|
# WinUI locale folders: keep only app-supported locales + en-us
|
|
$keepLocales = @('de','de-DE','en-us','en-GB','es','es-ES','it','it-IT',
|
|
'ja','ja-JP','pl','pl-PL','ru','ru-RU','zh','zh-CN','zh-TW','zh-Hans','zh-Hant')
|
|
Get-ChildItem $mmContent -Directory |
|
|
Where-Object { $_.Name -match '^[a-z]{2}(-[A-Za-z]+)?$' -and $_.Name -notin $keepLocales } |
|
|
ForEach-Object {
|
|
Remove-Item $_.FullName -Recurse -Force
|
|
}
|
|
$removedLocales = 110 - $keepLocales.Count
|
|
Write-Host "[workshop] Removed ~$removedLocales unused WinUI locale folders"
|
|
|
|
$afterSize = (Get-ChildItem $mmContent -Recurse -File | Measure-Object Length -Sum).Sum
|
|
Write-Host "[workshop] Post-cleanup size: $([math]::Round($afterSize / 1MB, 1)) MB (saved $([math]::Round(($beforeSize - $afterSize) / 1MB, 1)) MB)"
|
|
#endregion
|
|
|
|
Write-Host "[workshop] WorkshopUploader -> $mmContent"
|
|
|
|
$mmMeta = @{
|
|
publishedFileId = 0
|
|
title = 'Gregtools Modmanager'
|
|
description = 'All-in-one Mod Manager and Workshop Uploader for Data Center. Browse, install, and publish Steam Workshop content. Manage mod dependencies (MelonLoader, gregCore, plugins) in one place.'
|
|
visibility = 'Private'
|
|
previewImageRelativePath = 'preview.png'
|
|
tags = @('tool', 'modmanager', 'workshop', 'greg')
|
|
} | ConvertTo-Json -Depth 3
|
|
|
|
$mmMetaPath = Join-Path $mmProject 'metadata.json'
|
|
if (-not (Test-Path -LiteralPath $mmMetaPath)) {
|
|
Set-Content -LiteralPath $mmMetaPath -Value $mmMeta -Encoding utf8NoBOM
|
|
Write-Host "[workshop] Created $mmMetaPath"
|
|
} else {
|
|
Write-Host "[workshop] Skipped $mmMetaPath (already exists)"
|
|
}
|
|
#endregion
|
|
|
|
Write-Host ""
|
|
Write-Host "[workshop] Done. All projects packaged under: $WorkshopRoot"
|
|
Write-Host "[workshop] Use WorkshopUploader to publish each folder to Steam."
|
|
|