ValveSoftware / halflife

Half-Life 1 engine based games
Other
3.72k stars 625 forks source link

[HL25] Issues with View Distance on Certain Maps #3683

Open 0Ky opened 11 months ago

0Ky commented 11 months ago

Description

I have identified a significant issue related to the view distance on specific maps, notably on xen_dm. When players are positioned with a clear line of sight, they, along with any rendered objects, become prematurely clipped and entirely omitted from the screen. This issue seems to be map-specific and occurs under standard gameplay conditions. This problem is similar to what was reported in issues #784 and #1415, also issue #1125 claims a similar problem on map c2a2a.

Modifying gl_zmax from 4096 to 8192 and toggling gl_ztrick_old between 0 and 1 had no effect. This leads me to believe these commands might be deprecated, especially since the D3D renderer was removed. Changing sv_zmax to a higher value like 8192 seems to resolve the issue on the xen_dm map, suggesting it's a maximum view distance limitation. However, when I "create server" from the main menu, adjusting sv_zmax is not possible (error message: Can't set sv_zmax in multiplayer). This error message does not apply when hosting via Half-Life Dedicated Server (HLDS).

It seems that the default value of sv_zmax needs to be increased from 4096. It's expected that players and any rendered objects should remain visible at long distances when there is a clear line of sight, without needing to modify server-side settings in unconventional ways.

HL Version

Protocol version 48
Exe version 1.1.2.2/Stdio (valve)
Exe build: 01:03:30 Dec  1 2023 (9899)

HLDS Version

Protocol version 48
Exe version 1.1.2.2 (valve)
Exe build: 01:01:49 Dec  1 2023 (9899)

Video Demonstration

https://github.com/ValveSoftware/halflife/assets/16103757/e2928316-78b7-43d2-a78e-834a1f780586

SmileyAG commented 11 months ago

Let me clarify a little: the mapper itself can set the value for visibility using the MaxRange parameter in the worldspawn entity (that value got written into pev->speed): https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/world.cpp#L694-L698

And later, value for sv_zmax is set from pev->speed if it's more than 0:

https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/world.cpp#L631-L634

Modifying gl_zmax from 4096 to 8192 and toggling gl_ztrick_old between 0 and 1 had no effect.

Well, because this value is not only overwritten from the value of movevars.zmax, but it also doesn’t actually do anything in the engine code:

  // At the bottom of CL_ParseMovevars function in engine
  if (movevars.zmax != gl_zmax.value) {
    Cvar_SetValue("gl_zmax",movevars.zmax);
  }

movevars.zmax value is written from the value of sv_zmax:

// In the middle of SV_SetMoveVars function in engine
movevars.zmax = sv_zmax.value;

movevars.zmax after would be used in code of R_SetupGL and MakeSkyVec functions

So, speaking briefly, changing the value for sv_zmax would be a more reasonable solution, but it also can be limited to simply increasing the value of MaxRange for the mapper

0Ky commented 11 months ago

...changing the value for sv_zmax would be a more reasonable solution

This is opposed to the gl_zmax cvar right? If not, then it would definitely not be a 'reasonable solution' when an official map (presumably) does not have a higher value set for MaxRange (max viewable distance) in the map's worldspawn entity.

There clearly is an issue with maps that have not set the maximum viewable distance, which sets sv_zmax to the default value of 4096 which is not enough for two players to see each other in a line of sight on xen_dm and supposedly other maps.

It's also not ideal to request every player that creates a server facing this issue to directly change the value of sv_zmax, due to the lack of player knowledge and accessibility. Not all players that create a server is aware of advanced settings or console commands like sv_zmax. Expecting casual players that create a server to modify this value to address viewable distance issue in official maps can be unrealistic, as it requires a level of technical knowledge that many players may not have.

SmileyAG commented 11 months ago

If not, then it would definitely not be a 'reasonable solution' when an official map (presumably) does not have a higher value set for MaxRange (max viewable distance) in the map's worldspawn entity.

Yes, I understand that, some mapper could specifically design it for use with standard settings, but on the other hand, there are enough custom maps where sv_zmax would like to have more, and therefore a change globally can seems like a minus for some maps, but overall it’s more like a plus

And, besides the some new cvar as sv_zmax_override could be created with a bit of changing code in engine-side for it implementation, so that despite the fact that the mapper even sets the own value in MaxRange to more than 0, you could still override as you think is necessary and might even set the specific value for each map in their configs Because the mapper may set the value too low or high for being it not enough in gameplay, that's the purpose for having a new cvar such as sv_zmax_override

