Skip to content

Add sync for stalkers#2255

Open
dartasen wants to merge 8 commits intoSubnauticaNitrox:masterfrom
dartasen:feature/stalkersync
Open

Add sync for stalkers#2255
dartasen wants to merge 8 commits intoSubnauticaNitrox:masterfrom
dartasen:feature/stalkersync

Conversation

@dartasen
Copy link
Copy Markdown
Member

@dartasen dartasen commented Jan 12, 2025

  • Stalker FindNest : [O] : leashPosition can be changed by FindNest
  • Stalker DropTooth : [O] : RemotePlayer cause DropTooth to duplicate items
  • AttackLastTarget (Done through current system)
  • MoveTowardsTarget (Done through current system)
  • FleeOnDamage : [O] StopPerform might change Creature.leashPosition
  • SwimToHeroPeeper : [CAW]
  • AggressiveWhenSeeTarget (Done through current system)
  • MeleeAttack
  • PrisonPredatorSwimToPlayer : [O] Add support for RemotePlayer target
  • CreatureFlinch [X]
  • CreatureFear [X]
  • PrisonCreatureBehaviour [X]
  • AvoidObstacles [X]
  • StayAtLeashPosition [X]
  • AvoidEscapePod [O] : StopPerform might change Creature.leashPosition

Will need work after this PR :

  • MeleeAttack (Pickup held item from remote player)
  • CreatureFriend System
  • CollectShiny

Closes #2250
Closes #2243
Contributes to #2627

@dartasen dartasen requested a review from tornac1234 January 12, 2025 14:04
@tornac1234 tornac1234 added the Area: AI Related to state machines (as used by the fish) label Jan 12, 2025
@dartasen dartasen marked this pull request as draft January 12, 2025 19:35
@dartasen dartasen force-pushed the feature/stalkersync branch from 24c8a58 to 19d2afe Compare January 12, 2025 22:36
@dartasen dartasen force-pushed the feature/stalkersync branch from 7029e10 to f916df4 Compare January 26, 2025 12:04
@dartasen dartasen force-pushed the feature/stalkersync branch from f916df4 to b47a533 Compare March 3, 2025 12:06
@dartasen dartasen added this to the 1.8 milestone Mar 17, 2025
@AtlantaDEV-ui

This comment has been minimized.

@dartasen dartasen force-pushed the feature/stalkersync branch 2 times, most recently from f98dea9 to 8844ac0 Compare April 10, 2025 19:39
@dartasen dartasen requested a review from Copilot April 10, 2025 21:50
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

NitroxClient/GameLogic/Spawning/Metadata/Extractor/StayAtLeashPositionMetadataExtractor.cs:7

  • The class name 'StayAtLeastPositionMetadataExtractor' appears inconsistent with the metadata type 'StayAtLeashPositionMetadata'; renaming it to 'StayAtLeashPositionMetadataExtractor' would improve clarity.
public sealed class StayAtLeastPositionMetadataExtractor : EntityMetadataExtractor<Creature, StayAtLeashPositionMetadata>

@dartasen dartasen force-pushed the feature/stalkersync branch from 8844ac0 to 50240e7 Compare April 11, 2025 11:56
@dartasen dartasen requested a review from Jannify April 12, 2025 08:23
@dartasen dartasen marked this pull request as ready for review April 12, 2025 10:01
@dartasen dartasen force-pushed the feature/stalkersync branch 2 times, most recently from ae17e14 to 0d25ae2 Compare April 12, 2025 17:18
@dartasen dartasen force-pushed the feature/stalkersync branch from 0d25ae2 to 063426c Compare April 26, 2025 09:37
@OhmV-IR
Copy link
Copy Markdown
Collaborator

OhmV-IR commented May 6, 2025

  • Cameras are super desynced with stalkers grabbing them, I don't see the camera in the position that the other client does and they can pick it up after the stalker drops it to dupe cameras
  • yellow goo attack VFX is not shown on the other client and neither is the SFX
  • cuddlefish can escape alien containment through animation with player(probably out of scope for the PR)
  • Stalkers hatched in alien containment but we did not see any change in behavior when we entered the room or the tank

@dartasen dartasen modified the milestones: 1.8, 1.9 May 9, 2025
@rylaix

This comment was marked as spam.

@dartasen dartasen force-pushed the feature/stalkersync branch from 063426c to 025ee09 Compare October 8, 2025 19:38
@github-actions
Copy link
Copy Markdown

github-actions bot commented Oct 8, 2025

Test Results

  1 files   -   1    1 suites   - 1   15s ⏱️ -11s
243 tests ±  0  242 ✅ ±  0  1 💤 ±0  0 ❌ ±0 
243 runs   - 243  242 ✅  - 242  1 💤  - 1  0 ❌ ±0 

Results for commit cfe27a8. ± Comparison against base commit f5ab747.

♻️ This comment has been updated with latest results.

@dartasen dartasen mentioned this pull request Jan 9, 2026
@dartasen
Copy link
Copy Markdown
Member Author

PrisonPredatorSwimToPlayer behavior is weird in singleplayer as well :

  • Will swim towards the player for 1s
  • Will cancel and move somewhere else

