Skip to content

Commit

Permalink
etc
Browse files Browse the repository at this point in the history
  • Loading branch information
aedenthorn committed Mar 17, 2022
1 parent c2135f5 commit bdff321
Show file tree
Hide file tree
Showing 27 changed files with 1,561 additions and 1 deletion.
120 changes: 120 additions & 0 deletions CustomSigns/CodePatches.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using HarmonyLib;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Netcode;
using StardewValley;
using StardewValley.Tools;
using System;
using Object = StardewValley.Object;

namespace CustomSigns
{
public partial class ModEntry
{
private static Object placedSign;

[HarmonyPatch(typeof(GameLocation), nameof(GameLocation.isCollidingPosition), new Type[] { typeof(Rectangle), typeof(xTile.Dimensions.Rectangle), typeof(bool), typeof(int), typeof(bool), typeof(Character), typeof(bool), typeof(bool), typeof(bool) })]
public class isCollidingPosition_Patch
{
public static bool Prefix(GameLocation __instance, Rectangle position, xTile.Dimensions.Rectangle viewport, bool isFarmer, int damagesFarmer, bool glider, Character character, bool pathfinding, bool projectile, bool ignoreCharacterRequirement, ref bool __result)
{
if (!Config.EnableMod)
return true;
foreach(var obj in __instance.objects.Values)
{
if (!customSignTypeDict.ContainsKey(obj.Name) || !obj.modData.ContainsKey(templateKey))
continue;
if(obj.getBoundingBox(obj.TileLocation).Intersects(position))
{
__result = true;
return false;
}
}
return true;
}
}
[HarmonyPatch(typeof(Object), nameof(Object.placementAction))]
public class placementAction_Patch
{
public static void Postfix(Object __instance, GameLocation location, int x, int y, bool __result)
{
if (!Config.EnableMod || !__result || !SHelper.Input.IsDown(Config.ModKey) || !customSignTypeDict.ContainsKey(__instance.Name))
return;
Vector2 placementTile = new Vector2(x / 64, y / 64);
if (!location.objects.TryGetValue(placementTile, out Object obj))
return;
placedSign = obj;
ReloadSignData();
OpenPlacementDialogue();
}
}
[HarmonyPatch(typeof(Object), nameof(Object.getBoundingBox))]
public class getBoundingBox_Patch
{
public static void Postfix(Object __instance, Vector2 tileLocation, ref Rectangle __result, NetRectangle ___boundingBox)
{
if (!Config.EnableMod || !customSignTypeDict.ContainsKey(__instance.Name) || !__instance.modData.TryGetValue(templateKey, out string template) || !customSignDataDict.TryGetValue(template, out CustomSignData data))
return;
var x = Environment.StackTrace;
__result = new Rectangle((int)tileLocation.X * 64 + 32 / 2 - data.tileWidth * 64 / 2, (int)tileLocation.Y * 64 + 64 - data.tileHeight * 64, data.tileWidth * 64, data.tileHeight * 64);
___boundingBox.Set(__result);
}
}
[HarmonyPatch(typeof(Pickaxe), nameof(Pickaxe.DoFunction))]
public class Pickaxe_DoFunction_Patch
{
public static void Postfix(Pickaxe __instance, GameLocation location, int x, int y, int power, Farmer who)
{
if (!Config.EnableMod)
return;
foreach(var kvp in location.objects.Pairs)
{
if(kvp.Value.boundingBox.Value.Contains(x, y) && customSignTypeDict.ContainsKey(kvp.Value.Name) && kvp.Value.modData.TryGetValue(templateKey, out string template) && customSignDataDict.ContainsKey(template))
{
if (kvp.Value.performToolAction(__instance, location))
{
kvp.Value.performRemoveAction(kvp.Key, location);
Game1.currentLocation.debris.Add(new Debris(kvp.Value.bigCraftable.Value ? (-kvp.Value.ParentSheetIndex) : kvp.Value.ParentSheetIndex, who.GetToolLocation(false), new Vector2(who.GetBoundingBox().Center.X, who.GetBoundingBox().Center.Y)));
Game1.currentLocation.Objects.Remove(kvp.Key);
return;
}

}
}
}
}
[HarmonyPatch(typeof(Object), nameof(Object.draw), new Type[] { typeof(SpriteBatch), typeof(int), typeof(int), typeof(float) })]
public class draw_Patch
{

public static bool Prefix(Object __instance, SpriteBatch spriteBatch, int x, int y, float alpha)
{
if (!Config.EnableMod || __instance.isTemporarilyInvisible || !__instance.bigCraftable.Value || !customSignTypeDict.ContainsKey(__instance.Name) || !__instance.modData.TryGetValue(templateKey, out string template) || !customSignDataDict.TryGetValue(template, out CustomSignData data) || data.texture == null)
return true;
Vector2 position = Game1.GlobalToLocal(Game1.viewport, new Vector2(x * 64 + 32, y * 64 + 64)) - new Vector2(data.texture.Width / 2, data.texture.Height) * data.scale;
float draw_layer = Math.Max(0f, ((y + 1) * 64 - 24) / 10000f) + x * 1E-05f;
spriteBatch.Draw(data.texture, position, null, Color.White * alpha, 0f, Vector2.Zero, data.scale, SpriteEffects.None, draw_layer);
if(data.text != null)
{
for(int i = 0; i < data.text.Length; i++)
{
var text = data.text[i];
if (!fontDict.ContainsKey(text.fontPath))
continue;
Vector2 pos;
if (text.center)
{
pos = new Vector2(position.X + text.X - fontDict[text.fontPath].MeasureString(text.text).X / 2 * text.scale, position.Y + text.Y);
}
else
{
pos = new Vector2(position.X + text.X, position.Y + text.Y);
}
spriteBatch.DrawString(fontDict[text.fontPath], text.text, pos, text.color, 0, Vector2.Zero, text.scale, SpriteEffects.None, draw_layer + 1 / 10000f * (i+1));
}
}
return false;
}
}
}
}
30 changes: 30 additions & 0 deletions CustomSigns/CustomSignData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace CustomSigns
{
public class CustomSignData
{
public string texturePath;
public string packID;
public int tileWidth;
public int tileHeight;
public int heldObjectX;
public int heldObjectY;
public float scale = 4;
public string[] types;
public SignText[] text;
public Texture2D texture;
}

public class SignText
{
public string text;
public int X;
public int Y;
public bool center = true;
public string fontPath;
public float scale;
public Color color = Color.White;
}
}
25 changes: 25 additions & 0 deletions CustomSigns/CustomSigns.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>1.0.0</Version>
<TargetFramework>net5.0</TargetFramework>
<EnableHarmony>true</EnableHarmony>
</PropertyGroup>
<ItemGroup>
<None Remove="i18n\default.json" />
</ItemGroup>
<ItemGroup>
<Content Include="i18n\default.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Pathoschild.Stardew.ModBuildConfig" Version="4.0.0" />
</ItemGroup>