It's also not ideal to request every player facing this issue to directly change the value of sv_zmax, due to the lack of player knowledge and accessibility. Not all players are aware of advanced settings or console commands like sv_zmax.

Well, this is of course not an entirely correct conclusion, here in general I would say that the client doesn't even should to have control over of that settings such as visibility distance and responsibility for that should fall on the server owner (as it done with sv_zmax), and if server owner does not even know such cvars for settings, well it is only his problem

0Ky commented 11 months ago

Yes, I understand that, some mapper could specifically design it for use with standard settings, but on the other hand, there are enough custom maps where sv_zmax would like to have more, and therefore a change globally can seems like a minus for some maps, but overall it’s more like a plus

I'm not sure what you're trying to say here... The map designer can already set the MaxRange to what ever they like, this is not going to change or hinder custom map designers, if they require a lower MaxRange value, then they are more than welcome to set it, also it would be great if you can provide an actual example where a map takes advantage of the default sv_zmax 4096 value and breaks the map when the default value is increased, since you claim it's a minus for some maps, I'd like to know which maps.

I'm not asking to increase what ever the maximum limitation of MaxRange can be set to. I'm only requesting that the default sv_zmax value on HLDS and listen server is set to a slightly higher value than 4096 so that it fixes the culling distance issue in the official maps xen_dm / c2a2a which is shipped with Half-Life.

And, besides the some new cvar as sv_zmax_override could be created...Because the mapper may set the value too low or high for being it not enough in gameplay...

There is no need to create a new cvar, no one is asking for that. The issue is not about the map designer mistakenly setting the MaxRange value too high or low, it's the absence of it. Which defaults the value of sv_zmax to 4096 and that causes problems to some official maps. Our primary focus should be on resolving the existing culling distance issue that affects gameplay on certain official maps, not by making speculative assumptions about map creators' intentions or players' preferences.

...I would say that the client doesn't even should to have control over of that settings such as visibility distance and responsibility for that should fall on the server owner (as it done with sv_zmax), and if server owner does not even know such cvars for settings, well it is only his problem

Yes, that was my mistake for not clarifying, I was actually implying players that hosts a server.

SmileyAG commented 11 months ago

I once again emphasize the fact that if you are interested for solving that issue only for official Half-Life maps, and not on a global scale, then the Valve mapper can solve it by setting the MaxRange value without a need of changing sv_zmax, I tried to express myself as clearly as possible in this matter

There is no need to create a new cvar, no one is asking for that. The issue is not about the map designer mistakenly setting the MaxRange value too high or low, it's the absence of it.

Well, in your defense I can say that value for sv_zmax in server-side code is only set at world initialization, so it's simply enough to set it afterwards once and then the require in sv_zmax_override not needed (and there is no need in restarting map after changing, it applies in real-time)

But if this were not so, then my argument in sv_zmax_override had a valid reason, because imagine what that code is placed in function that called each frame and sv_zmax was overwritten each time with a value from MaxRange, that mapper is set to the same 4096 for example or even more lower, and what would you do in this case? That’s right, you wouldn’t be able to do anything, unless you would set the value with some amx plugin or whatever right after function that sets original value is called, but luckly for us, in reality this only set at init of world, so there is no need to do such of that stuff

SmileyAG commented 11 months ago

because imagine what that code is placed in function that called each frame and was overwritten each time with a value

In case if someone would think that Valve devs don't go for such step, then let me simply to show a real proof of that take:

  // CHud:Redraw function in Counter-Strike 1.6 code from decompiled linux client binary

  bVar13 = cl_drawviewmodel == (cvar_t *)0x0;
  if (bVar13) {
    cl_drawviewmodel = (*gEngfuncs.pfnGetCvarPointer)("r_drawviewmodel");
  }

  if ((cl_drawviewmodel != (cvar_t *)0x0) && (cl_drawviewmodel->value != 1.0)) {
    (*gEngfuncs.Cvar_SetValue)("r_drawviewmodel",1.0);
  }

There in fact even more cvars that couldn't be set in Counter-Strike 1.6 that placed in the same function, since it would set to hardcoded value each time you will try to change them

0Ky commented 11 months ago

I once again emphasize the fact that if you are interested for solving that issue only for official Half-Life maps, and not on a global scale, then the Valve mapper can solve it by setting the MaxRange value without a need of changing sv_zmax

