Fixed FloorCleanupParent to work

Added custom connection rule for broken doorways
Fixed ghost knight to work in multiplayer
This commit is contained in:
LadyAliceMargatroid 2025-02-10 12:39:14 -08:00
parent ab02b47d77
commit f0ef413d2f
7 changed files with 90 additions and 55 deletions

View File

@ -15,12 +15,15 @@ using GameNetcodeStuff;
using ScarletMansion.GamePatch.Components;
using ScarletMansion.Configs;
using DunGen.Graph;
using static DunGen.TileConnectionRule;
using DunGen.Tags;
namespace ScarletMansion.DunGenPatch {
public static class Patch {
public static bool active;
public static DungeonGenerator generatorInstance;
public static TileConnectionRule scarletConnectionRule = new TileConnectionRule(CanScarletTilesConnect);
public static RandomStream GetRandomStream(){
return generatorInstance.RandomStream;
@ -37,6 +40,7 @@ namespace ScarletMansion.DunGenPatch {
public static void Activate(DungeonGenerator generator){
active = true;
generatorInstance = generator;
DoorwayPairFinder.CustomConnectionRules.Add(scarletConnectionRule);
}
public static string GetLength(IntRange range, float multi){
@ -46,6 +50,7 @@ namespace ScarletMansion.DunGenPatch {
public static void Deactivate(bool ignoreScarletPlayer = false){
active = false;
generatorInstance = null;
DoorwayPairFinder.CustomConnectionRules.Remove(scarletConnectionRule);
GamePatch.JesterAIPatch.active = false;
@ -115,5 +120,18 @@ namespace ScarletMansion.DunGenPatch {
);
}
private static Tag brokenDoorwayTag = new Tag(199);
private static Tag treasureDoomTag = new Tag(7);
public static ConnectionResult CanScarletTilesConnect(Tile tileA, Tile tileB, Doorway doorwayA, Doorway doorwayB){
// if not we fuck up initial generation
if (doorwayA.Socket != doorwayB.Socket) return ConnectionResult.Passthrough;
// if not we bypass the treasure room rules
if (tileA.Tags.Contains(treasureDoomTag) || tileB.Tags.Contains(treasureDoomTag)) return ConnectionResult.Passthrough;
if (doorwayA.Tags.Contains(brokenDoorwayTag) || doorwayB.Tags.Contains(brokenDoorwayTag)) return ConnectionResult.Allow;
return ConnectionResult.Passthrough;
}
}
}

View File

@ -1,29 +1,36 @@
using System;
using System.Collections.Generic;
using DunGen;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using DunGen;
namespace ScarletMansion {
public class FloorCleanUpParent : MonoBehaviour {
namespace ScarletMansion
{
public class FloorCleanUpParent : MonoBehaviour, IDungeonCompleteReceiver {
public FloorCleanup[] children;
public string tileParentName;
void Reset(){
children = GetComponentsInChildren<FloorCleanup>();
}
void Awake(){
DunGenPlus.Managers.DoorwayManager.AddActionHook(DunGenPlus.Components.Scripting.DunGenScriptingHook.OnMainEntranceTeleportSpawned, OnDungeonComplete);
tileParentName = $"{GetComponentInParent<Tile>().gameObject.name}";
}
public void OnDungeonComplete() {
public void OnDungeonComplete(Dungeon dungeon) {
// somehow registereding in OnDungeonComplete fixes issues
DunGenPlus.Managers.DoorwayManager.AddActionHook(DunGenPlus.Components.Scripting.DunGenScriptingHook.OnMainEntranceTeleportSpawned, UpdateChildren);
}
public void UpdateChildren() {
var anyChanges = true;
while(anyChanges) {
anyChanges = false;
foreach(var c in children) {
if (c == null) {
continue;
}
var lastChanges = c.UpdateRender();
anyChanges|= lastChanges;
}

View File

@ -1,4 +1,5 @@
using System;
using DunGen;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -53,6 +54,11 @@ namespace ScarletMansion {
}
}
if (targerGameObject == null) {
Plugin.logger.LogError($"FloorCleanup null. dev fix plz");
return false;
}
var wasActive = targerGameObject.activeSelf;
targerGameObject.SetActive(false);
return wasActive;

View File

@ -9,6 +9,7 @@ using UnityEngine.AI;
using GameNetcodeStuff;
using ScarletMansion.GamePatch.Components;
using ScarletMansion.Configs;
using LethalLib.Modules;
namespace ScarletMansion {
@ -32,9 +33,23 @@ namespace ScarletMansion {
maxChaseSpeed = ConfigMain.Instance.revEnemyValue.speed;
if (IsOwner && KnightSpawnManager.Instance) {
var index = KnightSpawnManager.Instance.GetSpawnPointIndex();
if (index == -1) {
// grab target player
if (StartOfRound.Instance.ClientPlayerList.TryGetValue(NetworkObject.OwnerClientId, out var index)){
targetPlayer = StartOfRound.Instance.allPlayerScripts[index];
Plugin.logger.LogInfo($"Targeting {targetPlayer.playerUsername} for death");
}
if (!IsOwner) {
// other clients will only see eyes of death
foreach(var m in knightMeshRenderers) {
m.enabled = false;
}
}
// only server can deal with spawn stuff
if (IsServer) {
var knightSpawnIndex = KnightSpawnManager.Instance ? KnightSpawnManager.Instance.GetSpawnPointIndex() : -1;
if (knightSpawnIndex == -1) {
// grab position instead
var allVents = RoundManager.Instance.allEnemyVents;
var anyEnemyVent = allVents[UnityEngine.Random.Range(0, allVents.Length)];
@ -42,10 +57,8 @@ namespace ScarletMansion {
return;
}
SyncKnightReplacementClientRpc(index);
SyncKnightReplacementClientRpc(knightSpawnIndex);
}
}
public override void DoAIInterval() {
@ -57,6 +70,8 @@ namespace ScarletMansion {
if (isEnemyDead) return;
if (timeSinceSpawn < 1f) return;
var targetOutOfMap = !PlayerIsTargetable(targetPlayer);
if (targetOutOfMap){
CallDisappear();
@ -142,41 +157,6 @@ namespace ScarletMansion {
}
}
public void FindAndTunnelPlayer(Vector3 searchPosition){
var validPlayers = StartOfRound.Instance.allPlayerScripts.Where(p => p != null && PlayerIsTargetable(p));
if (validPlayers.Count() == 0) {
Plugin.logger.LogWarning("Could not find valid target to tunnel");
return;
}
var closestPlayer = validPlayers
.OrderBy(p => Vector3.SqrMagnitude(p.transform.position - searchPosition))
.FirstOrDefault();
if (closestPlayer != null) {
ChangeOwnershipOfEnemy(closestPlayer.actualClientId);
TunnelPlayerClientRpc(closestPlayer);
}
}
[ClientRpc]
public void TunnelPlayerClientRpc(NetworkBehaviourReference playerRef){
if (playerRef.TryGet<PlayerControllerB>(out var player)){
targetPlayer = player;
Plugin.logger.LogDebug($"Targeting {player.playerUsername} for death");
if (targetPlayer.IsOwner) return;
// other clients will only see eyes of death
foreach(var m in knightMeshRenderers) {
m.enabled = false;
}
} else {
Plugin.logger.LogWarning("Could not find target player through reference");
}
}
private bool calledDisappear = false;
public void CallDisappear(){
if (calledDisappear) return;

View File

@ -1,5 +1,6 @@
//using System;
using System.Collections;
using System.Linq;
using GameNetcodeStuff;
using ScarletMansion.Configs;
using ScarletMansion.GamePatch.Items;
@ -280,8 +281,18 @@ namespace ScarletMansion.GamePatch.Enemies {
if (IsServer) {
if (ConfigMain.Instance.revEnemyValue.enabled){
var enemy = ScarletNetworkManagerUtility.CreateEnemyWithType<KnightGhostVariant>(knightGhostEnemy, transform.position, 0f);
enemy.FindAndTunnelPlayer(transform.position);
// I need to parent the network at spawn
// so we gotta do the search stuff more early
var validPlayers = StartOfRound.Instance.allPlayerScripts.Where(p => p != null && PlayerIsTargetable(p));
if (validPlayers.Count() > 0) {
var closestPlayer = validPlayers
.OrderBy(p => Vector3.SqrMagnitude(p.transform.position - transform.position))
.FirstOrDefault();
ScarletNetworkManagerUtility.CreateEnemyWithTypeAndOwnership<KnightGhostVariant>(knightGhostEnemy, transform.position, 0f, closestPlayer.actualClientId);
} else {
Plugin.logger.LogWarning("Could not find valid target to tunnel. Not spawning ghost.");
}
}
var newKnife = Object.Instantiate(knifePrefab, base.transform.position + Vector3.up * 0.5f, Quaternion.identity, RoundManager.Instance.spawnedScrapContainer);

View File

@ -5,7 +5,6 @@ using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using DunGen;
using static LethalLevelLoader.ExtendedEvent;
using UnityEngine.AI;
namespace ScarletMansion {
@ -83,7 +82,7 @@ namespace ScarletMansion {
enemyAI.transform.rotation = rotation;
enemyAI.serverPosition = position;
if (enemyAI.agent == null) enemyAI.agent = GetComponentInChildren<NavMeshAgent>();
if (enemyAI.agent == null) enemyAI.agent = enemyAI.GetComponentInChildren<NavMeshAgent>();
enemyAI.agent.Warp(position);
if (enemyAI.IsOwner) {

View File

@ -404,6 +404,20 @@ namespace ScarletMansion {
return null;
}
public static T CreateEnemyWithTypeAndOwnership<T>(EnemyType enemy, Vector3 position, float yRotation, ulong ownerID) where T: EnemyAI {
if (enemy != null) {
var gameObject = GameObject.Instantiate(enemy.enemyPrefab, position, Quaternion.Euler(0f, yRotation, 0f));
var networkScript = gameObject.GetComponentInChildren<NetworkObject>();
networkScript.SpawnWithOwnership(ownerID, true);
Plugin.logger.LogFatal(ownerID);
var enemyScript = gameObject.GetComponent<T>();
RoundManager.Instance.SpawnedEnemies.Add(enemyScript);
return enemyScript;
}
return null;
}
public static bool CreateFlashlight(PlayerControllerB player, FlashlightItem flashLight, FlandreCrystal crystal){
var color = crystal.colorIndex;
var position = crystal.transform.position + Vector3.up * 0.25f;