Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OS X Packaging (Q2Pro.app) #106

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
497ebe2
Basic OS X support, compiles and runs on 10.7 (Lion)
jdolan Mar 31, 2013
c376be7
Packaging for OS X.
jdolan Mar 31, 2013
92823a1
Update Makefile to use ~/.quake2 on Unix.
jdolan Apr 2, 2013
5ed545d
Build packaging for Mac OS X and Linux.
jdolan Apr 2, 2013
63abbe9
Revert "Build packaging for Mac OS X and Linux."
jdolan Sep 15, 2013
dfd88f2
Revert "Update Makefile to use ~/.quake2 on Unix."
jdolan Sep 15, 2013
403399f
Revert "Packaging for OS X."
jdolan Sep 15, 2013
e7ebb3f
Revert "Basic OS X support, compiles and runs on 10.7 (Lion)"
jdolan Sep 15, 2013
869fa22
Merge branch 'master' of https://github.com/AndreyNazarov/q2pro
jdolan Sep 15, 2013
e919147
Fix OpenGL on Mac.
jdolan Sep 15, 2013
50ff57c
Merge branch 'master' of https://github.com/AndreyNazarov/q2pro
jdolan Nov 1, 2013
cdf9173
Merge branch 'master' of https://github.com/AndreyNazarov/q2pro
jdolan Jan 16, 2014
1ab18f6
Merge branch 'master' of https://github.com/AndreyNazarov/q2pro
jdolan Jul 9, 2016
d374072
Fix a bunch of compiler warnings.
jdolan Jul 9, 2016
d8c32a4
Fix OpenAL includes for OS X.
jdolan Jul 9, 2016
7660510
Default s_enable to 2 so that it tries OpenAL. It's harmless to try.
jdolan Jul 9, 2016
0095c0b
On OS X, detect if running from within an Application bundle, and if …
jdolan Jul 10, 2016
0176366
Add build directories to .gitignore.
jdolan Jul 10, 2016
03ddefa
Packaging scripts for OS X.
jdolan Jul 10, 2016
febaf39
Add install-data script to .app scaffolding.
jdolan Jul 10, 2016
1d0e935
Merging upstream
jdolan Jul 16, 2020
9b3f5e5
Update README with link to download.
jdolan Jul 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
<<<<<<< HEAD
.*.swp
.DS_Store
.baseq2
.config
.q2pro
.q2proded
q2pro
q2proded
game*.so
*target/
=======
/.config*
/.q2pro/
/.q2proded/
Expand All @@ -9,3 +21,4 @@
/game*.dll
/tags
/TAGS
>>>>>>> upstream/master
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
Q2PRO
=====

Quetoo.org macOS build
---
This fork of q2pro includes fixes and packaging scripts for macOS. If you are
simply looking to play Quake 2 on macOS with q2pro, you can download the
precompiled macOS app bundle here:

[http://quetoo.org/files/Q2Pro.dmg](http://quetoo.org/files/Q2Pro.dmg)




Q2PRO is an enhanced, multiplayer oriented Quake 2 client and server.

Features include:
Expand Down
49 changes: 49 additions & 0 deletions apple/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Makefile for Q2Pro.app, requires http://macdylibbundler.sourceforge.net/

TARGET = target
Q2PRO = $(TARGET)/Q2Pro.app
BINDIR = $(Q2PRO)/Contents/MacOS
DATADIR = $(Q2PRO)/Contents/Resources
DIST = $(TARGET)/Q2Pro.dmg
VOLUME_NAME = Q2Pro
REMOTE_USER = $(shell whoami)
HTTP_REPOSITORY = quetoo.org:/var/www/quetoo.org/files
HTTP_TARGET = $(REMOTE_USER)@$(HTTP_REPOSITORY)

all: install

pre-install:
install -d $(TARGET)
cp -R Q2Pro.app $(Q2PRO)
find $(Q2PRO) -name .turd -delete

install-bin: pre-install
install ../q2pro $(BINDIR)
install ../q2proded $(BINDIR)
install ../gamex86_64.so $(BINDIR)/baseq2

install-lib: install-bin
install -d $(TARGET)/lib
dylibbundler -b \
-x "$(BINDIR)/q2pro" \
-x "$(BINDIR)/q2proded" \
-d $(TARGET)/lib -of -p @executable_path/lib
mv $(TARGET)/lib $(BINDIR)/lib

install-share:
install -m 0644 ../INSTALL.md $(DATADIR)
install -m 0644 ../LICENSE $(DATADIR)
install -m 0644 ../README.md $(DATADIR)
install -m 0644 ../src/client/ui/q2pro.menu $(DATADIR)/baseq2

install: pre-install install-bin install-lib install-share

dist:
ln -f -s /Applications $(TARGET)/Applications
hdiutil create $(DIST) -srcfolder $(TARGET) -volname $(VOLUME_NAME)

dist-release:
rsync -rzhP $(DIST) $(HTTP_TARGET)

clean:
rm -rf $(TARGET)/*
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is based on the packaging I've created for Quake II, Quetoo, GtkRadiant, etc.. It uses dylibbundler to find, copy and fix dynamically linked dependencies.

28 changes: 28 additions & 0 deletions apple/Q2Pro.app/Contents/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDisplayName</key>
<string>Q2Pro</string>
<key>CFBundleExecutable</key>
<string>q2pro</string>
<key>CFBundleIconFile</key>
<string>quake2.icns</string>
<key>CFBundleIdentifier</key>
<string>org.quetoo.q2pro.launcher</string>
<key>CFBundleName</key>
<string>Q2Pro</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>Quetoo.org</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>Quetoo.org</string>
<key>LSMinimumSystemVersion</key>
<string>10.10</string>
</dict>
</plist>
Empty file.
Empty file.
105 changes: 105 additions & 0 deletions apple/Q2Pro.app/Contents/MacOS/install-data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/python

from os import path, system
import sys

class Dictionary(dict):
"""A dict allowing dot notation."""
def __getattr__(self, attr):
return self.get(attr, None)
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__

config = Dictionary({
'root': 'quetoo.org::quake2',
'base': [
'baseq2/pak[1-3].pak',
'baseq2/pak-quake2-extras.pak',
'baseq2/players/*',
'3.20_changes.txt',
'license.txt',
'readme.txt',
],
'ctf': [
'ctf/*'
],
'demo': [
'baseq2/pak-quake2-demo.pak',
'license-demo.txt'
],
'hud': [
'baseq2/pak-kmquake2-hud.pak',
],
'models': [
'baseq2/pak-generations-models.pak'
],
'textures': [
'baseq2/pak-jimw-textures.pak'
]
})

messages = Dictionary({
'begin': 'This script will install optional game data. Continue?',
'home': 'Enter your Quake2 directory:',
'base': 'Install the 3.20 point release? (25MB)',
'ctf': 'Install ThreeWave Capture the Flag? (12MB)',
'demo': 'Install the demo? Select this if you do not own Quake2. (48MB)',
'hud': 'Install the KMQuake2 high-resolution HUD? (0.5MB)',
'models': 'Install the Generations high-resolution models? (37MB)',
'textures': 'Install Jim W\'s high-resolution textures? (320MB)',
'end': 'Installation complete.'
})

def _rsync(source, target):
"""Fetches a single source pattern to the specified target."""
system("rsync -rRzhP %s/%s %s" % (config.root, source, target))

def rsync(module):
"""Fetches all path patterns in the specified module."""
for path in module:
_rsync(path, config.home)

def less(file):
"""Dumps the file to the console."""
system("less %s/%s" % (config.home, file))

def prompt(message, default=''):
"""Prompts the user for input, returning their response."""
while True:
sys.stdout.write("%s [%s] " % (message, default))
response = raw_input().lower()
if response == '':
if default == '':
continue
response = default
return response.lower()

if __name__ == '__main__':

if prompt(messages.begin, 'y') != 'y':
sys.exit()

config.home = path.expanduser('~/.quake2')
config.home = prompt(messages.home, config.home)

if prompt(messages.base, 'y') == 'y':
rsync(config.base)
less('license.txt')

if prompt(messages.ctf, 'y') == 'y':
rsync(config.ctf)

if prompt(messages.demo, 'n') == 'y':
rsync(config.demo)
less('license-demo.txt')

if prompt(messages.hud, 'y') == 'y':
rsync(config.hud)

if prompt(messages.models, 'y') == 'y':
rsync(config.models)

if prompt(messages.textures, 'y') == 'y':
rsync(config.textures)

print messages.end
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the game data installation script I developed for my AprQ2 fork. Users can run this to optionally install the 3.20 point release, the game demo, CTF, high res textures, Generations Arena models, etc.. It's like Q2Starter for Apple and Linux.

Empty file.
Binary file added apple/Q2Pro.app/Contents/Resources/quake2.icns
Binary file not shown.
3 changes: 3 additions & 0 deletions inc/shared/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#if (defined _WIN32)
#define LIBGL "opengl32"
#define LIBAL "openal32"
#elif (defined __APPLE__)
#define LIBGL "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
#define LIBAL "/System/Library/Frameworks/OpenAL.framework/Libraries/libAL.dylib"
#elif (defined __OpenBSD__)
#define LIBGL "libGL.so"
#define LIBAL "libopenal.so"
Expand Down
2 changes: 1 addition & 1 deletion src/client/sound/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ S_Init
*/
void S_Init(void)
{
s_enable = Cvar_Get("s_enable", "1", CVAR_SOUND);
s_enable = Cvar_Get("s_enable", "2", CVAR_SOUND);
if (s_enable->integer <= SS_NOT) {
Com_Printf("Sound initialization disabled.\n");
return;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default this to 2 so that OpenAL is tried if available. Seems like a logical thing to do?

Copy link

@Raptor007 Raptor007 Jun 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I built a version without OpenAL and it correctly resets to s_enable 1 with working sound, so I think this is a pretty safe change... as long as OpenAL doesn't sound worse. With Apple's OpenAL.framework, I noticed the same attenuation problems you mentioned, but MacPorts openal-soft sounds fine.

Expand Down
22 changes: 21 additions & 1 deletion src/unix/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <SDL.h>
#endif

#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif

cvar_t *sys_basedir;
cvar_t *sys_libdir;
cvar_t *sys_homedir;
Expand Down Expand Up @@ -282,7 +286,23 @@ void Sys_Init(void)
signal(SIGPIPE, SIG_IGN);
signal(SIGUSR1, hup_handler);

// basedir <path>
#ifdef __APPLE__
// set Q2Pro.app/Contents/Resources as basedir
char path[MAX_OSPATH], *c;
unsigned int i = sizeof(path);

if (_NSGetExecutablePath(path, &i) > -1) {
if ((c = strstr(path, "Q2Pro.app"))) {
strcpy(c, "Q2Pro.app/Contents/Resources");
Cvar_FullSet("basedir", path, CVAR_NOSET, FROM_CODE);

strcpy(c, "Q2Pro.app/Contents/MacOS");
Cvar_FullSet("libdir", path, CVAR_NOSET, FROM_CODE);
}
}
#endif

// basedir <path>
// allows the game to run from outside the data tree
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change forces basedir and libdir to the correct defaults when running from an OS X .app bundle.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of hard-coding, you could put these in your .config file:

CONFIG_PATH_DATA = ./Q2Pro.app/Contents/Resources
CONFIG_PATH_LIB= ./Q2Pro.app/Contents/MacOS

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skullernet is the code suitable for upstreaming after passing review? Distributing binaries with dependencies is a major pain for OSX unlike Windows or ELF-based Unix.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sthalik I would recommend not including the changes to unix/system.c or guarding them behind an #ifdef that can be toggled by the .config file. These forced path changes require the user to modify the .app to install mods, as you can't change libdir at runtime. The only thing required for making an app with included dependencies is the apple subdirectory of @jdolan's fork.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change only modifies the game's behavior if it's running on macOS and is launched from within a .app bundle. I don't think the .config changes you're proposing would work for all environments / use cases. I have similar code in Quetoo and in my own Quake2 fork.

Copy link

@Raptor007 Raptor007 Jun 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might be right, I recall having problems with relative paths in some versions of macOS which I solved with chdir in a different project. With my Q2Pro.app adjacent to baseq2 and mods, I want to use local paths, but I think even autoexec.cfg is too late to change libdir. Maybe a good solution is to change #ifdef __APPLE__ to #if defined(__APPLE__) && !defined(LIBDIR) instead, or check CONFIG_APPLE_PATHS in the Makefile to toggle this block?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, either of those sound responsible enough ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a wrapper shell script as the executable in the .app .plist. You'll save yourself plenty of trouble...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to do whatever you like with this PR, including closing it. I was porting things over from my own projects over 2 years ago to help Q2Pro reach macOS users. You may take it or leave it ¯_(ツ)_/¯

sys_basedir = Cvar_Get("basedir", DATADIR, CVAR_NOSET);

Expand Down