Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - QwazyWabbit

Pages: [1] 2
1
Railwarz / TMG Version 0.2.61 Release
« on: May 18, 2023, 01:17:45 PM »
Release for server admins Railwarz for Linux and Windows.
Zip file contains game dll for x86/x64 Windows and Ubuntu Linux 22.04 LTS.
This version fixes the 'modop' command.

Git repo is at https://github.com/QwazyWabbitWOS/tmg and https://bitbucket.org/jwaggoner/tmg/src/master/

2
Railwarz / TMG Version 0.2.60 Release
« on: December 24, 2022, 09:37:10 AM »
Release for server admins Railwarz for Linux and Windows.
Zip file contains game dll for x86/x64 Windows and Ubuntu Linux 20.04 LTS.

Git repo is at https://github.com/QwazyWabbitWOS/tmg and https://bitbucket.org/jwaggoner/tmg/src/master/


3
https://github.com/QwazyWabbitWOS/lmctf60.git

This code is based on the archive recovered by the team at https://www.lmctf.com/index.htm

I've cleaned it up and brought the code up to more current usage per ISO C11 and it now compiles without warnings or errors on Linux, Windows and OSX on Visual Studio 2019, GCC and clang. The code in the original ZIP has a gravity tweak that didn't appear to have a logical reason but I left the code in place and added a macro to turn it on if some really wants it that way. See my discussion in the issues tab for the repository, Issue #1.

Linux admins: git clone https://github.com/QwazyWabbitWOS/lmctf60.git
then
make (for x86_64 build)
or setarch i386 make (for i386)

Copy/rename the binary as needed.

Warning to Windows  VS2019 users: The project is currently set to build straight into the c:\quake2\lmctf folder for debugging purposes so be sure to backup your older gamex86 binaries before building this. When switching from Debug to Release builds, be sure to do a Rebuild solution to fully build the objs and binary.

Q2admin users, rename the binary to gamex86.real.dll or gamei386.real.so to allow q2admin to cascade to it.

Modders: If you make changes, please fork the repo and post pull requests so I can keep it current. Thanks.

QW

4
0x1337c0de / Toward a better DoRespawn
« on: March 22, 2020, 04:20:47 AM »
Every time I had to look at DoRespawn it always annoyed me to see these lines in it:

Code: [Select]
for (count = 0, ent = master; ent; ent = ent->chain, count++)
;

and

Code: [Select]
for (count = 0, ent = master; count < choice; ent = ent->chain, count++)
;

The crazy comma operators and the dangling semicolon always pressed my WFT button.

Since my age and health conditions make it dangerous for me to venture forth into the dirty world of Coronavirus infestations and since zombie-making infection carriers are indistinguishable from normal humans unless you have infrared vision to spot the fevers, I am confined to my home for the weekend, doing my part to flatten the curve and save the world. I was "essential personnel" Friday and I will be again Monday but once I solve one problem Monday I will be back to saving the world by not participating in it.

So I decided to focus on this one function in Q2 mods called DoRespawn. This is the "Think" function that gets triggered when it's time to respawn items like armor shards, armor jackets, weapons, health boxes and pills, megas, etc. Anything that gets picked up and needs to be respawned after a scheduled time period.

Modern C has different rules than it did back in the days of the creation of Q2 and Microsoft Visual C++ of 1997. Some idioms remain but the particular idiom used by Zoid just makes a code maintainer stop and say "Oh? Hmmmm." Modern C compilers are also better at optimizing code so it's not necessary to resort to idioms in an attempt to make the code faster. Succinct C is not necessarily efficient C.

So here's a fix for the most basic version of DoRespawn with the idiomatic syntax removed and some error checking and reporting in place and some coverage for cases of null pointer dereference. Some versions have more code in place to take various actions on respawn but my primary goal was to refactor the for loops into something more easily understood at a glance and to maintain.