@SmileyAG It's really up to Valve to decide how they fix the issue, either solutions will do. Although, I'm not sure if it would be feasible for them to modify a map, as it would create inconsistencies between players who have updated the map and those who have not. It just might be easier for them to modify the server's default sv_zmax value instead.

...value for sv_zmax in server-side code is only set at world initialization...

I have no idea what you're trying to imply with the additional cvar, you already can modify the sv_zmax after the map is loaded which will take effect immediately each time you change the value, you don't need to restart map. The value will persist, even if the map itself has a MaxRange value set. So, adding a custom sv_zmax value to server.cfg will override the map's MaxRange value.

that mapper is set to the same 4096 for example or even more lower, and what would you do in this case?

Then do nothing, the map designer intentionally set that value for a reason, as I said before the issue is not addressing missetting the value, but the absence of it.

N7P0L3ON commented 11 months ago

@0Ky I think forcing a value for this setting will create more issues that actually resolving. For example there are maps that actually require bigger visible distance... in order to render for example 3d skybox. If a command is set to override that, all those maps will be broken.

There are 2 solutions I see here, 1 is the easy one solution, the 2 is a bit harder one...

Solution 1: Since that map is Valve made, they can simply recompile it with the correct visible distance and push it to the Steam release... It should not cause issues with "other" versions of the map... unless you're considering the pirated servers... Since everyone playing should be actually using legitimate downloaded version of the game... (that includes server too).

Solution 2: Implement a server/engine check if the max visible distance is set for the map to be loaded, and in case it's set, to do nothing and leave the value that's set by the mapper; if however there's no given value only then to actually add the correct value.

Still, I would go for solution 1. Solution 2 is with potential to break more stuff than resolving anything...

We already have a lot of old mods broken, and most likely they will remain broken... Don't add more to the list...

0Ky commented 11 months ago

I think forcing a value for this setting will create more issues that actually resolving. For example there are maps that actually require bigger visible distance... in order to render for example 3d skybox. If a command is set to override that, all those maps will be broken.

@N7P0L3ON I never suggested to enforce or replace the MaxRange (maximum viewable distance) from the map's worldspawn entity. If the map designer does not specifically set a MaxRange value, the server will automatically default sv_zmax to 4096, as noted in https://github.com/ValveSoftware/halflife/issues/3683#issuecomment-1843317134. In other words, when the map designer requires bigger visible distance, they typically will set the MaxRange to a certain value, which will specify a custom value for sv_zmax, replacing the default setting.

Solution 1: Since that map is Valve made, they can simply recompile it with the correct visible distance and push it to the Steam release... It should not cause issues with "other" versions of the map... unless you're considering the pirated servers... Since everyone playing should be actually using legitimate downloaded version of the game... (that includes server too).

Ideally this would be the most logical approach, which is a targeted fix that addresses the problem at its source. However, this would break map comparability amongst different branches of Half-Life, steam_legacy and beta. There will be many players complaining about Your map differs from the server's error that comes with this solution. Remember that the server and client must have the same map, so if you're on the latest version with the new map fix, you will not be able to join servers that's running an old build of HLDS. There are plenty servers currently that are not running on the latest HLDS version.

Solution 2: Implement a server/engine check if the max visible distance is set for the map to be loaded, and in case it's set, to do nothing and leave the value that's set by the mapper; if however there's no given value only then to actually add the correct value.

I believe this is how the game already works. Have a look at the following code:

https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/world.cpp#L631-L634

^ Here's a pseudocode explanation of that code snippet:

If the mapper has specified a MaxRange value:
    Set sv_zmax to the specified MaxRange value.
Otherwise:
    Set sv_zmax to the default value of 4096.
SamVanheer commented 11 months ago

Ideally this would be the most logical approach, which is a targeted fix that addresses the problem at its source. However, this would break map comparability amongst different branches of Half-Life, steam_legacy and beta. There will be many players complaining about Your map differs from the server's error that comes with this solution. Remember that the server and client must have the same map, so if you're on the latest version with the new map fix, you will not be able to join servers that's running an old build of HLDS. There are plenty servers currently that are not running on the latest HLDS version.

This is not correct. The engine ignores the entity data lump when calculating the CRC value used to compare the client's copy of the map with the server's. This is to allow servers to edit the map's entity data and still allow clients to join and play.

0Ky commented 11 months ago

This is not correct. The engine ignores the entity data lump when calculating the CRC value used to compare the client's copy of the map with the server's. This is to allow servers to edit the map's entity data and still allow clients to join and play.

