FunkyFr3sh / cnc-ddraw

GDI, OpenGL and Direct3D 9 re-implementation of the DirectDraw API for classic 2D games for better compatibility with Windows 2000, XP, Vista, 7, 8, 10, 11, Wine (Linux/macOS/Android) and Virtual Machines
https://discord.gg/afWXJNDDF5
MIT License
2.12k stars 143 forks source link

Feature request: ddraw.ini name mimicry #287

Closed eierfrucht closed 4 months ago

eierfrucht commented 4 months ago

A number of fanmade game extensions (like sFall for fallout) also come as ddraw.dll/ddraw.ini. I’ve just had to hex edit cnc’s ddraw.dll to change the config name to wardd.ini so that I’m able to chain-load cnc-ddraw after the base hook library as wardd.dll (also had to patch the game extension’s ddraw.dll to redirect its calls to wardd.dll).

Making ddraw.ini mimic the name of ddraw.dll would eliminate the need for any binary patching at least of cnc’s own resources. It could work like this: whenever cnc’s ddraw.dll is renamed to whatever.dll, it looks for a namesake whatever.ini for its configuration. I.e. when renamed to 123.dll, it will look for 123.ini.

Currently dxwrapper has this exact capability which is a godsend when you need to pump a game’s drawcalls through multiple dll’s (the first one normally doesn't affect screen rendering proper but makes edits to viewport resolution, aspect ratio, rearranges game UI, adds in-game QoL features, etc.)

P.S. And it goddamn worked for Fallout: Sonora

https://i.postimg.cc/mT7WGyCT/Sonora1.png https://i.postimg.cc/D2dtDfs6/Sonora2.png https://i.postimg.cc/bpDjmhvD/Sonora3.png

FunkyFr3sh commented 4 months ago

That's not going to be possible, the config tool would not find the file then. But you can override the .ini file name via a ENV var (which does work for both, the game and the config tool)

Example: run game.zip

eierfrucht commented 4 months ago

In the few fringe cases where this matters, the target audience would happily throw the utility under the bus since it doesn't expose all the parameters anyway (I only edit the .ini manually).

If it absolutely must be kept functional at all times, upon not finding ddraw.ini the utility could simply ask the user to point it to the new filename and save the relative path to a registry key or even simply scan its folder for all .ini’s looking for the first file to contain a specific line that tells it’s a cnc-ddraw configuration file.

I hex edited the tool, too, and it works with the new name, but it’s so much easier to use Notepad...

P.S. ENV var worked for me on Windows but I see how it could cause wonky behavior with some specific setups of Unofficial Winery by Gcenx: https://github.com/Gcenx/WineskinServer esp. on M1 Macs.

FunkyFr3sh commented 4 months ago

I'll have to think about it, but TBH this is such a rare case that it probably doesn't matter, it's like 1 game out of 1000. There is also a fork of cnc-ddraw for fallout mods that doesn't require such workarounds. I think it's replacing their ddraw.dll, but not sure (I don't have a link, but it was somewhere on gitlab)

eierfrucht commented 4 months ago

You might have meant sFall, of which there exist multiple branches, and which is exactly the engine extension (with a rudimentary graphics wrapping capacity) that I’ve been seeking to enhance with the superior cnc-ddraw:

https://github.com/sfall-team/sfall

https://gitflic.ru/project/fakelshub/sfall

It’s a strict dependency for most modern mods and comes as a draw.dll/ddraw.ini duo, but mostly affects QoL and engine modding features.

When set to SCALE_2X, which always gives you half your screen resolution, it looks great. However when set to anything that can't be integer scaled, it’s only capable of muddy linear filtering.

I suggested that the devs (different people for different forks) be kindly asked to rename their ddraw.ini into something else and to add a "CustomDLLPath"-like feature to chainload cnc-ddraw.dll (thankfully your ddraw.dll can be freely renamed), and cnc’s ddraw.ini just stays under that name.

