The features for filtering by class and team are not always enough for what we/I/somebody want to do. Sometimes it would be useful to apply a different filter. With this patch, that is possible. This visibility is purely a rendering matter, and does not affect game logic. (The actor is not considered invisible when this feature prevents it from rendering for any given player)
Decorate property: int VisibleFilter
Decorate flag: FILTERHIDES
The filter uses AAPTR_ values to identify actors (players) that may render this actor.
If the filter is 0 no filtering occurs.
If FILTERHIDES is set, the filter identifies actors (players) that may not render the actor.
I have not set up string parsing for the VisibleProperty (yet). That means that the property in decorate syntax is next to useless. I might add that later, or try to make the decorate parser expression-aware (so that you can use named constants directly. This would change Actvation and other properties, which must now use string constants to identify individual flags. An expression aware parser would accept any constant decorate expression.)
However, you can change the flag and filter at runtime from ACS or decorate.
ACS-property identifiers:
APROP_VisibleFilter
APROP_FilterHides
Decorate declarations:
int VisibleFilter -- setting 0 will disable filtering (default)
flag FILTERHIDES -- only applies when VisibleFilter is non-0.
Decorate modifiers:
A_FilterVisibility(int filter)
A_ChangeFlag("FILTERHIDES", true|false)
For those who want to filter one actor so that only master sees it, and one so that only master does not see it, who also happen already to have this particular actor as an activator at some point in an acs script:
Code: Select all
SetActorProperty(0, APROP_VisibleFilter, AAPTR_MASTER);
Code: Select all
SetActorProperty(0, APROP_VisibleFilter, AAPTR_MASTER);
SetActorProperty(0, APROP_FilterHides, true);
Spoiler: Technical notes
The filtering function was implemented for VisibleToTeam and VisibleToClass. I have extended it to manage this filter. However, that function has been declared const (making *this a const), which meant that the calling actor could only be passed to functions that promised to preserve its data. Since this is a clientside function (rendering, not gameplay) it makes sense to have this restriction, but most functions don't declare their parameters as const even if they can. I had to update a subset of method declarations for this reason, but method bodies were untouched. There were no assignments; they were const-ready.
With that horrific exception. When TObjPtr<T> resolves into T, there is a possible assignment of 0 to data that is part of the actor. It violated const-rules.
I didn't want to take away the const-constraint; I approved of it. However, much of zdoom doesn't bother with it, and I considered it a possibility.
The resolution of TObjPtr<T> to T would not at a later point return non-0, so it might be safe and stable to use const_cast and knowingly violate that rule. However, I don't know optimizers, compilers and internal behaviours that well. I wouldn't be the one to do that. Still, it might be better than what I chose to do.
I chose to add a cast operator that was itself const. It resolves to T through an overload of ReadBarrier that takes a const parameter and does not assign NULL to it when it returns NULL. Thus, it gets the same result, but postpones modification of the data in any way whatsoever until the non-const version is called. This seems semantically sound.
However, there are people who do these things for a living, and know why we do and do not do the things we do and do not do. I'm not among them.
If my solution is not the best one, or not good enough, I'm sure the explanation of why it cannot be done that way also points to the proper solution.
Spoiler: About the demo
The effect can be rather hard to spot. DoomImpBalls visible only to the one they are fired at (and incidentally to the one who fired them, as AAPTR_TARGET; I just put it there because I could, monsters don't render anything). Usually, they'll be fired at you. Try a multiplayer game, or summon a friendly doomimp, or encourage ranged infighting, or do something else to have an imp fire not at you, and you will not see the projectile.
The features for filtering by class and team are not always enough for what we/I/somebody want to do. Sometimes it would be useful to apply a different filter. With this patch, that is possible. This visibility is purely a rendering matter, and does not affect game logic. (The actor is not considered invisible when this feature prevents it from rendering for any given player)
Decorate property: int VisibleFilter
Decorate flag: FILTERHIDES
The filter uses AAPTR_ values to identify actors (players) that may render this actor.
If the filter is 0 no filtering occurs.
If FILTERHIDES is set, the filter identifies actors (players) that may not render the actor.
I have not set up string parsing for the VisibleProperty (yet). That means that the property in decorate syntax is next to useless. I might add that later, or try to make the decorate parser expression-aware (so that you can use named constants directly. This would change Actvation and other properties, which must now use string constants to identify individual flags. An expression aware parser would accept any constant decorate expression.)
However, you can change the flag and filter at runtime from ACS or decorate.
ACS-property identifiers:
APROP_VisibleFilter
APROP_FilterHides
Decorate declarations:
int VisibleFilter -- setting 0 will disable filtering (default)
flag FILTERHIDES -- only applies when VisibleFilter is non-0.
Decorate modifiers:
A_FilterVisibility(int filter)
A_ChangeFlag("FILTERHIDES", true|false)
For those who want to filter one actor so that only master sees it, and one so that only master does not see it, who also happen already to have this particular actor as an activator at some point in an acs script:[code]SetActorProperty(0, APROP_VisibleFilter, AAPTR_MASTER);[/code][code]SetActorProperty(0, APROP_VisibleFilter, AAPTR_MASTER);
SetActorProperty(0, APROP_FilterHides, true);[/code]
[spoiler=Technical notes]The filtering function was implemented for VisibleToTeam and VisibleToClass. I have extended it to manage this filter. However, that function has been declared const (making *this a const), which meant that the calling actor could only be passed to functions that promised to preserve its data. Since this is a clientside function (rendering, not gameplay) it makes sense to have this restriction, but most functions don't declare their parameters as const even if they can. I had to update a subset of method declarations for this reason, but method bodies were untouched. There were no assignments; they were const-ready.
With that horrific exception. When TObjPtr<T> resolves into T, there is a possible assignment of 0 to data that is part of the actor. It violated const-rules.
I didn't want to take away the const-constraint; I approved of it. However, much of zdoom doesn't bother with it, and I considered it a possibility.
The resolution of TObjPtr<T> to T would not at a later point return non-0, so it [i]might[/i] be safe and stable to use const_cast and knowingly violate that rule. However, I don't know optimizers, compilers and internal behaviours that well. I wouldn't be the one to do that. Still, it [i]might[/i] be better than what I chose to do.
I chose to add a cast operator that was itself const. It resolves to T through an overload of ReadBarrier that takes a const parameter and does not assign NULL to it when it returns NULL. Thus, it gets the same result, but postpones modification of the data in any way whatsoever until the non-const version is called. This seems semantically sound.
However, there are people who do these things for a living, and know why we do and do not do the things we do and do not do. I'm not among them.
If my solution is not the best one, or not good enough, I'm sure the explanation of why it cannot be done that way also points to the proper solution.[/spoiler][spoiler=About the demo]The effect can be rather hard to spot. DoomImpBalls visible only to the one they are fired at (and incidentally to the one who fired them, as AAPTR_TARGET; I just put it there because I could, monsters don't render anything). Usually, they'll be fired at you. Try a multiplayer game, or summon a friendly doomimp, or encourage ranged infighting, or do something else to have an imp fire not at you, and you will not see the projectile.[/spoiler]