This is an old revision of the document!
Here-in lies documentation for efforts to compile the server in VS2022 (latest available as of 2025).
I have done all this from within a docker-based VM so I could start with a clean slate and not clobber any existing setup.
To begin with, you must acquire VS2019 to convert the VC6 .dsw workspace into a modern .sln. 2022 dropped support, so this is necessary. Once converted, 2022 can be used to convert the 2019 .sln to 2022. It should be noted that I think it would actually be better to create a fresh SLN file, as there is a lot of cruft left over both from upconverting and the original projects solutions output locations.
Once you have that, you need to update all the source and header files to point to the appropriate new files (as well as add any new files over time) – I'd also recommend changing the various source/header file filters (“directories”) to English from German. Once again, I think just starting fresh would be simpler overall.
Some other steps:
Intermediary stuff done to get to a baseline state:
I'm not going to bother with 32-bit in this day and age. The python version available with VS2022 doesn't even seem to include support.
So, go to the top-left solutions property → configuration manager, and add a new active solution platform for x64. Let it inherit from x86. Switch all project solutions to use x64.
Just install the latest available Python for VS2022. It'll say outdated, but there doesn't seem to be a newer one, so oh well. I'm sure it's easy to swap out.
Once installed, add the include directory to the plugin_python solution (it'll be C:\Program Files %28×86%29\Microsoft Visual Studio\Shared\Python39_64\include). Also add the python libs directory to linker additional library dependencies field. And, of course, add python39.lib as a linker dependency.
As it says… some of this got clobbered with the upgrading, but mixed with all the other stuff, it's hard to tell. So, let's just reset it to a default which is already nicer. Basically, everywhere in a project solution where FullDebug is an output, just set the field to use project settings/inherit. This will change it to something like `$(OutDir)$(TargetName)$(TargetExt)`. This results in an output directory like `crossfire32/x64/FullDebug` instead of just `FullDebug/`.
There are ancient references to `afxres.h` in the .rc files. Delete this line. I think you might have to replace with `#include “windows.h”`, but not really sure.
Maybe these .rc files can be removed or re-created from scratch? There's a lot of archaic garbage in them.
Well, the easiest is to add a header-only dirent.h implementation. I added https://github.com/tronkko/dirent/blob/master/include/dirent.h to a `make_win32/include/` directory and added that folder as an include path.
As it says… if the solution is looking for .h files but can't find them, double-check it's pointing to the correct locations.
The call to `clock_gettime(CLOCK_MONOTONIC, …)` is unavailable to Windows. What _should_ be done to the codebase is to replace it with std::chrono::steady_clock. However, the following can be used to replace it:
timespec your_var; static LARGE_INTEGER tps; LARGE_INTEGER ticks; if (!tps.QuadPart) { QueryPerformanceCounter(&tps); } QueryPerformanceCounter(&ticks); your_var.tv_sec = (long)(ticks.QuadPart / tps.QuadPart); your_var.tv_nsec = (long(((ticks.QuadPart % tps.QuadPart) * (1000000000ULL)) / tps.QuadPart);
For now just manually create this. What should be done is a pre-build step that runs a .bat that does the same thing that a shell script currently does to generate this file (check for git and attempt to use current tag (or commit??) as a #define).
There are numerous uses of erroneous code where a non compile-time C string is used to create compile-time sized arrays. e.g., malloc should be used not `char [strlen(dynamic_string)] my_bad_string`. For the time being, I've just used `std::string` where these have been used, as I'm lazy – a real fix would be to switch to std::string in such places for all strings so that we're not mixing unnecessarily (or if someone wants, properly use malloc and free).
R_OK isn't defined in MSVC, it seems. This is in map.cpp… I just added
#define R_OK 4
:)
For Forward's Sake – this can be replaced with _BitScanForward. NOTE, however, that there is actually an assembly language replacement in the code that is active if the `CF_MXE_CROSS_COMPILE` flag is set (see object.cpp:42). However, for better portability/readability, I added the following definition for ffs:
#ifdef _MSC_VER int ffs(unsigned long v) { unsigned long index; if (_BitScanForward(&index, v)) { return (int)index + 1; } return 0; } #endif
Although there is a definition for this in win32.h, we can just use some built-in calls… also, we need strcasecmp.
So, in win32.h
#ifdef _MSC_VER #define strncasecmp _strnicmp #define strcasecmp _stricmp #desfine strtok_r strtok_s #endif
Unfortunately, we'll need to acquire and setup flex to build the needed loader and parser .cpp files. I'm using winflexbison, as it has direct integration with visual studio.
Install it, then follow these steps.
Now add `loader.l` to crossfire32's Source Files/common filter dir and `reader.l` to Source Files/random_map. Edit their properties and change the Output File Name to be `%(Filename).cpp` instead of `%(Filename).flex.cpp`. Additionally, change the `reader.l` 's “Prefix” Flex Option to `readeryy`… This prevents flex symbols colliding with loader's output during final linking.
Now ensure the location where win_flex_bison is extracted to is as an Executable Directory in crossfire32's Solution → Properties → VC++ Directories → Executable Directors.
Finally, build the loader.l and reader.l files and then add the resulting .cpp files to common/ and random_maps/ (if a proper VS solution project file is made, this won't be necessary).
Although git can force LF line encoding, might as well update CF to allow both \r\n and \n. This involves modifying `bufferreader.cpp`'s `bufferreader_next_line` and `bufferreader_get_line` functions.
bufferreader_next_line:
. . . int index = 0; char *newline = strchr(br->current_line, '\r'); if (newline == NULL) { newline = strchr(br->current_line, '\n'); index = 1; } else { index = 2; } . . . if (newline) { br->current_line = newline + index; . . .
bufferreader_get_line:
. . . int index = 0; char *newline = strchr(br->current_line, '\r'); if (newline == NULL) { newline = strchr(br->current_line, '\n'); index = 1; } else { index = 2; } . . . if (newline) { br->current_line = newline + index; strncpy(buffer, curr, cp); if (index == 2) { buffer[cp - 1] = '\n'; } buffer[cp] = '\0'; } else { . . .
Maybe because of using winflex, but the “^object{S}” on line 430 doesn't ever match. Changing it to be “^Object{S}” fixes it… it feels that it should have been capitalized in the first place, since that is how archetypes declare it. In the end I changed it to:
^[o|O]bject{S}
and it built archetypes ok.
This is a file that is generated from Python… Add a Pre-Build Event to crossfire32 project with the command:
"<some sort of path to>\python.exe" ../common/is_valid_types_gen.py ../include/object.h > ../common/arch_types_valid.cpp
It's goofy, but build once to generate this file, then we can add it as an existing item to source files/common (this won't be necessary with a complete VS project once that's a thing).
I'm too much of a bonehead when it comes to GCC attributes and how to convert that over, so we just define the following in global.h, before the definition of PRINTF_ARGS:
#ifndef __GNUC__ #define __attribute__(a) #endif
I think this is some sort of terrible catch-all, but it seems to work.
There are other minor things, like missing includes for the MSVC environment, but those are easy to figure out.