Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 12 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## LethalLib [0.16.5]

### Added
- Ability for items, levels, outside and inside mapobjects to register to levels through their content tag.

### Fixed
- mapobjects maybe having the same issues that items and enemies had the previous two versions with case sensitivity and leveltype validation.

## LethalLib [0.16.4]
- Fixed `AddEnemyToLevel` needing a `LevelType` to validate custom moon enemy rarities.
- Fixed `AddScrapItemToLevel` having the same issue as above.

### Fixed
- `AddEnemyToLevel` needing a `LevelType` to validate custom moon enemy rarities.
- `AddScrapItemToLevel` having the same issue as above.

## LethalLib [0.16.3]

Expand Down
46 changes: 46 additions & 0 deletions LethalLib/Compats/LethalLevelLoaderCompat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using BepInEx.Bootstrap;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace LethalLib.Compats;
internal static class LethalLevelLoaderCompat
{
public static bool LethalLevelLoaderExists => Chainloader.PluginInfos.ContainsKey("imabatby.lethallevelloader");

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static List<string> TryGetLLLTagsFromLevels(SelectableLevel level)
{
if (LethalLevelLoaderExists)
{
return GetLLLTagsFromLevel(level); // do i need to make another method? i forgor
}
return new();
}

[MethodImpl(MethodImplOptions.NoInlining)]
internal static List<string> GetLLLTagsFromLevel(SelectableLevel level)
{
List<string> tagsForLevel = [];
foreach (LethalLevelLoader.ExtendedLevel extendedLevel in LethalLevelLoader.PatchedContent.CustomExtendedLevels)
{
if (extendedLevel.SelectableLevel != level) continue;
foreach (LethalLevelLoader.ContentTag tag in extendedLevel.ContentTags)
{
tagsForLevel.Add(tag.contentTagName.Trim().ToLowerInvariant());
}
break;
}

foreach (LethalLevelLoader.ExtendedLevel extendedLevel in LethalLevelLoader.PatchedContent.VanillaExtendedLevels)
{
if (extendedLevel.SelectableLevel != level) continue;
foreach (LethalLevelLoader.ContentTag tag in extendedLevel.ContentTags)
{
tagsForLevel.Add(tag.contentTagName.Trim().ToLowerInvariant());
}
break;
}

return tagsForLevel;
}
}
1 change: 1 addition & 0 deletions LethalLib/LethalLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="IAmBatby-LethalLevelLoader" Version="1.4.*" PrivateAssets="all" />
<PackageReference Include="BepInEx.PluginInfoProps" Version="2.1.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.2" Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
<PrivateAssets>all</PrivateAssets>
Expand Down
19 changes: 12 additions & 7 deletions LethalLib/Modules/Enemies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ private static void RegisterLethalLibEnemiesForAllLevels()

