ValveSoftware / halflife

Half-Life 1 engine based games
Other
3.66k stars 616 forks source link

Extend Generic Precache #2705

Open DarthMan opened 5 years ago

DarthMan commented 5 years ago

Hello. There are servers precaching stuff like wave sounds or custom player models (for the internet computer game Team Fortress Classic). The problem here is that there is a limit for the generic precache. However, unlike the others, this one is only server-side. A lot of servers are precaching a lot of say sounds and extending this value to say 4096 as it is on the Reverse Engineered Half-Life Dedicated Server would be a much better idea. Right now, it's only possible with - what I consider a stupid way, by using memory hacking (can also cause segmentation faults on Linux), when it could have been already implemented into the engine.

kisak-valve commented 5 years ago

Hello @DarthMan, this feature request is already being tracked at #421. Closing in favor of the existing request.

DarthMan commented 5 years ago

Hello @DarthMan, this feature request is already being tracked at #421. Closing in favor of the existing request.

Hello. That had to do with precache in general. My request was only related to generic precache, excluding models and sounds.

kisak-valve commented 5 years ago

I'm going to need a little help to understand why it makes sense to have yet another please extend the engine feature request instead of the existing #421 / #1551 / #12 issue reports before I re-open this request.

StevenKal commented 5 years ago

The #421 is not very accurate (lack of details) and more global (models + sounds + generics), the #1551 is more about a precache generic "problem" (not a limit), while the #12 is like the #421, but with accuracy. The one on this current topic by DarthMan (#2705) is about the generic buffer only, which is a little separated and can normally be increased easier and without the need to have a client binary updated (one of the reasons why this is a bit annoying to do this and why no extra addon/plugin has done this yet over time). From that I recall, this has been done in the ReHLDS engine (up to 4096), which is a server-side only binary.