Code: [Select]
void DoRespawn(edict_t* ent)
{
if (ent == NULL)
{
gi.dprintf("NULL ent passed to %s\n", __func__);
return;
}

if (ent->team)
{
edict_t* master;
unsigned count;
unsigned choice;

master = ent->teammaster;
if (master == NULL)
return;

count = 0;
for (ent = master; ent; ent = ent->chain)
count++;

assert(count != 0);
choice = rand() % count;

count = 0;
for (ent = master; count < choice; ent = ent->chain)
count++;
}

if (ent)
{
ent->svflags &= ~SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
gi.linkentity(ent);

// send an effect
ent->s.event = EV_ITEM_RESPAWN;
}
}

QW

5
Railwarz / TMG Version 0.2.48 Release
« on: June 27, 2019, 11:56:04 PM »
Files attached are TMG 0.2.48 full source and binaries for Windows and Linux.
The Windows binary targets Windows 10 using VS2019 and is 32-bit code.
I encourage all server admins to update to this version.

TMG_0.2.48.zip is the binaries
TMG_0.2.48_Full.zip is the source plus binaries.

As before the Git repo is at https://github.com/QwazyWabbitWOS/tmg and https://bitbucket.org/jwaggoner/tmg/src/master/


6
Railwarz / TMG Version 0.2.43 Release
« on: September 08, 2018, 09:17:09 PM »
This archive includes Windows and Linux DLLs for TMG Railwarz 0.2.43.

I recommend upgrading all servers to this version.

The Linux versions were built on Debian using GCC 4.3.2 for 32 and 64 bit platforms. If they don't work on your system they can be rebuilt from source obtained at https://bitbucket.org/jwaggoner/tmg.git


7
Q2 Training Camp / How does Quake2 handle the client configuration files?
« on: December 04, 2017, 03:47:47 PM »
How does Quake2 handle the client configuration files?

There are three files Quake II uses on startup of the client
and on shutdown, they are:

default.cfg, config.cfg, autoexec.cfg

Quake II creates it's own "virtual file system" on startup and
once it's initialized it tries to execute each of these from
within the "current directory". These files are loaded in the
order listed above so anything you write into them overrides
any equivalent setting in the previous file. This virtual
file system is a security feature of the game to prevent
malicious directory traversal attacks and it also includes
the pak files shipped with the game or included with any
mods. This allows mod authors to pak configuration files
into their mods and conveniently ship them with their mod's
custom files.

The Quake II file system is rooted in the Quake2 directory
where the Quake II executable is installed. The maximum path
that Quake II can handle is 64 characters, so you don't want
to use long directory names or long file names and you shouldn't
go very deep. This 64 character limit is hard coded into the game.

How to manage your configuration files.

The original default.cfg is used by the engine when selecting
the "reset defaults" menu item in the Options menu of the game
console. This file may or may not exist on your system as a
"normal" disk file but the default.cfg is defined in pak0.pak
of the original game from idSoftware. Never alter this file.
WARNING: altering idSoftware's pak0.pak should not be attempted.
You can make your game inoperable or incompatible.

NEVER EDIT config.cfg. Why? Because the game writes a new one
each and every time you quit the client. It's used to save the
last state of your binds. Likewise, never make it read-only.
This file is normally located in C:\quake2\baseq2\. You can
copy-paste anything from this file into your autoexec.cfg file
and it makes a handy starting point for your customizations.
One technique you can use is to launch the game, alter the settings
or add binds, then exit the client which forces your current
settings and binds to be written to config.cfg, then copy the
contents into autoexec.cfg and begin your hand edits. This file
is written to the current mod folder when you quit the game from
within a mod, this can be a multiplayer or single player mod.

The autoexec.cfg file is what you or the mod authors want it to
be. THIS is the file you should edit for your default binds and
for your mod-specific binds or parameter settings. There can be
a unique autoexec.cfg file in every mod folder and even in baseq2.

This file is ALWAYS loaded from the current folder for the client
binary you have launched. If you launched the game directly from a
shortcut or from the executable in c:\quake2\ for example, then the
autoexec.cfg will come from c:\quake2\ and not from any subdirectory.

If you launch your game from a game launcher with a target Quake2
server then the configuration files are loaded from the current
mod folder given by the gamedir cvar specified by the server.
Once you are in-game on a modded server the autoexec.cfg and
the config.cfg will be read from and written into the mod folder
for that particular mod.