foreach (SelectableLevel level in StartOfRound.Instance.levels)
{
if(levelsAlreadyAddedTo.Contains(level))
if (levelsAlreadyAddedTo.Contains(level))
continue;
foreach (SpawnableEnemy spawnableEnemy in spawnableEnemies)
{
Expand All @@ -206,10 +206,12 @@ private static void AddEnemyToLevel(SpawnableEnemy spawnableEnemy, SelectableLev
name = customName;
}

string tagName = string.Empty;
bool enemyValidToAdd = spawnableEnemy.levelRarities.ContainsKey(Levels.LevelTypes.All)
|| (spawnableEnemy.customLevelRarities != null && Levels.Compatibility.ContentIncludedToLevelViaTag(spawnableEnemy.customLevelRarities.Keys.ToArray(), level, out tagName))
|| (isCurrentLevelFromVanilla && spawnableEnemy.levelRarities.ContainsKey(Levels.LevelTypes.Vanilla))
|| (isCurrentLevelFromVanilla && spawnableEnemy.levelRarities.ContainsKey(currentLevelType))
|| (!isCurrentLevelFromVanilla && spawnableEnemy.levelRarities.ContainsKey(Levels.LevelTypes.Modded))
|| (isCurrentLevelFromVanilla && spawnableEnemy.levelRarities.ContainsKey(currentLevelType))
|| (!isCurrentLevelFromVanilla && spawnableEnemy.customLevelRarities != null && spawnableEnemy.customLevelRarities.ContainsKey(customName));

if (Plugin.extendedLogging.Value)
Expand All @@ -223,14 +225,18 @@ private static void AddEnemyToLevel(SpawnableEnemy spawnableEnemy, SelectableLev
{
rarity = spawnableEnemy.levelRarities[currentLevelType];
}
else if (isCurrentLevelFromVanilla && spawnableEnemy.levelRarities.ContainsKey(Levels.LevelTypes.Vanilla))
{
rarity = spawnableEnemy.levelRarities[Levels.LevelTypes.Vanilla];
}
else if (spawnableEnemy.customLevelRarities != null && spawnableEnemy.customLevelRarities.ContainsKey(name))
{
rarity = spawnableEnemy.customLevelRarities[name];
}
else if (spawnableEnemy.customLevelRarities != null && tagName != string.Empty && spawnableEnemy.customLevelRarities.ContainsKey(tagName))
{
rarity = spawnableEnemy.customLevelRarities[tagName];
}
else if (isCurrentLevelFromVanilla && spawnableEnemy.levelRarities.ContainsKey(Levels.LevelTypes.Vanilla))
{
rarity = spawnableEnemy.levelRarities[Levels.LevelTypes.Vanilla];
}
else if (!isCurrentLevelFromVanilla && spawnableEnemy.levelRarities.ContainsKey(Levels.LevelTypes.Modded))
{
rarity = spawnableEnemy.levelRarities[Levels.LevelTypes.Modded];
Expand Down Expand Up @@ -557,5 +563,4 @@ public static void RemoveEnemyFromLevels(EnemyType enemyType, Levels.LevelTypes
}
}
}

}
16 changes: 11 additions & 5 deletions LethalLib/Modules/Items.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,12 @@ private static void AddScrapItemToLevel(ScrapItem scrapItem, SelectableLevel lev
name = customName;
}

string tagName = string.Empty;
bool itemValidToAdd = scrapItem.levelRarities.ContainsKey(Levels.LevelTypes.All)
|| (scrapItem.customLevelRarities != null && Levels.Compatibility.ContentIncludedToLevelViaTag(scrapItem.customLevelRarities.Keys.ToArray(), level, out tagName))
|| (isCurrentLevelFromVanilla && scrapItem.levelRarities.ContainsKey(Levels.LevelTypes.Vanilla))
|| (isCurrentLevelFromVanilla && scrapItem.levelRarities.ContainsKey(currentLevelType))
|| (!isCurrentLevelFromVanilla && scrapItem.levelRarities.ContainsKey(Levels.LevelTypes.Modded))
|| (isCurrentLevelFromVanilla && scrapItem.levelRarities.ContainsKey(currentLevelType))
|| (!isCurrentLevelFromVanilla && scrapItem.customLevelRarities != null && scrapItem.customLevelRarities.ContainsKey(customName));

if (Plugin.extendedLogging.Value)
Expand All @@ -206,14 +208,18 @@ private static void AddScrapItemToLevel(ScrapItem scrapItem, SelectableLevel lev
{
rarity = scrapItem.levelRarities[currentLevelType];
}
else if (isCurrentLevelFromVanilla && scrapItem.levelRarities.ContainsKey(Levels.LevelTypes.Vanilla))
{
rarity = scrapItem.levelRarities[Levels.LevelTypes.Vanilla];
}
else if (scrapItem.customLevelRarities != null && scrapItem.customLevelRarities.ContainsKey(name))
{
rarity = scrapItem.customLevelRarities[name];
}
else if (scrapItem.customLevelRarities != null && tagName != string.Empty && scrapItem.customLevelRarities.ContainsKey(tagName))
{
rarity = scrapItem.customLevelRarities[tagName];
}
else if (isCurrentLevelFromVanilla && scrapItem.levelRarities.ContainsKey(Levels.LevelTypes.Vanilla))
{
rarity = scrapItem.levelRarities[Levels.LevelTypes.Vanilla];
}
else if (!isCurrentLevelFromVanilla && scrapItem.levelRarities.ContainsKey(Levels.LevelTypes.Modded))
{
rarity = scrapItem.levelRarities[Levels.LevelTypes.Modded];
Expand Down
22 changes: 22 additions & 0 deletions LethalLib/Modules/Levels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,27 @@ internal static Dictionary<string, int> LLLifyLevelRarityDictionary(Dictionary<s
}
return LLLifiedCustomLevelRarities;
}


internal static bool ContentIncludedToLevelViaTag(string[] potentialTags, SelectableLevel level, out string chosenTag)
{
chosenTag = string.Empty;
List<string> levelsCurrentTags = LethalLib.Compats.LethalLevelLoaderCompat.TryGetLLLTagsFromLevels(level);
foreach (string levelTag in levelsCurrentTags)
{
foreach (string potentialTag in potentialTags)
{
string cleanedTag = potentialTag.Remove(potentialTag.Length - 5);
if (levelTag == cleanedTag)
{
chosenTag = levelTag;
if (Plugin.extendedLogging.Value)
Plugin.logger.LogInfo($"Level {level.name} has valid tag {cleanedTag}");
return true;
}
}
}
return false;
}
}
}
170 changes: 96 additions & 74 deletions LethalLib/Modules/MapObjects.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,85 +95,107 @@ private static void StartOfRound_Awake(On.StartOfRound.orig_Awake orig, StartOfR
{
foreach (SelectableLevel level in self.levels)
{
var name = level.name;
var alwaysValid = mapObject.levels.HasFlag(Levels.LevelTypes.All) || (mapObject.spawnLevelOverrides != null && mapObject.spawnLevelOverrides.Any(item => item.ToLowerInvariant() == name.ToLowerInvariant()));
var isModded = mapObject.levels.HasFlag(Levels.LevelTypes.Modded) && !Enum.IsDefined(typeof(Levels.LevelTypes), name);
AddMapObjectToLevel(mapObject, level);
}
}
}

