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
Implement client bubble PVS. #983
Conversation
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.
Awesome
FYI there are still some outstanding known errata w/ picking parents/children. Needs more testing to narrow down when/where/how. I will be making client changes to support position being NaN in state updates as "don't vanish until seen" mechanics so the client can't see things are being unseen. |
58c4c65
to
9827f0a
Compare
from discord, a rough explanation;
|
include contained entities fix line edit crash when clipboard contents are null somehow use CVar for update bubble range remove seenMovers that get NaN'd out of MaxUpdateRange - huge reduction in network traffic from bullets cut default of MaxUpdateRange down to 12.5 for now maybe handle teleported things handle removing player state on disconnect fixed positional audio errors make UpdateEntityTree also update player's last seen ents make net.maxupdaterange cvar tunable at runtime w/o impacting performance back to position nan as means to hide from client revert work pooling as the wrong player was getting the wrong game state ffs needed to think less about *if* something is *seen* and more about *when* it must be *unseen* clean up usings handle parenting and sequencing issues that arise on the client gather needed ents to update recursively applied suggestions from code review fix missing recursively contained ents make assumption that client last saw things on first tick instead of tick zero, as zero would be the "from tick" and first would be he "to tick" add First tick as constant to GameTick due to relevance above renamed includedEnts to checkedEnts to make usage more clear added comments inverted some conditions to flatten parts of the pvs logic fixed sending states when already seen (lastChange < lastSeen to lastChange <= lastSeen) fix sending states when no actual changes (other bugs?) local caching of currentTick, remove priorTick
…ating network state if AttachParent isn't invoked
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.
Would it be possible to introduce an explicit off switch (that also would work if changed mid game?).
if (!source.SetPosition(entity.Transform.WorldPosition)) | ||
{ | ||
Logger.Warning("Can't play positional audio, can't set position."); | ||
return null; |
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.
Not sure it's a good idea for this to ever return null. Even in the worst scenario it might just be better to have this return a dummy value that's seen as stopped?
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.
The only outer caller doesn't evaluate the result of Play.
How should it handle this case?
if (!source.SetPosition(coordinates.ToMapPos(_mapManager))) | ||
{ | ||
Logger.Warning("Can't play positional audio, can't set position."); | ||
return null; |
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.
Ditto on returning null here.
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.
PlayAudioPositionalHandler as the only outer caller doesn't check the return value.
Do you want it to verify if a sound played?
{ | ||
_checkDisposed(); | ||
|
||
var (x, y) = position; | ||
|
||
if (!ValidatePosition(x, y)) |
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.
This feels like really bad API design to me.
Maybe make this throw on NaN and have the uses explicitly check for it before calling?
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.
Outside of the API it's used like this;
if (!renderer.Source.SetPosition(renderer.TrackingEntity.Transform.WorldPosition))
{
Shared.Log.Logger.Warning("Interrupting positional audio, can't set position.");
renderer.Source.StopPlaying();
}
Adding [MustUseReturnValue]
makes the API require the bool to be checked or issue a warning on complying IDEs.
The caller should just stop playing the sound if the position is NaN, because that indicates it's an entity the client is unaware of the position. If this ever occurs, it's probably intentional.
I think Audio that's not relatively quiet or localized needs to be sent with a specifically with a position and not an entity. There should be no guarantee that a sound can play at any position.
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.
Do you think it should be TrySetPosition
instead?
#pragma warning restore 649 | ||
|
||
private int _nextServerEntityUid = (int)EntityUid.FirstUid; | ||
private float? _maxUpdateRangeCache; |
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.
This thing doesn't actually get assigned outside of that null down there.
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.
That's correct... so the server can update _maxUpdateRangeCache
related cvar once per frame.
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.
Oh I read this wrong, I thought you meant it doesn't get assigned except for the null and where it gets assigned...
public float MaxUpdateRange => _maxUpdateRangeCache
??= _configurationManager.GetCVar<float>("net.maxupdaterange");
^ It gets assigned there. It's just 2 lines down.
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.
Oh, my bad.
public List<EntityState> UpdatePlayerSeenEntityStates(GameTick fromTick, IPlayerSession player, float range) | ||
{ | ||
var playerEnt = player.AttachedEntity; | ||
if (playerEnt == null) |
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.
Players in the lobby have no entity, so...
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.
What does this mean?
…nt's Children collection and other stuff rotating parent entities now are visible with their orbiting children if one of their children moves into view
introduce net.pvs to configure enabling/disabling PVS
Added. |
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.
There are a few edge cases that need to be looked at, mainly around world parenting and shuttles. As far as I can tell these problems are because the TransformComponent is poorly implemented, and really needs some testing and API tweaks. The main features were successfully implemented and seem stable enough for the CM test at the end of the month, so I am approving this.
You guys call it bubbling. PVS means Potentially Visible Set.