update patches and asset propagation

This commit is contained in:
Jesse Plamondon-Willard 2020-12-20 22:34:59 -05:00
parent 85cb824c3b
commit ffe74869ca
No known key found for this signature in database
GPG Key ID: CF8B1456B3E29F49
3 changed files with 78 additions and 32 deletions

View File

@ -138,12 +138,20 @@ namespace StardewModdingAPI.Metadata
{
if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.NormalizeAssetNameIgnoringEmpty(location.mapPath.Value) == key)
{
// reset town caches
if (location is Town town)
// reset patch caches
switch (location)
{
this.Reflection.GetField<bool>(town, "ccRefurbished").SetValue(false);
this.Reflection.GetField<bool>(town, "isShowingDestroyedJoja").SetValue(false);
this.Reflection.GetField<bool>(town, "isShowingUpgradedPamHouse").SetValue(false);
case Town _:
this.Reflection.GetField<bool>(location, "ccRefurbished").SetValue(false);
this.Reflection.GetField<bool>(location, "isShowingDestroyedJoja").SetValue(false);
this.Reflection.GetField<bool>(location, "isShowingUpgradedPamHouse").SetValue(false);
break;
case Beach _:
case BeachNightMarket _:
case Forest _:
this.Reflection.GetField<bool>(location, "hasShownCCUpgrade").SetValue(false);
break;
}
// general updates
@ -271,6 +279,9 @@ namespace StardewModdingAPI.Metadata
case "data\\farmanimals": // FarmAnimal constructor
return this.ReloadFarmAnimalData();
case "data\\hairdata": // Farmer.GetHairStyleMetadataFile
return this.ReloadHairData();
case "data\\moviesreactions": // MovieTheater.GetMovieReactions
this.Reflection
.GetField<List<MovieCharacterReaction>>(typeof(MovieTheater), "_genericReactions")
@ -388,13 +399,19 @@ namespace StardewModdingAPI.Metadata
Game1.shadowTexture = content.Load<Texture2D>(key);
return true;
case "loosesprites\\suspensionbridge": // SuspensionBridge constructor
return this.ReloadSuspensionBridges(content, key);
/****
** Content\TileSheets
****/
case "tilesheets\\critters": // Critter constructor
this.ReloadCritterTextures(content, key);
case "tilesheets\\chairtiles": // Game1.LoadContent
MapSeat.mapChairTexture = content.Load<Texture2D>(key);
return true;
case "tilesheets\\critters": // Critter constructor
return this.ReloadCritterTextures(content, key) > 0;
case "tilesheets\\crops": // Game1.LoadContent
Game1.cropSpriteSheet = content.Load<Texture2D>(key);
return true;
@ -411,6 +428,10 @@ namespace StardewModdingAPI.Metadata
Furniture.furnitureTexture = content.Load<Texture2D>(key);
return true;
case "tilesheets\\furniturefront": // Game1.LoadContent
Furniture.furnitureFrontTexture = content.Load<Texture2D>(key);
return true;
case "tilesheets\\projectiles": // Game1.LoadContent
Projectile.projectileSheet = content.Load<Texture2D>(key);
return true;
@ -612,7 +633,7 @@ namespace StardewModdingAPI.Metadata
// update sprites
Texture2D texture = content.Load<Texture2D>(key);
foreach (TAnimal animal in animals)
this.SetSpriteTexture(animal.Sprite, texture);
animal.Sprite.spriteTexture = texture;
return true;
}
@ -642,7 +663,7 @@ namespace StardewModdingAPI.Metadata
// reload asset
if (expectedKey == key)
this.SetSpriteTexture(animal.Sprite, texture.Value);
animal.Sprite.spriteTexture = texture.Value;
}
return texture.IsValueCreated;
}
@ -682,9 +703,8 @@ namespace StardewModdingAPI.Metadata
Critter[] critters =
(
from location in this.GetLocations()
let locCritters = this.Reflection.GetField<List<Critter>>(location, "critters").GetValue()
where locCritters != null
from Critter critter in locCritters
where location.critters != null
from Critter critter in location.critters
where this.NormalizeAssetNameIgnoringEmpty(critter.sprite?.Texture?.Name) == key
select critter
)
@ -695,7 +715,7 @@ namespace StardewModdingAPI.Metadata
// update sprites
Texture2D texture = content.Load<Texture2D>(key);
foreach (var entry in critters)
this.SetSpriteTexture(entry.sprite, texture);
entry.sprite.spriteTexture = texture;
return critters.Length;
}
@ -752,10 +772,7 @@ namespace StardewModdingAPI.Metadata
(
from location in this.GetLocations()
from grass in location.terrainFeatures.Values.OfType<Grass>()
let textureName = this.NormalizeAssetNameIgnoringEmpty(
this.Reflection.GetMethod(grass, "textureName").Invoke<string>()
)
where textureName == key
where this.NormalizeAssetNameIgnoringEmpty(grass.textureName()) == key
select grass
)
.ToArray();
@ -764,13 +781,28 @@ namespace StardewModdingAPI.Metadata
{
Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(key));
foreach (Grass grass in grasses)
this.Reflection.GetField<Lazy<Texture2D>>(grass, "texture").SetValue(texture);
grass.texture = texture;
return true;
}
return false;
}
/// <summary>Reload hair style metadata.</summary>
/// <returns>Returns whether any assets were reloaded.</returns>
/// <remarks>Derived from the <see cref="Farmer.GetHairStyleMetadataFile"/> and <see cref="Farmer.GetHairStyleMetadata"/>.</remarks>
private bool ReloadHairData()
{
if (Farmer.hairStyleMetadataFile == null)
return false;
Farmer.hairStyleMetadataFile = null;
Farmer.allHairStyleIndices = null;
Farmer.hairStyleMetadata.Clear();
return true;
}
/// <summary>Reload the disposition data for matching NPCs.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
/// <param name="key">The asset key to reload.</param>
@ -813,7 +845,7 @@ namespace StardewModdingAPI.Metadata
// update sprite
foreach (var target in characters)
{
this.SetSpriteTexture(target.Npc.Sprite, content.Load<Texture2D>(target.Key));
target.Npc.Sprite.spriteTexture = content.Load<Texture2D>(target.Key);
propagated[target.Key] = true;
}
}
@ -877,6 +909,29 @@ namespace StardewModdingAPI.Metadata
return players.Any();
}
/// <summary>Reload suspension bridge textures.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
/// <param name="key">The asset key to reload.</param>
/// <returns>Returns whether any textures were reloaded.</returns>
private bool ReloadSuspensionBridges(LocalizedContentManager content, string key)
{
Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(key));
foreach (GameLocation location in this.GetLocations(buildingInteriors: false))
{
// get suspension bridges field
var field = this.Reflection.GetField<IEnumerable<SuspensionBridge>>(location, nameof(IslandNorth.suspensionBridges), required: false);
if (field == null || !typeof(IEnumerable<SuspensionBridge>).IsAssignableFrom(field.FieldInfo.FieldType))
continue;
// update textures
foreach (SuspensionBridge bridge in field.GetValue())
this.Reflection.GetField<Texture2D>(bridge, "_texture").SetValue(texture.Value);
}
return texture.IsValueCreated;
}
/// <summary>Reload tree textures.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
/// <param name="key">The asset key to reload.</param>
@ -958,7 +1013,8 @@ namespace StardewModdingAPI.Metadata
int lastScheduleTime = villager.Schedule.Keys.Where(p => p <= Game1.timeOfDay).OrderByDescending(p => p).FirstOrDefault();
if (lastScheduleTime != 0)
{
villager.scheduleTimeToTry = NPC.NO_TRY; // use time that's passed in to checkSchedule
villager.queuedSchedulePaths.Clear();
villager.lastAttemptedSchedule = 0;
villager.checkSchedule(lastScheduleTime);
}
}
@ -969,14 +1025,6 @@ namespace StardewModdingAPI.Metadata
/****
** Helpers
****/
/// <summary>Reload the texture for an animated sprite.</summary>
/// <param name="sprite">The animated sprite to update.</param>
/// <param name="texture">The texture to set.</param>
private void SetSpriteTexture(AnimatedSprite sprite, Texture2D texture)
{
this.Reflection.GetField<Texture2D>(sprite, "spriteTexture").SetValue(texture);
}
/// <summary>Get all NPCs in the game (excluding farm animals).</summary>
private IEnumerable<NPC> GetCharacters()
{

View File

@ -135,11 +135,9 @@ namespace StardewModdingAPI.Patches
IReflectedMethod translateArraysOfStrings = DialogueErrorPatch.Reflection.GetMethod(typeof(Dialogue), "TranslateArraysOfStrings");
IReflectedMethod parseDialogueString = DialogueErrorPatch.Reflection.GetMethod(__instance, "parseDialogueString");
IReflectedMethod checkForSpecialDialogueAttributes = DialogueErrorPatch.Reflection.GetMethod(__instance, "checkForSpecialDialogueAttributes");
IReflectedField<List<string>> dialogues = DialogueErrorPatch.Reflection.GetField<List<string>>(__instance, "dialogues");
// replicate base constructor
if (dialogues.GetValue() == null)
dialogues.SetValue(new List<string>());
__instance.dialogues ??= new List<string>();
// duplicate code with try..catch
try

View File

@ -51,7 +51,7 @@ namespace StardewModdingAPI.Patches
#endif
{
harmony.Patch(
original: AccessTools.Method(typeof(NPC), "parseMasterSchedule"),
original: AccessTools.Method(typeof(NPC), nameof(NPC.parseMasterSchedule)),
#if HARMONY_2
finalizer: new HarmonyMethod(this.GetType(), nameof(ScheduleErrorPatch.Finalize_NPC_parseMasterSchedule))
#else