if (isModded)
{
alwaysValid = true;
}
private static void AddMapObjectToLevel(RegisteredMapObject mapObject, SelectableLevel level)
{
string name = level.name;
string customName = Levels.Compatibility.GetLLLNameOfLevel(name);
Levels.LevelTypes currentLevelType = Levels.LevelTypes.None;
bool isCurrentLevelFromVanilla = false;

if (Enum.IsDefined(typeof(Levels.LevelTypes), name) || alwaysValid)
{
var levelEnum = alwaysValid ? Levels.LevelTypes.All : (Levels.LevelTypes)Enum.Parse(typeof(Levels.LevelTypes), name);
if (Enum.TryParse(name, true, out currentLevelType)) // It'd be weird if a level was called "Modded" or "All" so I think im good to not check that lol
{
isCurrentLevelFromVanilla = true;
}
else
{
name = customName;
}

string tagName = string.Empty;
bool mapObjectValidToAdd = mapObject.levels.HasFlag(Levels.LevelTypes.All)
|| Levels.Compatibility.ContentIncludedToLevelViaTag(mapObject.spawnLevelOverrides.ToArray(), level, out tagName)
|| (isCurrentLevelFromVanilla && mapObject.levels.HasFlag(Levels.LevelTypes.Vanilla))
|| (!isCurrentLevelFromVanilla && mapObject.levels.HasFlag(Levels.LevelTypes.Modded))
|| (isCurrentLevelFromVanilla && mapObject.levels.HasFlag(currentLevelType))
|| (!isCurrentLevelFromVanilla && mapObject.spawnLevelOverrides.Contains(customName));

if (alwaysValid || mapObject.levels.HasFlag(levelEnum))
{
if (mapObject.mapObject != null)
{
// Remove existing object if it exists
if (level.spawnableMapObjects.Any(x => x.prefabToSpawn == mapObject.mapObject.prefabToSpawn))
{
var list = level.spawnableMapObjects.ToList();
list.RemoveAll(x => x.prefabToSpawn == mapObject.mapObject.prefabToSpawn);
level.spawnableMapObjects = list.ToArray();
}

// Create a new instance so it can have its own `numberToSpawn` value
SpawnableMapObject spawnableMapObject = new()
{
prefabToSpawn = mapObject.mapObject.prefabToSpawn,
spawnFacingAwayFromWall = mapObject.mapObject.spawnFacingAwayFromWall,
spawnFacingWall = mapObject.mapObject.spawnFacingWall,
spawnWithBackToWall = mapObject.mapObject.spawnWithBackToWall,
spawnWithBackFlushAgainstWall = mapObject.mapObject.spawnWithBackFlushAgainstWall,
requireDistanceBetweenSpawns = mapObject.mapObject.requireDistanceBetweenSpawns,
disallowSpawningNearEntrances = mapObject.mapObject.disallowSpawningNearEntrances,
};

if (mapObject.spawnRateFunction != null)
{
spawnableMapObject.numberToSpawn = mapObject.spawnRateFunction(level);
}

var mapObjectsList = level.spawnableMapObjects.ToList();
mapObjectsList.Add(spawnableMapObject);
level.spawnableMapObjects = mapObjectsList.ToArray();

if (Plugin.extendedLogging.Value)
Plugin.logger.LogInfo($"Added {spawnableMapObject.prefabToSpawn.name} to {name}");
}
else if (mapObject.outsideObject != null)
{
if (level.spawnableOutsideObjects.Any(x => x.spawnableObject.prefabToSpawn == mapObject.outsideObject.spawnableObject.prefabToSpawn))
{
var list = level.spawnableOutsideObjects.ToList();
list.RemoveAll(x => x.spawnableObject.prefabToSpawn == mapObject.outsideObject.spawnableObject.prefabToSpawn);
level.spawnableOutsideObjects = list.ToArray();
}

SpawnableOutsideObjectWithRarity spawnableOutsideObject = new()
{
spawnableObject = mapObject.outsideObject.spawnableObject
};

if (mapObject.spawnRateFunction != null)
{
spawnableOutsideObject.randomAmount = mapObject.spawnRateFunction(level);
}

var mapObjectsList = level.spawnableOutsideObjects.ToList();
mapObjectsList.Add(spawnableOutsideObject);
level.spawnableOutsideObjects = mapObjectsList.ToArray();

if (Plugin.extendedLogging.Value)
Plugin.logger.LogInfo($"Added {spawnableOutsideObject.spawnableObject.prefabToSpawn.name} to {name}");
}
}
}
string mapObjectName = "invalid!";
if (mapObject.mapObject != null)
{
mapObjectName = mapObject.mapObject.prefabToSpawn.name;
}
else if (mapObject.outsideObject != null && mapObject.outsideObject != null)
{
mapObjectName = mapObject.outsideObject.spawnableObject.prefabToSpawn.name;
}
if (Plugin.extendedLogging.Value)
Plugin.logger.LogInfo($"{name} for mapObject: {mapObjectName}, isCurrentLevelFromVanilla: {isCurrentLevelFromVanilla}, Found valid: {mapObjectValidToAdd}");

if (!mapObjectValidToAdd) return;
if (mapObject.mapObject != null)
{
// Remove existing object if it exists
if (level.spawnableMapObjects.Any(x => x.prefabToSpawn == mapObject.mapObject.prefabToSpawn))
{
var list = level.spawnableMapObjects.ToList();
list.RemoveAll(x => x.prefabToSpawn == mapObject.mapObject.prefabToSpawn);
level.spawnableMapObjects = list.ToArray();
}

// Create a new instance so it can have its own `numberToSpawn` value
SpawnableMapObject spawnableMapObject = new()
{
prefabToSpawn = mapObject.mapObject.prefabToSpawn,
spawnFacingAwayFromWall = mapObject.mapObject.spawnFacingAwayFromWall,
spawnFacingWall = mapObject.mapObject.spawnFacingWall,
spawnWithBackToWall = mapObject.mapObject.spawnWithBackToWall,
spawnWithBackFlushAgainstWall = mapObject.mapObject.spawnWithBackFlushAgainstWall,
requireDistanceBetweenSpawns = mapObject.mapObject.requireDistanceBetweenSpawns,
disallowSpawningNearEntrances = mapObject.mapObject.disallowSpawningNearEntrances,
};

if (mapObject.spawnRateFunction != null)
{
spawnableMapObject.numberToSpawn = mapObject.spawnRateFunction(level);
}

var mapObjectsList = level.spawnableMapObjects.ToList();
mapObjectsList.Add(spawnableMapObject);
level.spawnableMapObjects = mapObjectsList.ToArray();

if (Plugin.extendedLogging.Value)
Plugin.logger.LogInfo($"Added {spawnableMapObject.prefabToSpawn.name} to {name}");
}
else if (mapObject.outsideObject != null)
{
if (level.spawnableOutsideObjects.Any(x => x.spawnableObject.prefabToSpawn == mapObject.outsideObject.spawnableObject.prefabToSpawn))
{
var list = level.spawnableOutsideObjects.ToList();
list.RemoveAll(x => x.spawnableObject.prefabToSpawn == mapObject.outsideObject.spawnableObject.prefabToSpawn);
level.spawnableOutsideObjects = list.ToArray();
}

SpawnableOutsideObjectWithRarity spawnableOutsideObject = new()
{
spawnableObject = mapObject.outsideObject.spawnableObject
};

if (mapObject.spawnRateFunction != null)
{
spawnableOutsideObject.randomAmount = mapObject.spawnRateFunction(level);
}

var mapObjectsList = level.spawnableOutsideObjects.ToList();
mapObjectsList.Add(spawnableOutsideObject);
level.spawnableOutsideObjects = mapObjectsList.ToArray();

if (Plugin.extendedLogging.Value)
Plugin.logger.LogInfo($"Added {spawnableOutsideObject.spawnableObject.prefabToSpawn.name} to {name}");
}
}

Expand Down
1 change: 1 addition & 0 deletions NuGet.Config
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
<configuration>
<packageSources>
<add key="BepInEx" value="https://nuget.bepinex.dev/v3/index.json" />
<add key="Thunderstore" value="https://nuget.windows10ce.com/nuget/v3/index.json" />
</packageSources>
</configuration>
Loading