Enhanced Quake II Clients

R1Q2 and Q2Pro clients also load "postinit.cfg" after loading
autoexec.cfg.

Q2E clients use q2econfig.cfg instead of config.cfg, preserving
the old quake2 configuration file for backward compatibility.

8
Railwarz / Library of 3ZB2 Chaining files for TMG Railwarz
« on: November 06, 2017, 03:42:39 PM »
This is as complete a library of bot chain files as I have found on the net. This is what 3ZB2 bots use to navigate semi-intelligently around various maps. There was an inherent bug in TMG that stifled use of the full library which I have fixed in the 0.2.40 TMG. It is now possible to select between the original *.chf/*.chn files for CTF and DM the *.nav files others have made under the old system. (*.nav files are really just *.chn files and weren't usable in CTF mode. Simply extract this zip archive into your server ctf/cfg/ folder and you're done.

9
Railwarz / Railwarz TMG 0.2.40 Release
« on: November 06, 2017, 03:35:12 PM »
This is the latest release of Railwarz TMG. It adds MoTD text file instead of fixed text, removes the annoying command blockage when connecting to the server and spawns players correctly as spectators and fixes the initial spectator mode. It also adds player stats logging for those admins interested in creating a statistics page for their website. More details in the changelog.txt file. Binaries for Windows and Linux are included. If you don't run q2admin simply extract the *.real.* game mod binaries and rename them per standard.

Source code is available at: https://bitbucket.org/jwaggoner/tmg


10
Quake FAQs, HOWTOs, and Articles / Centerprinted Text
« on: October 04, 2017, 08:04:51 AM »
Tired of exercising your speed reading skills trying to read game banners that were centerprinted when you connect to a server or when presented in-game?

set scr_centertime 5 will make center-printed text banners 5 seconds of dwell in r1q2 and q2pro clients.

Maximum allowed value in q2pro is 10 seconds.

QW

11
0x1337c0de / Building r1q2ded-old from Source
« on: April 29, 2017, 03:35:45 PM »
The last archive of r1q2 source code is here:
https://github.com/tastyspleen/r1q2-archive

I have been asked a couple of times now this year how to build r1q2ded-old but I don't have the answer. It's probably staring me in the face and I can build r1q2ded b8012 without much trouble but I'm not sure how to do it with the existing source. All the links in the readme.txt file are dead.

If it's possible to do it I'd like to document it here or in the TS repository for historical purposes.

QW

12
0x1337c0de / Unsequenced modification and access to 'n'
« on: May 12, 2016, 01:28:14 AM »
While hacking TMG mod I found this little gem:

Code: [Select]
// From QDevels, posted by outlaw
void convert_string(char *src, char start, char end, char add, char *dest)
{
    int n = -1;
    while ((dest[++n] = src[n]))
        if ((dest[n] >= start) && (dest[n] <= end) && (dest[n] != '\n'))
            dest[n] += add;
}

/* Examples of convert_string usage
 {
 char  text[] = "abcdefgABCDEFG1234567\n\0";
 convert_string(text, 'a', 'z', ('A'-'a'), text); // a -> A
my_bprintf (PRINT_CHAT, "text = %s\n", text);
 convert_string(text, 'A', 'Z', ('a'-'A'), text); // A -> a
my_bprintf (PRINT_CHAT, "text = %s\n", text);
 convert_string(text, 0, 127, 128, text); // white -> green
my_bprintf (PRINT_CHAT, "text = %s\n", text);
 convert_string(text, 128, 255, -128, text); // green -> white
my_bprintf (PRINT_CHAT, "text = %s\n", text);
 }
 */

What first caught my eye was the warning from the compiler per the subject line but second was the fun and exciting int n = -1; initialization. OK, so we're being really 1337 coder and were starting the index off below the array bounds of dest and the ++n is going to make it 0 before it puts the value of src[n] into the destination.... or does it?