Cnc-ddraw JINC2-modified vs sFall DirectX9 SCALE_X2 at 960x540 upscaled to 1920x1080: https://i.postimg.cc/ys9YX1Y1/screen00001.png

Cnc-ddraw JINC2-modified at 1280x720 upscaled to 1920x1080: https://i.postimg.cc/mRsd2Vzm/attal.jpg

Cnc-ddraw JINC2-modified at 1366x768 upscaled to 1920x1080: https://i.postimg.cc/xY6KDPKJ/screen00002.png

elishacloud commented 4 months ago

That's not going to be possible, the config tool would not find the file then. But you can override the .ini file name via a ENV var (which does work for both, the game and the config tool)

Actually, there are three ways to handle this:

  1. Automatic: in this case you put something in the dll (like a specific description, etc.). Then you have the config tool search for the dll file by looking at all files in the folder. Once the dll is found then you know what the ini file is because it is similarly named. Note: you could also have the config tool search for the ini file, but that could be an issue if the user manually modifies the ini file and changes it in someway so that the config tool can no longer recognize it. There is less chance of that happening with the dll, IMHO.
  2. Manual: in this case you can have have the user manually select the ini file of choice. In this case you could default to ddraw.ini but if you don't recognize it then you allow them to manually select the new file name. You could even have a config file for the config tool so that once the user selects the ini file it would remember it later.
  3. Synchronized: make the config file the same naming convention with the dll and ini file. So for example if the dll file is called dxdraw.dll then the ini file would be dxdraw.ini and the config tool would be dxdraw.exe.

There are probably many other ways, but these are the most obvious ways.

eierfrucht commented 4 months ago

Synchronized: make the config file the same naming convention with the dll and ini file. So for example if the dll file is called dxdraw.dll then the ini file would be dxdraw.ini and the config tool would be dxdraw.exe.

Synchronized IMO is the easiest and most user friendly way. No registry keys or obscure ID tokens to rely on. Almost foolproof. Least effort needed to implement. The rest do come across as too effort-demanding solutions to a "1 game in a 1000" problem.

After I patched cnc-config.exe to look for wardd.ini, I renamed it to wardd.exe as a reminder that this copy of the tool was modified to use that exact .ini name.

egornovivan commented 4 months ago

hardcode shit shit


if fix it, then need add support the cnc-ddraw subdirectory

eierfrucht commented 4 months ago

What if...

  1. Check if ENVVAR is empty at launch time
  2. If not, probably purposely set by user, proceed as usual
  3. If empty, default to own filename
  4. GUI tool can now discover the .ini via ENVVAR
FunkyFr3sh commented 4 months ago

