-
Notifications
You must be signed in to change notification settings - Fork 1
My contribution to stabilizing release #365
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
BoroBongo
merged 16 commits into
releases/stabilizing-for-2026-07
from
borobongo/stabilizing-for-2026-07
Jun 13, 2026
Merged
Changes from 10 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
649bfc7
fix: Restore VRMouth food detection — add VobItem/VobItemNoWorldColli…
BoroBongo 2218d63
feat: player -> NPC melee combat
BoroBongo df877d1
NPC -> Player attack foundation
BoroBongo b5477f3
fix: guard remote grabbers and restrict draw sounds and mouth detecti…
BoroBongo a153929
catching null references
BoroBongo f3977a2
added NpcAttackAdapter through the prefab
BoroBongo ffbf5d6
feat: NPC loot panel — grab dead NPCs to open inventory
BoroBongo b833c9c
fix: VobMeshCullingDomain — guard dynamically-spawned items against c…
BoroBongo da2b7ee
null-check destroyed renderers to prevent stuck ghost shader
BoroBongo d6a1eff
fix: loot item texture corruption and VRSocket destroy-time re-parent…
BoroBongo c17aa93
swapped Debug.Log to our own Logger service, using LogCat.Npc
BoroBongo ecde8d8
feat: Move config to NPC-WIP section.
JaXt0r a96a179
refactor: Remove NpcAttackAdapter for now and changed logging of othe…
JaXt0r b10b80b
refactor: Move WeaponAttackAdapter to VR module.
JaXt0r 2cb2a49
refactor: Remove reflections.
JaXt0r 27f90a1
requested cleanup: moved populate sockets logic into its own method
BoroBongo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
161 changes: 161 additions & 0 deletions
161
Assets/Gothic-Core/Scripts/Adapters/Npc/NpcAttackAdapter.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| using System.Linq; | ||
| using Gothic.Core.Const; | ||
| using Gothic.Core.Models.Container; | ||
| using Gothic.Core.Domain.Npc.Actions.AnimationActions; | ||
| using MyBox; | ||
| using UnityEngine; | ||
| using ZenKit.Daedalus; | ||
|
|
||
| namespace Gothic.Core.Adapters.Npc | ||
| { | ||
| /// <summary> | ||
| /// Attached to NPC/Monster root collider to allow them to deal melee damage via unarmed attacks. | ||
| /// Fires FightHit events when the NPC's collider hits an opponent during attack animations. | ||
| /// </summary> | ||
| public class NpcAttackAdapter : MonoBehaviour | ||
| { | ||
| private NpcContainer _npcContainer; | ||
| private BoxCollider _collider; | ||
| private float _attackHitCooldown; | ||
|
|
||
| private void Start() | ||
| { | ||
| var npcLoader = GetComponentInParent<NpcLoader>(); | ||
| if (npcLoader != null) | ||
| { | ||
| _npcContainer = npcLoader.Container; | ||
| } | ||
|
|
||
| _collider = GetComponent<BoxCollider>(); | ||
| } | ||
|
|
||
| private void Update() | ||
| { | ||
| // Reduce cooldown timer each frame | ||
| if (_attackHitCooldown > 0) | ||
| { | ||
| _attackHitCooldown -= Time.deltaTime; | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Called when the NPC's collider hits something during combat. | ||
| /// Checks if the NPC is actively attacking and if the target is valid. | ||
| /// </summary> | ||
| private void OnTriggerEnter(Collider other) | ||
| { | ||
| // Can't hit without a valid container | ||
| if (_npcContainer == null) | ||
| { | ||
| Debug.LogWarning($"[NpcAttackAdapter] No NPC container"); | ||
| return; | ||
| } | ||
|
|
||
| // Check if this is within attack hit cooldown to prevent multiple hits per attack | ||
| if (_attackHitCooldown > 0) | ||
| { | ||
| Debug.LogWarning($"[NpcAttackAdapter] Hit in cooldown (remaining: {_attackHitCooldown:F2}s)"); | ||
| return; | ||
| } | ||
|
|
||
| // The target must have a hitbox layer | ||
| if (other.gameObject.layer != Constants.VobHitbox) | ||
| { | ||
| Debug.LogWarning($"[NpcAttackAdapter] Wrong layer: {LayerMask.LayerToName(other.gameObject.layer)}"); | ||
| return; | ||
| } | ||
|
|
||
| Debug.Log($"[NpcAttackAdapter] Collision with hitbox layer: {other.gameObject.name}"); | ||
|
|
||
| // Try to get the target NPC/Player | ||
| var targetNpcLoader = other.GetComponentInParent<NpcLoader>(); | ||
| if (targetNpcLoader == null) | ||
| { | ||
| Debug.LogWarning($"[NpcAttackAdapter] No target NpcLoader found"); | ||
| return; | ||
| } | ||
|
|
||
| var targetNpcContainer = targetNpcLoader.Container; | ||
| if (targetNpcContainer == null) | ||
| { | ||
| Debug.LogWarning($"[NpcAttackAdapter] No target NpcContainer found"); | ||
| return; | ||
| } | ||
|
|
||
| Debug.Log($"[NpcAttackAdapter] Target NPC: {targetNpcContainer.Instance.GetName(NpcNameSlot.Slot0)}"); | ||
|
|
||
| // Don't let NPCs hit themselves | ||
| if (targetNpcContainer == _npcContainer) | ||
| { | ||
| Debug.LogWarning($"[NpcAttackAdapter] Target is self, ignoring"); | ||
| return; | ||
| } | ||
|
|
||
| Debug.Log($"[NpcAttackAdapter] Checking if {_npcContainer.Instance.GetName(NpcNameSlot.Slot0)} is attacking..."); | ||
|
|
||
| // Check if the NPC is currently attacking | ||
| if (!IsNpcCurrentlyAttacking()) | ||
| { | ||
| Debug.LogWarning($"[NpcAttackAdapter] Not in attack state"); | ||
| return; | ||
| } | ||
|
|
||
| // Fire the hit event | ||
| var hitPosition = transform.position; | ||
| Debug.Log($"[NpcAttackAdapter] *** HIT FIRED! {_npcContainer.Instance.GetName(NpcNameSlot.Slot0)} → {targetNpcContainer.Instance.GetName(NpcNameSlot.Slot0)} at {hitPosition}"); | ||
| GlobalEventDispatcher.FightHit.Invoke(_npcContainer, targetNpcContainer, hitPosition); | ||
|
|
||
| // Set cooldown to prevent multiple hits in rapid succession (0.5 seconds) | ||
| _attackHitCooldown = 0.5f; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Determines if the NPC is currently in an attack animation. | ||
| /// Checks if the current animation action is an attack-related action. | ||
| /// </summary> | ||
| private bool IsNpcCurrentlyAttacking() | ||
| { | ||
| if (_npcContainer?.Props?.CurrentAction == null) | ||
| { | ||
| Debug.LogWarning($"[NpcAttackAdapter] No CurrentAction"); | ||
| return false; | ||
| } | ||
|
|
||
| // Check if the current action is an attack-based action | ||
| // AttackPlayAni is used for all NPC melee attacks | ||
| var currentAction = _npcContainer.Props.CurrentAction; | ||
| var actionTypeName = currentAction.GetType().Name; | ||
|
|
||
| Debug.Log($"[NpcAttackAdapter] CurrentAction type: {actionTypeName}"); | ||
|
|
||
| // Direct check for AttackPlayAni type (preferred, most reliable) | ||
| if (actionTypeName == "AttackPlayAni") | ||
| { | ||
| Debug.Log($"[NpcAttackAdapter] IsAttacking=TRUE (AttackPlayAni)"); | ||
| return true; | ||
| } | ||
|
|
||
| // Also support PlayAni with attack animations by checking the animation name | ||
| if (actionTypeName == "PlayAni") | ||
| { | ||
| // PlayAni stores animation name in Action.String0 | ||
| // Animation names for attacks typically contain "attack" or follow pattern like "s_1hAttack", "s_2hAttack" | ||
| if (currentAction.Action?.String0 != null) | ||
| { | ||
| var aniName = currentAction.Action.String0.ToLower(); | ||
| Debug.Log($"[NpcAttackAdapter] PlayAni animation: {aniName}"); | ||
| var isAttack = aniName.Contains("attack"); | ||
| Debug.Log($"[NpcAttackAdapter] IsAttacking={isAttack}"); | ||
| return isAttack; | ||
| } | ||
| else | ||
| { | ||
| Debug.LogWarning($"[NpcAttackAdapter] PlayAni but no animation name"); | ||
| } | ||
| } | ||
|
|
||
| Debug.LogWarning($"[NpcAttackAdapter] IsAttacking=FALSE (type: {actionTypeName})"); | ||
| return false; | ||
| } | ||
| } | ||
| } |
2 changes: 2 additions & 0 deletions
2
Assets/Gothic-Core/Scripts/Adapters/Npc/NpcAttackAdapter.cs.meta
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,3 +12,4 @@ public class NpcLoader : MonoBehaviour | |
| public bool IsLoaded; | ||
| } | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. I need to check if this duplicates the hit detection. I set it up like this before, just commented it out.
But keep it there, I will confirm first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah now I get it. It is that a NPC can hit another NPC.
I would like to remove this feature for now. Let's discuss on how to implement it with the existing logic of WeaponAttackAdapter (my idea is something like: AttackAdapter -> WeaponAttackAdapter/FistAttackAdapter (both for NPC+Monster+Hero).
I send you the source code for a reimplementation in another branch.