The warning is about that dest[++n] thing. This is a reliance on undefined behavior in C and it can be a nasty bug. It will work fine in one platform and fail in another and it can take some time to fix if it's buried deep enough. As it was, Microsoft Visual Studio 2010 likes it and it works. It also works on Ubuntu and GCC 4.8.4 but it doesn't work on OS X, using clang/LLVM. Since Microsoft is migrating to using clang on their compiler suite you can expect this function will break when compiled on the new tools or in their Azure cloud. It may also fail on newer versions of GCC on other Linux distributions.

OK, so how to fix it? Answer: pointers instead of array indexes.

Code: [Select]
/**
 Replace characters in destination string.
 Parameter 'add' is added to each character found in source and result is placed in dest.
 Parameters 'start' and 'end' specify character range to replace.
 Source text must be a valid C string.
*/
//QwazyWabbit// A pointer version to eliminate undefined behavior.
void convert_string(char *src, char start, char end, char add, char *dest)
{
while ((*dest = *src)) {
if ((*dest >= start) && (*dest <= end) && (*dest != '\n'))
*dest += add;
src++, dest++;
}
}

In keeping with the existing 1337ness of the code, I made good use of the comma operator. :)

If your projects contain this original Qdevels/outlaw function I urge you replace it ASAP. You'll know the old one is broken when your Q2 strings and chats suddenly become blank when you port your mod instead of green or white.

In addition, I offer the following wrapper functions to use in place of the rather complicated direct uses of the 'convert_string' function:

Code: [Select]
/**
 Set msb in specified string characters, copying them to destination.
 Text must be a valid C string.
 Source and destination can be the same.
 If dest == NULL the action occurs in-place.
 */
void highlight_text (char *src, char *dest)
{
if (dest == NULL)
dest = src;
convert_string(src, 0, 127, 128, dest); // white -> green
}

/**
 Clear msb in specified string characters, copying them to destination.
 Text must be a valid C string.
 Source and destination can be the same.
 If dest == NULL the action occurs in-place.
 */
void white_text (char *src, char *dest)
{
if (dest == NULL)
dest = src;
convert_string(src, 128, 255, -128, dest); // green -> white
}

/**
 Make text uppercase.
 Text must be a valid C string.
 Source and destination can be the same.
 If dest == NULL the action occurs in-place.
 */
void toupper_text(char *src, char *dest)
{
if (dest == NULL)
dest = src;
convert_string(src, 'a', 'z', ('A'-'a'), dest); // a -> A
}

/**
 Make text lowercase.
 Text must be a valid C string.
 Source and destination can be the same string.
 If dest == NULL the action occurs in-place.
 */
void tolower_text(char *src, char *dest)
{
if (dest == NULL)
dest = src;
convert_string(src, 'A', 'Z', ('a'-'A'), dest); // A -> a
}


Testbed code:

Code: [Select]
#include <stdio.h>

int main(int argc, const char * argv[])
{
char otext[] = "abcdefgABCDEFG1234567";
char text[]  = "abcdefgABCDEFG1234567\n";
char target[sizeof text];

toupper_text(otext, target); // a -> A
printf ("otext   = %s\n", otext);
printf ("target  = %s\n", target);
toupper_text(text, NULL); // a -> A
printf ("text    = %s\n", text);

tolower_text(otext, target); // A -> a
printf ("otext   = %s\n", otext);
printf ("target  = %s\n", target);
tolower_text(text, NULL); // A -> a
printf ("text    = %s\n", text);

highlight_text(otext, target); // white -> green
printf ("otext   = %s\n", otext);
printf ("target  = %s\n", target);
highlight_text(text, NULL); // white -> green
printf ("text    = %s\n", text);

white_text(target, otext); // green -> white
printf ("target  = %s\n", target);
printf ("otext   = %s\n", otext);
white_text(text, NULL); // green -> white
printf ("text    = %s\n", text);

return 0;
}

13
Science / Interactive Images of Lunar North Pole
« on: March 19, 2014, 03:17:27 PM »
Quote
March 18, 2014
     
NASA Releases First Interactive Mosaic of Lunar North Pole

Scientists, using cameras aboard NASA's Lunar Reconnaissance Orbiter (LRO), 
have created the largest high resolution mosaic of our moon's north polar 
region. The six-and-a-half feet (two-meters)-per-pixel images cover an area 
equal to more than one-quarter of the United States.