Which has a weird look & feel when looking at the creature.
Multiple CreatureAction are evaluating different target independently : MoveTowardsTarget, PrisonPredatorSwimToPlayer, SwimToHeroPeeper

MoveTowardsTarget is very likely to run after PrisonPredatorSwimToPlayer, which is pretty quick since there's no delay between creatureActions

@Measurity Measurity removed this from the 1.9 milestone Feb 16, 2026
@dartasen dartasen force-pushed the feature/stalkersync branch from fab078a to a23b4f5 Compare March 3, 2026 19:36
@dartasen
Copy link
Copy Markdown
Member Author

dartasen commented Mar 3, 2026

All systems online

@dartasen dartasen force-pushed the feature/stalkersync branch from a23b4f5 to cfe27a8 Compare March 3, 2026 20:07
@dartasen dartasen requested a review from Coding-Hen March 4, 2026 23:20
Copy link
Copy Markdown
Collaborator

@Coding-Hen Coding-Hen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM CW just a few minor points

return false;
}

// TODO: Add transpiler to add support for held item eat from remote players, we might need to add an equivalent of Inventory.GetHeldItem()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe worth creating a issue for this so we don't forget and someone can pick it up later. Let's not delay this, just think worth tracking for something separate and specific in another ticket as another bit of work.

Copy link
Copy Markdown
Collaborator

@tornac1234 tornac1234 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you're at it, would you patch MeleeAttack.CanDealDamageTo with a prefix like to ensure remote players aren't attacked when they shouldn't be ?

public static bool Prefix(GameObject target, ref bool __result)
{
    if (target.TryGetComponent(out RemotePlayerIdentifier remotePlayerIdentifier) && !remotePlayerIdentifier.RemotePlayer.CanBeAttacked())
    {
        __result = false;
        return false;
    }
    return true;
}

}

float num = Vector3.Distance(gameobject.transform.position, instance.transform.position);
if (num > instance.maxDistance || num < instance.minDistance)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we wanted to keep that minDistance logic, we should probably move it to GetNearestTarget so it actually acts as a filter

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove it, the rings behavior already implies to have a maxDistance

return 0f;
}

if (!creature.GetCanSeeObject(gameobject))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, GetCanSeeObject should be moved to IsTargetValid to be an actual filter
The current implementation could lead to situations like this one:

              player2 (distance = 50 => not target, GetCanSeeObject=true)
                             

 
               

Stalker |||wall||| player1 (distance = 30 => target, GetCanSeeObject=false)

player1 is closer to Stalker so they're picked as target, but then they're forgotten because they can't be seen, while player 2 might be in range and in sight range too (which means they're the only valid target here)

return 0f;
}

LastTarget lastTarget = creature.GetComponent<LastTarget>();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain why this is important ? (this is not in the base game and it seems to me that this wouldn't have any feedback on the current behaviour which might end up in situations where a player is a locked target so the stalker tries to attack it, but then another player is closer so the stalker randomly starts swimming towards that other player) (also if we were too keep that, we'd probably have to adapt the whole behaviour to drop the player as locked target when they're no longer a valid target)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain why this is important ? (this is not in the base game and it seems to me that this wouldn't have any feedback on the current behaviour

Initial issue is that PrisonPredatorSwimToPlayer is using Player.main exclusively to decide behaviors of this Action. Other behaviors almost always have a local state (or another behavior like LastTarget that stores this information) to share the "target" between Evaluate and Perform methods.

So I do need a state to persist this information in whatever form it can take (static states in patch, Custom component, LastTarget, ...). With that being said it's not excluded that other behaviors are also using LastTarget, in fact it's the case for Stalker. Which is why I used SetLockedTarget instead of usual SetTarget.
However it does not prevent other behaviors to have another target state which can be different from LastTarget. But that's up to SN devs that implemented behaviors that can conflict with each other, that's not really the result of my choices (see #2255 (comment))

As a side note PrisonPredatorSwim behavior guarantee that the creature is inside the prison, thereferore they're friendly and all the agressive behaviors are disabled. Which can limit the weird behaviors between conflicting behaviors

also if we were too keep that, we'd probably have to adapt the whole behaviour to drop the player as locked target when they're no longer a valid target

I can implement that in Perform if needed

    public static void Perform(PrisonPredatorSwimToPlayer instance, Creature creature, float time)
    {
        LastTarget lastTarget = creature.GetComponent<LastTarget>();
        if (!lastTarget)
        {
            Log.ErrorOnce($"[{nameof(PrisonPredatorSwimToPlayer_Perform_Patch)}]: Creature {creature} does not have a LastTarget component.");
            return;
        }

       if (!IsValidTarget(lastTarget.target))
       {
            lastTarget.UnlockTarget();
            return;
       }

        Transform targetTransform = lastTarget.target ? lastTarget.target.transform : null;
        if (targetTransform && time > instance.timeNextSwim)
        {
            instance.timeNextSwim = time + instance.swimInterval;
            instance.swimBehaviour.SwimTo(targetTransform.position, instance.swimVelocity);
        }

        lastTarget.UnlockTarget();
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: AI Related to state machines (as used by the fish)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add sync for Stalker Stalker teeth invisible?

9 participants