Skip to content

Commit 80f0d44

Browse files
committed
Slay the DynamicData
1 parent 11975c4 commit 80f0d44

14 files changed

+251
-221
lines changed

CustomCrystalHeartHelper.cs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,20 @@ private static void customizeParticles(On.Celeste.HeartGem.orig_Awake orig, Hear
2222

2323
if (!self.IsGhost && LobbyHelper.IsHeartSide(self.SceneAs<Level>().Session.Area.GetSID())) {
2424
// we are in a heartside: make the heart particles match the heart sprite.
25-
DynData<HeartGem> selfData = new DynData<HeartGem>(self);
26-
switch (selfData.Get<Sprite>("sprite").Texture.AtlasPath) {
25+
switch (self.sprite.Texture.AtlasPath) {
2726
case "collectables/heartGem/1/00":
28-
selfData["shineParticle"] = HeartGem.P_RedShine;
27+
self.shineParticle = HeartGem.P_RedShine;
2928
break;
3029
case "collectables/heartGem/2/00":
31-
selfData["shineParticle"] = HeartGem.P_GoldShine;
30+
self.shineParticle = HeartGem.P_GoldShine;
3231
break;
3332
case "CollabUtils2/crystalHeart/expert/00":
34-
selfData["shineParticle"] = new ParticleType(HeartGem.P_BlueShine) {
33+
self.shineParticle = new ParticleType(HeartGem.P_BlueShine) {
3534
Color = Color.Orange
3635
};
3736
break;
3837
case "CollabUtils2/crystalHeart/grandmaster/00":
39-
selfData["shineParticle"] = new ParticleType(HeartGem.P_BlueShine) {
38+
self.shineParticle = new ParticleType(HeartGem.P_BlueShine) {
4039
Color = Color.DarkViolet
4140
};
4241
break;
@@ -54,24 +53,23 @@ private static void customizePoemDisplay(On.Celeste.Poem.orig_ctor orig, Poem se
5453
self.Heart.Play("spin");
5554

5655
// and adjust the screen color to the heart.
57-
DynData<Poem> selfData = new DynData<Poem>(self);
5856
switch (self.Heart.Texture.AtlasPath) {
5957
case "collectables/heartgem/1/spin00":
60-
selfData["Color"] = Calc.HexToColor("ff668a");
58+
self.Color = Calc.HexToColor("ff668a");
6159
break;
6260
case "collectables/heartgem/2/spin00":
63-
selfData["Color"] = Calc.HexToColor("D2AD01");
61+
self.Color = Calc.HexToColor("D2AD01");
6462
break;
6563
case "CollabUtils2/crystalHeart/expert/spin00":
66-
selfData["Color"] = Color.Orange;
64+
self.Color = Color.Orange;
6765
break;
6866
case "CollabUtils2/crystalHeart/grandmaster/spin00":
69-
selfData["Color"] = Calc.HexToColor("d9a2ff");
67+
self.Color = Calc.HexToColor("d9a2ff");
7068
break;
7169
default:
7270
Match match = Regex.Match(self.Heart.Texture.AtlasPath, "poemtextcolor_([0-9a-fA-F]{6})");
7371
if (match.Success) {
74-
selfData["Color"] = Calc.HexToColor(match.Groups[1].Value);
72+
self.Color = Calc.HexToColor(match.Groups[1].Value);
7573
}
7674
break;
7775
}

Entities/GoldenBerryPlayerRespawnPoint.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ internal static void Unload() {
2323
private static Session onSessionRestart(On.Celeste.Session.orig_Restart orig, Session self, string intoLevel) {
2424
Session restartSession = orig(self, intoLevel);
2525

26-
if (intoLevel != null && Engine.Scene is LevelExit exit && new DynData<LevelExit>(exit).Get<LevelExit.Mode>("mode") == LevelExit.Mode.GoldenBerryRestart) {
26+
if (intoLevel != null && Engine.Scene is LevelExit exit && exit.mode == LevelExit.Mode.GoldenBerryRestart) {
2727
// we are doing a golden berry restart! look for a golden berry player respawn point.
2828
LevelData levelData = restartSession.MapData.Levels.Find(level => level.Name == intoLevel);
2929
EntityData goldenRespawn = levelData.Entities.FirstOrDefault(entityData => entityData.Name == "CollabUtils2/GoldenBerryPlayerRespawnPoint");

Entities/MiniHeartDoorUnlockCutscene.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ private IEnumerator Cutscene(Level level) {
3434
door.ForceTrigger = true;
3535

3636
// wait for door to be open.
37-
DynData<HeartGemDoor> doorData = new DynData<HeartGemDoor>(door);
38-
while (doorData.Get<float>("openPercent") < 1f) {
37+
while (door.openPercent < 1f) {
3938
yield return null;
4039
}
4140
yield return 1f;
@@ -56,11 +55,10 @@ public override void OnEnd(Level level) {
5655
level.Camera.Position = player.CameraTarget;
5756

5857
// instant open the door
59-
DynData<HeartGemDoor> doorData = new DynData<HeartGemDoor>(door);
60-
doorData["openPercent"] = 1f;
61-
doorData["Opened"] = true;
62-
doorData["Counter"] = door.Requires;
63-
float openDistance = doorData.Get<float>("openDistance");
58+
door.openPercent = 1f;
59+
door.Opened = true;
60+
door.Counter = door.Requires;
61+
float openDistance = door.openDistance;
6462
door.TopSolid.Bottom = door.Y - openDistance;
6563
door.BotSolid.Top = door.Y + openDistance;
6664

Entities/RainbowBerry.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ public override void Added(Scene scene) {
4545
base.Added(scene);
4646

4747
// fix the bloom to match golden alpha
48-
DynData<Strawberry> self = new DynData<Strawberry>(this);
49-
self.Get<BloomPoint>("bloom").Alpha = 0.5f;
48+
bloom.Alpha = 0.5f;
5049

5150
if (CollabMapDataProcessor.SilverBerries.ContainsKey(levelSet)) {
5251
int missingBerries = 0;
@@ -90,7 +89,7 @@ public override void Added(Scene scene) {
9089
// make rainbow berry invisible for now...
9190
Visible = false;
9291
Collidable = false;
93-
self.Get<BloomPoint>("bloom").Visible = (self.Get<VertexLight>("light").Visible = false);
92+
bloom.Visible = (light.Visible = false);
9493

9594
// now we wait for the player to enter the trigger. filling the HologramForCutscene field will tell the trigger to create the cutscene.
9695
HologramForCutscene = hologram;

Entities/SilverBerry.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class SilverBerry : Strawberry {
1919
private readonly bool alwaysSpawn;
2020

2121
public SilverBerry(EntityData data, Vector2 offset, EntityID gid) : base(data, offset, gid) {
22-
new DynData<Strawberry>(this)["Golden"] = true;
22+
Golden = true;
2323
alwaysSpawn = data.Bool("alwaysSpawn");
2424

2525
if (P_SilverGlow == null) {

Entities/SpeedBerry.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ private static void onTransitionEnd(On.Celeste.Player.orig_OnTransition orig, Pl
6262

6363
public SpeedBerry(EntityData data, Vector2 offset, EntityID id, bool restored) : base(data, offset, id) {
6464
EntityData = data;
65-
new DynData<Strawberry>(this)["Golden"] = true;
65+
Golden = true;
6666
BronzeTime = data.Float("bronzeTime", 15f);
6767
SilverTime = data.Float("silverTime", 10f);
6868
GoldTime = data.Float("goldTime", 5f);

Entities/StrawberryHooks.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ private static string replaceStrawberryGetSound(string orig, Strawberry self) {
175175
/// </summary>
176176
private static SpeedBerry storedSpeedBerry;
177177

178+
private static bool hasSilver;
179+
private static bool hasSpeedBerry;
180+
178181
private static PlayerDeadBody onPlayerDie(On.Celeste.Player.orig_Die orig, Player self, Vector2 direction, bool evenIfInvincible, bool registerDeathInStats) {
179182
bool hasSilver = false;
180183
SpeedBerry speedBerry = null;
@@ -187,22 +190,23 @@ private static PlayerDeadBody onPlayerDie(On.Celeste.Player.orig_Die orig, Playe
187190
speedBerry = (SpeedBerry) speedBerryFollower.Entity;
188191
// Don't restart the player to the starting room if there's still time left on the speed berry
189192
if (!speedBerry.TimeRanOut) {
190-
DynData<Strawberry> data = new DynData<Strawberry>(speedBerry);
191-
data["Golden"] = false;
193+
speedBerry.Golden = false;
192194
// set the starting position to the spawn point
193195
Level level = self.SceneAs<Level>();
194-
data["start"] = level.GetSpawnPoint(new Vector2(level.Bounds.Left, level.Bounds.Top)) + new Vector2(8, -16);
196+
speedBerry.start = level.GetSpawnPoint(new Vector2(level.Bounds.Left, level.Bounds.Top)) + new Vector2(8, -16);
195197
}
196198
}
197199
}
198200

199201
PlayerDeadBody body = orig(self, direction, evenIfInvincible, registerDeathInStats);
200202

201203
if (body != null) {
202-
DynData<PlayerDeadBody> data = new DynData<PlayerDeadBody>(body);
203-
data["hasSilver"] = hasSilver;
204-
data["hasSpeedBerry"] = (speedBerry != null);
204+
StrawberryHooks.hasSilver = hasSilver;
205+
StrawberryHooks.hasSpeedBerry = (speedBerry != null);
205206
storedSpeedBerry = speedBerry;
207+
} else {
208+
StrawberryHooks.hasSilver = false;
209+
StrawberryHooks.hasSpeedBerry = false;
206210
}
207211
return body;
208212
}
@@ -222,9 +226,6 @@ private static void modDeathSound(ILContext il) {
222226
}
223227

224228
private static string modGoldenDeathSound(string orig, PlayerDeadBody self) {
225-
DynData<PlayerDeadBody> data = new DynData<PlayerDeadBody>(self);
226-
bool hasSilver = data.Get<bool>("hasSilver");
227-
bool hasSpeedBerry = data.Get<bool>("hasSpeedBerry");
228229
if (hasSilver && hasSpeedBerry) {
229230
return "event:/SC2020_silverTimedBerry_death";
230231
}

LobbyHelper.cs

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
namespace Celeste.Mod.CollabUtils2 {
2121
public static class LobbyHelper {
2222

23+
internal static bool pauseTimerUntilAction = false;
2324
private static bool unpauseTimerOnNextAction = false;
2425

2526
private static ILHook hookOnOuiFileSelectRenderDisplayName;
@@ -196,6 +197,9 @@ internal static void Load() {
196197
On.Celeste.OuiFileSelectSlot.Show += onOuiFileSelectSlotShow;
197198
On.Celeste.OuiChapterPanel.UpdateStats += onChapterPanelUpdateStats;
198199

200+
On.Monocle.Entity.Removed += onEntityRemoved;
201+
On.Celeste.Overworld.End += onOverworldEnd;
202+
199203
hookOnOuiFileSelectRenderDisplayName = new ILHook(typeof(OuiFileSelectSlot).GetMethod("orig_Render"), modSelectSlotLevelSetDisplayName);
200204
hookOnOuiFileSelectRenderStrawberryStamp = new ILHook(typeof(OuiFileSelectSlot).GetMethod("orig_Render"), modSelectSlotCollectedStrawberries);
201205
hookOnOuiJournalPoemLines = new ILHook(typeof(OuiJournalPoem).GetNestedType("PoemLine", BindingFlags.NonPublic).GetMethod("Render"), modJournalPoemHeartColors);
@@ -235,6 +239,9 @@ internal static void Unload() {
235239
On.Celeste.OuiFileSelectSlot.Show -= onOuiFileSelectSlotShow;
236240
On.Celeste.OuiChapterPanel.UpdateStats -= onChapterPanelUpdateStats;
237241

242+
On.Monocle.Entity.Removed -= onEntityRemoved;
243+
On.Celeste.Overworld.End -= onOverworldEnd;
244+
238245
hookOnOuiFileSelectRenderDisplayName?.Dispose();
239246
hookOnOuiFileSelectRenderStrawberryStamp?.Dispose();
240247
hookOnOuiJournalPoemLines?.Dispose();
@@ -317,9 +324,8 @@ public static void OnSessionCreated() {
317324
private static void onLoadLevel(On.Celeste.Level.orig_LoadLevel orig, Level self, Player.IntroTypes playerIntro, bool isFromLoader) {
318325
orig(self, playerIntro, isFromLoader);
319326

320-
DynData<Session> sessionData = new DynData<Session>(self.Session);
321-
if (sessionData.Data.ContainsKey("pauseTimerUntilAction") && sessionData.Get<bool>("pauseTimerUntilAction")) {
322-
sessionData["pauseTimerUntilAction"] = false;
327+
if (pauseTimerUntilAction) {
328+
pauseTimerUntilAction = false;
323329
self.TimerStopped = true;
324330
unpauseTimerOnNextAction = true;
325331
}
@@ -550,7 +556,7 @@ private static IEnumerator onAssistUnlockRoutine(On.Celeste.OuiChapterSelectIcon
550556
// we just assist unlocked the lobbies!
551557
LevelSetStats stats = SaveData.Instance.GetLevelSetStatsFor($"{collab}/0-Lobbies");
552558
stats.UnlockedAreas = stats.Areas.Count - 1;
553-
List<OuiChapterSelectIcon> icons = new DynData<OuiChapterSelect>((self.Scene as Overworld).GetUI<OuiChapterSelect>()).Get<List<OuiChapterSelectIcon>>("icons");
559+
List<OuiChapterSelectIcon> icons = (self.Scene as Overworld).GetUI<OuiChapterSelect>().icons;
554560
icons[self.Area + 1].AssistModeUnlockable = false;
555561
for (int i = self.Area + 2; i <= SaveData.Instance.MaxArea; i++) {
556562
icons[i].Show();
@@ -573,6 +579,21 @@ private static void onJournalEnter(OuiJournal journal, Oui from) {
573579
}
574580
}
575581

582+
// those are Everest fields, so they aren't publicized :despair:
583+
private static readonly FieldInfo f_totalGoldenStrawberries = typeof(OuiFileSelectSlot).GetField("totalGoldenStrawberries", BindingFlags.NonPublic | BindingFlags.Instance);
584+
private static readonly FieldInfo f_totalHeartGems = typeof(OuiFileSelectSlot).GetField("totalHeartGems", BindingFlags.NonPublic | BindingFlags.Instance);
585+
private static readonly FieldInfo f_totalCassettes = typeof(OuiFileSelectSlot).GetField("totalCassettes", BindingFlags.NonPublic | BindingFlags.Instance);
586+
private static readonly FieldInfo f_maxStrawberryCount = typeof(OuiFileSelectSlot).GetField("maxStrawberryCount", BindingFlags.NonPublic | BindingFlags.Instance);
587+
private static readonly FieldInfo f_maxGoldenStrawberryCount = typeof(OuiFileSelectSlot).GetField("maxGoldenStrawberryCount", BindingFlags.NonPublic | BindingFlags.Instance);
588+
private static readonly FieldInfo f_maxStrawberryCountIncludingUntracked = typeof(OuiFileSelectSlot).GetField("maxStrawberryCountIncludingUntracked", BindingFlags.NonPublic | BindingFlags.Instance);
589+
private static readonly FieldInfo f_maxCassettes = typeof(OuiFileSelectSlot).GetField("maxCassettes", BindingFlags.NonPublic | BindingFlags.Instance);
590+
private static readonly FieldInfo f_maxCrystalHearts = typeof(OuiFileSelectSlot).GetField("maxCrystalHearts", BindingFlags.NonPublic | BindingFlags.Instance);
591+
private static readonly FieldInfo f_maxCrystalHeartsExcludingCSides = typeof(OuiFileSelectSlot).GetField("maxCrystalHeartsExcludingCSides", BindingFlags.NonPublic | BindingFlags.Instance);
592+
private static readonly FieldInfo f_summitStamp = typeof(OuiFileSelectSlot).GetField("false", BindingFlags.NonPublic | BindingFlags.Instance);
593+
private static readonly FieldInfo f_farewellStamp = typeof(OuiFileSelectSlot).GetField("false", BindingFlags.NonPublic | BindingFlags.Instance);
594+
595+
private static readonly Dictionary<OuiFileSelectSlot, List<string>> customHeartsPerSaveFileSlot = new Dictionary<OuiFileSelectSlot, List<string>>();
596+
576597
private static void onOuiFileSelectSlotShow(On.Celeste.OuiFileSelectSlot.orig_Show orig, OuiFileSelectSlot self) {
577598
// If we are currently in a collab map, display the lobby level set stats instead.
578599
AreaKey? savedLastArea = null;
@@ -618,24 +639,23 @@ private static void onOuiFileSelectSlotShow(On.Celeste.OuiFileSelectSlot.orig_Sh
618639
}
619640
}
620641

621-
DynData<OuiFileSelectSlot> slotData = new DynData<OuiFileSelectSlot>(self);
622-
slotData["totalGoldenStrawberries"] = totalGoldenStrawberries;
623-
slotData["totalHeartGems"] = totalHeartGems;
624-
slotData["totalCassettes"] = totalCassettes;
625-
slotData["maxStrawberryCount"] = maxStrawberryCount;
626-
slotData["maxGoldenStrawberryCount"] = maxGoldenStrawberryCount;
627-
slotData["maxStrawberryCountIncludingUntracked"] = maxStrawberryCountIncludingUntracked;
628-
slotData["maxCassettes"] = maxCassettes;
629-
slotData["maxCrystalHearts"] = maxCrystalHearts;
630-
slotData["maxCrystalHeartsExcludingCSides"] = maxCrystalHeartsExcludingCSides;
631-
slotData["summitStamp"] = false;
632-
slotData["farewellStamp"] = false;
642+
f_totalGoldenStrawberries.SetValue(self, totalGoldenStrawberries);
643+
f_totalHeartGems.SetValue(self, totalHeartGems);
644+
f_totalCassettes.SetValue(self, totalCassettes);
645+
f_maxStrawberryCount.SetValue(self, maxStrawberryCount);
646+
f_maxGoldenStrawberryCount.SetValue(self, maxGoldenStrawberryCount);
647+
f_maxStrawberryCountIncludingUntracked.SetValue(self, maxStrawberryCountIncludingUntracked);
648+
f_maxCassettes.SetValue(self, maxCassettes);
649+
f_maxCrystalHearts.SetValue(self, maxCrystalHearts);
650+
f_maxCrystalHeartsExcludingCSides.SetValue(self, maxCrystalHeartsExcludingCSides);
651+
f_summitStamp.SetValue(self, false);
652+
f_farewellStamp.SetValue(self, false);
633653

634654
self.Strawberries.Amount = totalStrawberries;
635655
self.Strawberries.OutOf = maxStrawberryCount;
636656
}
637657

638-
// figure out if some hearts are customized, and store it in DynData so that a IL hook can access it later.
658+
// figure out if some hearts are customized, and store it in a static variable so that an IL hook can access it later.
639659
SaveData oldInstance = SaveData.Instance;
640660
SaveData.Instance = self.SaveData;
641661
List<string> customJournalHearts = new List<string>();
@@ -654,7 +674,7 @@ private static void onOuiFileSelectSlotShow(On.Celeste.OuiFileSelectSlot.orig_Sh
654674
}
655675
}
656676
}
657-
new DynData<OuiFileSelectSlot>(self)["collabutils2_customhearts"] = customJournalHearts;
677+
customHeartsPerSaveFileSlot[self] = customJournalHearts;
658678
SaveData.Instance = oldInstance;
659679

660680
// Restore the last area if it was replaced at the beginning of this method.
@@ -668,7 +688,7 @@ private static void onChapterPanelUpdateStats(On.Celeste.OuiChapterPanel.orig_Up
668688

669689
if (IsCollabLobby(self.Area.SID)) {
670690
// hide the deaths counter for collab lobbies.
671-
new DynData<OuiChapterPanel>(self).Get<DeathsCounter>("deaths").Visible = false;
691+
self.deaths.Visible = false;
672692
}
673693
}
674694

@@ -763,13 +783,23 @@ private static void modOuiFileSelectSlotRender(ILContext il) {
763783
}
764784

765785
private static MTexture reskinJournalHearts(MTexture orig, OuiFileSelectSlot self, int index) {
766-
List<string> customJournalHearts = new DynData<OuiFileSelectSlot>(self).Get<List<string>>("collabutils2_customhearts");
786+
List<string> customJournalHearts = customHeartsPerSaveFileSlot.GetValueOrDefault(self);
767787
if (customJournalHearts != null && customJournalHearts[index] != null) {
768788
return MTN.Journal[customJournalHearts[index]]; // "Journal" and not "FileSelect" because it re-uses the setup people made for their custom journals.
769789
}
770790
return orig;
771791
}
772792

793+
private static void onEntityRemoved(On.Monocle.Entity.orig_Removed orig, Monocle.Entity self, Scene scene) {
794+
if (self is OuiFileSelectSlot slot) customHeartsPerSaveFileSlot.Remove(slot);
795+
orig(self, scene);
796+
}
797+
798+
private static void onOverworldEnd(On.Celeste.Overworld.orig_End orig, Overworld self) {
799+
customHeartsPerSaveFileSlot.Clear();
800+
orig(self);
801+
}
802+
773803
private static void modJournalPoemHeartColors(ILContext il) {
774804
ILCursor cursor = new ILCursor(il);
775805

0 commit comments

Comments
 (0)