diff --git a/.gitignore b/.gitignore index 6e79db6..e31eb74 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ build/ /*/package/*.zip /*/package/patchers/ /*/package/plugins/ + +# UpdateGameDlls build-time lock file (created by UpdateGameDlls.ps1) +AssemblyFromGame/.update.lock diff --git a/AGENTS.md b/AGENTS.md index fc315c3..7646c9f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -78,13 +78,16 @@ Individual `.csproj` files only declare what is unique to that project (GUID, ve ### Automatic Game DLL Update -`AssemblyFromGame/` holds publicized copies of two game DLLs used as compile-time references. They are refreshed automatically **before every build** by the `UpdateGameDlls` MSBuild target, which calls `UpdateGameDlls.ps1`. +`AssemblyFromGame/` holds publicized copies of two game DLLs used as compile-time references. They are refreshed automatically **once per solution build** by the `UpdateGameDlls` MSBuild target, which calls `UpdateGameDlls.ps1`. + +The target runs only when the `UXAssist` project is being built (the designated trigger project), or when either DLL is missing from `AssemblyFromGame/`. This prevents redundant executions and file-write conflicts when projects are built in parallel (`dotnet build -m`). The PowerShell script additionally acquires an exclusive file lock (`AssemblyFromGame/.update.lock`) so that the rare case where the `!Exists` fallback triggers multiple projects concurrently is also handled safely. The script: 1. Reads the Steam installation path from the Windows registry (`HKCU\Software\Valve\Steam`). 2. Parses `steamapps/libraryfolders.vdf` to find the library that contains DSP (AppID `1366540`). 3. Locates `/DSPGAME_Data/Managed/`. -4. For each DLL (`Assembly-CSharp.dll`, `UnityEngine.UI.dll`): if the game copy is newer than the local copy, runs `assembly-publicizer … --strip --overwrite` to regenerate the local file and stamps it with the source timestamp. +4. Acquires an exclusive file lock on `AssemblyFromGame/.update.lock` (waits up to 60 s). +5. For each DLL (`Assembly-CSharp.dll`, `UnityEngine.UI.dll`): if the game copy is newer than the local copy, runs `assembly-publicizer … --strip --overwrite` to regenerate the local file and stamps it with the source timestamp. The target can also be run explicitly: ``` diff --git a/AssemblyFromGame/Assembly-CSharp.dll b/AssemblyFromGame/Assembly-CSharp.dll index 3d58485..a8efb84 100644 Binary files a/AssemblyFromGame/Assembly-CSharp.dll and b/AssemblyFromGame/Assembly-CSharp.dll differ diff --git a/Directory.Build.targets b/Directory.Build.targets index 4e217a3..f95247f 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -12,7 +12,22 @@ Requires assembly-publicizer on PATH or in %USERPROFILE%\.dotnet\tools\: dotnet tool install -g BepInEx.AssemblyPublicizer.Cli --> - + + var consume = (byte)Math.Min(DarkFogItemsInVoid[itemIdx], 4); if (consume < 4) { - var metaverse = propertySystem.GetItemAvaliableProperty(_clusterSeedKey, 6006); - if (metaverse > 0) + var metaverseLong = propertySystem.GetItemAvaliableProperty(_clusterSeedKey, 6006); + if (metaverseLong > 0L) { - if (metaverse > 10) - metaverse = 10; + var metaverse = metaverseLong > 10 ? 10 : (int)metaverseLong; propertySystem.AddItemConsumption(_clusterSeedKey, 6006, metaverse); var mainPlayer = GameMain.mainPlayer; GameMain.history.AddPropertyItemConsumption(6006, metaverse, true); diff --git a/UpdateGameDlls.ps1 b/UpdateGameDlls.ps1 index 9fadf80..8d01c38 100644 --- a/UpdateGameDlls.ps1 +++ b/UpdateGameDlls.ps1 @@ -130,7 +130,34 @@ if (-not $publicizer) { } # --------------------------------------------------------------------------- -# 5. For each DLL: compare timestamps, publicize if game copy is newer +# 5. Acquire an exclusive file lock so that concurrent MSBuild nodes (triggered +# by the !Exists fallback condition) cannot write the DLLs simultaneously. +# The lock is released automatically in the finally block. +# --------------------------------------------------------------------------- +$lockPath = Join-Path $OUTPUT_DIR '.update.lock' +$lockStream = $null +try { + # Retry loop: wait up to 60 s for the lock (another node may be updating) + $deadline = [DateTime]::UtcNow.AddSeconds(60) + while ($true) { + try { + $lockStream = [System.IO.File]::Open( + $lockPath, + [System.IO.FileMode]::OpenOrCreate, + [System.IO.FileAccess]::ReadWrite, + [System.IO.FileShare]::None) + break # lock acquired + } catch [System.IO.IOException] { + if ([DateTime]::UtcNow -ge $deadline) { + Write-Warning 'UpdateGameDlls: Timed out waiting for lock; skipping DLL update.' + exit 0 + } + Start-Sleep -Milliseconds 200 + } + } + +# --------------------------------------------------------------------------- +# 6. For each DLL: compare timestamps, publicize if game copy is newer # --------------------------------------------------------------------------- $updated = 0 foreach ($dll in $DSP_DLLS) { @@ -176,3 +203,8 @@ if ($updated -gt 0) { } else { Write-Host 'UpdateGameDlls: All DLLs are up-to-date.' } + +} finally { + # Release the exclusive lock regardless of success or failure + if ($lockStream) { $lockStream.Close() } +}