--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: freeze-exception
(Cc'd to the bug being fixed, because updated patches are attached.)
I have patches ready to fix important bug
<http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=592965>, which is a failure
to interoperate with older servers (our 0.8.5 client with a 0.8.1 server),
caused by the way in which I patched openarena to be DFSG-compliant.
Changes are necessary in both openarena and openarena-data; I suggest
looking at the openarena diff first.
The openarena-data changes also update the binary blobs generated by
qvmbrute.c, which are included in the source tarball since re-generating them
is entirely deterministic and includes a brute-force step taking a few minutes.
The new versions contain more information, which is ignored by the current
openarena.
I've tested the current openarena with the upgraded openarena-data, so
if this turns out to introduce regressions, we can revert the changes to
openarena without needing a new openarena-data. The most likely failure mode
would be that it's incompatible with 0.8.1 in a way I haven't spotted,
in which case we've neither gained nor lost anything.
Thanks,
Simon
diff --git a/debian/changelog b/debian/changelog
index b2204d6..8c780d3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+openarena (0.8.5-4) UNRELEASED; urgency=low
+
+ * Build a second copy of the game logic and install it in a subdirectory.
+ It turns out that OpenArena 0.8.1 and 0.8.5 aren't network-compatible.
+ * Depend on openarena-data (>= 0.8.5-3~) which causes us to load the
+ 0.8.1-compatible game logic whenever the upstream version would use
+ 0.8.1's bytecode (Closes: #592965)
+
+ -- Simon McVittie <smcv@debian.org> Sat, 21 Aug 2010 00:02:54 +0100
+
openarena (0.8.5-3) unstable; urgency=medium
* Add patch from oax r203 to fix server crashes if a player joins, then
diff --git a/debian/control b/debian/control
index fe3244e..10a6efa 100644
--- a/debian/control
+++ b/debian/control
@@ -14,7 +14,7 @@ Homepage: http://openarena.ws/
Package: openarena
Architecture: any
Depends: ${misc:Depends}, ${shlibs:Depends},
- openarena-data (>= 0.8.5), openarena-data (<< 0.8.6~),
+ openarena-data (>= 0.8.5-3~), openarena-data (<< 0.8.6~),
openarena-server (= ${binary:Version})
Description: fast-paced 3D first-person shooter
OpenArena is an open-source content package for ioQuake3 licensed under the
diff --git a/debian/openarena-server.install b/debian/openarena-server.install
index 714e52f..e475b7d 100644
--- a/debian/openarena-server.install
+++ b/debian/openarena-server.install
@@ -1,2 +1,3 @@
debian/tmp/usr/games/openarena-server
debian/tmp/usr/lib/games/openarena/*/*.so
+debian/tmp/usr/lib/games/openarena/*/*/*.so
diff --git a/debian/patches/0040-Add-OPENARENA_081_COMPATIBLE-define-for-network-comp.patch b/debian/patches/0040-Add-OPENARENA_081_COMPATIBLE-define-for-network-comp.patch
new file mode 100644
index 0000000..56f590f
--- /dev/null
+++ b/debian/patches/0040-Add-OPENARENA_081_COMPATIBLE-define-for-network-comp.patch
@@ -0,0 +1,387 @@
+From aee4d733e1e9324e8392ecc0e024b50e3176b938 Mon Sep 17 00:00:00 2001
+From: Simon McVittie <smcv@debian.org>
+Date: Fri, 20 Aug 2010 23:27:28 +0100
+Subject: [PATCH] Add OPENARENA_081_COMPATIBLE define for network compat with 0.8.1
+
+0.8.1 was approximately compatible with Quake III Arena, whereas 0.8.5
+is more like Team Arena. Unfortunately, these are not the same.
+
+Not forwarded: upstream expect everyone to use the precompiled bytecode they
+supply, which was built from unmodified 0.8.5 and 0.8.1 source code. We're not
+doing that in Debian for DFSG reasons, and I'd rather not add a second complete
+copy of the source.
+
+Origin: vendor, Debian
+Bug: http://openarena.ws/board/index.php?topic=3717.0
+Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=592965
+Forwarded: no
+---
+ game/Makefile | 4 ++++
+ game/code/cgame/cg_draw.c | 6 +++---
+ game/code/game/ai_dmq3.c | 2 ++
+ game/code/game/bg_misc.c | 15 ++++++++++++---
+ game/code/game/bg_pmove.c | 2 ++
+ game/code/game/bg_public.h | 11 ++++++++++-
+ game/code/game/g_active.c | 11 ++++++++++-
+ game/code/game/g_combat.c | 4 ++++
+ game/code/game/g_items.c | 9 ++++++++-
+ 9 files changed, 55 insertions(+), 9 deletions(-)
+
+diff --git a/game/Makefile b/game/Makefile
+index 1520a96..f3dd3f1 100644
+--- a/game/Makefile
++++ b/game/Makefile
+@@ -852,6 +852,10 @@ endif
+
+ BASE_CFLAGS += -DPRODUCT_VERSION=\\\"$(VERSION)\\\"
+
++ifeq ($(OPENARENA_081_COMPATIBLE),1)
++ BASE_CFLAGS += -DOPENARENA_081_COMPATIBLE
++endif
++
+ ifeq ($(V),1)
+ echo_cmd=@:
+ Q=
+diff --git a/game/code/cgame/cg_draw.c b/game/code/cgame/cg_draw.c
+index e4d2b2a..32f74dd 100644
+--- a/game/code/cgame/cg_draw.c
++++ b/game/code/cgame/cg_draw.c
+@@ -1890,7 +1890,6 @@ static void CG_DrawHoldableItem( void ) {
+ }
+ #endif // MISSIONPACK
+
+-#ifndef MISSIONPACK
+ /*
+ ===================
+ CG_DrawPersistantPowerup
+@@ -1898,6 +1897,7 @@ CG_DrawPersistantPowerup
+ */
+ #if 1 // sos001208 - DEAD // sago - ALIVE
+ static void CG_DrawPersistantPowerup( void ) {
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ int value;
+
+ value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP];
+@@ -1905,9 +1905,9 @@ static void CG_DrawPersistantPowerup( void ) {
+ CG_RegisterItemVisuals( value );
+ CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2 - ICON_SIZE, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
+ }
++#endif
+ }
+ #endif
+-#endif // MISSIONPACK
+
+
+ /*
+@@ -3243,8 +3243,8 @@ static void CG_Draw2D(stereoFrame_t stereoFrame)
+
+ #ifndef MISSIONPACK
+ CG_DrawHoldableItem();
+- CG_DrawPersistantPowerup();
+ #endif
++ CG_DrawPersistantPowerup();
+
+ CG_DrawReward();
+ }
+diff --git a/game/code/game/ai_dmq3.c b/game/code/game/ai_dmq3.c
+index 9037445..9731fdd 100644
+--- a/game/code/game/ai_dmq3.c
++++ b/game/code/game/ai_dmq3.c
+@@ -1881,10 +1881,12 @@ void BotUpdateInventory(bot_state_t *bs) {
+ bs->inventory[INVENTORY_INVISIBILITY] = bs->cur_ps.powerups[PW_INVIS] != 0;
+ bs->inventory[INVENTORY_REGEN] = bs->cur_ps.powerups[PW_REGEN] != 0;
+ bs->inventory[INVENTORY_FLIGHT] = bs->cur_ps.powerups[PW_FLIGHT] != 0;
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ bs->inventory[INVENTORY_SCOUT] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_SCOUT;
+ bs->inventory[INVENTORY_GUARD] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_GUARD;
+ bs->inventory[INVENTORY_DOUBLER] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_DOUBLER;
+ bs->inventory[INVENTORY_AMMOREGEN] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_AMMOREGEN;
++#endif
+ bs->inventory[INVENTORY_REDFLAG] = bs->cur_ps.powerups[PW_REDFLAG] != 0;
+ bs->inventory[INVENTORY_BLUEFLAG] = bs->cur_ps.powerups[PW_BLUEFLAG] != 0;
+ bs->inventory[INVENTORY_NEUTRALFLAG] = bs->cur_ps.powerups[PW_NEUTRALFLAG] != 0;
+diff --git a/game/code/game/bg_misc.c b/game/code/game/bg_misc.c
+index 767cc7e..c701434 100644
+--- a/game/code/game/bg_misc.c
++++ b/game/code/game/bg_misc.c
+@@ -655,6 +655,7 @@ Only in CTF games
+ /* sounds */ ""
+ },
+
++#ifdef HAVE_MISSIONPACK_ITEMLIST
+ /*QUAKED holdable_kamikaze (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+ */
+ {
+@@ -702,6 +703,7 @@ Only in CTF games
+ /* precache */ "",
+ /* sounds */ ""
+ },
++#endif
+
+ /*QUAKED ammo_nails (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+ */
+@@ -751,6 +753,7 @@ Only in CTF games
+ /* sounds */ ""
+ },
+
++#ifdef HAVE_MISSIONPACK_ITEMLIST
+ //
+ // PERSISTANT POWERUP ITEMS
+ //
+@@ -817,6 +820,7 @@ Only in CTF games
+ /* precache */ "",
+ /* sounds */ ""
+ },
++#endif
+
+
+ /*QUAKED team_CTF_neutralflag (0 0 1) (-16 -16 -16) (16 16 16)
+@@ -1214,6 +1218,9 @@ qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const play
+ return qtrue;
+
+ case IT_ARMOR:
++ upperBound = ps->stats[STAT_MAX_HEALTH] * 2;
++
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
+ return qfalse;
+ }
+@@ -1222,9 +1229,7 @@ qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const play
+ if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ upperBound = ps->stats[STAT_MAX_HEALTH];
+ }
+- else {
+- upperBound = ps->stats[STAT_MAX_HEALTH] * 2;
+- }
++#endif
+
+ if ( ps->stats[STAT_ARMOR] >= upperBound ) {
+ return qfalse;
+@@ -1232,12 +1237,14 @@ qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const play
+ return qtrue;
+
+ case IT_HEALTH:
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ // small and mega healths will go over the max, otherwise
+ // don't pick up if already at max
+ if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ upperBound = ps->stats[STAT_MAX_HEALTH];
+ }
+ else
++#endif
+ if ( item->quantity == 5 || item->quantity == 100 ) {
+ if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] * 2 ) {
+ return qfalse;
+@@ -1253,6 +1260,7 @@ qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const play
+ case IT_POWERUP:
+ return qtrue; // powerups are always picked up
+
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ case IT_PERSISTANT_POWERUP:
+
+ //In Double D we don't want persistant Powerups (or maybe, can be discussed)
+@@ -1273,6 +1281,7 @@ qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const play
+ }
+
+ return qtrue;
++#endif
+
+ case IT_TEAM: // team items, such as flags
+ if( gametype == GT_1FCTF ) {
+diff --git a/game/code/game/bg_pmove.c b/game/code/game/bg_pmove.c
+index 8bb6a2c..2fd3ba5 100644
+--- a/game/code/game/bg_pmove.c
++++ b/game/code/game/bg_pmove.c
+@@ -1696,6 +1696,7 @@ static void PM_Weapon( void ) {
+ break;
+ }
+
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
+ addTime /= 1.5;
+ }
+@@ -1704,6 +1705,7 @@ static void PM_Weapon( void ) {
+ addTime /= 1.3;
+ }
+ else
++#endif
+ if ( pm->ps->powerups[PW_HASTE] ) {
+ addTime /= 1.3;
+ }
+diff --git a/game/code/game/bg_public.h b/game/code/game/bg_public.h
+index b0efb3e..3fcd777 100644
+--- a/game/code/game/bg_public.h
++++ b/game/code/game/bg_public.h
+@@ -25,6 +25,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ // because games can change separately from the main system version, we need a
+ // second version that must match between game and cgame
+
++#if defined(MISSIONPACK) || !defined(OPENARENA_081_COMPATIBLE)
++// MISSIONPACK and 0.8.5 break ABI and network compatibility, because
++// STAT_PERSISTANT_POWERUP wasn't added at the end of its enum. Sad times.
++# define HAVE_STAT_PERSISTANT_POWERUP
++// Adding objects to the middle of the bg_itemlist also breaks network compat.
++# define HAVE_MISSIONPACK_ITEMLIST
++#endif
++
+ #if defined(BG_PUBLIC_H)
+ #else
+ #define BG_PUBLIC_H 1
+@@ -223,13 +231,14 @@ void Pmove (pmove_t *pmove);
+
+ //===================================================================================
+
+-
+ // player_state->stats[] indexes
+ // NOTE: may not have more than 16
+ typedef enum {
+ STAT_HEALTH,
+ STAT_HOLDABLE_ITEM,
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ STAT_PERSISTANT_POWERUP,
++#endif
+ STAT_WEAPONS, // 16 bit fields
+ STAT_ARMOR,
+ STAT_DEAD_YAW, // look this direction when dead (FIXME: get rid of?)
+diff --git a/game/code/game/g_active.c b/game/code/game/g_active.c
+index c905261..b66f982 100644
+--- a/game/code/game/g_active.c
++++ b/game/code/game/g_active.c
+@@ -437,10 +437,13 @@ void ClientTimerActions( gentity_t *ent, int msec ) {
+ continue;
+
+ // regenerate
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ maxHealth = client->ps.stats[STAT_MAX_HEALTH] / 2;
+ }
+- else if ( client->ps.powerups[PW_REGEN] ) {
++ else
++#endif
++ if ( client->ps.powerups[PW_REGEN] ) {
+ maxHealth = client->ps.stats[STAT_MAX_HEALTH];
+ }
+ else {
+@@ -484,6 +487,7 @@ void ClientTimerActions( gentity_t *ent, int msec ) {
+ client->ps.stats[STAT_ARMOR]--;
+ }
+ }
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
+ int w, max, inc, t, i;
+ int weapList[]={WP_MACHINEGUN,WP_SHOTGUN,WP_GRENADE_LAUNCHER,WP_ROCKET_LAUNCHER,WP_LIGHTNING,WP_RAILGUN,WP_PLASMAGUN,WP_BFG,WP_NAILGUN,WP_PROX_LAUNCHER,WP_CHAINGUN};
+@@ -520,6 +524,7 @@ void ClientTimerActions( gentity_t *ent, int msec ) {
+ }
+ }
+ }
++#endif
+ }
+
+ /*
+@@ -968,10 +973,12 @@ void ClientThink_real( gentity_t *ent ) {
+ // set speed
+ client->ps.speed = g_speed.value;
+
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
+ client->ps.speed *= 1.5;
+ }
+ else
++#endif
+ if ( client->ps.powerups[PW_HASTE] ) {
+ client->ps.speed *= 1.3;
+ }
+@@ -1278,6 +1285,7 @@ void ClientEndFrame( gentity_t *ent ) {
+ }
+
+ // set powerup for player animation
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ ent->client->ps.powerups[PW_GUARD] = level.time;
+ }
+@@ -1290,6 +1298,7 @@ void ClientEndFrame( gentity_t *ent ) {
+ if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
+ ent->client->ps.powerups[PW_AMMOREGEN] = level.time;
+ }
++#endif
+ if ( ent->client->invulnerabilityTime > level.time ) {
+ ent->client->ps.powerups[PW_INVULNERABILITY] = level.time;
+ }
+diff --git a/game/code/game/g_combat.c b/game/code/game/g_combat.c
+index 8c81284..22ce65a 100644
+--- a/game/code/game/g_combat.c
++++ b/game/code/game/g_combat.c
+@@ -227,7 +227,9 @@ void TossClientPersistantPowerups( gentity_t *ent ) {
+ powerup->r.contents = CONTENTS_TRIGGER;
+ trap_LinkEntity( powerup );
+
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ ent->client->ps.stats[STAT_PERSISTANT_POWERUP] = 0;
++#endif
+ ent->client->persistantPowerup = NULL;
+ }
+
+@@ -1071,9 +1073,11 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
+ // unless they are rocket jumping
+ if ( attacker->client && attacker != targ ) {
+ max = attacker->client->ps.stats[STAT_MAX_HEALTH];
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ if( bg_itemlist[attacker->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ max /= 2;
+ }
++#endif
+ damage = damage * max / 100;
+ }
+
+diff --git a/game/code/game/g_items.c b/game/code/game/g_items.c
+index cc003bc..1fd4619 100644
+--- a/game/code/game/g_items.c
++++ b/game/code/game/g_items.c
+@@ -118,6 +118,7 @@ int Pickup_Powerup( gentity_t *ent, gentity_t *other ) {
+ //======================================================================
+
+ int Pickup_PersistantPowerup( gentity_t *ent, gentity_t *other ) {
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ int clientNum;
+ char userinfo[MAX_INFO_STRING];
+ float handicap;
+@@ -185,6 +186,7 @@ int Pickup_PersistantPowerup( gentity_t *ent, gentity_t *other ) {
+ break;
+ }
+
++#endif
+ return -1;
+ }
+
+@@ -277,11 +279,13 @@ int Pickup_Health (gentity_t *ent, gentity_t *other) {
+ int max;
+ int quantity;
+
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ // small and mega healths will go over the max
+ if( other->client && bg_itemlist[other->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ max = other->client->ps.stats[STAT_MAX_HEALTH];
+ }
+ else
++#endif
+ if ( ent->item->quantity != 5 && ent->item->quantity != 100 ) {
+ max = other->client->ps.stats[STAT_MAX_HEALTH];
+ } else {
+@@ -315,10 +319,13 @@ int Pickup_Armor( gentity_t *ent, gentity_t *other ) {
+
+ other->client->ps.stats[STAT_ARMOR] += ent->item->quantity;
+
++#ifdef HAVE_STAT_PERSISTANT_POWERUP
+ if( other->client && bg_itemlist[other->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ upperBound = other->client->ps.stats[STAT_MAX_HEALTH];
+ }
+- else {
++ else
++#endif
++ {
+ upperBound = other->client->ps.stats[STAT_MAX_HEALTH] * 2;
+ }
+
+--
+1.7.1
+
diff --git a/debian/patches/0041-If-a-QVM-starts-with-NTVE-followed-by-a-nonempty-str.patch b/debian/patches/0041-If-a-QVM-starts-with-NTVE-followed-by-a-nonempty-str.patch
new file mode 100644
index 0000000..8aee1d4
--- /dev/null
+++ b/debian/patches/0041-If-a-QVM-starts-with-NTVE-followed-by-a-nonempty-str.patch
@@ -0,0 +1,57 @@
+From 88632d58a1bb664b54621aac6bdf14b80315cfd9 Mon Sep 17 00:00:00 2001
+From: Simon McVittie <smcv@debian.org>
+Date: Sat, 21 Aug 2010 16:03:22 +0100
+Subject: [PATCH] If a QVM starts with NTVE followed by a nonempty string, look in that subdir
+
+This lets each version have a different substitute shared object, if
+necessary for network compatibility (OpenArena broke network
+compatibility between 0.8.1 and 0.8.5 by removing some #ifdef MISSIONPACK).
+
+Origin: vendor, Debian
+Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=592965
+Forwarded: no (amends an earlier patch which hasn't been forwarded yet)
+---
+ engine/code/qcommon/vm.c | 20 ++++++++++++++++++++
+ 1 files changed, 20 insertions(+), 0 deletions(-)
+
+diff --git a/engine/code/qcommon/vm.c b/engine/code/qcommon/vm.c
+index 83832d1..2c1a7f5 100644
+--- a/engine/code/qcommon/vm.c
++++ b/engine/code/qcommon/vm.c
+@@ -372,6 +372,7 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
+ union {
+ vmHeader_t *h;
+ void *v;
++ char *s;
+ } header;
+
+ // load the image
+@@ -386,6 +387,25 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
+
+ if (LittleLong( header.h->vmMagic ) == VM_MAGIC_USE_NATIVE) {
+ Com_Printf( "...which has vmMagic VM_MAGIC_USE_NATIVE.\n" );
++
++ if (header.s[sizeof(int)] != '\0') {
++ Com_sprintf( filename, sizeof(filename), "%.*s/%s", length - sizeof(int), header.s + sizeof(int), vm->name );
++ filename[sizeof(filename)-1] = '\0';
++
++ if (FS_CheckDirTraversal( filename )) {
++ Com_Printf( "Directory traversal detected! %s", filename );
++ VM_Free( vm );
++ return NULL;
++ }
++
++ vm->dllHandle = Sys_LoadDll( filename, vm->fqpath , &vm->entryPoint, VM_DllSyscall );
++
++ if (vm->dllHandle != NULL) {
++ Com_Printf( "Loaded prefixed DLL file %s.\n", filename );
++ return header.h;
++ }
++ }
++
+ Com_Printf( "Loading DLL file %s instead.\n", vm->name );
+ vm->dllHandle = Sys_LoadDll( vm->name, vm->fqpath , &vm->entryPoint, VM_DllSyscall );
+ if ( !vm->dllHandle ) {
+--
+1.7.1
+
diff --git a/debian/patches/series b/debian/patches/series
index 4f37be5..485ad3a 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -31,3 +31,5 @@
0037-Put-a-error-marker-in-engine-s-ui_shared.h-to-make-s.patch
0038-Fix-buffer-overflow-report-and-patch-by-Eugene-C.-46.patch
0039-Used-self-enemy-before-it-was-initialized.-Might-hav.patch
+0040-Add-OPENARENA_081_COMPATIBLE-define-for-network-comp.patch
+0041-If-a-QVM-starts-with-NTVE-followed-by-a-nonempty-str.patch
diff --git a/debian/rules b/debian/rules
index e8216f8..67adff2 100755
--- a/debian/rules
+++ b/debian/rules
@@ -44,11 +44,17 @@ GAME_OPTIONS = \
BUILD_GAME_SO=1 \
CROSS_COMPILING=1
+GAME_081_OPTIONS = \
+ $(GAME_OPTIONS) \
+ BUILD_DIR=build-0.8.1-compat \
+ OPENARENA_081_COMPATIBLE=1
+
build: build-stamp
build-stamp:
dh_testdir
$(MAKE) -C engine $(ENGINE_OPTIONS)
$(MAKE) -C game $(GAME_OPTIONS)
+ $(MAKE) -C game $(GAME_081_OPTIONS)
touch $@
clean:
@@ -57,6 +63,7 @@ clean:
rm -f build-stamp
rm -rf engine/build
rm -rf game/build
+ rm -rf game/build-0.8.1-compat
rm -f debian/openarena32.xpm
dh_clean
@@ -65,7 +72,7 @@ install: build
dh_testroot
dh_clean -k
install -d debian/tmp/usr/games
- install -d debian/tmp/usr/lib/games/openarena/baseoa/
+ install -d debian/tmp/usr/lib/games/openarena/baseoa/pak0/
install -d debian/tmp/usr/lib/games/openarena/missionpack/
install engine/build/release-$(Q3PLATFORM)-$(Q3ARCH)/ioquake3.$(Q3ARCH) \
debian/tmp/usr/games/openarena
@@ -73,6 +80,8 @@ install: build
debian/tmp/usr/games/openarena-server
install -m644 game/build/release-$(Q3PLATFORM)-$(Q3ARCH)/baseq3/*.so \
debian/tmp/usr/lib/games/openarena/baseoa/
+ install -m644 game/build-0.8.1-compat/release-$(Q3PLATFORM)-$(Q3ARCH)/baseq3/*.so \
+ debian/tmp/usr/lib/games/openarena/baseoa/pak0/
install -m644 game/build/release-$(Q3PLATFORM)-$(Q3ARCH)/missionpack/*.so\
debian/tmp/usr/lib/games/openarena/missionpack/
convert -scale 32x32 debian/openarena128.png debian/openarena32.xpm
Index: qvmbrute.c
===================================================================
--- qvmbrute.c (revision 11184)
+++ qvmbrute.c (working copy)
@@ -1,5 +1,7 @@
/* Attempt to find CRC-32 collisions for QVM files.
*
+ * Usage: qvmbrute.c DESIRED-CRC [OUTPUT-FILENAME [SUBDIRECTORY]]
+ *
* Copyright 2010 Simon McVittie <smcv@debian.org>
* Copying and distribution of this file, with or without modification, are
* permitted in any medium without royalty provided this notice is preserved.
@@ -19,21 +21,40 @@
main (int argc, char **argv)
{
u_int32_t i;
- unsigned char qvm[] = { 'N', 'T', 'V', 'E', 0, 0, 0, 0,
- 'c', 'c', 'c', 'c', 'x', 'x', 'x', 'x' };
+ unsigned char qvm[1024] = { 0 };
u_int32_t target = strtoul (argv[1], NULL, 0);
+ char *subdir = "";
+ size_t fixed_len;
u_int32_t crc;
- /* calculate CRC of first 8 bytes */
- crc = crc32 (crc32 (0, NULL, 0), qvm, 8);
+ /* subdirectory to embed in the dummy file */
+ if (argc > 3) {
+ subdir = argv[3];
+ }
+
+ /* length of fixed part */
+ fixed_len = strlen (subdir) + 8;
+
+ /* The fixed part is "NTVE" + subdir + four reserved '\0' bytes
+ * (the first of which acts as '\0' termination for subdir).
+ *
+ * CCCC is replaced by the complement of the CRC-32 of the fixed part,
+ * yielding crc32 (fixed part + CCCC) = FFFFFFFF.
+ * XXXX is replaced by a brute-forced number such that
+ * crc32 (fixed part + CCCC + XXXX) is as desired. */
+ snprintf ((char *) qvm, sizeof (qvm) - 1, "NTVE%s%c%c%c%cCCCCXXXX",
+ subdir, 0, 0, 0, 0);
+
+ /* calculate CRC of first fixed_len bytes */
+ crc = crc32 (crc32 (0, NULL, 0), qvm, fixed_len);
/* put the complement of it, in little-endian, in the next 4 */
- qvm[8] = ~(crc & 0xFF);
- qvm[9] = ~((crc >> 8) & 0xFF);
- qvm[10] = ~((crc >> 16) & 0xFF);
- qvm[11] = ~((crc >> 24) & 0xFF);
- /* by mathematical properties of CRC32, the CRC of those 12 bytes is
+ qvm[fixed_len + 0] = ~(crc & 0xFF);
+ qvm[fixed_len + 1] = ~((crc >> 8) & 0xFF);
+ qvm[fixed_len + 2] = ~((crc >> 16) & 0xFF);
+ qvm[fixed_len + 3] = ~((crc >> 24) & 0xFF);
+ /* by mathematical properties of CRC32, the CRC up to that point is
* 0xFFFFFFFF */
- crc = crc32 (crc32 (0, NULL, 0), qvm, 12);
+ crc = crc32 (crc32 (0, NULL, 0), qvm, fixed_len + 4);
assert (crc == 0xFFFFFFFF);
/* it's possible to do the last bit by mathematics, but brute force
@@ -59,13 +80,14 @@
}
/* check our working */
- memcpy (qvm + 12, &i, 4);
- crc = crc32 (crc32 (0, NULL, 0), qvm, 16);
+ memcpy (qvm + fixed_len + 4, &i, 4);
+ crc = crc32 (crc32 (0, NULL, 0), qvm, fixed_len + 8);
assert (crc == target);
- printf ("crc32(\"NTVE\" 00000000 %.8x %.8x) == 0x%.8x\n",
- ntohl(*((u_int32_t *) (qvm + 8))),
- ntohl(*((u_int32_t *) (qvm + 12))),
+ printf ("crc32(\"NTVE%s\" 00000000 %.8x %.8x) == 0x%.8x\n",
+ subdir,
+ ntohl(*((u_int32_t *) (qvm + fixed_len))),
+ ntohl(*((u_int32_t *) (qvm + fixed_len + 4))),
crc);
if (argc > 2) {
@@ -75,7 +97,7 @@
f = fopen (argv[2], "w");
if (f == NULL ||
- fwrite (qvm, 16, 1, f) < 1 ||
+ fwrite (qvm, fixed_len + 8, 1, f) < 1 ||
fclose (f) < 0) {
perror ("writing fake QVM");
return 1;
Index: changelog
===================================================================
--- changelog (revision 11185)
+++ changelog (working copy)
@@ -1,3 +1,11 @@
+openarena-data (0.8.5-3) UNRELEASED; urgency=low
+
+ * Encode a search prefix into the fake QVM files so we can load different
+ native code; OA 0.8.1 and 0.8.5 turn out not to be network-compatible.
+ (When combined with changes to openarena, this will close #592965)
+
+ -- Simon McVittie <smcv@debian.org> Fri, 20 Aug 2010 23:57:11 +0100
+
openarena-data (0.8.5-2) unstable; urgency=low
* Include directory entries explicitly in the repacked PK3 files, so the
Index: rules
===================================================================
--- rules (revision 11184)
+++ rules (working copy)
@@ -12,12 +12,13 @@
set -e && \
cd debian && for c in baseoa/*.contents missionpack/*.contents; do \
pk3=$${c%.contents}; \
+ prefix=$$(basename $${pk3%.pk3}); \
dir=$${pk3%.pk3}; \
echo "adding any missing fake QVM files for $$c"; \
sed -n -e 's/#.*//; /\.qvm$$/p;' < $$c | \
while read crc filename; do \
- test -f $$crc.qvm || $(MAKE) -C .. -f debian/rules debian/$$crc.qvm; \
- cp $$crc.qvm ../$$dir/$$filename; \
+ test -f $$prefix-$$crc.qvm || $(MAKE) -C .. -f debian/rules QVMPREFIX=$$prefix QVMCRC=$$crc debian/$$prefix-$$crc.qvm; \
+ cp $$prefix-$$crc.qvm ../$$dir/$$filename; \
done; \
echo "compressing $$dir to $$pk3"; \
rm -f ../$$pk3; \
@@ -29,8 +30,8 @@
DEB_BUILD_GNU_TYPE := $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
-debian/%.qvm: debian/qvmbrute
- ./debian/qvmbrute 0x$* $@
+debian/$(QVMPREFIX)-$(QVMCRC).qvm: debian/qvmbrute
+ ./debian/qvmbrute 0x$(QVMCRC) $@ $(QVMPREFIX)
debian/qvmbrute: debian/qvmbrute.c
$(DEB_BUILD_GNU_TYPE)-gcc -Wall -lz -o debian/qvmbrute debian/qvmbrute.c
Index: source/include-binaries
===================================================================
--- source/include-binaries (revision 11184)
+++ source/include-binaries (working copy)
@@ -1,9 +1,9 @@
-debian/087acd9c.qvm
-debian/37554497.qvm
-debian/438cf2c5.qvm
-debian/449831c5.qvm
-debian/6602cd55.qvm
-debian/73428e1b.qvm
-debian/b2b99e5d.qvm
-debian/c8703d61.qvm
-debian/d2225dd5.qvm
+debian/mp-pak0-449831c5.qvm
+debian/mp-pak0-73428e1b.qvm
+debian/mp-pak0-c8703d61.qvm
+debian/pak0-37554497.qvm
+debian/pak0-b2b99e5d.qvm
+debian/pak0-d2225dd5.qvm
+debian/pak6-patch085-087acd9c.qvm
+debian/pak6-patch085-438cf2c5.qvm
+debian/pak6-patch085-6602cd55.qvm
--- End Message ---