I think the bigger problems are that game patches were placed into a ddraw.dll proxy, now you cannot replace it with any other DirectDraw wrapper (it's not actually a cnc-ddraw problem since it affects any other wrapper as well). Not sure if that can be fixed easily in sfall, not really an expert with it.

egornovivan commented 4 months ago
  1. ENVVAR

It is created within the cmd file, this shit can only be used as a last resort


GAME_PATH + "ddraw.ini"

The correct use of paths should look like this

GAME_PATH + "\ddraw.ini" or GAME_PATH + "\\ddraw.ini"


Later I will deal with this problem, but it will take me a lot of very long time since I wrote almost no code in C++

eierfrucht commented 4 months ago

now you cannot replace it with any other DirectDraw wrapper

The binary patching method has proven successful for both sFall forks. Aside from conflicting filenames, cnc-ddraw and sFall seem to be getting along really well with all the wrapping/postprocessing stuff offloaded to cnc-ddraw:

https://i.postimg.cc/CLXtFNFT/cnc-sfall-opengl.jpg

https://i.postimg.cc/1tTNVLgK/sfall4-ddraw-dll-hack.jpg

Some work is underway to avoid binary patching and automate cnc-ddraw chainloading on sFall’s end https://github.com/sfall-team/sfall/issues/504

It is created within the cmd file, this shit can only be used as a last resort

Can't envvars be set by executing code from within the .dll at an early stage? Aren't envvars somewhat persistent and shared between processes? Yeah I see the fault in my logic concerning the config tool, it won’t be able to get the correct value if that hasn’t already been set by an outside agent.

FunkyFr3sh commented 4 months ago
  1. ENVVAR

It is created within the cmd file, this shit can only be used as a last resort

GAME_PATH + "ddraw.ini"

The correct use of paths should look like this

GAME_PATH + "\ddraw.ini" or GAME_PATH + "\\ddraw.ini"

Later I will deal with this problem, but it will take me a lot of very long time since I wrote almost no code in C++

Why would that matter? In any case, the absolute path is needed (relative path will not work in some cases)

now you cannot replace it with any other DirectDraw wrapper

The binary patching method has proven successful for both sFall forks. Aside from conflicting filenames, cnc-ddraw and sFall seem to be getting along really well with all the wrapping/postprocessing stuff offloaded to cnc-ddraw:

https://i.postimg.cc/CLXtFNFT/cnc-sfall-opengl.jpg

https://i.postimg.cc/1tTNVLgK/sfall4-ddraw-dll-hack.jpg

Some work is underway to avoid binary patching and automate cnc-ddraw chainloading on sFall’s end sfall-team/sfall#504

It is created within the cmd file, this shit can only be used as a last resort

Can't envvars be set by executing code from within the .dll at an early stage? Aren't envvars somewhat persistent and shared between processes? Yeah I see the fault in my logic concerning the config tool, it won’t be able to get the correct value if that hasn’t already been set by an outside agent.

Ah nice!

You guys might want to check this here, this is a cnc-ddraw fork with sfall support (I didn't try it): https://gitlab.com/pdish1/cnc-ddraw-sfall/

image

eierfrucht commented 4 months ago

I haven't been able to google that up for the life of me, thanks! It hasn't seen any updates in a while but still is a great discovery.

My tests show that Mode=1 is preferable (fullscreen DX7). Maybe I’m in the wrong though.

sFall started out as a ddraw proxy because of its built-in (not great) optional DX9 wrapper.

egornovivan commented 4 months ago

Why would that matter?

I concatenated a lot of paths in AutoIt scripts and the understanding of the difference came to me over time. Now I don’t even remember the nuances.


You guys might want to check this here, this is a cnc-ddraw fork with sfall support (I didn't try it): https://gitlab.com/pdish1/cnc-ddraw-sfall/

изображение Shitty implementation

FunkyFr3sh commented 4 months ago

Why would that matter?

I concatenated a lot of paths in AutoIt scripts and the understanding of the difference came to me over time. Now I don’t even remember the nuances.

You guys might want to check this here, this is a cnc-ddraw fork with sfall support (I didn't try it): https://gitlab.com/pdish1/cnc-ddraw-sfall/

изображение Shitty implementation

I don't know what this is supposed to do and why it's needed. It's not original cnc-ddraw code, he may have added it for some reason.

Does sfall need WS_EX_APPWINDOW?

egornovivan commented 4 months ago

Does sfall need WS_EX_APPWINDOW?

mmmm.... I don't know(Probably no). With proper implementation, sfall will only need normal rename/path work. sfall is independent, it can translate DD/DX7 to DX9, it doesn’t need HRP and CNC, just as additional functionality


Yes, Fallout 1/2 has a bug with the icon disappearing from the taskbar. This may also happen in other older games. But WS_EX_APPWINDOW doesn't seem to fix it Using an engine hack, this problem was solved in sfall by adding an extended style https://github.com/sfall-team/sfall/issues/504#issuecomment-1945380530


https://gitlab.com/pdish1/cnc-ddraw-sfall/

This version of the CNC is well suited for older versions of sfall which did not have DX9

eierfrucht commented 4 months ago

This version of the CNC is well suited for older versions of sfall which did not have DX9

Any advantage over mainline cnc? You can't get any kind of cnc working unless you engage pure DX7 mode in sfall anyway. Cnc expects nothing but ddraw calls.

egornovivan commented 4 months ago

Any advantage over mainline cnc?

Nope. Only allows you to run old versions of sfall and sfall for Fallout 1

pdishh commented 4 months ago

Any advantage over mainline cnc?

It was made mostly for personal use. Gitlab repo happened only because of a conversation on a public forum. The cnc-ddraw version is ~8 months old, may 2023. It should work on all sfalls including 5.0.6.2 and 4.4.2. The patch to cnc-ddraw mostly comes down to supporting the different load orders, hooking keyboard input for reshade/steam overlay and a small cosmetic change to extend DIALOG_SCRN_BACKGROUND to all screens.

I didn't really update it since then mostly because I didn't want to deal with potential regressions and ~5.2.0.0 is already fully compatible with Fallout. If some major update happens, like multipass presets, I might update it/sanitize it :)

I tested it on sfall1 1.8, sfall 3.2 (Steam), sfall 3.7.6 (Resurrection), sfall 4.x (pre-HRP), sfall 4.x (post-HRP), sfall 5.x

eierfrucht commented 4 months ago

Mainline cnc-ddraw can be made compatible with at least sFall 4.X and 5.X via a handful of HEX patches: https://github.com/sfall-team/sfall/issues/504#issuecomment-1942844856

To avoid patching altogether, sFall needs to introduce support for forwarding ddraw calls to a user-specified DLL, and cnc-ddraw needs to support what elishacloud calls "filename synchronization" mentioned by him under #3: https://github.com/FunkyFr3sh/cnc-ddraw/issues/287#issuecomment-1938060060

pdishh commented 4 months ago

While I'm not sure about the generalized use case, as far as Fallout is concerned I don't think any changes on the side of cnc-ddraw are required? Sfall can always redirect to a different .ini via the ENV variable. The only exception being the config manager. There could be a text field added in the GUI where you can specify the path to .ini. Maybe some MAGIC_VALUE could be added to the cnc's ddraw.ini so that the config can check whether it's a cnc ddraw.ini.

Edit: Assuming that your average user doesn't know that you can redirect config.exe path via env variable. Then again, it's a borderline usecase.

FunkyFr3sh commented 4 months ago

You could probably also just merge the two .ini files into one or you simply use the sfall ddraw.ini as is (cnc-ddraw doesn't need its .ini, it can run just fine off the default values). The config tool would just add a [ddraw] section to the bottom if needed, this shouldn't be a problem for sfall

eierfrucht commented 4 months ago

The config tool would just add a [ddraw] section to the bottom if needed, this shouldn't be a problem for sfall

So you say cnc won't go crazy because of some unexpected sections at the beginning of the the .ini? Sounds like it could save the day!

Sfall can always redirect to a different .ini via the ENV variable.

I suggested this but people were like "ehhh that’s clunky af"

elishacloud commented 4 months ago

The only concern I would have with merging the settings from both ini files into a single file is how config tools would handle the extra settings. Many config tools will just write the while ini file at once meaning all unknown settings will get lost after changing a setting.

egornovivan commented 4 months ago

Later I will deal with this problem, but it will take me a lot of very long time since I wrote almost no code in C++

I'll do something like this for dll DLL_PATCH = get curent dll full patch without using names and using win api/functions INI_PATCH = trim extension DLL_PATCH and concatenate "ini"

for exe PROCESS_PATH = get curent process patch without using names and using win api/functions INI_PATCH = trim extension PROCESS_PATH and concatenate "ini"

Will this be the right decision?🤔

FunkyFr3sh commented 4 months ago

The only concern I would have with merging the settings from both ini files into a single file is how config tools would handle the extra settings. Many config tools will just write the while ini file at once meaning all unknown settings will get lost after changing a setting.

hm yeah, that could happen. But at least cnc-ddraw config is not doing that, so it may be fine

FunkyFr3sh commented 4 months ago

Later I will deal with this problem, but it will take me a lot of very long time since I wrote almost no code in C++

I'll do something like this for dll DLL_PATCH = get curent dll full patch without using names and using win api/functions INI_PATCH = trim extension DLL_PATCH and concatenate "ini"

for exe PROCESS_PATH = get curent process patch without using names and using win api/functions INI_PATCH = trim extension PROCESS_PATH and concatenate "ini"

Will this be the right decision?🤔

Probably the best to focus on the sfall patch, cnc-ddraw may not need any updates. the ddraw.ini is optional in cnc-ddraw, you don't need it and it would merge itself automatically using the config tool

I posted a possible solution in the sfall issue, might be really simple to fix

egornovivan commented 4 months ago

Probably the best to focus on the sfall patch

Most likely it’s already ready, the commits just haven’t been pushed


The problem with the cnc-ddraw hardcode will still have to be solved someday

egornovivan commented 4 months ago

I have no way to compile and test. Please check. This should be enough to work in a subdirectory without renaming.


Also, did I add this correctly?+ "\\" +

egornovivan commented 4 months ago

Correct version.

FunkyFr3sh commented 4 months ago

@egornovivan It looks good (Got a little bug, GetModuleHandleA("user32.dll") should be g_ddraw_module).

I'm not sure yet about the ddraw.ini rename, there are so many potential issues with it.... But I like the subdir support, this could probably be enough to solve all problems.

egornovivan commented 4 months ago

should be g_ddraw_module

Just write it like this? GetModuleFileNameA(g_ddraw_module, g_config.dll_path, sizeof(g_config.dll_path)

FunkyFr3sh commented 4 months ago

should be g_ddraw_module

Just write it like this? GetModuleFileNameA(g_ddraw_module, g_config.dll_path, sizeof(g_config.dll_path)

yes

egornovivan commented 4 months ago

Name synchronization is only for those who understand what they are doing. The name of the dll and ini files remains the same ddraw


Well, we will use the subdirectory with the sfall

egornovivan commented 4 months ago

Need a test build. By the way, FunkyFr3sh you can peek build.yml from the sfall repository.

FunkyFr3sh commented 4 months ago

Need a test build. By the way, FunkyFr3sh you can peek build.yml from the sfall repository.

I posted a test build here: https://github.com/sfall-team/sfall/issues/504#issuecomment-1950259720

Currently needs sfall build from cnc-loader branch to work

egornovivan commented 4 months ago

Alt + Enter doesn't work.

FunkyFr3sh commented 4 months ago

Alt + Enter doesn't work.

Yes I know, I think it's because the game got a keyboard hook (SetWindowsHookEx) and cnc-ddraw doesn't know that any keys were pressed because of that

egornovivan commented 4 months ago

It's not a good idea to compare/use dll names in a wrapper https://github.com/FunkyFr3sh/cnc-ddraw/blob/caa06c77c0f3d7c25fd37a91c6870e6c6722574f/src/hook.c#L204 https://github.com/FunkyFr3sh/cnc-ddraw/blob/caa06c77c0f3d7c25fd37a91c6870e6c6722574f/src/hook.c#L326 https://github.com/FunkyFr3sh/cnc-ddraw/blob/caa06c77c0f3d7c25fd37a91c6870e6c6722574f/src/hook.c#L438

FunkyFr3sh commented 4 months ago

These are just the names of the IAT (import address table)

For example, it looks for "GetCursorPos" but only hooks it if it's the right one in "user32.dll"

FunkyFr3sh commented 4 months ago

With a small game patch Alt+Enter is working, still nto sure what this hook in the game is supposed to do

image

FunkyFr3sh commented 4 months ago

Actually, I'm closing this as the original issue with the ddraw.ini has been solved now. We can just create a new issue if there's still something that needs to be updated

egornovivan commented 4 months ago

In my opinion, should not use a relative path to the wrapper. Searches all over the system for the file. LoadLibraryA("wrapper\ddraw.dll")

111