<ItemGroup>
<None Update="manifest.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
75 changes: 75 additions & 0 deletions CustomSigns/IGenericModConfigMenuApi.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using StardewModdingAPI;
using System;

namespace CustomSigns
{
/// <summary>The API which lets other mods add a config UI through Generic Mod Config Menu.</summary>
public interface IGenericModConfigMenuApi
{
/*********
** Methods
*********/
/****
** Must be called first
****/
/// <summary>Register a mod whose config can be edited through the UI.</summary>
/// <param name="mod">The mod's manifest.</param>
/// <param name="reset">Reset the mod's config to its default values.</param>
/// <param name="save">Save the mod's current config to the <c>config.json</c> file.</param>
/// <param name="titleScreenOnly">Whether the options can only be edited from the title screen.</param>
/// <remarks>Each mod can only be registered once, unless it's deleted via <see cref="Unregister"/> before calling this again.</remarks>
void Register(IManifest mod, Action reset, Action save, bool titleScreenOnly = false);

/// <summary>Add a section title at the current position in the form.</summary>
/// <param name="mod">The mod's manifest.</param>
/// <param name="text">The title text shown in the form.</param>
/// <param name="tooltip">The tooltip text shown when the cursor hovers on the title, or <c>null</c> to disable the tooltip.</param>
void AddSectionTitle(IManifest mod, Func<string> text, Func<string> tooltip = null);

/// <summary>Add a key binding at the current position in the form.</summary>
/// <param name="mod">The mod's manifest.</param>
/// <param name="getValue">Get the current value from the mod config.</param>
/// <param name="setValue">Set a new value in the mod config.</param>
/// <param name="name">The label text to show in the form.</param>
/// <param name="tooltip">The tooltip text shown when the cursor hovers on the field, or <c>null</c> to disable the tooltip.</param>
/// <param name="fieldId">The unique field ID for use with <see cref="OnFieldChanged"/>, or <c>null</c> to auto-generate a randomized ID.</param>
void AddKeybind(IManifest mod, Func<SButton> getValue, Action<SButton> setValue, Func<string> name, Func<string> tooltip = null, string fieldId = null);

/// <summary>Add a boolean option at the current position in the form.</summary>
/// <param name="mod">The mod's manifest.</param>
/// <param name="getValue">Get the current value from the mod config.</param>
/// <param name="setValue">Set a new value in the mod config.</param>
/// <param name="name">The label text to show in the form.</param>
/// <param name="tooltip">The tooltip text shown when the cursor hovers on the field, or <c>null</c> to disable the tooltip.</param>
/// <param name="fieldId">The unique field ID for use with <see cref="OnFieldChanged"/>, or <c>null</c> to auto-generate a randomized ID.</param>
void AddBoolOption(IManifest mod, Func<bool> getValue, Action<bool> setValue, Func<string> name, Func<string> tooltip = null, string fieldId = null);


/// <summary>Add an integer option at the current position in the form.</summary>
/// <param name="mod">The mod's manifest.</param>
/// <param name="getValue">Get the current value from the mod config.</param>
/// <param name="setValue">Set a new value in the mod config.</param>
/// <param name="name">The label text to show in the form.</param>
/// <param name="tooltip">The tooltip text shown when the cursor hovers on the field, or <c>null</c> to disable the tooltip.</param>
/// <param name="min">The minimum allowed value, or <c>null</c> to allow any.</param>
/// <param name="max">The maximum allowed value, or <c>null</c> to allow any.</param>
/// <param name="interval">The interval of values that can be selected.</param>
/// <param name="fieldId">The unique field ID for use with <see cref="OnFieldChanged"/>, or <c>null</c> to auto-generate a randomized ID.</param>
void AddNumberOption(IManifest mod, Func<int> getValue, Action<int> setValue, Func<string> name, Func<string> tooltip = null, int? min = null, int? max = null, int? interval = null, string fieldId = null);

/// <summary>Add a string option at the current position in the form.</summary>
/// <param name="mod">The mod's manifest.</param>
/// <param name="getValue">Get the current value from the mod config.</param>
/// <param name="setValue">Set a new value in the mod config.</param>
/// <param name="name">The label text to show in the form.</param>
/// <param name="tooltip">The tooltip text shown when the cursor hovers on the field, or <c>null</c> to disable the tooltip.</param>
/// <param name="allowedValues">The values that can be selected, or <c>null</c> to allow any.</param>
/// <param name="formatAllowedValue">Get the display text to show for a value from <paramref name="allowedValues"/>, or <c>null</c> to show the values as-is.</param>
/// <param name="fieldId">The unique field ID for use with <see cref="OnFieldChanged"/>, or <c>null</c> to auto-generate a randomized ID.</param>
void AddTextOption(IManifest mod, Func<string> getValue, Action<string> setValue, Func<string> name, Func<string> tooltip = null, string[] allowedValues = null, Func<string, string> formatAllowedValue = null, string fieldId = null);

/// <summary>Remove a mod from the config UI and delete all its options and pages.</summary>
/// <param name="mod">The mod's manifest.</param>
void Unregister(IManifest mod);
}
}
71 changes: 71 additions & 0 deletions CustomSigns/Methods.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using HarmonyLib;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using StardewModdingAPI;
using StardewValley;
using StardewValley.Menus;
using System;
using System.Collections.Generic;
using System.Linq;
using Rectangle = Microsoft.Xna.Framework.Rectangle;

