diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index ec9dfba9f..c16faa565 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -67,7 +67,7 @@ cvar_t cl_nopext = CVARF("cl_nopext", "0", CVAR_ARCHIVE); cvar_t cl_pext_mask = CVAR("cl_pext_mask", "0xffffffff"); cvar_t cl_nolerp = CVARD("cl_nolerp", "0", "Disables interpolation. If set, missiles/monsters will be show exactly what was last received, which will be jerky. Does not affect players. A value of 2 means 'interpolate only in single-player/coop'."); cvar_t cl_nolerp_netquake = CVARD("cl_nolerp_netquake", "0", "Disables interpolation when connected to an NQ server. Does affect players, even the local player. You probably don't want to set this."); -cvar_t cl_fullpitch_nq = CVARAFD("cl_fullpitch", "0", "pq_fullpitch", CVAR_SEMICHEAT, "When set, attempts to unlimit the default view pitch. Note that some servers will screw over your angles if you use this, resulting in terrible gameplay, while some may merely clamp your angle serverside. This is also considered a cheat in quakeworld, so this will not function there. For the equivelent in quakeworld, use serverinfo minpitch+maxpitch instead, which applies to all players fairly."); +cvar_t cl_fullpitch_nq = CVARAFD("cl_fullpitch", "0", "pq_fullpitch", CVAR_SEMICHEAT, "When set, attempts to unlimit the default view pitch. Note that some servers will screw over your angles if you use this, resulting in terrible gameplay, while some may merely clamp your angle serverside. This is also considered a cheat in quakeworld, ^1so this will not function there^7. For the equivelent in quakeworld, use serverinfo minpitch+maxpitch instead, which applies to all players fairly."); cvar_t *hud_tracking_show; cvar_t *hud_miniscores_show; extern cvar_t net_compress; @@ -2387,6 +2387,8 @@ void CL_CheckServerInfo(void) if (oldteamplay != cl.teamplay) Skin_FlushPlayers(); + + CSQC_ServerInfoChanged(); } /* @@ -4924,7 +4926,8 @@ void Host_WriteConfiguration (void) f = FS_OpenVFS(savename, "wb", FS_GAMEONLY); if (!f) { - Con_TPrintf (CON_ERROR "Couldn't write config.cfg.\n"); + FS_NativePath(savename, FS_GAMEONLY, sysname, sizeof(sysname)); + Con_TPrintf (CON_ERROR "Couldn't write %s.\n", sysname); return; } diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 4180e70d4..55637b317 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -143,7 +143,7 @@ static const char *svc_qwstrings[] = "svcfte_movepic", "svcfte_updatepic", - "???", + "NEW PROTOCOL(73)", "svcfte_effect", "svcfte_effect2", @@ -165,26 +165,26 @@ static const char *svc_qwstrings[] = "svcfte_updateentities", "svcfte_brushedit", "svcfte_updateseats", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", - "???", + "svcfte_setinfoblob", //89 + "NEW PROTOCOL(90)", + "NEW PROTOCOL(91)", + "NEW PROTOCOL(92)", + "NEW PROTOCOL(93)", + "NEW PROTOCOL(94)", + "NEW PROTOCOL(95)", + "NEW PROTOCOL(96)", + "NEW PROTOCOL(97)", + "NEW PROTOCOL(98)", + "NEW PROTOCOL(99)", + "NEW PROTOCOL(100)", + "NEW PROTOCOL(101)", + "NEW PROTOCOL(102)", + "NEW PROTOCOL(103)", + "NEW PROTOCOL(104)", + "NEW PROTOCOL(105)", + "NEW PROTOCOL(106)", + "NEW PROTOCOL(107)", + "NEW PROTOCOL(108)", }; #ifdef NQPROT @@ -286,7 +286,8 @@ static const char *svc_nqstrings[] = "nqsvcfte_setangledelta(85)", //85 "nqsvcfte_updateentities", //86 "NEW PROTOCOL(87)", //87 - "NEW PROTOCOL(88)" //88 + "NEW PROTOCOL(88)", //88 + "svcfte_setinfoblob"//89 }; #endif @@ -5236,6 +5237,8 @@ static void CL_ProcessUserInfo (int slot, player_info_t *player) CL_NewTranslation (slot); #endif Sbar_Changed (); + + CSQC_PlayerInfoChanged(slot); } /* @@ -5284,7 +5287,11 @@ static void CL_ParseSetInfoBlob (void) key = InfoBuf_DecodeString(key, key+strlen(key), &keysize); if (slot-- == 0) + { InfoBuf_SyncReceive(&cl.serverinfo, key, keysize, val, valsize, offset, final); + if (final) + CL_CheckServerInfo(); + } else if (slot >= MAX_CLIENTS) Con_Printf("INVALID SETINFO %i: %s=%s\n", slot, key, val); else diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index c7c4f2679..caf7bab09 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -757,7 +757,9 @@ beam_t *CL_NewBeam (int entity, int tag, tentmodels_t *btype) return NULL; } -#define STREAM_ATTACHED 16 +#define STREAM_ATTACHTOPLAYER 1 //if owned by the viewentity then attach to camera (but don't for other entities). +#define STREAM_JITTER 2 //moves up to 30qu forward/back (40qu per sec) +#define STREAM_ATTACHED 16 //attach it to any entity's origin #define STREAM_TRANSLUCENT 32 beam_t *CL_AddBeam (enum beamtype_e tent, int ent, vec3_t start, vec3_t end) //fixme: use TE_ numbers instead of 0 - 5 { @@ -847,7 +849,7 @@ beam_t *CL_AddBeam (enum beamtype_e tent, int ent, vec3_t start, vec3_t end) //f b->entity = ent; b->info = &beamtypes[tent]; b->tag = -1; - b->bflags |= /*STREAM_ATTACHED|*/1; + b->bflags |= /*STREAM_ATTACHED|*/STREAM_ATTACHTOPLAYER; b->endtime = cl.time + 0.2; b->alpha = 1; VectorCopy (start, b->start); @@ -953,15 +955,15 @@ void CL_ParseStream (int type) { case TEH2_STREAM_LIGHTNING_SMALL: info = &beamtypes[BT_H2LIGHTNING_SMALL]; - flags |= 2; + flags |= STREAM_JITTER; break; case TEH2_STREAM_LIGHTNING: info = &beamtypes[BT_H2LIGHTNING]; - flags |= 2; + flags |= STREAM_JITTER; break; case TEH2_STREAM_ICECHUNKS: info = &beamtypes[BT_H2ICECHUNKS]; - flags |= 2; + flags |= STREAM_JITTER; if (cl_legacystains.ival) Surf_AddStain(end, -10, -10, 0, 20); break; case TEH2_STREAM_SUNSTAFF1: @@ -2832,7 +2834,7 @@ void CL_UpdateBeams (void) lastrunningbeam = bnum; // if coming from the player, update the start position - if ((b->bflags & 1) && b->entity > 0 && b->entity <= cl.allocated_client_slots) + if ((b->bflags & STREAM_ATTACHTOPLAYER) && b->entity > 0 && b->entity <= cl.allocated_client_slots) { for (j = 0; j < cl.splitclients; j++) { @@ -2981,7 +2983,7 @@ void CL_UpdateBeams (void) // add new entities for the lightning d = VectorNormalize(dist); - if(b->bflags & 2) + if(b->bflags & STREAM_JITTER) { offset = (int)(cl.time*40)%30; for(i = 0; i < 3; i++) diff --git a/engine/client/client.h b/engine/client/client.h index 110055a68..be85f3f37 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1093,6 +1093,7 @@ void CL_ConnectionlessPacket (void); qboolean CL_DemoBehind(void); void CL_SaveInfo(vfsfile_t *f); void CL_SetInfo (int pnum, const char *key, const char *value); +void CL_SetInfoBlob (int pnum, const char *key, const char *value, size_t valuesize); void CL_BeginServerConnect(const char *host, int port, qboolean noproxy); char *CL_TryingToConnect(void); @@ -1433,6 +1434,8 @@ void CSQC_MapEntityEdited(int modelindex, int idx, const char *newe); qboolean CSQC_ParsePrint(char *message, int printlevel); qboolean CSQC_ParseGamePacket(int seat); qboolean CSQC_CenterPrint(int seat, const char *cmd); +void CSQC_ServerInfoChanged(void); +void CSQC_PlayerInfoChanged(int player); qboolean CSQC_Parse_Damage(int seat, float save, float take, vec3_t source); qboolean CSQC_Parse_SetAngles(int seat, vec3_t newangles, qboolean wasdelta); void CSQC_Input_Frame(int seat, usercmd_t *cmd); @@ -1460,6 +1463,8 @@ void CSQC_CvarChanged(cvar_t *var); #define CSQC_UnconnectedInit() false #define CSQC_UseGamecodeLoadingScreen() false #define CSQC_Parse_SetAngles(seat,newangles,wasdelta) false +#define CSQC_ServerInfoChanged() false +#define CSQC_PlayerInfoChanged(player) false #endif // diff --git a/engine/client/console.c b/engine/client/console.c index 8b94d86be..3cca2de5a 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -2630,7 +2630,13 @@ void Con_DrawConsole (int lines, qboolean noback) float x = 0; // float r = x+w->wnd_w-16; const char *buttons[] = {"bck", "fwd", "rld", "home", "", ((w->linebuffered == Con_Navigate)?(char*)key_lines[edit_line]:url)}; - const char *buttoncmds[] = {"cmd:back", "cmd:forward", "cmd:refresh", ENGINEWEBSITE, NULL, NULL}; + const char *buttoncmds[] = {"cmd:back", "cmd:forward", "cmd:refresh", + #ifdef QUAKETC //total conversions should have their own website. + ENGINEWEBSITE + #else //otherwise use some more useful page, for quake mods. + "https://www.quakeworld.nu/wiki/Overview" + #endif + , NULL, NULL}; float tw; int i, fl; diff --git a/engine/client/image.c b/engine/client/image.c index 9e4fc3761..c2f04d86c 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -662,12 +662,17 @@ qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, uploadfmt_ return NULL; mul = tgaheader.bpp/8; - *format = (mul==4)?PTI_RGBA8:PTI_RGBX8;; //flip +convert to 32 bit if (forceformat==PTI_L8) + { + *format = forceformat; outrow = &initbuf[(int)(0)*tgaheader.width]; + } else + { outrow = &initbuf[(int)(0)*tgaheader.width*mul]; + *format = (mul==4)?PTI_RGBA8:PTI_RGBX8; + } for (y = 0; y < tgaheader.height; y+=1) { if (flipped) @@ -5885,6 +5890,32 @@ static void Image_4X16to8888(struct pendingtextureinfo *mips) } } +//R8,G8,B8,X8 (aligned) -> R8,G8,B8 (tightly packed) +static void Image_32To24(struct pendingtextureinfo *mips) +{ + int mip; + for (mip = 0; mip < mips->mipcount; mip++) + { + qbyte *in = mips->mip[mip].data; + qbyte *out = mips->mip[mip].data; + unsigned int w = mips->mip[mip].width; + unsigned int h = mips->mip[mip].height; + unsigned int p = w*h; + if (!mips->mip[mip].needfree && !mips->extrafree) + { + mips->mip[mip].needfree = true; + mips->mip[mip].data = out = BZ_Malloc(sizeof(*out)*p*3); + } + while(p-->0) + { + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + in++; + } + } +} + //may operate in place static void Image_8_BGR_RGB_Swap(qbyte *data, unsigned int w, unsigned int h) { @@ -6541,12 +6572,12 @@ const char *Image_FormatName(uploadfmt_t fmt) case PTI_ARGB1555: return "ARGB1555"; case PTI_RGBA8: return "RGBA8"; case PTI_RGBX8: return "RGBX8"; - case PTI_BGRA8: return "RGBA8"; - case PTI_BGRX8: return "RGBX8"; + case PTI_BGRA8: return "BGRA8"; + case PTI_BGRX8: return "BGRX8"; case PTI_RGBA8_SRGB: return "RGBA8_SRGB"; case PTI_RGBX8_SRGB: return "RGBX8_SRGB"; - case PTI_BGRA8_SRGB: return "RGBA8_SRGB"; - case PTI_BGRX8_SRGB: return "RGBX8_SRGB"; + case PTI_BGRA8_SRGB: return "BGRA8_SRGB"; + case PTI_BGRX8_SRGB: return "BGRX8_SRGB"; case PTI_A2BGR10: return "A2BGR10"; case PTI_E5BGR9: return "E5BGR9"; case PTI_R16F: return "R16F"; @@ -6948,6 +6979,12 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla } if ((mips->encoding == PTI_RGBX8 && sh_config.texfmt[PTI_BGRX8]) || + (mips->encoding == PTI_BGRX8 && sh_config.texfmt[PTI_BGRX8])) + { + Image_32To24(mips); + mips->encoding = (mips->encoding == PTI_RGBX8)?PTI_RGB8:PTI_BGR8; + } + else if ((mips->encoding == PTI_RGBX8 && sh_config.texfmt[PTI_BGRX8]) || (mips->encoding == PTI_BGRX8 && sh_config.texfmt[PTI_RGBX8]) || (mips->encoding == PTI_RGBA8 && sh_config.texfmt[PTI_BGRA8]) || (mips->encoding == PTI_BGRA8 && sh_config.texfmt[PTI_RGBA8])) @@ -8728,6 +8765,8 @@ image_t *QDECL Image_GetTexture(const char *identifier, const char *subpath, uns case TF_HEIGHT8PAL: //we don't care about the actual palette. b *= 1; break; +// case PTI_LLLX8: +// case PTI_LLLA8: case TF_RGBX32: case TF_RGBA32: case TF_BGRX32: diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 1e8cfb187..ad74df559 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -621,7 +621,7 @@ static void PM_RemSubList(const char *url) } } -static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, const char *prefix) +static qboolean PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, const char *prefix) { char line[65536]; package_t *p; @@ -634,9 +634,10 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c int nummirrors = 0; qboolean isauto; char *tokstart; + qboolean forcewrite = false; if (!f) - return; + return forcewrite; Q_strncpyz(defaultgamedir, FS_GetGamedir(false), sizeof(defaultgamedir)); @@ -660,13 +661,13 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c } while (!Cmd_Argc()); if (strcmp(Cmd_Argv(0), "version")) - return; //it's not the right format. + return forcewrite; //it's not the right format. version = atoi(Cmd_Argv(1)); if (version != 0 && version != 1 && version != 2) { Con_Printf("Packagelist is of a future or incompatible version\n"); - return; //it's not the right version. + return forcewrite; //it's not the right version. } while(1) @@ -691,6 +692,16 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c subprefix = va("%s/%s", prefix, com_token); else subprefix = com_token; + +#ifdef HAVE_LEGACY + //hack. I'm trying to retire the self-signed cert on [fte.]triptohell.info + if (!strcmp(url, "https://triptohell.info/downloadables.php") || !strcmp(url, "https://fte.triptohell.info/downloadables.php")) + { + Q_strncpyz(url, "https://updates.triptohell.info/downloadables.php", sizeof(url)); + forcewrite = true; + } +#endif + PM_AddSubList(url, subprefix, (parseflags & DPF_ENABLED)?true:false, (parseflags&DPF_TRUSTED)); continue; } @@ -722,7 +733,7 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c { tokstart = COM_StringParse (tokstart, com_token, sizeof(com_token), false, false); if (parseflags & DPF_ENABLED) //don't use a downloaded file's version of this, only use the local version of it. - Cvar_ForceSet(&pm_autoupdate, com_token); + Cvar_ForceSet(&pkg_autoupdate, com_token); } else if (!strcmp(com_token, "declined")) { @@ -1041,6 +1052,8 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c PM_InsertPackage(p); } } + + return forcewrite; } #ifdef PLUGINS @@ -1168,7 +1181,8 @@ static void PM_PreparePackageList(void) loadedinstalled = true; if (f) { - PM_ParsePackageList(f, DPF_FORGETONUNINSTALL|DPF_ENABLED, NULL, ""); + if (PM_ParsePackageList(f, DPF_FORGETONUNINSTALL|DPF_ENABLED, NULL, "")) + PM_WriteInstalledPackages(); VFS_CLOSE(f); } @@ -1232,7 +1246,7 @@ void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const cha void PM_Shutdown(void) { //free everything... - pm_downloads_url.modified = false; + pkg_downloads_url.modified = false; downloadablessequence++; @@ -1545,7 +1559,7 @@ unsigned int PM_MarkUpdates (void) { if ((p->flags & DPF_ENGINE) && !(p->flags & DPF_HIDDEN)) { - if (!(p->flags & DPF_TESTING) || pm_autoupdate.ival >= UPD_TESTING) + if (!(p->flags & DPF_TESTING) || pkg_autoupdate.ival >= UPD_TESTING) if (!e || strcmp(e->version, p->version) < 0) //package must be more recent than the previously found engine if (strcmp(SVNREVISIONSTR, "-") && strcmp(SVNREVISIONSTR, p->version) < 0) //package must be more recent than the current engine too, there's no point auto-updating to an older revision. e = p; @@ -1557,7 +1571,7 @@ unsigned int PM_MarkUpdates (void) { if (p == o || (o->flags & DPF_HIDDEN)) continue; - if (!(o->flags & DPF_TESTING) || pm_autoupdate.ival >= UPD_TESTING) + if (!(o->flags & DPF_TESTING) || pkg_autoupdate.ival >= UPD_TESTING) if (!strcmp(o->name, p->name) && !strcmp(o->arch?o->arch:"", p->arch?p->arch:"") && strcmp(o->version, p->version) > 0) { if (!b || strcmp(b->version, o->version) < 0) @@ -1575,7 +1589,7 @@ unsigned int PM_MarkUpdates (void) } if (e && !(e->flags & DPF_MARKED)) { - if (pm_autoupdate.ival >= UPD_STABLE) + if (pkg_autoupdate.ival >= UPD_STABLE) { changecount++; PM_MarkPackage(e, DPF_AUTOMARKED); @@ -1763,14 +1777,14 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry) { unsigned int i; - if (retry>1 || pm_downloads_url.modified) + if (retry>1 || pkg_downloads_url.modified) PM_Shutdown(); PM_PreparePackageList(); //make sure our sources are okay. - if (*pm_downloads_url.string) - PM_AddSubList(pm_downloads_url.string, "", false, true); + if (*pkg_downloads_url.string) + PM_AddSubList(pkg_downloads_url.string, "", false, true); #ifndef WEBCLIENT for (i = 0; i < numdownloadablelists; i++) @@ -1853,14 +1867,14 @@ static void PM_WriteInstalledPackages(void) vfsfile_t *f = FS_OpenVFS(INSTALLEDFILES, "wb", FS_ROOT); if (!f) { - Con_Printf("menu_download: Can't update installed list\n"); + Con_Printf("package manager: Can't update installed list\n"); return; } s = "version 2\n"; VFS_WRITE(f, s, strlen(s)); - s = va("set updatemode %s\n", COM_QuotedString(pm_autoupdate.string, buf, sizeof(buf), false)); + s = va("set updatemode %s\n", COM_QuotedString(pkg_autoupdate.string, buf, sizeof(buf), false)); VFS_WRITE(f, s, strlen(s)); s = va("set declined %s\n", COM_QuotedString(declinedpackages?declinedpackages:"", buf, sizeof(buf), false)); VFS_WRITE(f, s, strlen(s)); @@ -2900,11 +2914,17 @@ void PM_Command_f(void) Con_Printf("<%i sources>\n", numdownloadablelists); } else + { PM_AddSubList(Cmd_Argv(2), "", true, true); + PM_WriteInstalledPackages(); + } } #endif else if (!strcmp(act, "remsource")) + { PM_RemSubList(Cmd_Argv(2)); + PM_WriteInstalledPackages(); + } else if (!strcmp(act, "apply")) { Con_Printf("Applying package changes\n"); @@ -3317,7 +3337,7 @@ static void MD_AutoUpdate_Draw (int x, int y, struct menucustom_s *c, struct men "Test Updates" }; char *text; - int setting = bound(0, pm_autoupdate.ival, 2); + int setting = bound(0, pkg_autoupdate.ival, 2); text = va("Auto Update: ^a%s", settings[setting]); // if (&m->selecteditem->common == &c->common) // Draw_AltFunString (x, y, text); @@ -3329,9 +3349,9 @@ static qboolean MD_AutoUpdate_Key (struct menucustom_s *c, struct menu_s *m, int if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1) { char nv[8] = "0"; - if (pm_autoupdate.ival < UPD_TESTING && pm_autoupdate.ival >= 0) - Q_snprintfz(nv, sizeof(nv), "%i", pm_autoupdate.ival+1); - Cvar_ForceSet(&pm_autoupdate, nv); + if (pkg_autoupdate.ival < UPD_TESTING && pkg_autoupdate.ival >= 0) + Q_snprintfz(nv, sizeof(nv), "%i", pkg_autoupdate.ival+1); + Cvar_ForceSet(&pkg_autoupdate, nv); PM_WriteInstalledPackages(); PM_UpdatePackageList(true, 0); @@ -3623,7 +3643,7 @@ void Menu_DownloadStuff_f (void) //should only be called AFTER the filesystem etc is inited. void Menu_Download_Update(void) { - if (!pm_autoupdate.ival) + if (!pkg_autoupdate.ival) return; PM_UpdatePackageList(true, 2); diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 60ec251f9..856ae10ba 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -5172,7 +5172,7 @@ void Media_Init(void) Cmd_AddCommand("playclip", Media_PlayVideoWindowed_f); Cmd_AddCommand("playvideo", Media_PlayFilm_f); Cmd_AddCommand("playfilm", Media_PlayFilm_f); - Cmd_AddCommand("cinematic", Media_PlayFilm_f); + Cmd_AddCommand("cinematic", Media_PlayFilm_f); //q3: name <1:hold, 2:loop> #endif Cmd_AddCommand("music", Media_NamedTrack_f); diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 28bdd7431..1f9872e97 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -991,7 +991,7 @@ const char *presetexec[] = "r_glsl_offsetmapping 1;" "r_shadow_realtime_world 1;" "gl_texture_anisotropic_filtering 16;" - "vid_hardwaregamma 6;" //scene gamma + "vid_hardwaregamma 4;" //scene gamma }; typedef struct fpsmenuinfo_s diff --git a/engine/client/m_single.c b/engine/client/m_single.c index d2c39a016..aaa66bcd5 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -414,37 +414,37 @@ void M_Menu_SinglePlayer_f (void) //yes, hexen2 has per-class names for the skill levels. because being weird and obtuse is kinda its forte static char *skillnames[6][4] = { - { + { //generic/random "Easy", "Medium", "Hard", "Nightmare" }, - { - "Apprentice", + { //barbarian + "Servant", //string changed, because somehow the original is malicious. was: "Apprentice", "Squire", "Adept", "Lord" }, - { + { //paladin "Gallant", "Holy Avenger", "Divine Hero", "Legend" }, - { + { //necromancer "Sorcerer", "Dark Servant", "Warlock", "Lich King" }, - { + { //assassin "Rogue", "Cutthroat", "Executioner", "Widow Maker" }, - { + { //demoness "Larva", "Spawn", "Fiend", diff --git a/engine/client/pr_clcmd.c b/engine/client/pr_clcmd.c index e6cc29240..cede53b00 100644 --- a/engine/client/pr_clcmd.c +++ b/engine/client/pr_clcmd.c @@ -978,6 +978,79 @@ void QCBUILTIN PF_cl_localsound(pubprogfuncs_t *prinst, struct globalvars_s *pr_ S_LocalSound2(s, chan, vol); } +void QCBUILTIN PF_cl_getlocaluserinfoblob (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int seat = G_FLOAT(OFS_PARM0); + const char *keyname = PR_GetStringOfs(prinst, OFS_PARM1); + int qcptr = G_INT(OFS_PARM2); + int qcsize = G_INT(OFS_PARM3); + void *ptr; + const char *blob; + size_t blobsize = 0; + infobuf_t *info; + if (seat < 0 || seat >= MAX_SPLITS) + { + PR_BIError(prinst, "PF_cs_getlocaluserinfoblob: invalid seat\n"); + return; + } + info = &cls.userinfo[seat]; + + if (qcptr < 0 || qcptr+qcsize >= prinst->stringtablesize) + { + PR_BIError(prinst, "PF_cs_getplayerkeyblob: invalid pointer\n"); + return; + } + ptr = (struct reverbproperties_s*)(prinst->stringtable + qcptr); + + blob = InfoBuf_BlobForKey(info, keyname, &blobsize, NULL); + if (qcptr) + { + blobsize = min(blobsize, qcsize); + memcpy(ptr, blob, blobsize); + G_INT(OFS_RETURN) = blobsize; + } + else + G_INT(OFS_RETURN) = blobsize; +} +void QCBUILTIN PF_cl_getlocaluserinfostring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int seat = G_FLOAT(OFS_PARM0); + const char *keyname = PR_GetStringOfs(prinst, OFS_PARM1); + infobuf_t *info; + if (seat < 0 || seat >= MAX_SPLITS) + { + PR_BIError(prinst, "PF_cs_getlocaluserinfoblob: invalid seat\n"); + return; + } + info = &cls.userinfo[seat]; + RETURN_TSTRING(InfoBuf_ValueForKey(info, keyname)); +} +void QCBUILTIN PF_cl_setlocaluserinfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int seat = G_FLOAT(OFS_PARM0); + const char *keyname = PR_GetStringOfs(prinst, OFS_PARM1); + if (seat < 0 || seat >= MAX_SPLITS) + { + PR_BIError(prinst, "PF_cs_getlocaluserinfoblob: invalid seat\n"); + return; + } + + if (prinst->callargc < 4) + CL_SetInfo(seat, keyname, PR_GetStringOfs(prinst, OFS_PARM2)); + else + { + int qcptr = G_INT(OFS_PARM2); + int qcsize = G_INT(OFS_PARM3); + const void *ptr; + if (qcptr < 0 || qcptr+qcsize >= prinst->stringtablesize) + { + PR_BIError(prinst, "PF_cs_getplayerkeyblob: invalid pointer\n"); + return; + } + ptr = (struct reverbproperties_s*)(prinst->stringtable + qcptr); + CL_SetInfoBlob(seat, keyname, ptr, qcsize); + } +} #include "fs.h" static struct modlist_s diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index b439cdaa2..3381d6a05 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -128,6 +128,8 @@ extern sfx_t *cl_sfx_r_exp3; globalfunction(parse_event, "CSQC_Parse_Event"); \ globalfunction(parse_damage, "CSQC_Parse_Damage"); \ globalfunction(parse_setangles, "CSQC_Parse_SetAngles"); \ + globalfunction(playerinfochanged, "CSQC_PlayerInfoChanged"); \ + globalfunction(serverinfochanged, "CSQC_ServerInfoChanged"); \ globalfunction(input_event, "CSQC_InputEvent"); \ globalfunction(input_frame, "CSQC_Input_Frame");/*EXT_CSQC_1*/ \ globalfunction(rendererrestarted, "CSQC_RendererRestarted"); \ @@ -6511,6 +6513,10 @@ static struct { {"getplayerkeyvalue", PF_cs_getplayerkeystring, 348}, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC) {"getplayerkeyfloat", PF_cs_getplayerkeyfloat, 0}, // #348 string(float playernum, string keyname) getplayerkeyvalue {"getplayerkeyblob", PF_cs_getplayerkeyblob, 0}, // #0 int(float playernum, string keyname, optional void *outptr, int size) getplayerkeyblob + {"setlocaluserinfo", PF_cl_setlocaluserinfo, 0}, + {"getlocaluserinfo", PF_cl_getlocaluserinfostring, 0}, + {"setlocaluserinfoblob", PF_cl_setlocaluserinfo, 0}, + {"getlocaluserinfoblob", PF_cl_getlocaluserinfoblob, 0}, {"isdemo", PF_cl_playingdemo, 349}, // #349 float() isdemo (EXT_CSQC) //350 @@ -7576,7 +7582,7 @@ qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int chec return false; } - if (csqc_nogameaccess && !PR_FindFunction (csqcprogs, "CSQC_DrawHud", PR_ANY)) + if (csqc_nogameaccess && !PR_FindFunction (csqcprogs, "CSQC_DrawHud", PR_ANY) && !PR_FindFunction (csqcprogs, "CSQC_DrawScores", PR_ANY)) { //simple csqc module is not csqc. abort now. CSQC_Shutdown(); Con_DPrintf("progs.dat is not suitable for SimpleCSQC - no CSQC_DrawHud\n"); @@ -8449,6 +8455,28 @@ static void CSQC_GameCommand_f(void) PR_ExecuteProgram (csqcprogs, csqcg.gamecommand); } +void CSQC_PlayerInfoChanged(int player) +{ + void *pr_globals; + if (!csqcprogs || !csqcg.playerinfochanged) + return; + + pr_globals = PR_globals(csqcprogs, PR_CURRENT); + G_FLOAT(OFS_PARM0) = player; +// (((string_t *)pr_globals)[OFS_PARM1] = PR_TempString(csqcprogs, keyname)); + PR_ExecuteProgram (csqcprogs, csqcg.playerinfochanged); +} +void CSQC_ServerInfoChanged(void) +{ +// void *pr_globals; + if (!csqcprogs || !csqcg.serverinfochanged) + return; + +// pr_globals = PR_globals(csqcprogs, PR_CURRENT); +// (((string_t *)pr_globals)[OFS_PARM0] = PR_TempString(csqcprogs, keyname)); + PR_ExecuteProgram (csqcprogs, csqcg.serverinfochanged); +} + qboolean CSQC_ParseTempEntity(void) { int orc; diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 24077f1e5..16dd4d35b 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -2367,6 +2367,13 @@ static struct { {"digest_hex", PF_digest_hex, 639}, {"digest_ptr", PF_digest_ptr, 0}, {"crypto_getmyidstatus", PF_crypto_getmyidfp, 641}, + + + {"setlocaluserinfo", PF_cl_setlocaluserinfo, 0}, + {"getlocaluserinfo", PF_cl_getlocaluserinfostring, 0}, + {"setlocaluserinfoblob", PF_cl_setlocaluserinfo, 0}, + {"getlocaluserinfoblob", PF_cl_getlocaluserinfoblob, 0}, + {NULL} }; static builtin_t menu_builtins[1024]; diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index 971b5e57f..817bd0436 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -305,8 +305,8 @@ extern qboolean noclip_anglehack; extern quakeparms_t host_parms; extern cvar_t fs_gamename; -extern cvar_t pm_downloads_url; -extern cvar_t pm_autoupdate; +extern cvar_t pkg_downloads_url; +extern cvar_t pkg_autoupdate; extern cvar_t com_protocolname; extern cvar_t com_protocolversion; extern cvar_t com_nogamedirnativecode; diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index caaae7791..9d18173ae 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -45,6 +45,7 @@ struct { lmalloc_t allocation; qboolean dirty; + uploadfmt_t fmt; int lastid; unsigned int *data; shader_t *shader; @@ -480,8 +481,9 @@ apic_t *R2D_LoadAtlasedPic(const char *name) { atlas.lastid = atlasid; if (atlas.dirty) - Image_Upload(atlas.tex, TF_BGRA32, atlas.data, NULL, atlas.allocation.width, atlas.allocation.height, IF_NOMIPMAP); + Image_Upload(atlas.tex, atlas.fmt, atlas.data, NULL, atlas.allocation.width, atlas.allocation.height, IF_NOMIPMAP); atlas.tex = r_nulltex; + atlas.fmt = sh_config.texfmt[PTI_BGRA8]?PTI_BGRA8:PTI_RGBA8; atlas.shader = NULL; atlas.dirty = false; if (atlas.data) //clear atlas data instead of reallocating it. @@ -515,25 +517,50 @@ apic_t *R2D_LoadAtlasedPic(const char *name) out += apic->y * atlas.allocation.width; apic->atlas = atlas.shader; - //pad above. extra casts because 64bit msvc is RETARDED. - out[-1 - (qintptr_t)atlas.allocation.width] = (indata[0] == 255)?0:d_8to24bgrtable[indata[0]]; //pad left - for (x = 0; x < apic->width; x++) - out[x-(qintptr_t)atlas.allocation.width] = (indata[x] == 255)?0:d_8to24bgrtable[indata[x]]; - out[x - (qintptr_t)atlas.allocation.width] = (indata[x-1] == 255)?0:d_8to24bgrtable[indata[x-1]]; //pad right - for (y = 0; y < apic->height; y++) + if (atlas.fmt == PTI_BGRA8) { + //pad above. extra casts because 64bit msvc is RETARDED. + out[-1 - (qintptr_t)atlas.allocation.width] = (indata[0] == 255)?0:d_8to24bgrtable[indata[0]]; //pad left + for (x = 0; x < apic->width; x++) + out[x-(qintptr_t)atlas.allocation.width] = (indata[x] == 255)?0:d_8to24bgrtable[indata[x]]; + out[x - (qintptr_t)atlas.allocation.width] = (indata[x-1] == 255)?0:d_8to24bgrtable[indata[x-1]]; //pad right + for (y = 0; y < apic->height; y++) + { + out[-1] = (indata[0] == 255)?0:d_8to24bgrtable[indata[0]]; //pad left + for (x = 0; x < apic->width; x++) + out[x] = (indata[x] == 255)?0:d_8to24bgrtable[indata[x]]; + out[x] = (indata[x-1] == 255)?0:d_8to24bgrtable[indata[x-1]]; //pad right + indata += x; + out += atlas.allocation.width; + } + //pad below out[-1] = (indata[0] == 255)?0:d_8to24bgrtable[indata[0]]; //pad left for (x = 0; x < apic->width; x++) out[x] = (indata[x] == 255)?0:d_8to24bgrtable[indata[x]]; out[x] = (indata[x-1] == 255)?0:d_8to24bgrtable[indata[x-1]]; //pad right - indata += x; - out += atlas.allocation.width; } - //pad below - out[-1] = (indata[0] == 255)?0:d_8to24bgrtable[indata[0]]; //pad left - for (x = 0; x < apic->width; x++) - out[x] = (indata[x] == 255)?0:d_8to24bgrtable[indata[x]]; - out[x] = (indata[x-1] == 255)?0:d_8to24bgrtable[indata[x-1]]; //pad right + else + { + //pad above. extra casts because 64bit msvc is RETARDED. + out[-1 - (qintptr_t)atlas.allocation.width] = (indata[0] == 255)?0:d_8to24rgbtable[indata[0]]; //pad left + for (x = 0; x < apic->width; x++) + out[x-(qintptr_t)atlas.allocation.width] = (indata[x] == 255)?0:d_8to24rgbtable[indata[x]]; + out[x - (qintptr_t)atlas.allocation.width] = (indata[x-1] == 255)?0:d_8to24rgbtable[indata[x-1]]; //pad right + for (y = 0; y < apic->height; y++) + { + out[-1] = (indata[0] == 255)?0:d_8to24rgbtable[indata[0]]; //pad left + for (x = 0; x < apic->width; x++) + out[x] = (indata[x] == 255)?0:d_8to24rgbtable[indata[x]]; + out[x] = (indata[x-1] == 255)?0:d_8to24rgbtable[indata[x-1]]; //pad right + indata += x; + out += atlas.allocation.width; + } + //pad below + out[-1] = (indata[0] == 255)?0:d_8to24rgbtable[indata[0]]; //pad left + for (x = 0; x < apic->width; x++) + out[x] = (indata[x] == 255)?0:d_8to24rgbtable[indata[x]]; + out[x] = (indata[x-1] == 255)?0:d_8to24rgbtable[indata[x-1]]; //pad right + } //pinch inwards, for linear sampling apic->sl = (apic->x+0.5)/(float)atlas.allocation.width; @@ -593,7 +620,7 @@ void R2D_ImageAtlas(float x, float y, float w, float h, float s1, float t1, floa return; if (atlas.dirty) { - Image_Upload(atlas.tex, TF_BGRA32, atlas.data, NULL, atlas.allocation.width, atlas.allocation.height, IF_NOMIPMAP); + Image_Upload(atlas.tex, atlas.fmt, atlas.data, NULL, atlas.allocation.width, atlas.allocation.height, IF_NOMIPMAP); atlas.dirty = false; } diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 2793a1838..1542cb5e5 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -4162,13 +4162,13 @@ void Surf_NewMap (void) CL_RegisterParticles(); Shader_DoReload(); - if (cl.worldmodel) { if (cl.worldmodel->loadstate == MLS_LOADING) COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING); Mod_ParseInfoFromEntityLump(cl.worldmodel); } + Shader_DoReload(); if (!pe) Cvar_ForceCallback(&r_particlesystem); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index b841aa5b0..0fc8c53ec 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -51,7 +51,7 @@ void QDECL SCR_Fov_Callback (struct cvar_s *var, char *oldvalue); void QDECL Image_TextureMode_Callback (struct cvar_s *var, char *oldvalue); void QDECL R_SkyBox_Changed (struct cvar_s *var, char *oldvalue) { - Shader_NeedReload(false); +// Shader_NeedReload(false); } void R_ForceSky_f(void) { @@ -472,7 +472,7 @@ cvar_t gl_screenangle = CVAR("gl_screenangle", "0"); #endif #ifdef VKQUAKE -cvar_t vk_stagingbuffers = CVARFD ("vk_stagingbuffers", "", CVAR_RENDERERLATCH, "Configures which dynamic buffers are copied into gpu memory for rendering, instead of reading from shared memory. Empty for default settings.\nAccepted chars are u, e, v, 0."); +cvar_t vk_stagingbuffers = CVARFD ("vk_stagingbuffers", "", CVAR_RENDERERLATCH, "Configures which dynamic buffers are copied into gpu memory for rendering, instead of reading from shared memory. Empty for default settings.\nAccepted chars are u(niform), e(lements), v(ertex), 0(none)."); cvar_t vk_submissionthread = CVARD ("vk_submissionthread", "", "Execute submits+presents on a thread dedicated to executing them. This may be a significant speedup on certain drivers."); cvar_t vk_debug = CVARFD("vk_debug", "0", CVAR_VIDEOLATCH, "Register a debug handler to display driver/layer messages. 2 enables the standard validation layers."); cvar_t vk_dualqueue = CVARFD("vk_dualqueue", "", CVAR_VIDEOLATCH, "Attempt to use a separate queue for presentation. Blank for default."); @@ -1795,9 +1795,6 @@ TRACE(("dbg: R_ApplyRenderer: efrags\n")); // Skin_FlushAll(); Skin_FlushPlayers(); -#ifdef CSQC_DAT - CSQC_RendererRestarted(); -#endif } else { @@ -1809,6 +1806,10 @@ TRACE(("dbg: R_ApplyRenderer: efrags\n")); #ifdef SKELETALOBJECTS skel_reload(); #endif +#ifdef CSQC_DAT + Shader_DoReload(); + CSQC_RendererRestarted(); +#endif if (newr && qrenderer != QR_NONE) { diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index 52d577f2e..cde26766b 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -16,17 +16,8 @@ #error ANDROID wasnt defined #endif -#if 0 -//FIXME: remove the nativeactivity shit. android's standard NativeActivity class is buggy and basically fucked. #include #include -// ANativeWindow_fromSurface((jobject)getSurfaceHolder().getSurface()) -#else -//NOTE: This is apache 2.0, which means GPL3.0+ ONLY, no gpl2. -#include <../../../../../sources/android/native_app_glue/android_native_app_glue.h> //Fucking frameworks suck big hairy donkey balls. -JNIEXPORT void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize); -#include <../../../../../sources/android/native_app_glue/android_native_app_glue.c> //Fucking frameworks suck big hairy donkey balls. -#endif #ifndef isDedicated #ifdef SERVERONLY @@ -39,21 +30,29 @@ extern int r_blockvidrestart; float sys_dpi_x, sys_dpi_y; static void *sys_memheap; //static unsigned int vibrateduration; +static char sys_binarydir[MAX_OSPATH]; static char sys_basedir[MAX_OSPATH]; static char sys_basepak[MAX_OSPATH]; extern jmp_buf host_abort; extern qboolean r_forceheadless; static qboolean r_forcevidrestart; ANativeWindow *sys_nativewindow; -static struct android_app *android_app_state; //basically used only for errors. //cvar_t sys_vibrate = CVARFD("sys_vibrate", "1", CVAR_ARCHIVE, "Enables the system vibrator for damage events and such things. The value provided is a duration scaler."); -cvar_t sys_osk = CVAR("sys_osk", "0"); //to be toggled -cvar_t sys_keepscreenon = CVARFD("sys_keepscreenon", "1", CVAR_ARCHIVE, "If set, the screen will never darken. This might cost some extra battery power, but then so will running a 3d engine."); //to be toggled +static cvar_t sys_osk = CVAR("sys_osk", "0"); //to be toggled +static cvar_t sys_keepscreenon = CVARFD("sys_keepscreenon", "1", CVAR_ARCHIVE, "If set, the screen will never darken. This might cost some extra battery power, but then so will running a 3d engine."); //to be toggled cvar_t sys_orientation = CVARFD("sys_orientation", "landscape", CVAR_ARCHIVE, "Specifies what angle to render quake at.\nValid values are: sensor (autodetect), landscape, portrait, reverselandscape, reverseportrait"); extern cvar_t vid_conautoscale; void VID_Register(void); +static qboolean sys_wantshutdown; +static JavaVM* sys_javavm; +static jobject *sys_activity; +static jobject *sys_cursurface; //surface we're currently trying to draw to +static jobject *sys_newsurface; //surface we're meant to be switching our gl context to +static void *sys_mainthread; +static void *sys_mainconditional; + #undef LOGI #undef LOGW #undef LOGE @@ -390,52 +389,12 @@ static int mapkey(int androidkey) return 0; } -static int32_t engine_handle_input(struct android_app *app, AInputEvent *event) +#if 0 +static void run_intent_url(void) { - switch(AInputEvent_getType(event)) - { - case AINPUT_EVENT_TYPE_MOTION: - case AINPUT_EVENT_TYPE_KEY: - return 0; //we handle these in the java code, so shouldn't ever see them. - } - return 0; //no idea what sort of event it is. -} -static void engine_handle_cmd(struct android_app *app, int32_t cmd) -{ - switch(cmd) - { - case APP_CMD_SAVE_STATE: - //FIXME: implement save-game-to-memory... - break; - case APP_CMD_INIT_WINDOW: - if (sys_nativewindow != app->window) - { - sys_nativewindow = app->window; - r_forceheadless = (sys_nativewindow==NULL); - - r_forcevidrestart = true; - } - break; - case APP_CMD_TERM_WINDOW: - r_forceheadless = true; - if (qrenderer && !r_forcevidrestart && sys_nativewindow) - R_RestartRenderer_f(); - sys_nativewindow = NULL; - break; - case APP_CMD_GAINED_FOCUS: - vid.activeapp = true; - break; - case APP_CMD_LOST_FOCUS: - vid.activeapp = false; - break; - } -} - -static void run_intent_url(struct android_app *app) -{ - jobject act = app->activity->clazz; + jobject act = sys_activity; JNIEnv *jni; - if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + if (JNI_OK == (*sys_javavm)->AttachCurrentThread(sys_javavm, &jni, NULL)) { jobject intent = (*jni)->CallObjectMethod(jni, act, (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "getIntent", "()Landroid/content/Intent;")); if (intent) @@ -463,16 +422,17 @@ static void run_intent_url(struct android_app *app) } } //FIXME: do we need to release methodids/objects? - (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + (*sys_javavm)->DetachCurrentThread(sys_javavm); } } +#endif -static qboolean read_apk_path(struct android_app *app, char *out, size_t outsize) +static qboolean read_apk_path(char *out, size_t outsize) { qboolean res = false; - jobject act = app->activity->clazz; + jobject act = sys_activity; JNIEnv *jni; - if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + if (JNI_OK == (*sys_javavm)->AttachCurrentThread(sys_javavm, &jni, NULL)) { jstring result = (*jni)->CallObjectMethod(jni, act, (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "getPackageCodePath", "()Ljava/lang/String;")); const char *tmp = (*jni)->GetStringUTFChars(jni, result, NULL); @@ -484,70 +444,70 @@ static qboolean read_apk_path(struct android_app *app, char *out, size_t outsize } //FIXME: do we need to release methodids/objects? - (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + (*sys_javavm)->DetachCurrentThread(sys_javavm); } return res; } -static void setsoftkeyboard(struct android_app *app, int flags) +static void setsoftkeyboard(int flags) { //the NDK is unusably buggy when it comes to keyboards, so call into java. - jobject act = app->activity->clazz; + jobject act = sys_activity; JNIEnv *jni; - if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + if (JNI_OK == (*sys_javavm)->AttachCurrentThread(sys_javavm, &jni, NULL)) { jmethodID func = (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "showKeyboard", "(I)V" ); if (func) (*jni)->CallVoidMethod(jni, act, func, flags); - (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + (*sys_javavm)->DetachCurrentThread(sys_javavm); } } -static void showMessageAndQuit(struct android_app *app, const char *errormsg) +static void showMessageAndQuit(const char *errormsg) { //no nice way to do this from native. - jobject act = app->activity->clazz; + jobject act = sys_activity; JNIEnv *jni; - if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + if (JNI_OK == (*sys_javavm)->AttachCurrentThread(sys_javavm, &jni, NULL)) { jmethodID func = (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "showMessageAndQuit", "(Ljava/lang/String;)V" ); if (func) (*jni)->CallVoidMethod(jni, act, func, (*jni)->NewStringUTF(jni, errormsg)); - (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + (*sys_javavm)->DetachCurrentThread(sys_javavm); } } -static void updateOrientation(struct android_app *app, const char *neworientation) +static void updateOrientation(const char *neworientation) { //no nice way to do this from native. - jobject act = app->activity->clazz; + jobject act = sys_activity; JNIEnv *jni; - if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + if (JNI_OK == (*sys_javavm)->AttachCurrentThread(sys_javavm, &jni, NULL)) { jmethodID func = (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "updateOrientation", "(Ljava/lang/String;)V" ); if (func) (*jni)->CallVoidMethod(jni, act, func, (*jni)->NewStringUTF(jni, neworientation)); - (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + (*sys_javavm)->DetachCurrentThread(sys_javavm); } } -static void updateScreenKeepOn(struct android_app *app, jboolean keepon) +static void updateScreenKeepOn(jboolean keepon) { //the NDK is unusably buggy when it comes to keyboards, so call into java. - jobject act = app->activity->clazz; + jobject act = sys_activity; JNIEnv *jni; - if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + if (JNI_OK == (*sys_javavm)->AttachCurrentThread(sys_javavm, &jni, NULL)) { jmethodID func = (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "updateScreenKeepOn", "(Z)V" ); if (func) (*jni)->CallVoidMethod(jni, act, func, keepon); - (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + (*sys_javavm)->DetachCurrentThread(sys_javavm); } } -static void setCursorVisibility(struct android_app *app, jboolean visible) +static void setCursorVisibility(jboolean visible) { //this is meant to use the nvidia-added setCursorVisibility function //but its fatal if it doesn't exist, and it doesn't seem to exist. #if 0 - jobject act = app->activity->clazz; + jobject act = sys_activity; JNIEnv *jni; - if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + if (JNI_OK == (*sys_javavm)->AttachCurrentThread(sys_javavm, &jni, NULL)) { jobject inputManager = NULL; jmethodID setvis = NULL; @@ -559,7 +519,7 @@ static void setCursorVisibility(struct android_app *app, jboolean visible) if (setvis) (*jni)->CallVoidMethod(jni, inputManager, setvis, visible); - (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + (*sys_javavm)->DetachCurrentThread(sys_javavm); } #endif } @@ -634,42 +594,14 @@ static void FTENativeActivity_axis(JNIEnv *env, jobject this, jint devid, jint a //{ // IN_Gyroscope(devid, pitch, yaw, roll); //} -static JNINativeMethod methods[] = { - {"keypress", "(IZII)V", FTENativeActivity_keypress}, - {"mousepress", "(II)V", FTENativeActivity_mousepress}, - {"motion", "(IIFFFF)V", FTENativeActivity_motion}, - {"wantrelative", "()Z", FTENativeActivity_wantrelative}, //so the java code knows if it should use (often buggy) relative mouse movement or (limited) abs cursor coords. - {"axis", "(IIF)V", FTENativeActivity_axis}, -// {"accelerometer", "(IFFF)V", FTENativeActivity_accelerometer}, -// {"gyroscope", "(IFFF)V", FTENativeActivity_gyroscope}, -}; -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) -{ - JNIEnv *jni; - if (JNI_OK == (*vm)->GetEnv(vm, (void**)&jni, JNI_VERSION_1_2)) - { - jclass naclass = (*jni)->FindClass(jni, "com/fteqw/FTENativeActivity"); - if (naclass) - { - (*jni)->RegisterNatives(jni, naclass, methods, countof(methods)); - return JNI_VERSION_1_2; - } - } - return -1; -} -void android_main(struct android_app *state) +static int FTEDroid_MainThread(void *arg) { - static pthread_mutex_t onemainthread = PTHREAD_MUTEX_INITIALIZER; //android likes spawning multiple 'main' threads int osk = 0, wantgrabs = 0, t; - double ltime,ctime,tdelta; - pthread_mutex_lock(&onemainthread); - android_app_state = state; - state->userData = NULL; - state->onAppCmd = engine_handle_cmd; - state->onInputEvent = engine_handle_input; + double newtime,oldtime=Sys_DoubleTime(), time, sleeptime; r_forceheadless = true; sys_nativewindow = NULL; + vid.activeapp = true; if (!host_initialized) { @@ -685,8 +617,9 @@ void android_main(struct android_app *state) if (sys_memheap) free(sys_memheap); memset(&parms, 0, sizeof(parms)); + parms.binarydir = sys_binarydir; parms.basedir = sys_basedir; /*filled in later*/ - parms.argc = read_apk_path(state, sys_basepak, sizeof(sys_basepak))?3:1; + parms.argc = read_apk_path(sys_basepak, sizeof(sys_basepak))?3:1; parms.argv = args; #ifdef CONFIG_MANIFEST_TEXT parms.manifest = CONFIG_MANIFEST_TEXT; @@ -694,13 +627,6 @@ void android_main(struct android_app *state) sys_dpi_x = 72; //no idea sys_dpi_y = 72; //no idea -#if 0 //google made this a fucking pain. - Q_strncpyz(sys_basedir, getenv("EXTERNAL_STORAGE"), sizeof(sys_basedir)); - Q_strncatz(sys_basedir, "/fte", sizeof(sys_basedir)); -#else //so now users have to use some big long path to install stuff instead - Q_strncpyz(sys_basedir, state->activity->externalDataPath, sizeof(sys_basedir)); -#endif - Sys_Printf("Starting up (apk=%s, usr=%s)\n", sys_basepak, parms.basedir); VID_Register(); @@ -712,89 +638,121 @@ void android_main(struct android_app *state) } else Sys_Printf("Restarting up!\n"); - ltime = Sys_DoubleTime(); sys_orientation.modified = false; - updateOrientation(state, sys_orientation.string); + updateOrientation(sys_orientation.string); sys_keepscreenon.modified = false; - updateScreenKeepOn(state, sys_keepscreenon.ival); + updateScreenKeepOn(sys_keepscreenon.ival); - run_intent_url(state); - if (state->savedState != NULL) +// run_intent_url(); + /*if (state->savedState != NULL) { //oh look, we're pretending to already be running... //oh. - } + }*/ - for(;;) + + //we're sufficiently done loading. let the ui thread resume. + Sys_LockConditional(sys_mainconditional); + Sys_ConditionSignal(sys_mainconditional); + Sys_UnlockConditional(sys_mainconditional); + + while (!sys_wantshutdown) { - int ident, events; - struct android_poll_source *source; - while((ident=ALooper_pollAll(vid.activeapp?0:250, NULL, &events, (void**)&source)) >= 0) + //handle things if the UI thread is blocking for us (video restarts) + Sys_LockConditional(sys_mainconditional); + if (r_forcevidrestart) { - if (source != NULL) - source->process(state, source); + ANativeWindow *oldwnd = NULL; + jobject oldsurf = NULL; + JNIEnv *env = NULL; + if (JNI_OK == (*sys_javavm)->AttachCurrentThread(sys_javavm, &env, NULL)) + { + oldsurf = sys_cursurface; + sys_cursurface = (*env)->NewGlobalRef(env, sys_newsurface); - //FIXME: sensor crap + oldwnd = sys_nativewindow; + if (sys_cursurface) + sys_nativewindow = ANativeWindow_fromSurface(env, sys_cursurface); + else + sys_nativewindow = NULL; + ANativeWindow_acquire(sys_nativewindow); + } - if (state->destroyRequested != 0) - { - Sys_Printf("Shutdown requested\n"); - Host_Shutdown (); - - pthread_mutex_unlock(&onemainthread); - return; - } - } - if (host_initialized) - { - if (r_forcevidrestart) - { - if (qrenderer) - R_RestartRenderer_f(); - r_forcevidrestart = false; - } - if (sys_nativewindow) - { - ctime = Sys_DoubleTime(); - tdelta = ctime-ltime; - ltime = ctime; - Host_Frame(tdelta); - } + r_forceheadless = r_forcevidrestart&1; + r_forcevidrestart = 0; + Sys_ConditionSignal(sys_mainconditional); //let the java ui thread thread wake up now that we've got a handle to the new+old surfaces + Sys_UnlockConditional(sys_mainconditional); + LOGI("Video Restart...\n"); + R_RestartRenderer_f(); + LOGI("Video Restarted...\n"); + //main thread can wake up now. + + if (oldsurf) + (*env)->DeleteGlobalRef(env, oldsurf); + if (oldwnd) + ANativeWindow_release(oldwnd); + if (env) + (*sys_javavm)->DetachCurrentThread(sys_javavm); + + continue; } + if (sys_nativewindow && vid.activeapp && !r_forcevidrestart) + { + // find time spent rendering last frame + newtime = Sys_DoubleTime (); + time = newtime - oldtime; + + sleeptime = Host_Frame(time); + oldtime = newtime; + + if (sleeptime) + Sys_Sleep(sleeptime); + } + else + sleeptime = 0.25; + Sys_UnlockConditional(sys_mainconditional); t = 0; - if (Key_Dest_Has(kdm_console|kdm_message)) - t |= ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT; - if (!Key_Dest_Has(~kdm_game) && cls.state == ca_disconnected) - t |= ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT; - if (sys_osk.ival) - t |= ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED; + if (sys_osk.ival >= 0) + { + if (Key_Dest_Has(kdm_console|kdm_message)) + t |= 1; + if (!Key_Dest_Has(~kdm_game) && cls.state == ca_disconnected) + t |= 1; + if (sys_osk.ival) + t |= 2; + } if (osk != t) { - setsoftkeyboard(state, t); + setsoftkeyboard(t); osk = t; } if (sys_orientation.modified) { sys_orientation.modified = false; - updateOrientation(state, sys_orientation.string); + updateOrientation(sys_orientation.string); } if (sys_keepscreenon.modified) { sys_keepscreenon.modified = false; - updateScreenKeepOn(state, sys_keepscreenon.ival); + updateScreenKeepOn(sys_keepscreenon.ival); } t = FTENativeActivity_wantrelative(NULL,NULL); if (wantgrabs != t) { wantgrabs = t; - setCursorVisibility(state, wantgrabs); + setCursorVisibility(wantgrabs); } + + + if (sleeptime) + Sys_Sleep(sleeptime); } + return 0; } static int secbase; @@ -870,7 +828,7 @@ void Sys_Quit(void) #endif LOGI("%s", "quitting"); - showMessageAndQuit(android_app_state, ""); + showMessageAndQuit(""); longjmp(host_abort, 1); exit(0); @@ -888,7 +846,7 @@ void Sys_Error (const char *error, ...) strcpy(string, "no error"); LOGE("e: %s", string); - showMessageAndQuit(android_app_state, string); + showMessageAndQuit(string); host_initialized = false; //don't keep calling Host_Frame, because it'll screw stuff up more. Can't trust Host_Shutdown either. :( vid.activeapp = false; //make sure we don't busyloop. @@ -954,6 +912,11 @@ dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs) h = dlopen(va("%s.so", name), RTLD_LAZY|RTLD_LOCAL); if (!h) h = dlopen(name, RTLD_LAZY|RTLD_LOCAL); + if (!h) + { + Con_DLPrintf(2,"%s\n", dlerror()); + return NULL; + } if (h && funcs) { @@ -965,6 +928,7 @@ dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs) } if (funcs[i].name) { + Con_DPrintf("Unable to find symbol \"%s\" in \"%s\"\n", funcs[i].name, name); Sys_CloseLibrary(h); h = NULL; } @@ -1162,3 +1126,142 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const return true; } +static jboolean FTENativeActivity_startup(JNIEnv *jni, jobject this, jstring externalDataPath, jstring libraryPath) +{ + const char *tmp; + if (sys_mainthread) + return false; + if (!sys_activity) + { + sys_activity = (*jni)->NewGlobalRef(jni, this); + + tmp = (*jni)->GetStringUTFChars(jni, externalDataPath, NULL); + if (tmp) + { + Q_strncpyz(sys_basedir, tmp, sizeof(sys_basedir)); + if (*sys_basedir && sys_basedir[strlen(sys_basedir)-1] != '/') + Q_strncatz(sys_basedir, "/", sizeof(sys_basedir)); + (*jni)->ReleaseStringUTFChars(jni, externalDataPath, tmp); + } + else + *sys_basedir = 0; + tmp = (*jni)->GetStringUTFChars(jni, libraryPath, NULL); + if (tmp) + { + Q_strncpyz(sys_binarydir, tmp, sizeof(sys_binarydir)); + if (*sys_binarydir && sys_binarydir[strlen(sys_binarydir)-1] != '/') + Q_strncatz(sys_binarydir, "/", sizeof(sys_binarydir)); + (*jni)->ReleaseStringUTFChars(jni, libraryPath, tmp); + } + else + *sys_binarydir = 0; + + LOGI("FTENativeActivity_startup: basedir=%s binarydir=%s\n", sys_basedir, sys_binarydir); + + sys_wantshutdown = false; + sys_mainconditional = Sys_CreateConditional(); + Sys_LockConditional(sys_mainconditional); + sys_mainthread = Sys_CreateThread("ftedroid", FTEDroid_MainThread, NULL, THREADP_NORMAL, -1); + if (sys_mainthread) + Sys_ConditionWait(sys_mainconditional); + Sys_UnlockConditional(sys_mainconditional); + return !!sys_mainthread; + } + LOGI("conflicting FTENativeActivity_startup. ignoring.\n"); + return false; +} + +static void FTENativeActivity_surfacechange(JNIEnv *env, jobject this, jboolean teardown, jboolean recreate, jobject surface) +{ + if (this == sys_activity) + { + LOGI("FTENativeActivity_surfacechange: inactive %p, active %p\n", this, sys_activity); + return; //wasn't me... + } + LOGI("FTENativeActivity_surfacechange: %i %i %p\n", teardown, recreate, surface); + +//FIXME: if teardown&&recreate then this is a window RESIZE. +//there shouldn't be a need to destroy the entire context but anbox crashes when simply moving the window if we early out here. +// if (teardown && recreate && (*env)->IsSameObject(env, surface, sys_newsurface)) +// return; +// LOGI("FTENativeActivity_surfacechange: %i %i (%p==%p)==%i\n", teardown, recreate, surface, sys_newsurface, (*env)->IsSameObject(env, surface, sys_newsurface)); + + Sys_LockConditional(sys_mainconditional); + //get the main thread to let us know when its done... + if (qrenderer || (r_forceheadless && recreate)) + r_forcevidrestart = recreate?2:1; + if (sys_newsurface) + (*env)->DeleteGlobalRef(env, sys_newsurface); + sys_newsurface = surface?(*env)->NewGlobalRef(env, surface):NULL; + //and wake up then + Sys_ConditionWait(sys_mainconditional); + //and we're done... + Sys_UnlockConditional(sys_mainconditional); +} +static void FTENativeActivity_shutdown(JNIEnv *env, jobject this) +{ + if (this != sys_activity) + { + LOGI("FTENativeActivity_shutdown: inactive %p, active %p\n", this, sys_activity); + return; //wasn't me... + } + LOGI("FTENativeActivity_shutdown\n"); + + sys_wantshutdown = true; + if (sys_mainthread) + Sys_WaitOnThread(sys_mainthread); + sys_mainthread = NULL; + if (sys_mainconditional) + Sys_DestroyConditional(sys_mainconditional); + sys_mainconditional = NULL; + + (*env)->DeleteGlobalRef(env, sys_newsurface); + sys_newsurface = NULL; + + (*env)->DeleteGlobalRef(env, sys_activity); + sys_activity = NULL; +} + +//FIXME: we need a version of this that takes a byte array instead of a filename, for android's content gibberish. +static void FTENativeActivity_openfile(JNIEnv *env, jobject this, jstring filename) +{ + const char *tmp = (*env)->GetStringUTFChars(env, filename, NULL); + if (tmp) + { + Sys_Printf("FTENativeActivity_openfile: %s\n", tmp); + Host_RunFile(tmp, strlen(tmp), NULL); + (*env)->ReleaseStringUTFChars(env, filename, tmp); + } +} + +static JNINativeMethod methods[] = { + // + {"startup", "(Ljava/lang/String;Ljava/lang/String;)Z", FTENativeActivity_startup}, //creates our 'main' thread too + {"surfacechange", "(ZZLandroid/view/Surface;)V", FTENativeActivity_surfacechange}, //syncs + {"shutdown", "()V", FTENativeActivity_shutdown}, //joins 'main' thread. + {"openfile", "(Ljava/lang/String;)V", FTENativeActivity_openfile}, + + //inputs. these use our in_generic.c ringbuffer so don't need to sync at all + {"keypress", "(IZII)V", FTENativeActivity_keypress}, + {"mousepress", "(II)V", FTENativeActivity_mousepress}, + {"motion", "(IIFFFF)V", FTENativeActivity_motion}, + {"wantrelative", "()Z", FTENativeActivity_wantrelative}, //so the java code knows if it should use (often buggy) relative mouse movement or (limited) abs cursor coords. + {"axis", "(IIF)V", FTENativeActivity_axis}, +// {"accelerometer", "(IFFF)V", FTENativeActivity_accelerometer}, +// {"gyroscope", "(IFFF)V", FTENativeActivity_gyroscope}, +}; +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv *jni; + sys_javavm = vm; + if (JNI_OK == (*vm)->GetEnv(vm, (void**)&jni, JNI_VERSION_1_2)) + { + jclass naclass = (*jni)->FindClass(jni, "com/fteqw/FTENativeActivity"); + if (naclass) + { + (*jni)->RegisterNatives(jni, naclass, methods, countof(methods)); + return JNI_VERSION_1_2; + } + } + return -1; +} diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index b94711100..614937a02 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -174,7 +174,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define FULLENGINENAME "FTE Quake" //the posh name for the engine #endif #ifndef ENGINEWEBSITE - #define ENGINEWEBSITE "http://fte.triptohell.info" //url for program + #define ENGINEWEBSITE "^8http://^4fte.triptohell.info" //url for program #endif #if !defined(_WIN32) || defined(WINRT) diff --git a/engine/common/common.c b/engine/common/common.c index f7b7f4b3c..ce7f5a47d 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -132,8 +132,11 @@ cvar_t ezcompat_markup = CVARD("ezcompat_markup", "1", "Attempt compatibility wi cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active."); cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger delayed eremote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients."); cvar_t sys_platform = CVAR("sys_platform", PLATFORM); -cvar_t pm_downloads_url = CVARFD("pm_downloads_url", NULL, CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "The URL of a package updates list."); //read from the default.fmf -cvar_t pm_autoupdate = CVARFD("pm_autoupdate", "1", CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "Controls autoupdates, can only be changed via the downloads menu.\n0: off.\n1: enabled (stable only).\n2: enabled (unstable).\nNote that autoupdate will still prompt the user to actually apply the changes."); //read from the package list only. +cvar_t pkg_downloads_url = CVARFD("pkg_downloads_url", NULL, CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "The URL of a package updates list."); //read from the default.fmf +cvar_t pkg_autoupdate = CVARFD("pkg_autoupdate", "1", CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "Controls autoupdates, can only be changed via the downloads menu.\n0: off.\n1: enabled (stable only).\n2: enabled (unstable).\nNote that autoupdate will still prompt the user to actually apply the changes."); //read from the package list only. +#ifdef HAVE_LEGACY +cvar_t pm_noround = CVARD("pm_noround", "0", "Disables player prediction snapping, in a way that cannot be reliably predicted but may be needed to avoid map bugs."); +#endif qboolean com_modified; // set true if using non-id files @@ -4806,7 +4809,7 @@ static void COM_Version_f (void) { Con_Printf("\n"); Con_Printf("^&F0%s\n", FULLENGINENAME); - Con_Printf("^[%s\\url\\%s^]\n", ENGINEWEBSITE, ENGINEWEBSITE); + Con_Printf("^4"ENGINEWEBSITE"\n"); Con_Printf("%s\n", version_string()); Con_TPrintf ("Exe: %s %s\n", __DATE__, __TIME__); @@ -5819,6 +5822,7 @@ void COM_Init (void) Cvar_Register (&com_parseutf8, "Internationalisation"); #ifdef HAVE_LEGACY Cvar_Register (&ezcompat_markup, NULL); + Cvar_Register (&pm_noround, NULL); #endif Cvar_Register (&com_highlightcolor, "Internationalisation"); com_parseutf8.ival = 1; diff --git a/engine/common/fs.c b/engine/common/fs.c index 37ecff53f..1bef56555 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -1068,7 +1068,9 @@ static void QDECL FS_AddFileHash(int depth, const char *fname, fsbucket_t *fileh if (!filehandle) { int nlen = strlen(fname)+1; - if (!fs_hash_filebuckets || fs_hash_filebuckets->used+sizeof(*filehandle)+nlen > fs_hash_filebuckets->total) + int plen = sizeof(*filehandle)+nlen; + plen = (plen+__alignof(*filehandle)-1) & ~(__alignof(*filehandle)-1); + if (!fs_hash_filebuckets || fs_hash_filebuckets->used+plen > fs_hash_filebuckets->total) { void *o = fs_hash_filebuckets; fs_hash_filebuckets = Z_Malloc(65536); @@ -1076,7 +1078,7 @@ static void QDECL FS_AddFileHash(int depth, const char *fname, fsbucket_t *fileh fs_hash_filebuckets->prev = o; } filehandle = (fsbucket_t*)(fs_hash_filebuckets->data+fs_hash_filebuckets->used); - fs_hash_filebuckets->used += sizeof(*filehandle)+nlen; + fs_hash_filebuckets->used += plen; if (!filehandle) return; //eep! @@ -4526,7 +4528,7 @@ void FS_Shutdown(void) fs_thread_mutex = NULL; Cvar_SetEngineDefault(&fs_gamename, NULL); - Cvar_SetEngineDefault(&pm_downloads_url, NULL); + Cvar_SetEngineDefault(&pkg_downloads_url, NULL); Cvar_SetEngineDefault(&com_protocolname, NULL); } @@ -5783,11 +5785,11 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean if (reloadconfigs) { Cvar_SetEngineDefault(&fs_gamename, man->formalname?man->formalname:"FTE"); - Cvar_SetEngineDefault(&pm_downloads_url, man->downloadsurl?man->downloadsurl:""); + Cvar_SetEngineDefault(&pkg_downloads_url, man->downloadsurl?man->downloadsurl:""); Cvar_SetEngineDefault(&com_protocolname, man->protocolname?man->protocolname:"FTE"); //FIXME: flag this instead and do it after a delay? Cvar_ForceSet(&fs_gamename, fs_gamename.enginevalue); - Cvar_ForceSet(&pm_downloads_url, pm_downloads_url.enginevalue); + Cvar_ForceSet(&pkg_downloads_url, pkg_downloads_url.enginevalue); Cvar_ForceSet(&com_protocolname, com_protocolname.enginevalue); #ifdef HAVE_CLIENT vidrestart = false; @@ -6475,8 +6477,8 @@ void COM_InitFilesystem (void) Cvar_Register(&cfg_reload_on_gamedir, "Filesystem"); Cvar_Register(&com_fs_cache, "Filesystem"); Cvar_Register(&fs_gamename, "Filesystem"); - Cvar_Register(&pm_downloads_url, "Filesystem"); - Cvar_Register(&pm_autoupdate, "Filesystem"); + Cvar_Register(&pkg_downloads_url, "Filesystem"); + Cvar_Register(&pkg_autoupdate, "Filesystem"); Cvar_Register(&com_protocolname, "Server Info"); Cvar_Register(&com_protocolversion, "Server Info"); Cvar_Register(&fs_game, "Filesystem"); diff --git a/engine/common/fs_stdio.c b/engine/common/fs_stdio.c index 22a20fb4d..76d2dcb31 100644 --- a/engine/common/fs_stdio.c +++ b/engine/common/fs_stdio.c @@ -316,7 +316,7 @@ static unsigned int QDECL FSSTDIO_FLocate(searchpathfuncs_t *handle, flocation_t if ((unsigned int)snprintf (netpath, sizeof(netpath), "%s/%s", sp->rootpath, filename) > sizeof(netpath)-1) return FF_NOTFOUND; -#ifdef ANDROID +#if 0//def ANDROID { vfsfile_t *f = VFSSTDIO_Open(netpath, "rb", NULL); if (!f) diff --git a/engine/common/fs_xz.c b/engine/common/fs_xz.c index ca8287623..9364543f7 100644 --- a/engine/common/fs_xz.c +++ b/engine/common/fs_xz.c @@ -401,12 +401,12 @@ typedef unsigned char bool; * NOTE: System headers on GNU/Linux may #define this macro already, * so if you want to change it, you need to #undef it first. */ -#ifndef __always_inline +#ifndef always_inline # ifdef __GNUC__ -# define __always_inline \ +# define always_inline \ inline __attribute__((__always_inline__)) # else -# define __always_inline inline +# define always_inline inline # endif #endif @@ -2216,7 +2216,7 @@ static inline bool rc_is_finished(const struct rc_dec *rc) } /* Read the next input byte if needed. */ -static __always_inline void rc_normalize(struct rc_dec *rc) +static always_inline void rc_normalize(struct rc_dec *rc) { if (rc->range < RC_TOP_VALUE) { rc->range <<= RC_SHIFT_BITS; @@ -2235,7 +2235,7 @@ static __always_inline void rc_normalize(struct rc_dec *rc) * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care, * and it generates 10-20 % faster code than GCC 3.x from this file anyway.) */ -static __always_inline int rc_bit(struct rc_dec *rc, uint16_t *prob) +static always_inline int rc_bit(struct rc_dec *rc, uint16_t *prob) { uint32_t bound; int bit; @@ -2257,7 +2257,7 @@ static __always_inline int rc_bit(struct rc_dec *rc, uint16_t *prob) } /* Decode a bittree starting from the most significant bit. */ -static __always_inline uint32_t rc_bittree(struct rc_dec *rc, +static always_inline uint32_t rc_bittree(struct rc_dec *rc, uint16_t *probs, uint32_t limit) { uint32_t symbol = 1; @@ -2273,7 +2273,7 @@ static __always_inline uint32_t rc_bittree(struct rc_dec *rc, } /* Decode a bittree starting from the least significant bit. */ -static __always_inline void rc_bittree_reverse(struct rc_dec *rc, +static always_inline void rc_bittree_reverse(struct rc_dec *rc, uint16_t *probs, uint32_t *dest, uint32_t limit) { diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 2141f57e2..838a7cc1f 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -1030,11 +1030,12 @@ size_t NET_StringToSockaddr2 (const char *s, int defaultport, netadrtype_t afhin return result; //EVIL HACK! - //updates.tth uses a known self-signed certificate. its not meant to be used for browsers etc, and I cba to register dns stuff for it. + //updates.tth uses a known self-signed certificate (to protect against dns hijacks like fteqw.com suffered). + //its not meant to be used for browsers etc, and I cba to register dns stuff for it. //besides, browsers/etc would just bitch about its cert, so w/e. //redirect the dns to the base host without affecting http(s) hosts/certificates. if (!strcmp(s, "updates.triptohell.info")) - s = "triptohell.info"; + s += 8; memset (sadr, 0, sizeof(*sadr)); diff --git a/engine/common/plugin.c b/engine/common/plugin.c index cb75d8eb1..826cb2785 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -289,9 +289,15 @@ static plugin_t *Plug_Load(const char *file, int type) newplug->vm = VM_Create(temp, Plug_SystemCallsNative, NULL, NULL); } if (!newplug->vm && (type & PLUG_NATIVE)) - newplug->vm = VM_Create(va("fteplug_%s_", file), Plug_SystemCallsNative, NULL, NULL); + { + Q_snprintfz(temp, sizeof(temp), "fteplug_%s_", file); + newplug->vm = VM_Create(temp, Plug_SystemCallsNative, NULL, NULL); + } if (!newplug->vm && (type & PLUG_NATIVE)) - newplug->vm = VM_Create(va("fteplug_%s", file), Plug_SystemCallsNative, NULL, NULL); + { + Q_snprintfz(temp, sizeof(temp), "fteplug_%s", file); + newplug->vm = VM_Create(temp, Plug_SystemCallsNative, NULL, NULL); + } if (!newplug->vm && (type & PLUG_QVM)) newplug->vm = VM_Create(NULL, NULL, file, Plug_SystemCallsVM); if (!newplug->vm && (type & PLUG_NATIVE)) diff --git a/engine/common/pmove.c b/engine/common/pmove.c index a3b5842ed..b29f050cb 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. movevars_t movevars; playermove_t pmove; +extern cvar_t pm_noround; //evile. #define movevars_dpflags MOVEFLAG_QWCOMPAT #define movevars_maxairspeed 30 @@ -1227,8 +1228,14 @@ static void PM_NudgePosition (void) //base[i] = MSG_FromCoord(MSG_ToCoord(pmove.origin[i], movevars.coordsize), movevars.coordsize); //but it has overflow issues, so do things the painful way instead. //this stuff is so annoying because we're trying to avoid biasing the position towards 0. you'll see the effects of that if you use a low forwardspeed or low sv_gamespeed etc, but its also noticable with default settings too. - if (movevars.coordsize == 4) //float precision on the network. no need to truncate. + if ( +#ifdef HAVE_LEGACY + pm_noround.ival || +#endif + movevars.coordsize == 4) //float precision on the network. no need to truncate. + { VectorCopy (pmove.origin, base); + } else if (movevars.coordsize) //1/8th precision, but don't truncate because that screws everything up. { for (i=0 ; i<3 ; i++) diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index ab684e930..202a95b2f 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -477,6 +477,9 @@ void QCBUILTIN PF_cl_bprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo void QCBUILTIN PF_cl_clientcount (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_cl_localsound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_cl_SendPacket(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cl_getlocaluserinfoblob (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cl_getlocaluserinfostring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cl_setlocaluserinfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void search_close_progs(pubprogfuncs_t *prinst, qboolean complain); diff --git a/engine/common/sys_linux_threads.c b/engine/common/sys_linux_threads.c index 931a768b3..64c07eba1 100644 --- a/engine/common/sys_linux_threads.c +++ b/engine/common/sys_linux_threads.c @@ -79,11 +79,14 @@ void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - if (stacksize < PTHREAD_STACK_MIN*2) - stacksize = PTHREAD_STACK_MIN*2; - if (stacksize < PTHREAD_STACK_MIN+65536*16) - stacksize = PTHREAD_STACK_MIN+65536*16; - pthread_attr_setstacksize(&attr, stacksize); + if (stacksize != -1) + { + if (stacksize < PTHREAD_STACK_MIN*2) + stacksize = PTHREAD_STACK_MIN*2; + if (stacksize < PTHREAD_STACK_MIN+65536*16) + stacksize = PTHREAD_STACK_MIN+65536*16; + pthread_attr_setstacksize(&attr, stacksize); + } if (pthread_create(thread, &attr, (pfunction_t)Sys_CreatedThread, qthread)) { free(thread); diff --git a/engine/droid/AndroidManifest.xml b/engine/droid/AndroidManifest.xml index 922874ae1..b2419e83b 100644 --- a/engine/droid/AndroidManifest.xml +++ b/engine/droid/AndroidManifest.xml @@ -22,9 +22,6 @@ - - diff --git a/engine/droid/src/com/fteqw/FTENativeActivity.java b/engine/droid/src/com/fteqw/FTENativeActivity.java index 998004191..31664f993 100644 --- a/engine/droid/src/com/fteqw/FTENativeActivity.java +++ b/engine/droid/src/com/fteqw/FTENativeActivity.java @@ -5,17 +5,147 @@ import android.view.MotionEvent; import android.view.InputDevice; import android.view.WindowManager; -public class FTENativeActivity extends android.app.NativeActivity +public class FTENativeActivity extends android.app.Activity implements android.view.SurfaceHolder.Callback2, android.view.ViewTreeObserver.OnGlobalLayoutListener { + //Native functions and stuff + private native boolean startup(String externalDataPath, String libraryPath); + private native void openfile(String url); + private native void surfacechange(boolean teardown, boolean restart, android.view.Surface surface); + private native void shutdown(); + private static native void keypress(int devid, boolean down, int androidkey, int unicode); private static native void mousepress(int devid, int buttonbits); private static native void motion(int devid, int action, float x, float y, float z, float size); private static native boolean wantrelative(); private static native void axis(int devid, int axisid, float value); -// private static native void oncreate(String basedir, byte[] savedstate); +// private static native void oncreate(String bindir, String basedir, byte[] savedstate); static { - System.loadLibrary("ftedroid"); + System.loadLibrary("ftedroid"); //registers the methods properly. + } + + static class NativeContentView extends android.view.View + { + FTENativeActivity mActivity; + public NativeContentView(android.content.Context context) + { + super(context); + } + public NativeContentView(android.content.Context context, android.util.AttributeSet attrs) + { + super(context, attrs); + } + } + private NativeContentView mNativeContentView; + +//SurfaceHolder.Callback2 methods + public void surfaceRedrawNeeded(android.view.SurfaceHolder holder) + { //we constantly redraw. + } + public void surfaceCreated(android.view.SurfaceHolder holder) + { +// surfacechange(false, true, holder.getSurface()); + } + public void surfaceChanged(android.view.SurfaceHolder holder, int format, int width, int height) + { + surfacechange(true, true, holder.getSurface()); + } + public void surfaceDestroyed(android.view.SurfaceHolder holder) + { + surfacechange(true, false, null); + } + +//OnGlobalLayoutListener methods + public void onGlobalLayout() + { +/* mNativeContentView.getLocationInWindow(mLocation); + int w = mNativeContentView.getWidth(); + int h = mNativeContentView.getHeight(); + if (mLocation[0] != mLastContentX || mLocation[1] != mLastContentY || w != mLastContentWidth || h != mLastContentHeight) + { + mLastContentX = mLocation[0]; + mLastContentY = mLocation[1]; + mLastContentWidth = w; + mLastContentHeight = h; + if (!mDestroyed) { + onContentRectChangedNative(mNativeHandle, mLastContentX, + mLastContentY, mLastContentWidth, mLastContentHeight); + } + } +*/ } + +//Activity methods + @Override + protected void onCreate(android.os.Bundle savedInstanceState) + { + getWindow().takeSurface(this); + getWindow().setFormat(android.graphics.PixelFormat.RGB_565); + getWindow().setSoftInputMode( + WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED + | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + mNativeContentView = new NativeContentView(this); + mNativeContentView.mActivity = this; + setContentView(mNativeContentView); + mNativeContentView.requestFocus(); + mNativeContentView.getViewTreeObserver().addOnGlobalLayoutListener(this); + +// byte[] nativeSavedState = savedInstanceState != null +// ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null; + startup(getAbsolutePath(getExternalFilesDir(null)), getNativeLibraryDirectory()); + handleIntent(getIntent()); + +// if (Build.VERSION.SDK_INT >= 19) +// { +// int flags = 0; +// flags |= 4096/*SYSTEM_UI_FLAG_IMMERSIVE_STICKY, api 19*/; +// flags |= 4/*SYSTEM_UI_FLAG_FULLSCREEN, api 16*/; +// flags |= 2/*SYSTEM_UI_FLAG_HIDE_NAVIGATION, api 14*/; +// mNativeContentView.setSystemUiVisibility(flags); /*api 11*/ +// } + + super.onCreate(savedInstanceState); + //Needed because the InputQueue stuff blocks dispatchKeyEvent + getWindow().takeInputQueue(null); + } + + //random helpers + private void handleIntent(android.content.Intent intent) + { + String s = intent.getScheme(); + if (s=="content") + { + android.database.Cursor cursor = this.getContentResolver().query(intent.getData(), null, null, null, null); + cursor.moveToFirst(); + String myloc = cursor.getString(0); + cursor.close(); + } + else + openfile(intent.getDataString()); + } + private static String getAbsolutePath(java.io.File file) + { + return (file != null) ? file.getAbsolutePath() : null; + } + public String getNativeLibraryDirectory() + { + android.content.Context context = getApplicationContext(); + int sdk_level = android.os.Build.VERSION.SDK_INT; + if (sdk_level >= android.os.Build.VERSION_CODES.GINGERBREAD) + { + try + { + String secondary = (String) android.content.pm.ApplicationInfo.class.getField("nativeLibraryRootDir").get(context.getApplicationInfo()); + return secondary; + } + catch (Exception e) + { + e.printStackTrace(); + } + return null; + } + if (sdk_level >= android.os.Build.VERSION_CODES.DONUT) + return context.getApplicationInfo().dataDir + "/lib"; + return "/data/data/" + context.getPackageName() + "/lib"; } //called by C code on errors / quitting. @@ -132,40 +262,6 @@ public class FTENativeActivity extends android.app.NativeActivity }); } - @Override - protected void onCreate(android.os.Bundle savedInstanceState) - { -/* getWindow().takeSurface(this); - getWindow().setFormat(PixelFormat.RGB_565); - getWindow().setSoftInputMode( - WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED - | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - mNativeContentView = new NativeContentView(this); - mNativeContentView.mActivity = this; - setContentView(mNativeContentView); - mNativeContentView.requestFocus(); - mNativeContentView.getViewTreeObserver().addOnGlobalLayoutListener(this); - - byte[] nativeSavedState = savedInstanceState != null - ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null; - mNativeHandle = oncreate( - getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()), - getAbsolutePath(getExternalFilesDir(null)), - Build.VERSION.SDK_INT, getAssets(), nativeSavedState); -*/ -// if (Build.VERSION.SDK_INT >= 19) -// { -// int flags = 0; -// flags |= 4096/*SYSTEM_UI_FLAG_IMMERSIVE_STICKY, api 19*/; -// flags |= 4/*SYSTEM_UI_FLAG_FULLSCREEN, api 16*/; -// flags |= 2/*SYSTEM_UI_FLAG_HIDE_NAVIGATION, api 14*/; -// mNativeContentView.setSystemUiVisibility(flags); /*api 11*/ -// } - - super.onCreate(savedInstanceState); - //Needed because the InputQueue stuff blocks dispatchKeyEvent - getWindow().takeInputQueue(null); - } @Override public boolean dispatchKeyEvent(KeyEvent event) { //needed because AKeyEvent_getUnicode is missing completely. @@ -374,11 +470,12 @@ public class FTENativeActivity extends android.app.NativeActivity //launching stuff - /*private static native int unicodeKeyPress(int unicode); + private static native int unicodeKeyPress(int unicode); @Override - void onNewIntent(Intent intent) + protected void onNewIntent(android.content.Intent intent) { + handleIntent(intent); super.onNewIntent(intent); - }*/ + } } diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 599c2b7b1..98b7fa9d1 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1157,6 +1157,7 @@ static void T_Gen_CurrentRender(int tmu) int vwidth, vheight; int pwidth = vid.fbpwidth; int pheight = vid.fbpheight; + GLenum fmt; if (r_refdef.recurse) return; @@ -1178,6 +1179,14 @@ static void T_Gen_CurrentRender(int tmu) vheight *= 2; } } + + if (vid.flags&VID_FP16) + fmt = GL_RGBA16F; + else if (vid.flags&VID_SRGB_CAPABLE) + fmt = GL_SRGB8; + else + fmt = GL_RGB; + // copy the scene to texture if (!TEXVALID(shaderstate.temptexture)) { @@ -1185,12 +1194,7 @@ static void T_Gen_CurrentRender(int tmu) qglGenTextures(1, &shaderstate.temptexture->num); } GL_MTBind(tmu, GL_TEXTURE_2D, shaderstate.temptexture); - if (vid.flags&VID_FP16) - qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 0, 0, vwidth, vheight, 0); - else if (vid.flags&VID_SRGBAWARE) - qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 0, 0, vwidth, vheight, 0); - else - qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, vwidth, vheight, 0); + qglCopyTexImage2D(GL_TEXTURE_2D, 0, fmt, 0, 0, vwidth, vheight, 0); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 650268542..d8b8e819d 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -135,39 +135,39 @@ void GL_SetupFormats(void) if (gl_config_gles) { //pre-3 gles doesn't support sized formats, and only a limited number of them too - glfmtc(PTI_RGB8, 0, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, tc_rgb); - glfmtc(PTI_RGBA8, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, tc_rgba8); - glfmt(PTI_L8A8, 0, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE); - glfmt(PTI_L8, 0, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE); -// glfmt(PTI_A8, 0, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE); + glfmtc(PTI_RGB8, (ver>=3)?GL_RGB8:0, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, tc_rgb); + glfmtc(PTI_RGBA8, (ver>=3)?GL_RGBA8:0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, tc_rgba8); + glfmt(PTI_L8A8, (ver>=3)?GL_LUMINANCE8_ALPHA8:0,GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE); + glfmt(PTI_L8, (ver>=3)?GL_LUMINANCE8:0, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE); +// glfmt(PTI_A8, (ver>=3)?GL_LUMINANCE8:0, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE); if (!gl_config.webgl_ie) { //these should work on all gles2+webgl1 devices, but microsoft doesn't give a shit. - glfmtc(PTI_RGB565, GL_RGB, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tc_rgb); -// glfmtc(PTI_RGBA4444,GL_RGBA, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, tc_rgba8); -// glfmtc(PTI_RGBA5551,GL_RGBA, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, tc_rgba1); + glfmtc(PTI_RGB565, (ver>=3)?GL_RGB565:0, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tc_rgb); +// glfmtc(PTI_RGBA4444,(ver>=3)?GL_RGBA4:0, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, tc_rgba8); +// glfmtc(PTI_RGBA5551,(ver>=3)?GL_RGB555A1:0, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, tc_rgba1); } if (GL_CheckExtension("GL_OES_texture_half_float")) - glfmtc(PTI_RGBA16F, GL_RGBA, GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES, 0); //not to be confused with GL_HALF_FLOAT[_ARB] which has a different value + glfmtc(PTI_RGBA16F, (ver>=3)?GL_RGBA16F:0, GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES, 0); //not to be confused with GL_HALF_FLOAT[_ARB] which has a different value if (GL_CheckExtension("GL_OES_texture_float")) - glfmtc(PTI_RGBA32F, GL_RGBA, GL_RGBA, GL_RGBA, GL_FLOAT, 0); + glfmtc(PTI_RGBA32F, (ver>=3)?GL_RGBA32F:0, GL_RGBA, GL_RGBA, GL_FLOAT, 0); if (GL_CheckExtension("GL_WEBGL_depth_texture")) { //24bit is okay with this one. - glfmt(PTI_DEPTH16, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT); - glfmt(PTI_DEPTH24, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8); - glfmt(PTI_DEPTH32, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); + glfmt(PTI_DEPTH16, (ver>=3)?GL_DEPTH_COMPONENT:0,GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT); + glfmt(PTI_DEPTH24, (ver>=3)?GL_DEPTH_COMPONENT:0,GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8); + glfmt(PTI_DEPTH32, (ver>=3)?GL_DEPTH_COMPONENT:0,GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); } else if (GL_CheckExtension("GL_OES_depth_texture") || GL_CheckExtension("GL_ANGLE_depth_texture")) { //16+32, not 24. - glfmt(PTI_DEPTH16, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT); - glfmt(PTI_DEPTH32, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); + glfmt(PTI_DEPTH16, (ver>=3)?GL_DEPTH_COMPONENT:0,GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT); + glfmt(PTI_DEPTH32, (ver>=3)?GL_DEPTH_COMPONENT:0,GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); } if (GL_CheckExtension("GL_EXT_texture_format_BGRA8888")) - glfmtc(PTI_BGRA8, GL_BGRA_EXT, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, tc_rgba8); + glfmtc(PTI_BGRA8, /*(ver>=3)?GL_BGRA8_EXT:*/0, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, tc_rgba8); if (GL_CheckExtension("GL_EXT_texture_type_2_10_10_10_REV")) - glfmtc(PTI_BGRA8, GL_RGBA, GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, tc_rgba8); + glfmtc(PTI_A2BGR10, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, tc_rgba8); } if (!gl_config_gles || ver >= 3.0) { @@ -642,7 +642,8 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) int nummips = mips->mipcount; uploadfmt_t encoding = mips->encoding; qboolean compress; - + qboolean storage = true; + unsigned int bb, bw, bh; if (gl_config.gles) { @@ -776,7 +777,12 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) ifmt = gl_config.formatinfo[encoding].sizedformat; if (!ifmt) - return false; + { + ifmt = gl_config.formatinfo[encoding].internalformat; + if (!ifmt) + return false; //dude, everything bad is happening today. + storage = false; //no sized format means we can't use glTexStorageND + } if (gl_config.formatinfo[encoding].swizzle_r != GL_RED || gl_config.formatinfo[encoding].swizzle_g != GL_GREEN || gl_config.formatinfo[encoding].swizzle_b != GL_BLUE || gl_config.formatinfo[encoding].swizzle_a != GL_ALPHA) @@ -787,10 +793,34 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) qglTexParameteri(targ, GL_TEXTURE_SWIZZLE_A, gl_config.formatinfo[encoding].swizzle_a); } + Image_BlockSizeForEncoding(encoding, &bb, &bw, &bh); + switch(bb) + { + case 3: + default: + bb = 1; //rows are completely unaligned + break; + case 1: + case 2: + case 4: + case 8: + break; //rows are aligned naturally + case 16: + case 32: + case 64: + bb = 8; //row alignment is capped to 8 by opengl, for some reason. + break; + } + if (gl_config.unpackalignment != bb) + { + gl_config.unpackalignment = bb; + qglPixelStorei(GL_UNPACK_ALIGNMENT, bb); + } + if (targ == GL_TEXTURE_3D || targ == GL_TEXTURE_2D_ARRAY) { //FIXME: support array textures properly - if (qglTexStorage3D) + if (qglTexStorage3D && storage) { if (tex->flags & IF_TEXTYPE) qglTexStorage3D(targ, nummips/countof(cubeface), ifmt, mips->mip[0].width, mips->mip[0].height, mips->mip[0].depth); @@ -821,7 +851,7 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) } else { - if (qglTexStorage2D) + if (qglTexStorage2D && storage) { //FIXME: destroy the old texture if (tex->flags & IF_TEXTYPE) qglTexStorage2D(targ, nummips/countof(cubeface), ifmt, mips->mip[0].width, mips->mip[0].height); diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 0a04ade5a..efd3e9c86 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -1771,7 +1771,7 @@ static texid_t Font_LoadFallbackConchars(void) Font_CopyGlyph('|', 131, lump); Font_CopyGlyph('>', 13, lump); } - tex = R_LoadTexture32("charset", width, height, (void*)lump, IF_PREMULTIPLYALPHA|IF_LOADNOW|IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA); + tex = Image_GetTexture("charset", NULL, IF_PREMULTIPLYALPHA|IF_LOADNOW|IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA, (void*)lump, NULL, width, height, PTI_RGBA8); BZ_Free(lump); return tex; } diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index e613cb679..94a6df9db 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -57,6 +57,7 @@ void (APIENTRY *qglGetIntegerv) (GLenum pname, GLint *params); const GLubyte * (APIENTRY *qglGetString) (GLenum name); void (APIENTRY *qglHint) (GLenum target, GLenum mode); GLboolean (APIENTRY *qglIsEnabled) (GLenum cap); +void (APIENTRY *qglPixelStorei) (GLenum pname, GLint param); void (APIENTRY *qglPolygonOffset) (GLfloat factor, GLfloat units); void (APIENTRY *qglLineWidth) (GLfloat width); void (APIENTRY *qglReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); @@ -680,6 +681,15 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglGenProgramsARB = NULL; */ + if (gl_config.glversion >= (gl_config.gles?3:1.2)) + qglDrawRangeElements = (void *)getglext("glDrawRangeElements"); + else if (GL_CheckExtension("GL_EXT_draw_range_elements")) + qglDrawRangeElements = (void *)getglext("glDrawRangeElementsEXT"); + else + qglDrawRangeElements = NULL; + if (qglDrawRangeElements == NULL) + qglDrawRangeElements = GL_DrawRangeElementsEmul; + gl_config.ext_packed_depth_stencil = GL_CheckExtension("GL_EXT_packed_depth_stencil"); if (GL_CheckExtension("GL_EXT_texture_filter_anisotropic")) @@ -3259,6 +3269,7 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) qglFinish = (void *)getglcore("glFinish"); qglFlush = (void *)getglcore("glFlush"); qglGenTextures = (void *)getglcore("glGenTextures"); + qglPixelStorei = (void *)getglcore("glPixelStorei"); qglGetFloatv = (void *)getglcore("glGetFloatv"); qglGetIntegerv = (void *)getglcore("glGetIntegerv"); qglGetString = (void *)getglcore("glGetString"); @@ -3301,10 +3312,6 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) qglEnableClientState = (void *)getglcore("glEnableClientState"); qglDisableClientState = (void *)getglcore("glDisableClientState"); - qglDrawRangeElements = (void *)getglext("glDrawRangeElements"); - if (qglDrawRangeElements == 0) - qglDrawRangeElements = GL_DrawRangeElementsEmul; - qglMultiDrawElements = (void *)getglext("glMultiDrawElements"); //since gl2 diff --git a/engine/gl/gl_viddroid.c b/engine/gl/gl_viddroid.c index 67147d985..db0485e39 100644 --- a/engine/gl/gl_viddroid.c +++ b/engine/gl/gl_viddroid.c @@ -76,7 +76,7 @@ void GLVID_DeInit(void) Sys_Printf("GLVID_DeInited\n"); } -static void EGL_ShowConfig(EGLDisplay egldpy, EGLConfig cfg) +/*static void EGL_ShowConfig(EGLDisplay egldpy, EGLConfig cfg) { struct { @@ -128,6 +128,7 @@ static void EGL_ShowConfig(EGLDisplay egldpy, EGLConfig cfg) Sys_Printf("%i.%s: UNKNOWN\n", (int)cfg, eglattrs[i].attrname); } }; +*/ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) { @@ -206,7 +207,7 @@ Sys_Printf("GLVID_Initing...\n"); Sys_Printf("Creating gles %i context\n", glesversion); - EGL_ShowConfig(sys_display, config); +// EGL_ShowConfig(sys_display, config); sys_surface = eglCreateWindowSurface(sys_display, config, sys_nativewindow, NULL); if (!sys_surface) @@ -233,7 +234,13 @@ Sys_Printf("GLVID_Initing...\n"); s++; gl_major_version = atoi(s); const char *driver; - if (gl_major_version>=3) + if ((glesversion<=1) != (gl_major_version<=1)) + { + Con_Printf(CON_ERROR "Requested gles %i context, but got incompatible %i instead.\n", glesversion, gl_major_version); + GLVID_DeInit(); + return false; + } + if (gl_major_version>=3) driver = "libGLESv3.so"; else if (gl_major_version>=2) driver = "libGLESv2.so"; diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 54737bfe2..7214ae22d 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -2890,6 +2890,7 @@ static void GetEvent(void) char *protname = x11.pXGetAtomName(vid_dpy, event.xclient.data.l[0]); if (!strcmp(protname, "WM_DELETE_WINDOW")) { + Key_Dest_Remove(kdm_console); if (Cmd_Exists("menu_quit") || Cmd_AliasExist("menu_quit", RESTRICT_LOCAL)) Cmd_ExecuteString("menu_quit prompt", RESTRICT_LOCAL); else if (Cmd_Exists("m_quit") || Cmd_AliasExist("m_quit", RESTRICT_LOCAL)) diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index ae4fdff10..07b6c58a3 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -251,6 +251,7 @@ typedef struct { int ext_texture_filter_anisotropic; struct glfmt_s formatinfo[PTI_MAX]; + int unpackalignment; } gl_config_t; extern gl_config_t gl_config; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 15fe3e418..b6a57784f 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -10950,9 +10950,12 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"getplayerkeyvalue", PF_Fixme,0, 0, 0, 348, D("string(float playernum, string keyname)", "Look up a player's userinfo, to discover things like their name, topcolor, bottomcolor, skin, team, *ver.\nAlso includes scoreboard info like frags, ping, pl, userid, entertime, as well as voipspeaking and voiploudness.")},// (EXT_CSQC) {"getplayerkeyfloat", PF_Fixme,0, 0, 0, 0, D("float(float playernum, string keyname, optional float assumevalue)", "Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings.")}, {"getplayerkeyblob", PF_Fixme,0, 0, 0, 0, D("int(float playernum, string keyname, optional void *outptr, int size)", "Obtains a copy of the full data blob. Will write up to size bytes but return the full size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")}, - - {"getlocalinfo", PF_getlocalinfo,0, 0, 0, 0, D("int(string keyname, optional void *outptr, int size)", "Obtains a copy of the full data blob. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")}, - {"setlocalinfo", PF_setlocalinfo,0, 0, 0, 0, D("void(string keyname, optional void *outptr, int size)", "Changes the server's localinfo. This data will be available for the following map, and will *usually* reload with saved games.")}, + {"setlocaluserinfo", PF_Fixme,0, 0, 0, 0, D("void(float seat, string keyname, string newvalue)", "Change a userinfo key for the local player, equivelent to the setinfo console command. The server will normally forward the setting to other clients.")}, + {"getlocaluserinfo", PF_Fixme,0, 0, 0, 0, D("string(float seat, string keyname)", "Reads a local userinfo key for the active seat. This is not quite the same as getplayerkeyvalue, due to latency and possible serverside filtering.")}, + {"setlocaluserinfoblob",PF_Fixme,0, 0, 0, 0, D("void(float seat, string keyname, void *outptr, int size)", "Sets the userinfo key to a blob that may contain nulls etc. Keys with a leading underscore will be visible to only the server (for user-specific binary settings).")}, + {"getlocaluserinfoblob",PF_Fixme,0, 0, 0, 0, D("int(float seat, string keyname, void *outptr, int maxsize)", "Obtains a copy of the full data blob. Will write up to size bytes but return the full size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")}, + {"getlocalinfo", PF_getlocalinfo,0, 0, 0, 0, D("int(string keyname, optional void *outptr, int size)", "Obtains a copy of a data blob (with spaces) from the server's private localinfo. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")}, + {"setlocalinfo", PF_setlocalinfo,0, 0, 0, 0, D("void(string keyname, optional void *outptr, int size)", "Changes the server's private localinfo. This data will be available for the following map, and will *usually* reload with saved games.")}, {"isdemo", PF_Fixme, 0, 0, 0, 349, D("float()", "Returns if the client is currently playing a demo or not. Returns 2 when playing an mvd (where other player's stats can be queried, or the pov can be changed freely).")},// (EXT_CSQC) {"isserver", PF_Fixme, 0, 0, 0, 350, D("float()", "Returns non-zero whenever the local console can directly affect the server (ie: listen servers or single-player). Compat note: DP returns 0 for single-player.")},//(EXT_CSQC) @@ -10960,10 +10963,10 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"setup_reverb", PF_Fixme, 0, 0, 0, 0, D("typedef struct {\n\tfloat flDensity;\n\tfloat flDiffusion;\n\tfloat flGain;\n\tfloat flGainHF;\n\tfloat flGainLF;\n\tfloat flDecayTime;\n\tfloat flDecayHFRatio;\n\tfloat flDecayLFRatio;\n\tfloat flReflectionsGain;\n\tfloat flReflectionsDelay;\n\tvector flReflectionsPan;\n\tfloat flLateReverbGain;\n\tfloat flLateReverbDelay;\n\tvector flLateReverbPan;\n\tfloat flEchoTime;\n\tfloat flEchoDepth;\n\tfloat flModulationTime;\n\tfloat flModulationDepth;\n\tfloat flAirAbsorptionGainHF;\n\tfloat flHFReference;\n\tfloat flLFReference;\n\tfloat flRoomRolloffFactor;\n\tint iDecayHFLimit;\n} reverbinfo_t;\nvoid(float reverbslot, reverbinfo_t *reverbinfo, int sizeofreverinfo_t)", "Reconfigures a reverb slot for weird effects. Slot 0 is reserved for no effects. Slot 1 is reserved for underwater effects. Reserved slots will be reinitialised on snd_restart, but can otherwise be changed. These reverb slots can be activated with SetListener. Note that reverb will currently only work when using OpenAL.")}, {"registercommand", PF_Fixme, 0, 0, 0, 352, D("void(string cmdname)", "Register the given console command, for easy console use.\nConsole commands that are later used will invoke CSQC_ConsoleCommand.")},//(EXT_CSQC) {"wasfreed", PF_WasFreed,0, 0, 0, 353, D("float(entity ent)", "Quickly check to see if the entity is currently free. This function is only valid during the two-second non-reuse window, after that it may give bad results. Try one second to make it more robust.")},//(EXT_CSQC) (should be availabe on server too) - {"serverkey", PF_sv_serverkeystring,0,0, 0, 354, D("string(string key)", "Look up a key in the server's public serverinfo string")},// + {"serverkey", PF_sv_serverkeystring,0,0, 0, 354, D("string(string key)", "Look up a key in the server's public serverinfo string. If the key contains binary data then it will be truncated at the first null.")},// {"serverkeyfloat", PF_sv_serverkeyfloat,0,0, 0, 0, D("float(string key, optional float assumevalue)", "Version of serverkey that returns the value as a float (which avoids tempstrings).")},// - {"serverkeyblob", PF_sv_serverkeyblob,0,0, 0, 0, D("int(int buf, string key, optional void *ptr, int size)", "Version of serverkey that can obtain entire serverinfo, localinfo, or (local)userinfo blobs. Returns blob size")},// - {"setserverkey", PF_setserverkey,0, 0, 0, 0, D("void(int buf, string key, void *ptr, optional int size)", "Changes the server's serverinfo.")},// + {"serverkeyblob", PF_sv_serverkeyblob,0,0, 0, 0, D("int(string key, optional void *ptr, int maxsize)", "Version of serverkey that returns data as a blob (ie: binary data that may contain nulls). Returns the full blob size, even if truncated (pass maxsize=0 to query required storage).")},// + {"setserverkey", PF_setserverkey,0, 0, 0, 0, D("void(string key, void *ptr, optional int size)", "Changes the server's serverinfo.")},// {"getentitytoken", PF_Fixme, 0, 0, 0, 355, D("string(optional string resetstring)", "Grab the next token in the map's entity lump.\nIf resetstring is not specified, the next token will be returned with no other sideeffects.\nIf empty, will reset from the map before returning the first token, probably {.\nIf not empty, will tokenize from that string instead.\nAlways returns tempstrings.")},//; {"findfont", PF_Fixme, 0, 0, 0, 356, D("float(string s)", "Looks up a named font slot. Matches the actual font name as a last resort.")},//; {"loadfont", PF_Fixme, 0, 0, 0, 357, D("float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset)", "too convoluted for me to even try to explain correct usage. Try drawfont = loadfont(\"\", \"cour\", \"16\", -1, 0, 0); to switch to the courier font (optimised for 16 virtual pixels high), if you have the freetype2 library in windows..")}, diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index dfcf688d4..deb824154 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -1038,7 +1038,7 @@ void SV_FullClientUpdate (client_t *client, client_t *to) MSG_WriteFloat(buf, realtime - client->connection_started); ClientReliable_FinishWrite(to); - InfoBuf_ToString(&client->userinfo, info, (pext&PEXT_BIGUSERINFOS)?BASIC_INFO_STRING:sizeof(info), basicuserinfos, privateuserinfos, (pext&PEXT_BIGUSERINFOS)?NULL:basicuserinfos, NULL, NULL); + InfoBuf_ToString(&client->userinfo, info, (pext&PEXT_BIGUSERINFOS)?BASIC_INFO_STRING:sizeof(info), basicuserinfos, privateuserinfos, (pext&PEXT_BIGUSERINFOS)?NULL:basicuserinfos, &to->infosync, &client->userinfo); buf = ClientReliable_StartWrite(to, 7 + strlen(info)); MSG_WriteByte(buf, svc_updateuserinfo); MSG_WriteByte(buf, i); @@ -1372,6 +1372,12 @@ static void SVC_InfoQ2 (void) } #endif +#ifdef MVD_RECORDING +static void SVC_QTVUsers (void) +{ +} +#endif + /* =================== SV_CheckLog @@ -3927,12 +3933,14 @@ qboolean SV_ConnectionlessPacket (void) if (SVC_ThrottleInfo()) SVC_DemoListRegex (); } +*/ +#ifdef MVD_RECORDING else if (!strcmp(c,"qtvusers")) { if (SVC_ThrottleInfo()) SVC_QTVUsers (); } -*/ +#endif else if (!PR_GameCodePacket(net_message.data+4)) { static unsigned int lt; diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 3070f7a8e..9d6a66e2e 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -2821,6 +2821,7 @@ static qboolean SV_SyncInfoBuf(client_t *client) if (!blobdata) blobdata = ""; +Con_DLPrintf(2, "%s: info %u:%s\n", client->name, (info == &svs.info)?0:(unsigned int)((client_t*)((char*)info-(char*)&((client_t*)NULL)->userinfo)-svs.clients), key); if (ISNQCLIENT(client)) { //except that nq never had any userinfo const char *s; @@ -2856,7 +2857,7 @@ static qboolean SV_SyncInfoBuf(client_t *client) char enckey[2048]; unsigned int pl; if (info == &svs.info) - pl = 0; //colourmaps being 1-based with these being 0-based means that only 0-254 are valid players, and 255 is unused, so lets use it for serverinfo blobs. + pl = 0; //players are 1-based. 0 is used for serverinfo. else pl = 1+((client_t*)((char*)info-(char*)&((client_t*)NULL)->userinfo)-svs.clients); @@ -2866,17 +2867,18 @@ static qboolean SV_SyncInfoBuf(client_t *client) return false; } if (!blobdata) - bloboffset = 0; //wiped or something? I dunno, don't bug out though.y + bloboffset = 0; //wiped or something? I dunno, don't bug out though. sendsize = blobsize - bloboffset; bufferspace = MAX_BACKBUFLEN - client->netchan.message.cursize; - bufferspace -= 8 - strlen(enckey) - 1; //extra overhead + bufferspace -= 8 + strlen(enckey) + 1; //extra overhead sendsize = min(bufferspace, sendsize); final = (bloboffset+sendsize >= blobsize); +Con_DLPrintf(2, "%s: blob %u:%s@%u-%u\n", client->name, pl, key, (unsigned int)bloboffset, (unsigned int)(bloboffset+sendsize)); buf = ClientReliable_StartWrite(client, 8+strlen(enckey)+1+sendsize); MSG_WriteByte(buf, svcfte_setinfoblob); - MSG_WriteByte(buf, pl); //special meaning to say that this is a partial update + MSG_WriteByte(buf, pl); MSG_WriteString(buf, enckey); MSG_WriteLong(buf, (final?0x80000000:0)|bloboffset); MSG_WriteShort(buf, sendsize); @@ -3415,7 +3417,7 @@ void SV_SendClientMessages (void) if (c->num_backbuf) { // will it fit? - if (c->netchan.message.cursize + c->backbuf_size[0] < + if (c->netchan.message.cursize + c->backbuf_size[0] <= c->netchan.message.maxsize) { diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index 72b0184f8..c8f73527f 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -3903,6 +3903,10 @@ void VK_CheckTextureFormats(void) {PTI_RG8, VK_FORMAT_R8G8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, {PTI_R8_SNORM, VK_FORMAT_R8_SNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, {PTI_RG8_SNORM, VK_FORMAT_R8G8_SNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_R16, VK_FORMAT_R16_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_RGBA16, VK_FORMAT_R16G16B16A16_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_R16F, VK_FORMAT_R16_SFLOAT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_R32F, VK_FORMAT_R32_SFLOAT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, {PTI_DEPTH16, VK_FORMAT_D16_UNORM, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, {PTI_DEPTH24, VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, @@ -4566,7 +4570,12 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre Con_Printf("VK_ERROR_INCOMPATIBLE_DRIVER: please install an appropriate vulkan driver\n"); return false; case VK_ERROR_EXTENSION_NOT_PRESENT: - Con_Printf("VK_ERROR_EXTENSION_NOT_PRESENT: something on a system level is probably misconfigured\n"); + case VK_ERROR_FEATURE_NOT_PRESENT: + case VK_ERROR_INITIALIZATION_FAILED: + case VK_ERROR_DEVICE_LOST: + case VK_ERROR_OUT_OF_HOST_MEMORY: + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + Con_Printf("%s: something on a system level is probably misconfigured\n", VK_VKErrorToString(err)); return false; default: Con_Printf("Unknown vulkan device creation error: %x\n", err); @@ -4635,12 +4644,12 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre sh_config.pValidateProgram = NULL; sh_config.pProgAutoFields = NULL; - if (sh_config.texfmt[PTI_DEPTH32]) - vk.depthformat = VK_FORMAT_D32_SFLOAT; - else if (sh_config.texfmt[PTI_DEPTH24]) + if (sh_config.texfmt[PTI_DEPTH24]) vk.depthformat = VK_FORMAT_X8_D24_UNORM_PACK32; else if (sh_config.texfmt[PTI_DEPTH24_8]) vk.depthformat = VK_FORMAT_D24_UNORM_S8_UINT; + else if (sh_config.texfmt[PTI_DEPTH32]) //nvidia recommend to de-prioritise 32bit (float) depth. + vk.depthformat = VK_FORMAT_D32_SFLOAT; else //16bit depth is guarenteed in vulkan vk.depthformat = VK_FORMAT_D16_UNORM; diff --git a/plugins/irc/ircclient.c b/plugins/irc/ircclient.c index 0076ed430..aa9b345c0 100644 --- a/plugins/irc/ircclient.c +++ b/plugins/irc/ircclient.c @@ -950,6 +950,68 @@ static void magic_etghack(char *thestring) } +static void IRC_TryNewNick(ircclient_t *irc, char *nickname) +{ + char *seedednick; + + IRC_CvarUpdate(); + + if (irc->tlsmode == TLS_STARTING) + { + //don't submit any of this info here. + return; + } + if (irc->connecting) + { + if (irc->nicktries == 0) + { + irc->nicktries++; + if (*irc->primarynick && strcmp(nickname, irc->primarynick)) + { + IRC_SetNick(irc, irc->primarynick); + return; + } + } + if (irc->nicktries == 1) + { + irc->nicktries++; + if (*irc_nick.string && strcmp(nickname, irc_nick.string)) + { + IRC_SetNick(irc, irc_nick.string); + return; + } + } + if (irc->nicktries == 2) + { + irc->nicktries++; + if (*irc_altnick.string && strcmp(nickname, irc_altnick.string)) + { + IRC_SetNick(irc, irc_altnick.string); + return; + } + } + + if (++irc->nicktries == 10) + { + IRC_Printf(irc, DEFAULTCONSOLE, COLOURRED "ERROR: Unable to obtain usable nickname\n"); + return; + } + + //panic and pick something at random + //IRC_Printf(irc, DEFAULTCONSOLE, COLOURRED "ERROR: primary nickname in use. Attempting random nickname.\n"); + if (*irc->primarynick && irc->nicktries < 7) + seedednick = va("%.6s%i", irc->primarynick, rand()); + else if (*irc_nick.string && irc->nicktries < 8) + seedednick = va("%.6s%i", irc_nick.string, rand()); + else if (*irc_altnick.string && irc->nicktries < 9) + seedednick = va("%.6s%i", irc_altnick.string, rand()); + else + seedednick = va("%.6s%i", "FTE", rand()); + seedednick[9] = 0; //'Each client is distinguished from other clients by a unique nickname having a maximum length of nine (9) characters' + + IRC_SetNick(irc, seedednick); + } +} //================================================== @@ -1154,7 +1216,8 @@ static void numbered_command(int comm, char *msg, ircclient_t *irc) // move vars case 432: /* #define ERR_ERRONEUSNICKNAME 432 */ { IRC_Printf(irc, DEFAULTCONSOLE, "Erroneous/invalid nickname given\n"); - goto trynewnick; + IRC_TryNewNick(irc, "FTEUser"); + return; } case 433: /* #define ERR_NICKNAMEINUSE 433 */ case 438: @@ -1162,73 +1225,15 @@ static void numbered_command(int comm, char *msg, ircclient_t *irc) // move vars { char *nickname = strtok(casevar[4], " "); char *badnickname = ":Nickname"; - char *seedednick; if ( !strcasecmp(nickname,badnickname) ) // bug with ircd, the nickname actually shifts position. { nickname = strtok(casevar[3], " "); } - IRC_CvarUpdate(); - // IRC_Printf(irc, DEFAULTCONSOLE, COLOURRED "ERROR: <%s> is already in use.\n",nickname); -trynewnick: - if (irc->tlsmode == TLS_STARTING) - { - //don't submit any of this info here. - return; - } - if (irc->connecting) - { - if (irc->nicktries == 0) - { - irc->nicktries++; - if (*irc->primarynick && strcmp(nickname, irc->primarynick)) - { - IRC_SetNick(irc, irc->primarynick); - return; - } - } - if (irc->nicktries == 1) - { - irc->nicktries++; - if (*irc_nick.string && strcmp(nickname, irc_nick.string)) - { - IRC_SetNick(irc, irc_nick.string); - return; - } - } - if (irc->nicktries == 2) - { - irc->nicktries++; - if (*irc_altnick.string && strcmp(nickname, irc_altnick.string)) - { - IRC_SetNick(irc, irc_altnick.string); - return; - } - } - - if (++irc->nicktries == 10) - { - IRC_Printf(irc, DEFAULTCONSOLE, COLOURRED "ERROR: Unable to obtain usable nickname\n"); - return; - } - - //panic and pick something at random - //IRC_Printf(irc, DEFAULTCONSOLE, COLOURRED "ERROR: primary nickname in use. Attempting random nickname.\n"); - if (*irc->primarynick && irc->nicktries < 7) - seedednick = va("%.6s%i", irc->primarynick, rand()); - else if (*irc_nick.string && irc->nicktries < 8) - seedednick = va("%.6s%i", irc_nick.string, rand()); - else if (*irc_altnick.string && irc->nicktries < 9) - seedednick = va("%.6s%i", irc_altnick.string, rand()); - else - seedednick = va("%.6s%i", "FTE", rand()); - seedednick[9] = 0; //'Each client is distinguished from other clients by a unique nickname having a maximum length of nine (9) characters' - - IRC_SetNick(irc, seedednick); - } + IRC_TryNewNick(irc, nickname); return; } case 471: /* ERR_CHANNELISFULL */