Web viewers can zoom in and out, and pan around an area. Constructed from 
10,581 pictures, the mosaic provides enough detail to see textures and subtle 
shading of the lunar terrain. Consistent lighting throughout the images makes 
it easy to compare different regions.

"This unique image is a tremendous resource for scientists and the public 
alike," said John Keller, LRO project scientist at NASA's Goddard Space 
Flight Center, Greenbelt, Md. "It's the latest example of the exciting 
insights and data products LRO has been providing for nearly five years."

The images making up the mosaic were taken by the two LRO Narrow Angle 
Cameras, which are part of the instrument suite known as the Lunar 
Reconnaissance Orbiter Camera (LROC). The cameras can record a tremendous 
dynamic range of lit and shadowed areas.

"Creation of this giant mosaic took four years and a huge team effort across 
the LRO project," said Mark Robinson, principal investigator for the LROC at 
Arizona State University in Tempe. "We now have a nearly uniform map to 
unravel key science questions and find the best landing spots for future 
exploration."

The entire image measures 931,070 pixels square - nearly 867 billion pixels 
total. A complete printout at 300 dots per inch - considered crisp 
resolution for printed publications - would require a square sheet of paper 
wider than a professional U.S. football field and almost as long. If the 
complete mosaic were processed as a single file, it would require 
approximately 3.3 terabytes of storage space. Instead, the processed mosaic 
was divided into millions of small, compressed files, making it manageable 
for users to view and navigate around the image using a web browser.

LRO entered lunar orbit in June 2009 equipped with seven instrument suites to 
map the surface, probe the radiation environment, investigate water and key 
mineral resources, and gather geological clues about the moon's evolution.

Researchers used additional information about the moon's topography from 
LRO's Lunar Orbiter Laser Altimeter, as well as gravity information from 
NASA's Gravity Recovery and Interior Laboratory (GRAIL) mission, to assemble 
the mosaic. Launched in September 2011, the GRAIL mission, employing twin 
spacecraft named Ebb and Flow, generated a gravity field map of the moon -- 
the highest resolution gravity field map of any celestial body.

LRO is managed by Goddard for the Science Mission Directorate (SMD) at NASA 
Headquarters in Washington. LROC was designed and built by Malin Space 
Science Systems and is operated by the University of Arizona. NASA's Jet 
Propulsion Laboratory in Pasadena, Calif., managed the GRAIL mission for SMD.

For more information about LRO, visit:

http://www.nasa.gov/lro

To access the complete collection of LROC images, visit:

http://lroc.sese.asu.edu/

To view the image with zoom and pan capability, visit:

http://lroc.sese.asu.edu/gigapan

-end-

Dwayne Brown
Headquarters, Washington
202-358-1726
dwayne.c.brown@nasa.gov

Nancy Neal-Jones/Elizabeth Zubritsky
Goddard Space Flight Center, Greenbelt, Md.
301-286-0039/301-614-5438
nancy.n.jones@nasa.gov/elizabeth.a.zubritsky@nasa.gov

14
Skins, Models and Maps / Faulty WAL files on Servers
« on: March 11, 2014, 02:02:56 AM »
Maps affected:
subtransit
subtransit2
nobeer

The WAL files textures/mia/xsinsign.wal and textures/nobeer/sinsign.wal as downloaded from the TS have invalid offsets and cause R1q2 clients to terminate abruptly when the maps listed above are active. The fix is to hack the wals and update them per attached files. They are identical files with different names but once hacked, they load and display correctly.

Updates to servers and the TS HTTP server are recommended.

15
0x1337c0de / Toward a Better MOTD
« on: September 21, 2013, 07:37:41 PM »
LOX has a feature that sends a motto of the day (MOTD) to players when they connect. This code was originally in-line in the ClientBeginDeathmatch function and it was an UGLY part of an otherwise simple ClientBeginDeathmatch function.

Today I decided to clean it up a bit, make it a callable function and publish it for use by other mod developers who might be interested in using a MOTD in their mod. I don't know where the original code came from, it was a part of LOX from a very long time ago and also exists in WODX and presumably WOD from where LOX and WODX derive their pedigree.