namespace CustomSigns
{
public partial class ModEntry : Mod
{
public static void OpenPlacementDialogue()
{
if (customSignDataDict.Count == 0)
{
SMonitor.Log("No custom sign templates.", LogLevel.Warn);
return;
}

List<Response> responses = new List<Response>();
foreach(var key in customSignDataDict.Keys)
{
responses.Add(new Response(key, key));
}
responses.Add(new Response("cancel", SHelper.Translation.Get("cancel")));
Game1.player.currentLocation.createQuestionDialogue(SHelper.Translation.Get("which-template"), responses.ToArray(), "CS_Choose_Template");
}

private static void ReloadSignData()
{
customSignDataDict.Clear();
customSignTypeDict.Clear();
fontDict.Clear();
var dict = SHelper.Content.Load<Dictionary<string, CustomSignData>>(dictPath, ContentSource.GameContent);
if (dict == null)
{
SMonitor.Log($"No custom signs found", LogLevel.Debug);
return;
}
foreach (var kvp in dict)
{
CustomSignData data = kvp.Value;
foreach (string type in data.types)
{
if (!customSignTypeDict.ContainsKey(type))
{
customSignTypeDict.Add(type, new List<string>() { type });
}
else
{
customSignTypeDict[type].Add(type);
}
}
if (data.packID != null && !loadedContentPacks.Contains(data.packID))
loadedContentPacks.Add(data.packID);
data.texture = SHelper.Content.Load<Texture2D>(data.texturePath, ContentSource.GameContent);
foreach(var text in data.text)
{
if (!fontDict.ContainsKey(text.fontPath))
fontDict.Add(text.fontPath, Game1.content.Load<SpriteFont>(text.fontPath));
}
}
customSignDataDict = dict;
}
}
}
12 changes: 12 additions & 0 deletions CustomSigns/ModConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

using StardewModdingAPI;

namespace CustomSigns
{
public class ModConfig
{
public bool EnableMod { get; set; } = true;
public SButton ModKey { get; set; } = SButton.LeftShift;
public SButton ResetKey { get; set; } = SButton.F5;
}
}
Loading

0 comments on commit bdff321

Please sign in to comment.