So knowing the importance of the request, and knowing the task could be easier for "mikela" rather than models/sounds (he might even take a look at how it's made on ReHLDS), this subject does not deserve to be skipped/closed. But that's up to you. Resources limits is one of the most annoying thing under GoldSrc (especially nowadays), this deserves to be considered more seriously.

SamVanheer commented 5 years ago

Generic precache is not server only. The server generates the resource list which combines the generic, sound, model, event and decal precache lists into one large list (in SV_CreateResourceList) to be sent to clients.

Increasing any of those limits involves raising the limit for the resource list, and since the list has not been reworked to send this in pieces, increasing the limit can result in reliable channel overflows. #2534 covers this problem.

Increasing the generic limit to 4096 just moves the problem from the precache call to when the server creates the resource list, causing a fatal error Too many resources on server.. Increasing the maximum server side resource list size can solve that problem, but that moves the problem to the transmission of the list, which is where the reliable channel overflow occurs.

It is possible to increase the limits to max out the use of the fixed size buffer used for sending the list, but that's a risk since it depends on filename length. Longer filenames will fill up the buffer more, lowering the overall limit.

As such, changing any precache list limits safely involves changing both client (networking changes) and server (change limits, rework networking), and changing the network protocol version (because it's a breaking change).

That said, ReHLDS seems to have the limit for generic precache set to 512, and it has not raised the total resource limit (1280) as far as i can tell: https://github.com/dreamstalker/rehlds/blob/65c6ce593b5eabf13e92b03352e4b429d0d797b0/rehlds/common/qlimits.h#L36-L37 (2^9 is 512) https://github.com/dreamstalker/rehlds/blob/65c6ce593b5eabf13e92b03352e4b429d0d797b0/rehlds/public/rehlds/custom.h#L21

They had an issue where they debated this: https://github.com/dreamstalker/rehlds/issues/180

This issue also spells out the need for client side changes: https://github.com/dreamstalker/rehlds/issues/233

This request is essentially the same as the issues that Kisak has linked to. They all revolve around increasing the limits.

This can be done in such a way that server operators can define the limits, by using dynamic allocation instead of fixed size arrays. That way, once reworked, the limit can be configured by server operators and mod developers. The server will need to send the limit values to the client before sending any lists so the client can parse it correctly.

Note that such a change would affect a lot of code, including globals on the client and server side, some of which may be accessed by both client and server on a listen server.

For example, this global: https://github.com/id-Software/Quake/blob/bf4ac424ce754894ac8f1dae6a3981954bc9852d/WinQuake/gl_model.c#L38

This is a list of all loaded models, accessed by both client and server when running a listen server. You will need special case code to avoid reallocating the list, which would result in loss of data otherwise.

It is possible to make this all work, but it'll take a fair amount of effort, and a lot of testing to make sure everything works. And any mods and plugins that assume the old limits are still in use could break if the limit were to be exceeded (which realistically can only happen when using custom maps and third party plugins that load more resources).

As long as the network protocol is being changed it may be a good idea to also apply this change to the weapon list transmission code, which would remove the weapon limit (64). But that also touches a lot of code.

DarthMan commented 5 years ago

Generic precache is not server only. The server generates the resource list which combines the generic, sound, model, event and decal precache lists into one large list (in SV_CreateResourceList) to be sent to clients.

Increasing any of those limits involves raising the limit for the resource list, and since the list has not been reworked to send this in pieces, increasing the limit can result in reliable channel overflows. #2534 covers this problem.

Increasing the generic limit to 4096 just moves the problem from the precache call to when the server creates the resource list, causing a fatal error Too many resources on server.. Increasing the maximum server side resource list size can solve that problem, but that moves the problem to the transmission of the list, which is where the reliable channel overflow occurs.

It is possible to increase the limits to max out the use of the fixed size buffer used for sending the list, but that's a risk since it depends on filename length. Longer filenames will fill up the buffer more, lowering the overall limit.

As such, changing any precache list limits safely involves changing both client (networking changes) and server (change limits, rework networking), and changing the network protocol version (because it's a breaking change).

That said, ReHLDS seems to have the limit for generic precache set to 512, and it has not raised the total resource limit (1280) as far as i can tell: https://github.com/dreamstalker/rehlds/blob/65c6ce593b5eabf13e92b03352e4b429d0d797b0/rehlds/common/qlimits.h#L36-L37 (2^9 is 512) https://github.com/dreamstalker/rehlds/blob/65c6ce593b5eabf13e92b03352e4b429d0d797b0/rehlds/public/rehlds/custom.h#L21

They had an issue where they debated this: dreamstalker/rehlds#180

This issue also spells out the need for client side changes: dreamstalker/rehlds#233

This request is essentially the same as the issues that Kisak has linked to. They all revolve around increasing the limits.

This can be done in such a way that server operators can define the limits, by using dynamic allocation instead of fixed size arrays. That way, once reworked, the limit can be configured by server operators and mod developers. The server will need to send the limit values to the client before sending any lists so the client can parse it correctly.

Note that such a change would affect a lot of code, including globals on the client and server side, some of which may be accessed by both client and server on a listen server.

For example, this global: https://github.com/id-Software/Quake/blob/bf4ac424ce754894ac8f1dae6a3981954bc9852d/WinQuake/gl_model.c#L38

This is a list of all loaded models, accessed by both client and server when running a listen server. You will need special case code to avoid reallocating the list, which would result in loss of data otherwise.

It is possible to make this all work, but it'll take a fair amount of effort, and a lot of testing to make sure everything works. And any mods and plugins that assume the old limits are still in use could break if the limit were to be exceeded (which realistically can only happen when using custom maps and third party plugins that load more resources).

As long as the network protocol is being changed it may be a good idea to also apply this change to the weapon list transmission code, which would remove the weapon limit (64). But that also touches a lot of code.

How about that? https://forums.alliedmods.net/showpost.php?p=2426643&postcount=257

SamVanheer commented 5 years ago

Looks like ReHLDS separates its changes from the replicated original code (which is hard to follow). It does increase the limits when ReHLDS fixes are enabled, but the resource list size is still limited by the buffer used to send it.

The buffer, 65536 bytes large, is filled as follows:

So that's at minimum 9 + 12 + 1 bit = 22 bits for an empty resource and consistency list, if no download URL is specified.

If you wanted to precache the maximum number of resources in vanilla HL, excluding the filename to determine the minimum size and no consistency info, you'd get the following: 22 + 1280 * 44 = 56342 bytes

That's almost the size of the complete buffer, not counting the filename, which would put it past the buffer size if all filenames were 8 bytes long. A filename like models/hgrunt.mdl is 18 bytes long: 22 + 1280 * 52 = 66582 bytes

Now change 1280 to 4096: 22 + 4096 * 44 = 180246

That's almost 3 times the buffer size.

Increasing the limits on the server side won't do you any good because it'll still overflow when players try to connect. All you're doing is preventing the fatal errors during precaching.

The only real solution that will allow the limits to be raised is to rework the networking code. Since that's a breaking change any other networking related issues can also be fixed, like the consistency list's absolute index value being sent with too few bits of precision.

You could just increase the server side limits, cross your fingers and hope it works, but it's like walking through traffic blindfolded. Maybe it works, maybe it drops players with reliable channel overflow errors. That's more likely to happen the more files you precache, the longer the filenames are, the more files you add to the consistency list.

It quite simply was not built to scale up, it doesn't even scale to the limits that engine currently has.

uniarch commented 4 years ago

Someone make SamVanheer GoldSrc products developer at Valve // sorry for offtopic but i am very impressed how he investigates most of requests here and gives useful info and ideas

WPMGPRoSToTeMa commented 4 years ago

@SamVanheer you mixed up bits and bytes in your calculations. 22 bits + 1280 * 44 bits = 56342 bits = 7043 bytes (upper-bound)

For the 18 bytes long case: 22 bits + 1280 (44 + 18 8) bits = 240 662 bits = 30083 bytes (upper-bound)

And there are a lot of short-named resources, like brush models (e.g. *1), events (e.g. events/ak47.sc) and decals (e.g. {arrow2a). So this change is still very useful.