@SamVanheer I've just compiled a map called view.bsp without adding MaxRange key, which should use the default 4096 value. I've put this into the maps folder of HLDS with version 11:25:48 Dec 11 2023 (9909). In the map editor, I've added the MaxRange key with a value of 8000, re-compiled this without making any other changes and placed it in the Half-Life's map folder. I've made sure to restart both HLDS and Half-Life, when I attempt to connect to the server I'm prompted with the following message:

Your map [maps/view.bsp] differs from the server's.
Host_Error: Disconnected

image

I thought maybe recompilation process introduced minor differences in the file, altering its CRC value. I've also tried copying the same map file from HLDS (with the default MaxRange value of 4096) into Half-Life's map folder, then used hex editor to change 1 byte of the value "MaxRange" "4096" in view.bsp and I am still prompted with the same message.

Are you able to reproduce what you claim ?

SamVanheer commented 11 months ago

I tested this with a dedicated server hosting boot_camp. With a default copy in the dedicated server and a modified copy on the client, modified using ripent to add "MaxRange" "8000" the client is perfectly capable of joining and playing.

Modifying both maps, the server with "MaxRange" "100" and the client with "MaxRange" "8000" still works as well, with sv_zmax being 8000 on the client (from loading the map locally before) and 100 on the server and the world only rendering 100 units out: afbeelding

The map, loaded by the client in a local server: afbeelding

If hex editing the map causes maps differs from server errors then the editor is probably changing something else as well. Only ever use ripent to modify a map's entity data, that's guaranteed to work.

And to be sure: the dedicated server installation is separate from the client, downloaded using SteamCMD.

I also checked the engine and the code used to calculate CRCs still skips the entity data lump.

0Ky commented 11 months ago

If hex editing the map causes maps differs from server errors then the editor is probably changing something else as well. Only ever use ripent to modify a map's entity data, that's guaranteed to work.

@SamVanheer Interesting, I had to use a different 3rd party tool called BSPEdit. I'm not sure why it had failed the map integrity check after editing only a single byte, perhaps the editor I used had modified something else or it might have been a case of user error.

I'm not prompted with the Your map differs from the server's message anymore, which means @N7P0L3ON's 1st solution could be feasible. Also, the same viewable distance issue is present in boot_camp map as well.

SmileyAG commented 11 months ago

Oh that issue is still active, I even forgot about that, but yeah @0Ky let me reply to previous message that you addressed me

Although, I'm not sure if it would be feasible for them to modify a map, as it would create inconsistencies between players who have updated the map and those who have not

In such modern ripent-like tools such as newbspguy there is a feature that could avoid after editing map of Your map differs from the server's message with CRC spoofing: https://github.com/UnrealKaraulov/newbspguy/blob/54879b5d1938f74925b20200886798c6fef61b84/src/bsp/Bsp.cpp#L3002

I have no idea what you're trying to imply with the additional cvar, you already can modify the sv_zmax after the map is loaded which will take effect immediately each time you change the value, you don't need to restart map. The value will persist, even if the map itself has a MaxRange value set. So, adding a custom sv_zmax value to server.cfg will override the map's MaxRange value.

It’s just that when I wrote the first messages, I forgot the simple fact that sv_zmax is set only when the world is initialized and that’s why I started talking about a separate cvar, but then I remembered about it and opposed my previous take for adding of new cvar as unnecessary in https://github.com/ValveSoftware/halflife/issues/3683#issuecomment-1846791589, and in next message you decided to write the almost word-by-word same as I said in comment that linked, but why? What were you trying to prove with this?

Then do nothing, the map designer intentionally set that value for a reason, as I said before the issue is not addressing missetting the value, but the absence of it.

I'd say that not a valid to use this as an excuse for everything, unexperienced mappers could simply set the value that they are saw in some mapping guide on YouTube or forum without taking a depth what exactly that option is does Having the cvar / command to control over of such things is a kind of must have in fact, but by default it of course disabled with priority to use decision from mapper, but if the server owner and/or community that playing on that server is not agreement with what mapper had set, then owner could overwrite it with cvar instead of using / coding plugins and ReHLDS for that purpose, you see now? Of course, in such cases are more rare to happen, but this is not a reason to excuse of forcing such things

But yeah let me repeat again in a third time - luckly for us, this all happens only at when the world is initialized, and therefore we do not need to use any plugins or ReHLDS to change the zmax that set by the mapper, so there is no point to continue discuss that case