Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0636ff6
Working tree, bush and grass reflections
Floogen Jan 3, 2026
c24a451
Simplified reflective tile check into IsTileReflective
Floogen Jan 3, 2026
33e44d8
Added caching for terrain reflections
Floogen Jan 3, 2026
41cffa3
Fixed water reflection not resetting player's height offset correctly
Floogen Jan 3, 2026
7a4f8e1
Now sorting locationToReflectableTerrainFeatures by Tile.Y
Floogen Jan 3, 2026
6269f3d
Added puddle reflections for terrain objects
Floogen Jan 3, 2026
1126b99
Added GMCM config options for grass and terrain reflections
Floogen Jan 3, 2026
88be46b
Added player building reflections
Floogen Jan 3, 2026
cf32b08
Refactored DrawReflectionViaMatrix to DrawPlayerWaterReflection
Floogen Jan 3, 2026
6bd9b43
Minor code cleanup
Floogen Jan 3, 2026
afbb710
Condensed terrain draw into playerWaterReflectionRender / playerPuddl…
Floogen Jan 4, 2026
223743f
Condensed grass draw into playerWaterReflectionRender / playerPuddleR…
Floogen Jan 4, 2026
57f2a03
Now only rendering terrain and buildings if they are on screen
Floogen Jan 4, 2026
0338dec
Simplified all terrain and building objects grabs and sorting via Ref…
Floogen Jan 5, 2026
48ea690
Added support for furniture reflections
Floogen Jan 5, 2026
195a575
Fixed cache list not sorting after removal of furniture or terrain
Floogen Jan 5, 2026
fd0a75b
Minor code cleanup
Floogen Jan 5, 2026
5b222e7
Added furniture reflection config option
Floogen Jan 5, 2026
75e22a3
Simplified the check for enabled reflection types
Floogen Jan 5, 2026
0c0fac1
Increased IsOnScreen max distance for terrain and buildings
Floogen Jan 5, 2026
ee428c2
Adjusted buildings to check tile reflection based on height
Floogen Jan 5, 2026
6962c5d
Fixed building reflections not updating when moving buildings
Floogen Jan 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
318 changes: 275 additions & 43 deletions DynamicReflections/DynamicReflections.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public static void Register(IGenericModConfigMenuApi configApi, DynamicReflectio
configApi.AddBoolOption(ModManifest, () => DynamicReflections.modConfig.ArePuddleReflectionsEnabled, value => DynamicReflections.modConfig.ArePuddleReflectionsEnabled = value, () => Helper.Translation.Get("config.general_settings.puddle_reflections"));
configApi.AddBoolOption(ModManifest, () => DynamicReflections.modConfig.AreNPCReflectionsEnabled, value => DynamicReflections.modConfig.AreNPCReflectionsEnabled = value, () => Helper.Translation.Get("config.general_settings.npc_reflections"));
configApi.AddBoolOption(ModManifest, () => DynamicReflections.modConfig.AreCompanionReflectionsEnabled, value => DynamicReflections.modConfig.AreCompanionReflectionsEnabled = value, () => Helper.Translation.Get("config.general_settings.companion_reflections"));
configApi.AddBoolOption(ModManifest, () => DynamicReflections.modConfig.AreGrassReflectionsEnabled, value => DynamicReflections.modConfig.AreGrassReflectionsEnabled = value, () => Helper.Translation.Get("config.general_settings.grass_reflections"));
configApi.AddBoolOption(ModManifest, () => DynamicReflections.modConfig.AreTerrainReflectionsEnabled, value => DynamicReflections.modConfig.AreTerrainReflectionsEnabled = value, () => Helper.Translation.Get("config.general_settings.terrain_reflections"));
configApi.AddBoolOption(ModManifest, () => DynamicReflections.modConfig.ArePlayerBuildingReflectionsEnabled, value => DynamicReflections.modConfig.ArePlayerBuildingReflectionsEnabled = value, () => Helper.Translation.Get("config.general_settings.player_buildings_reflections"));
configApi.AddBoolOption(ModManifest, () => DynamicReflections.modConfig.AreFurnitureReflectionsEnabled, value => DynamicReflections.modConfig.AreFurnitureReflectionsEnabled = value, () => Helper.Translation.Get("config.general_settings.furniture_reflections"));
configApi.AddBoolOption(ModManifest, () => DynamicReflections.modConfig.AreSkyReflectionsEnabled, value => DynamicReflections.modConfig.AreSkyReflectionsEnabled = value, () => Helper.Translation.Get("config.general_settings.sky_reflections"));
configApi.AddKeybind(ModManifest, () => DynamicReflections.modConfig.QuickMenuKey, value => DynamicReflections.modConfig.QuickMenuKey = value, () => Helper.Translation.Get("config.general_settings.shortcut_key"), () => Helper.Translation.Get("config.general_settings.shortcut_key.description"));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ public class ModConfig
public bool ArePuddleReflectionsEnabled { get; set; } = true;
public bool AreNPCReflectionsEnabled { get; set; } = true;
public bool AreCompanionReflectionsEnabled { get; set; } = true;
public bool AreGrassReflectionsEnabled { get; set; } = true;
public bool AreTerrainReflectionsEnabled { get; set; } = true;
public bool ArePlayerBuildingReflectionsEnabled { get; set; } = true;
public bool AreFurnitureReflectionsEnabled { get; set; } = true;
public bool AreSkyReflectionsEnabled { get; set; } = true;

public WaterSettings WaterReflectionSettings { get; set; } = new WaterSettings();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
using StardewValley.Buildings;

namespace DynamicReflections.Framework.Models.Reflections
{
public class ReflectableBuilding : ReflectableObject
{
public Building Building;

public ReflectableBuilding(Building building)
{
Building = building;
Tile = new Vector2(building.tileX.Value, building.tileY.Value);
}

public override void Draw(SpriteBatch spriteBatch)
{
Building.draw(spriteBatch);
}

public override bool IsOnScreen()
{
return Utility.isOnScreen(Tile * 64, 8 * 64);
}

public override bool IsEnabled()
{
return DynamicReflections.modConfig.ArePlayerBuildingReflectionsEnabled;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
using StardewValley.Objects;

namespace DynamicReflections.Framework.Models.Reflections
{
public class ReflectableFurniture : ReflectableObject
{
public Furniture Furniture;

public ReflectableFurniture(Furniture furniture)
{
Furniture = furniture;
Tile = furniture.TileLocation;
}

public override void Draw(SpriteBatch spriteBatch)
{
Furniture.isDrawingLocationFurniture = true;
Furniture.draw(spriteBatch, -1, -1);
Furniture.isDrawingLocationFurniture = false;
}

public override bool IsOnScreen()
{
// Allow for three tile (3 * 64) spacing for trees and bushes
return Utility.isOnScreen(Tile * 64, 3 * 64);
}

public override bool IsEnabled()
{
return DynamicReflections.modConfig.AreFurnitureReflectionsEnabled;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace DynamicReflections.Framework.Models.Reflections
{
public abstract class ReflectableObject
{
public Vector2 Tile { get; set; }

public abstract void Draw(SpriteBatch spriteBatch);
public abstract bool IsOnScreen();
public abstract bool IsEnabled();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
using StardewValley.TerrainFeatures;

namespace DynamicReflections.Framework.Models.Reflections
{
public class ReflectableTerrain : ReflectableObject
{
public TerrainFeature Terrain;

public ReflectableTerrain(TerrainFeature terrain)
{
Terrain = terrain;
Tile = terrain.Tile;
}

public override void Draw(SpriteBatch spriteBatch)
{
if (Terrain is Tree tree)
{
float alphaCache = tree.alpha;
tree.alpha = 1f;

Terrain.draw(spriteBatch);
tree.alpha = alphaCache;
}
else
{
Terrain.draw(spriteBatch);
}
}

public override bool IsOnScreen()
{
// Allow for three tile (3 * 64) spacing for trees and bushes
return Utility.isOnScreen(Tile * 64, 8 * 64);
}

public override bool IsEnabled()
{
if (Terrain is Grass)
{
return DynamicReflections.modConfig.AreGrassReflectionsEnabled;
}

return DynamicReflections.modConfig.AreTerrainReflectionsEnabled;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void Reset(WaterSettings referencedSettings = null)
AreReflectionsEnabled = true;
ReflectionDirection = Direction.South;
ReflectionOverlay = Color.White;
PlayerReflectionOffset = new Vector2(0f, 0.5f);
PlayerReflectionOffset = new Vector2(0f, 1.5f);
NPCReflectionOffset = new Vector2(0f, 0.7f);
CompanionReflectionOffset = new Vector2(0f, 0.3f);
IsReflectionWavy = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ internal void Apply(Harmony harmony)
harmony.CreateReversePatcher(AccessTools.Method(_type, nameof(GameLocation.drawWater), new[] { typeof(SpriteBatch) }), new HarmonyMethod(GetType(), nameof(DrawWaterReversePatch))).Patch();

harmony.Patch(AccessTools.Method(_type, nameof(GameLocation.UpdateWhenCurrentLocation), new[] { typeof(GameTime) }), postfix: new HarmonyMethod(GetType(), nameof(UpdateWhenCurrentLocationPostfix)));
harmony.Patch(AccessTools.Method(_type, nameof(GameLocation.OnBuildingMoved), new[] { typeof(Building) }), postfix: new HarmonyMethod(GetType(), nameof(OnBuildingMovedPostfix)));
}

[HarmonyBefore(new string[] { "shekurika.WaterFish" })]
Expand Down Expand Up @@ -154,6 +155,11 @@ private static void UpdateWhenCurrentLocationPostfix(GameLocation __instance, Ga
}
}

private static void OnBuildingMovedPostfix(GameLocation __instance, Building building)
{
DynamicReflections.ResetLocationTerrainCache(__instance);
}

private static void GenerateRipple(GameLocation location, Point puddleTile, bool playSound = false)
{
TemporaryAnimatedSprite splashSprite = new TemporaryAnimatedSprite("TileSheets\\animations", new Microsoft.Xna.Framework.Rectangle(0, 0, 64, 64), Game1.random.Next(50, 100), 9, 1, new Vector2(puddleTile.X, puddleTile.Y) * 64f, flicker: false, flipped: false, 0f, 0f, DynamicReflections.currentPuddleSettings.RippleColor, 1f, 0f, 0f, 0f);
Expand Down
2 changes: 1 addition & 1 deletion DynamicReflections/Framework/Patches/xTile/LayerPatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ private static bool DrawNormalPrefix(Layer __instance, IDisplayDevice displayDev
}

// Handle preliminary water reflection logic
if (DynamicReflections.shouldDrawWaterReflection is true)
if (DynamicReflections.modConfig.AreWaterReflectionsEnabled)
{
DynamicReflections.isFilteringWater = true;
SpriteBatchToolkit.RenderWaterReflectionPlayerSprite();
Expand Down
Loading