Until now the server just called remove() to delete the servers state
from the HDD. That was fine on Linux were UTF-8 is used but failed
silently on Windows in case that the working dir path had some Unicode
characters. Replace remove() by Sys_Remove(), on Linux it's just a
wrapper around remove() on Windows it does a UTF8->UTF-16 conversion
and calls _wremove(). This fixes issue 318.
I've chosen the minimal invasive way for this:
* Import miniz and remove -lz linker flags.
* Create a short header minizconf.h roviding everything we need
originally defined by zconf.h and not provided by miniz.
* Replace zlib.h with miniz.h and minizconf.h.
I've used _wfopen_s() because it's newer and the older variants are said
to throw warning when build with MSVC. But apparently Windows XP hasn't
got that symbol... So just use the normal _wfopen(), MSVC is unsupported
anyways. The may or may not enough to restore Win XP compatibility.
The 'game' command was more or less functional after the last commit.
We just need to reset the initialGame (renamed to userGivenGame) so we
don't revert back to the old game at server disconnect.
When connecting to a multiplayer game that runs a different mod
("game" cvar) than you are, it didn't load the corresponging configs
from the mod, but saved your changes to the config to the mod's config.
Which is doubly useless.
Now when the "game" cvar is changed, the configs are reloaded (from
the right directories for the mod), and when disconnecting the configs
are written, so the changes you did for a mod while playing MP are saved
before game is reset to the game you started with.
Until now we did an easy calculation to determine the frame timing:
1000000 microseconds (== 1 second) / targetframerate == delay between
frames. This works if the CPU and GPU are fast enough since the time
process to process the frame is negligible. But if one of them is too
slow or the GPU driver takes too long (see issue #277 for an example)
we render too few frames.
Work around this by calculating the average time used to process the
last 60 render oder packet frames and take that into account when
determining the delay between the frames. With this change even my
rotten AMD Radeon and it's broken Windows GL driver is able to hold
the displays famerate (enforced by vsync) just fine.
While here add a 5% security margin to our target packet frame rate if
the vsync is enabled. Just to be sure that we never process more render
than packet frames.
There were two ways to implement this. One was to go with the stuff
already included in minizip and one to implement our own wrapper around
fopen(). This is the second options since @DanielGibson convinced me
that it would be safer.
We can't rely on the game.dll being unicode conformant. Work around
that by changing the current working directory before calling into
the game.dll, pass a non unicode string to it and chang back after
we return.
To be able to pass UTF-8 encoded pathes through cvars both the cvar
subsystem and the command parser would need a fair amount of UTF-8
understanding. And I'm not the poor soul that's going to implement
that. Therefor pass the datadir trough a global variable.
This is done in shared.c so that's available for both the client /
server / renderer and the game. A work around for older game DLL will
be added at a later time.
On Unix platforms unicode is implemented through UTF-8 which is
transparent for applications. But on Windows a UTF-16 dialect is
used which needs alteration at application side. This wrapper is
another step to unicode support on Windows, now we can replace
fopen() by a function that converts our internal UTF-8 pathes to
Windows UTF-16 dialect.
This is a noop for Unix platforms. The Windows build is broken,
the compiler errors out in shared.h. This will be fixed in a
later commit.
Caveats:
* fopen() calls in 3rd party code (std_* and unzip) are not replaced.
This may become a problem. We need to check that.
* In the Unix specific code fopen() isn't replaced since it's not
necessayry.
There's no need to exclude directories from search by flags. In fact
the Unix backend has worked nicely for years without it... Sadly we
can't remove the now superfluous 'canhave' and 'musthave' attributes
from Sys_FindFirst() and Sys_FindNext() since they're defined in
shared.h and may be used from custom game DLLs.
* Remove a bunch of unnecessary functions.
* Reorder functions into logical groups. The orderig is now the same
on Unix and Windows.
While at it add several TODOs to the code. There's not need for special
library loading functions for the game, the Windows backend still uses
a lot of old and fishy DOS functions, etc. All this will be done at a
later time.
There's no need to duplicate machine independent parts of the client
initialization and the main loop for every platform.
While at it remove the nearly empty unix.h header and move Windows
main() into an own file. Not both platform have the same basic layout.
With this renamed cvars can be rewritten when config.cfg is first
loaded. Please note that once this was done older YQ2 versions can't
parse that config.cfg anymore.
gl_maxfps > 1000 breaks things, and cl_maxfps starts to behave weird
at >90, and while up to 125 or so you get the bugfeature of higher
jumping, beyond that things just get even buggier, at some point causing
bugs like #261
The original client used single precision mode on Windows and the
default mode on all other platforms. Most platform (at least OS X,
FreeBSD, NetBSD up to 6.0, OpenBSD and Solaris) set double precision
as default, Linux sets extended double precision... When playing a
network game there're several possibilities:
* Same precision on both sides: This one is okay, of course.
* single precision <-> double precision: This one is okay, too. I guess
this is because the code allows a small deviation between client and
server to work around imprecisions introduced be the network protocol.
* double precision <-> extended double precision: This one is okay,
likely for the same reasons given above.
* single precision <-> extended double precision: This one gives a lot
of misspredictions at client side.
All of these are more or less academic these days. Yamagi Quake II used
the platforms default mode for ages. And both gcc and clang default to
SSE2 math (with double precision as default on all platforms) when
compiling for amd64. So the only reasonable case is Linux/i386 on one
side and the original client or another source port on Windows/i386 at
the other side.
Work around this by forcing the x87 to double precision mode.
Miscframes are coupled to renderframes and are just checking for
renderer changes (very cheap) and advancing CD audio if implemented.
There's no reason not to that at every frame.
Until now the curtime variable was set at every call Sys_*seconds().
That's a little bit unfortunate because calls to that functions are
scattered around the code. Instead set it once every frame in
Qcommon_Frame().
Yes, this duplicates some code. But it's at least 100 times more
readable to have two distinct functions for distinct purposes instead
of about 25 #ifdef.
Having the server in an own timing zone seems to simplify things but
introduces slight timing discrepancies. The most visible effect is that
the game runs a little bit too fast, especially in the first cl_maxfps
frames.
Therefor: Remove timeframes, they're unnecessary. Track the time since
the last (client|server) frame instead and pass it to the client and
server when it's called.
This allows us to implement the global timing without an artificial
brake slowing the game unnecessary down. This is only partial working,
more changes and fixes are coming.
This is a no-op for now. We need this to get a much higher precision
when calculating the frame times. This changes the fixedtime cvar from
milli- to microseconds.
This is the same as the client does for it's realtime. It looks at least
somewhat more correct since it pevents rounding errors. And things are
simplified a litte bit since the server timing is now independent of the
global timing.
This is the same as the well known Sys_Milliseconds() but like the name
suggests with microsecond precision. To be used in the upcoming new
framecounter.
While here reimplement the same hack for baseq2/players, lost somewhere
on the way. This is just another searchpath f*ckup. For some reasons
paks have a higher priority than plain directories. We do not want that
for the maps.lst and players/ since id Software decided to put updated
versions of them directly into baseq2/...
This closes issue #217.
The big problem with the old implementation was that stdout.txt and
stderr.txt on Windows became available when nearly all the low level
initialization was already done. Regardless if the client was in
normal or in portable mode.
Solve this by scanning the command line for the string '-portable'. If
it's not found, stdout and stderr are redirected as early as possible.
If found the global variable (*sigh*) is_portable is set to true. It's
evaluated later on to set the cvar 'portable', which in turn is used
be the filesystem to decide if the home directory should be added to
the search path.
Maybe we should remove the cvar and stick to the global variable.
While at it change the maximum path length for qconsole.log from
MAX_QPATH to MAX_OSPATH. At least on my Linux laptop MAX_QPATH is
too short.
This commit is still untested on Windows!
A new linked list fs_rawPath with nodes of type fsRawPath_t is added.
The new function FS_BuildRawPath() fills it at filesystem initialization
with the raw search path directories. Later FS_BuildGenericSearchPath()
and FS_BuildGameSpecificSearchPath() use it to derive the actual search
directories.
Remove all functions that are no longer used:
* FS_AddGameDirectory()
* FS_SetGameDir()
* FS_AddHomeAsGameDirectory()
* FS_AddBinaryDirAsGameDirectory()
While at it try remove as much global variables from filesystem.c as
possible. Also fix a small, longstandig bug: The download code should
treat .zip and .pk3 files as pak files and not as normal directories.
Refactor FS_SetGamedir() into FS_BuildGameSpecificSearchPath(). The new
function removes the specialized part of the search path if necessary
and create a new specialized part based upon the given directory. It
uses the FS_AddDirToSearchpath() function added in the last commit.
This moves the code used to add a directory and it's paks to the search
path into one well defined function FS_AddDirToSearchPath(). Also create
a new function FS_BuildGenericSearchPath() that builds the generic part
of the global search path. This obsoletes several other, specialized
functions. They'll be removed in a later commit.
Resurrect support for render / refresher loadable libraries and use them to implement an experimental OpenGL 3.2 renderer. Please note that the new renderer interface is somewhat different from the original one, old render libraries will NOT work!
To be able to test if the game is running portable all checks of the
portable cvar must be done after Cvar_Init(). Instead of redirecting
stdout and stderr as early as possible, delay the redirection right
after Cvar_Init(). After this change the printf() in WinMain() aren't
printed into stdout.txt, but I guess that it isn't a big problem. All
interessting stuff like the search pathes is still there.
Rename fs_portable to portable. It's no longer filesystem specific.
Normally Q2 writes all persistent data (the configurations, saves, etc.)
into a subdirectory in the users $HOME. That can be a problem when the
game is installed onto an thumb drive or something like that. Therefor
provide a cvar fs_portable. When set to 1 the games uses it binary dir
as it's persistent storage location.
Examples:
./quake2 +set fs_portable 1
./quake2 +set basedir ~/games/quake2 +set fs_portable 1
fs_portable is _not_ saved into the config file. It must be set at
every start!
This closed issue #158.
So in all code in the reflib (ref_gl.dll/.so/.dylib) calls to
ri.Con_Printf(print_level, fmt, ...) have been replaced by calls to
R_Printf(print_level, fmt, ...) which uses ri.Com_VPrintf().
somehow all the printf()-like things in Q2 wrap each other and each
one prints into a buffer and then calls the next one with ("%s", buf).
That's not very clever and kinda annoying.
As in the end everyone calls Com_Printf() I created Com_VPrintf()
that can be called instead with the va_list.
I also added printf-format annotation to Com_Printf() and Com_DPrintf()
and fixed places where Com_Printf() was called with the wrong type.
Until now autoexec.cfg was a special case. It was read several
times, whenever the 'game' cvar was altered or when the client was
restarted. But only if it was in the right directory in the right
position of the internal search path... Remove this altogether and
replace it by an ordinary 'exec autoexec.cfg' at startup.
This may break some mods that depend on an autoexec.cfg if the user has
his own version in ~/.yq2/. Such mods should use default.cfg instead.
This closes issue #163.
especially in the intermission videos, the text looked broken, as parts
of the characters were missing.
This is because Draw_StretchRaw() converts the 320x240 video frame into
a 256x256 texture, without doing proper interpolation (just skipping
some pixels instead).
Now, if the GPU supports non-power-of-two texture sizes, the video
frames are uploaded as textures in their original size.
(Also fixed a harmless typo in common.h)
The old implementation had two problems:
* OSTYPE and ARCH are systemwide defines, overriding them may break
the global libc headers. This is a theoretical problem, I've never
seen it in praxis.
* Not all system set ARCH correctly when building in a chroot env.
For example on Linux ARCH is set to x86_64 when building in an
i386 chroot. Now the user can do something like "make YQ2ARCH=i386"
to get things right.
This is more than enough for everyone and prevents wasting CPU time.
Without this change as many client frames as possible are rendered,
Quake II uses a complete core.
For deterministic/reproducible builds (where the same source and
toolchain can be verified to produce the same binary, allowing
maliciously substituted binaries to be detected) it is desirable to
take the software's idea of the build date from the build system;
otherwise, the real-time clock at the time of building affects the
result, making it non-reproducible.
SOURCE_DATE_EPOCH is a distribution-neutral specification for how
to do that. It is meant to be set by meta-build systems such as
dpkg or RPM, using a date/time that is already part of the source code,
for example the date of the latest git commit, the date in
the package's debian/changelog, or the date in the RPM spec file.
See https://reproducible-builds.org/specs/source-date-epoch/ for the
specification of SOURCE_DATE_EPOCH, or https://reproducible-builds.org/
for more information on reproducible builds in general.