Skip to content

Commit

Permalink
Merge branch 'dev' into fix-reddash-uptransition
Browse files Browse the repository at this point in the history
  • Loading branch information
0x0ade authored Sep 28, 2021
2 parents 6e7eadc + 618b611 commit ddfdda8
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 61 deletions.
3 changes: 2 additions & 1 deletion Celeste.Mod.mm/Mod/Everest/Everest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public static partial class Everest {
/// <summary>
/// The currently present Celeste version combined with the currently installed Everest build.
/// </summary>
public static string VersionCelesteString => $"{Celeste.Instance.Version}-{(Flags.IsFNA ? "fna" : "xna")} [Everest: {BuildString}]";
// we cannot use Everest.Flags.IsFNA at this point because flags aren't initialized yet when it's used for the first time in log
public static string VersionCelesteString => $"{Celeste.Instance.Version}-{(typeof(Game).Assembly.FullName.Contains("FNA") ? "fna" : "xna")} [Everest: {BuildString}]";

/// <summary>
/// UTF8 text encoding without a byte order mark, to be preferred over Encoding.UTF8
Expand Down
2 changes: 1 addition & 1 deletion Celeste.Mod.mm/Mod/Registry/DecalRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public static void ApplyDecalRegistry(List<KeyValuePair<string, DecalInfo>> elem
GFX.Game.GetTextures().Keys
.GroupBy(
s => s.StartsWith("decals/") ?
s.Substring(7).TrimEnd('0','1','2','3','4','5','6','7','8','9') :
s.Substring(7).TrimEnd('0','1','2','3','4','5','6','7','8','9').ToLower() :
null,
(s, matches) => s
)
Expand Down
55 changes: 39 additions & 16 deletions Celeste.Mod.mm/MonoModRules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,10 @@ class PatchPathfinderRenderAttribute : Attribute { };
class PatchTotalHeartGemChecksAttribute : Attribute { };

/// <summary>
/// Same as above, but for references in routines.
/// Patch TotalHeartGems to refer to TotalHeartGemsInVanilla, and whether to show the UnlockCSide postcard
/// </summary>
[MonoModCustomMethodAttribute(nameof(MonoModRules.PatchTotalHeartGemChecksInRoutine))]
class PatchTotalHeartGemChecksInRoutineAttribute : Attribute { };
[MonoModCustomMethodAttribute(nameof(MonoModRules.PatchTotalHeartGemCSidePostcard))]
class PatchTotalHeartGemCSidePostcardAttribute : Attribute { };

/// <summary>
/// Patch a reference to TotalHeartGems in the OuiJournalGlobal constructor to unharcode the check for golden berry unlock.
Expand Down Expand Up @@ -398,7 +398,10 @@ class PatchMountainRendererUpdate : Attribute { }
/// Patches the method to only set the player Speed.X if not in the RedDash state.
/// </summary>
[MonoModCustomMethodAttribute(nameof(MonoModRules.PatchPlayerBeforeUpTransition))]
class PatchPlayerBeforeUpTransition: Attribute { }
class PatchPlayerBeforeUpTransition : Attribute { }

[MonoModCustomMethodAttribute(nameof(MonoModRules.PatchDeathEffectUpdate))]
class PatchDeathEffectUpdateAttribute : Attribute { }

static class MonoModRules {

Expand Down Expand Up @@ -1481,20 +1484,21 @@ public static void PatchPathfinderRender(ILContext context, CustomAttribute attr

}

public static void PatchTotalHeartGemChecks(MethodDefinition method, CustomAttribute attrib) {
MethodDefinition m_getTotalHeartGemsInVanilla = method.Module.GetType("Celeste.SaveData").FindMethod("System.Int32 get_TotalHeartGemsInVanilla()");
public static void PatchTotalHeartGemChecks(ILContext context, CustomAttribute attrib) {
MethodDefinition m_getTotalHeartGemsInVanilla = context.Module.GetType("Celeste.SaveData").FindMethod("System.Int32 get_TotalHeartGemsInVanilla()");

Mono.Collections.Generic.Collection<Instruction> instrs = method.Body.Instructions;
for (int instri = 0; instri < instrs.Count; instri++) {
Instruction instr = instrs[instri];
ILCursor cursor = new ILCursor(context);

if (instr.MatchCallvirt(out MethodReference m) && m.Name == "get_TotalHeartGems") {
// replace the call to the TotalHeartGems property with a call to TotalHeartGemsInVanilla.
instr.Operand = m_getTotalHeartGemsInVanilla;
}
}
cursor.GotoNext(instr => instr.MatchCallvirt("Celeste.SaveData", "get_TotalHeartGems"));
cursor.Next.Operand = m_getTotalHeartGemsInVanilla;
}
public static void PatchTotalHeartGemChecksInRoutine(MethodDefinition method, CustomAttribute attrib) {

public static void PatchTotalHeartGemCSidePostcard(MethodDefinition method, CustomAttribute attrib) {
FieldDefinition f_SaveData_Instance = method.Module.GetType("Celeste.SaveData").FindField("Instance");
MethodDefinition m_SaveData_get_LevelSetStats = method.Module.GetType("Celeste.SaveData").FindMethod("Celeste.LevelSetStats get_LevelSetStats()");
MethodDefinition m_LevelSetStats_get_MaxAreaMode = method.Module.GetType("Celeste.LevelSetStats").FindMethod("System.Int32 get_MaxAreaMode()");


// Routines are stored in compiler-generated methods.
foreach (TypeDefinition nest in method.DeclaringType.NestedTypes) {
if (!nest.Name.StartsWith("<" + method.Name + ">d__"))
Expand All @@ -1503,7 +1507,19 @@ public static void PatchTotalHeartGemChecksInRoutine(MethodDefinition method, Cu
break;
}

PatchTotalHeartGemChecks(method, attrib);
new ILContext(method).Invoke(il => {
ILCursor cursor = new ILCursor(il);

cursor.GotoNext(MoveType.After, instr => instr.MatchLdfld("Celeste.Session", "UnlockedCSide"));
cursor.Emit(cursor.Next.OpCode, cursor.Next.Operand);
cursor.Emit(OpCodes.Ldsfld, f_SaveData_Instance);
cursor.Emit(OpCodes.Callvirt, m_SaveData_get_LevelSetStats);
cursor.Emit(OpCodes.Callvirt, m_LevelSetStats_get_MaxAreaMode);
cursor.Emit(OpCodes.Ldc_I4_2);
cursor.Next.OpCode = OpCodes.Blt_S;

PatchTotalHeartGemChecks(il, attrib);
});
}

public static void PatchOuiJournalStatsHeartGemCheck(ILContext context, CustomAttribute attrib) {
Expand Down Expand Up @@ -2269,6 +2285,13 @@ public static void PatchPlayerBeforeUpTransition(ILContext context, CustomAttrib
cursor.Emit(OpCodes.Beq_S, target);
}

public static void PatchDeathEffectUpdate(ILContext context, CustomAttribute attrib) {
ILCursor cursor = new ILCursor(context);
cursor.GotoNext(instr => instr.OpCode == OpCodes.Ble_Un_S);
cursor.Next.OpCode = OpCodes.Blt_Un_S;

}

public static void PostProcessor(MonoModder modder) {
// Patch CrushBlock::AttackSequence's first alarm delegate manually because how would you even annotate it?
PatchCrushBlockFirstAlarm(modder.Module.GetType("Celeste.CrushBlock/<>c__DisplayClass41_0").FindMethod("<AttackSequence>b__1"));
Expand Down
20 changes: 20 additions & 0 deletions Celeste.Mod.mm/Patches/DeathEffect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Microsoft.Xna.Framework;
using MonoMod;

namespace Celeste {
class patch_DeathEffect : DeathEffect {

public patch_DeathEffect(Color color, Vector2 offset)
: base(color, offset) { }

[MonoModIgnore]
[PatchDeathEffectUpdate]
public override extern void Update();

[MonoModReplace]
public override void Render() {
if (Entity != null)
Draw(Entity.Position + Position, Color, Percent);
}
}
}
22 changes: 22 additions & 0 deletions Celeste.Mod.mm/Patches/LevelSetStats.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Celeste {
class patch_LevelSetStats : LevelSetStats {
public int MaxAreaMode {
get {
if (Name == "Celeste") {
return (int) AreaMode.CSide;
}
int areaOffset = AreaOffset;
int maxAreaMode = 0;
for (int i = 0; i <= MaxArea; i++) {
ModeProperties[] mode = AreaData.Areas[areaOffset + i].Mode;
foreach (ModeProperties modeProperties in mode) {
if ((int) modeProperties.MapData.Area.Mode > maxAreaMode) {
maxAreaMode = (int) modeProperties.MapData.Area.Mode;
}
}
}
return maxAreaMode;
}
}
}
}
2 changes: 1 addition & 1 deletion Celeste.Mod.mm/Patches/OverworldLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public patch_OverworldLoader(Overworld.StartMode startMode, HiresSnow snow = nul
private extern void CheckVariantsPostcardAtLaunch();

[MonoModIgnore] // don't change anything in the method...
[PatchTotalHeartGemChecksInRoutine] // except for replacing TotalHeartGems with TotalHeartGemsInVanilla through MonoModRules
[PatchTotalHeartGemCSidePostcard] // except for replacing TotalHeartGems with TotalHeartGemsInVanilla through MonoModRules
private extern IEnumerator Routine(Session session);
}
}
34 changes: 0 additions & 34 deletions azure-pipelines-ext.cs

This file was deleted.

46 changes: 41 additions & 5 deletions azure-pipelines-postbuild.ps1
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
Add-Type -AssemblyName System.IO.Compression.FileSystem
Add-Type -Path "azure-pipelines-ext.cs" -ReferencedAssemblies "System.IO.Compression.FileSystem"

$OLYMPUS="$env:Build_ArtifactStagingDirectory/olympus/"
$OLYMPUS="$env:BUILD_ARTIFACTSTAGINGDIRECTORY/olympus/"
if ($OLYMPUS -eq "/olympus/") {
$OLYMPUS = "./tmp-olympus/"
}
Expand All @@ -15,9 +14,46 @@ New-Item -ItemType "directory" -Path $OLYMPUS/meta
New-Item -ItemType "directory" -Path $OLYMPUS/build

Write-Output "Building Olympus build artifact"
# Azure Pipelines apparently hates to write to the artifact staging dir directly.
[EverestPS]::Zip("$env:Build_ArtifactStagingDirectory/main", "olympus-build.zip")
Move-Item -Path "olympus-build.zip" -Destination $ZIP
$compress = @{
Path = "$env:BUILD_ARTIFACTSTAGINGDIRECTORY/main"
CompressionLevel = "Optimal"
DestinationPath = "$ZIP"
}
Compress-Archive @compress

Write-Output "Building Olympus metadata artifact"
Write-Output (Get-Item -Path $ZIP).length | Out-File -FilePath $OLYMPUS/meta/size.txt

# lib-stripped setup
if ([string]::IsNullOrEmpty("$env:BIN_URL") -or ($env:BIN_URL -eq '$(BIN_URL)')) {
Write-Output "Skipping lib-stripped artifact"
Exit 0
}

$LIB_STRIPPED="$env:BUILD_ARTIFACTSTAGINGDIRECTORY/lib-stripped"
if ($LIB_STRIPPED -eq "/lib-stripped") {
$LIB_STRIPPED = "./tmp-lib-stripped"
}

Write-Output "Creating lib-stripped artifact directories"
Remove-Item -ErrorAction Ignore -Recurse -Force -Path $LIB_STRIPPED
New-Item -ItemType "directory" -Path $LIB_STRIPPED
New-Item -ItemType "directory" -Path $LIB_STRIPPED/build

Write-Output "Downloading Celeste package"
$creds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$($env:BIN_USERNAME):$($env:BIN_PASSWORD)"))
$headers = @{'Authorization'= "Basic $creds"}
Invoke-WebRequest -URI "$env:BIN_URL/Celeste_Linux.zip" -OutFile "$env:AGENT_TEMPDIRECTORY/Celeste.zip" -Headers $headers
Expand-Archive -Path "$env:AGENT_TEMPDIRECTORY/Celeste.zip" -DestinationPath $LIB_STRIPPED

Write-Output "Applying Everest patch"
Copy-Item -Path "$env:BUILD_ARTIFACTSTAGINGDIRECTORY/main/*" -Destination $LIB_STRIPPED
Start-Process -FilePath "mono" -ArgumentList "$LIB_STRIPPED/MiniInstaller.exe" -WorkingDirectory $LIB_STRIPPED -Wait

Write-Output "Generating stripped files"
$files = Get-ChildItem -Path "$LIB_STRIPPED/*" -Include *.dll,*.exe
foreach ($dll in $files) {
mono-cil-strip -q $dll
}
Copy-Item $files -Destination "$LIB_STRIPPED/build"
Write-Host "##vso[task.setvariable variable=lib_stripped]True"
21 changes: 18 additions & 3 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net

pool:
vmImage: 'windows-latest'
vmImage: 'ubuntu-latest'

variables:
solution: '**/*.sln'
Expand Down Expand Up @@ -54,10 +54,15 @@ steps:

# Post-build steps.
- task: PowerShell@2
name: PostBuild
condition: succeeded()
displayName: 'Run azure-pipelines-postbuild.ps1'
inputs:
filePath: 'azure-pipelines-postbuild.ps1'
env:
BIN_URL: $(BIN_URL)
BIN_USERNAME: $(BIN_USERNAME)
BIN_PASSWORD: $(BIN_PASSWORD)

# Create and "publish" Olympus artifacts.
- task: PublishBuildArtifacts@1
Expand All @@ -77,9 +82,19 @@ steps:
artifactName: 'olympus-build'
publishLocation: 'Container'

# Create and "publish" mono-cil-strip binary artifacts
- task: PublishBuildArtifacts@1
condition: eq(variables['PostBuild.lib_stripped'], 'True')
displayName: 'Publish lib-stripped artifact'
continueOnError: true
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)/lib-stripped/build/'
artifactName: 'lib-stripped'
publishLocation: 'Container'

# Announce new stable versions on Discord (#modding_updates).
- script: |
set /a "BUILD_NUMBER=$(Build.BuildId)+$(Build.BuildIdOffset)"
curl -H "Content-Type: application/json" -d "{\"content\": \"**A new Everest stable was just released!**\nThe latest stable version is now **%BUILD_NUMBER%**.\"}" $(WEBHOOK_URL)
declare -i BUILD_NUMBER=$(Build.BuildId)+$(Build.BuildIdOffset)
curl -H "Content-Type: application/json" -d "{\"content\": \"**A new Everest stable was just released!**\nThe latest stable version is now **$BUILD_NUMBER**.\"}" $(WEBHOOK_URL)
displayName: 'Celeste Discord webhook'
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/stable'))

0 comments on commit ddfdda8

Please sign in to comment.