Package: release.debian.org Severity: normal User: release.debian....@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 <s...@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 <s...@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 <s...@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 <s...@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 <s...@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