ClientBeginDeathmatch isn't called frequently so there is no advantage to writing the code in-line and avoiding a function call. It also goes against discipline to write something in line where a function will be more advantageous and the resulting code much more clear.

The ClientPrintMOTD function prototype belongs at the top of p_client.c or in g_local.h if you intend to access it globally:
void ClientPrintMOTD (edict_t *ent);
The function body belongs in p_client.c:
Code: [Select]
// Store the message of the day in memory.
char *gMOTD = ((char *)-1); // initialized at startup as bad pointer
cvar_t *motdfile;

void ClientPrintMOTD (edict_t *ent)
{
FILE *in;
char motdPath[MAX_QPATH + 1];
int c;
int motdBytes;
char *here;

// If the MOTD hasn't been loaded, do so.
if (gMOTD == ((char *)-1))
{

// Generate the path to the MOTD file.
if (gamedir == NULL || motdfile == NULL
|| !gamedir->string[0] || !motdfile->string[0])
{
gMOTD = NULL; // null pointer means we'll never try again
return;
}

sprintf (motdPath, "./%s/%s", gamedir->string, motdfile->string);

// Open the file.
in = fopen (motdPath, "rt");
if (in == NULL)
{
gi.dprintf("Opening MOTD file failed, error: %i.\n", errno);
gMOTD = NULL;
return;
}

// Count the number of bytes in the file.
motdBytes = 0;
while ((c = fgetc (in)), c != EOF)
motdBytes++;

// Make space for that many bytes.
gMOTD = gi.TagMalloc (motdBytes + 1, TAG_GAME);
gi.dprintf("Allocating %i bytes for MOTD\n", motdBytes +1);

// Now read the MOTD in for real.  Null-terminate the string.
fclose (in);
in = fopen (motdPath, "rt");
here = gMOTD; //extra pointer for writing into gMOTD
while ((c = fgetc (in)), c != EOF)
{
*here = c;
here++;
motdBytes--;
}
*here = '\0';

// If anything went wrong, warn the console.
if (motdBytes != 0)
gi.dprintf ("MOTD error: off by %d bytes", motdBytes);

}
if (gMOTD != NULL) // If a MOTD was successfully loaded, print it.
gi.centerprintf (ent, "%s", gMOTD);
return;
}

Define the necessary CVAR in GameInit:
Code: [Select]
motdfile = gi.cvar ("motdfile", "motd.txt", 0);

Add the CVAR to g_local.h:
Code: [Select]
extern cvar_t *motdfile;

Restore the ClientBeginDeathmatch to it's original beauty.
Code: [Select]
/*=====================
ClientBeginDeathmatch

A client has just connected to the server in deathmatch
mode, so clear everything out before starting them.
=====================*/
void ClientBeginDeathmatch (edict_t *ent)
{
G_InitEdict (ent);
InitClientResp (ent->client);

// locate ent at a spawn point
PutClientInServer (ent);

if (level.intermissiontime)
MoveClientToIntermission (ent);
else
{
// send effect
gi.WriteByte (svc_muzzleflash);
gi.WriteShort (ent-g_edicts);
gi.WriteByte (MZ_LOGIN);
gi.multicast (ent->s.origin, MULTICAST_PVS);
gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
}

ClientPrintMOTD(ent);

// make sure all view stuff is valid
ClientEndServerFrame (ent);
return;
}

You will notice the ClientPrintMOTD function has a trapdoor in the gMOTD pointer. It's initialized at definition to -1 and the function sets it to NULL if there's a problem initializing the cache it is supposed point to that contains the MOTD text. I'm not sure I would have done it exactly that way but you may see a modified version later, I decided to publish this as-is and may polish it up another time. The trapdoor closes the first time the function is called and the gMOTD pointer either points to a valid MOTD string or it is NULL. The trapdoor prevents the function from taking the time to open/read/close the motd.txt file every time someone connects. The problem with this technique is that if you change the MOTD file you must restart the server to get it to read it again and update the cache.

Add a motd.txt file to your server's mod folder and enjoy your center-printed MOTD.

Pages: [1] 2