diff options
Diffstat (limited to 'src/jake2/client/CL.java')
-rw-r--r-- | src/jake2/client/CL.java | 3207 |
1 files changed, 1625 insertions, 1582 deletions
diff --git a/src/jake2/client/CL.java b/src/jake2/client/CL.java index 3170112..dcdf7db 100644 --- a/src/jake2/client/CL.java +++ b/src/jake2/client/CL.java @@ -2,36 +2,39 @@ * CL.java * Copyright (C) 2004 * - * $Id: CL.java,v 1.10 2004-09-08 09:37:39 hzi Exp $ + * $Id: CL.java,v 1.11 2004-09-22 19:22:08 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + Copyright (C) 1997-2001 Id Software, Inc. -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -See the GNU General Public License for more details. + See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ + */ package jake2.client; import jake2.Defines; import jake2.Globals; import jake2.game.*; import jake2.qcommon.*; +import jake2.qcommon.qfiles.dmdl_t; import jake2.server.SV_MAIN; import jake2.sound.*; import jake2.sys.*; +import jake2.util.Lib; +import jake2.util.Math3D; import jake2.util.Vargs; import java.io.IOException; @@ -42,1590 +45,1630 @@ import java.nio.ByteOrder; /** * CL */ -public final class CL extends CL_pred { - - /* - ==================== - CL_WriteDemoMessage - - Dumps the current net message, prefixed by the length - ==================== - */ - static void WriteDemoMessage() { - int swlen; - - // the first eight bytes are just packet sequencing stuff - swlen = net_message.cursize - 8; - - try { - cls.demofile.writeInt(swlen); - //fwrite (&swlen, 4, 1, cls.demofile); - cls.demofile.write(net_message.data, 8, swlen); - //fwrite (net_message.data+8, len, 1, cls.demofile); - } catch (IOException e) {} - - } - - /* - ==================== - CL_Stop_f - - stop recording a demo - ==================== - */ - static xcommand_t Stop_f = new xcommand_t() { - public void execute() { - try { - - int len; - - if (!cls.demorecording) { - Com.Printf("Not recording a demo.\n"); - return; - } - - // finish up - len = -1; - cls.demofile.writeInt(len); - cls.demofile.close(); - cls.demofile = null; - cls.demorecording = false; - Com.Printf("Stopped demo.\n"); - } - catch (IOException e) { - } - } - }; - - /* - ==================== - CL_Record_f - - record <demoname> - - Begins recording a demo from the current position - ==================== - */ - static entity_state_t nullstate = new entity_state_t(null); - - static xcommand_t Record_f = new xcommand_t() { - public void execute() { - try { - String name; - byte buf_data[] = new byte[MAX_MSGLEN]; - sizebuf_t buf = new sizebuf_t(); - int i; - entity_state_t ent; - - if (Cmd.Argc() != 2) { - Com.Printf("record <demoname>\n"); - return; - } - - if (cls.demorecording) { - Com.Printf("Already recording.\n"); - return; - } - - if (cls.state != ca_active) { - Com.Printf("You must be in a level to record.\n"); - return; - } - - // - // open the demo file - // - name = FS.Gamedir() + "/demos/" + Cmd.Argv(1) + ".dm2"; - - Com.Printf("recording to " + name + ".\n"); - FS.CreatePath(name); - cls.demofile = new RandomAccessFile(name, "rw"); - if (cls.demofile == null) { - Com.Printf("ERROR: couldn't open.\n"); - return; - } - cls.demorecording = true; - - // don't start saving messages until a non-delta compressed message is received - cls.demowaiting = true; - - // - // write out messages to hold the startup information - // - SZ.Init(buf, buf_data, MAX_MSGLEN); - - // send the serverdata - MSG.WriteByte(buf, svc_serverdata); - MSG.WriteInt(buf, PROTOCOL_VERSION); - MSG.WriteInt(buf, 0x10000 + cl.servercount); - MSG.WriteByte(buf, 1); // demos are always attract loops - MSG.WriteString(buf, cl.gamedir); - MSG.WriteShort(buf, cl.playernum); - - MSG.WriteString(buf, cl.configstrings[CS_NAME]); - - // configstrings - for (i = 0; i < MAX_CONFIGSTRINGS; i++) { - if (cl.configstrings[i].length()>0) { - if (buf.cursize + cl.configstrings[i].length() + 32 > buf.maxsize) { // write it out - //len = LittleLong(buf.cursize); - //fwrite(& len, 4, 1, cls.demofile); - cls.demofile.writeInt(buf.cursize); - //fwrite(buf.data, buf.cursize, 1, cls.demofile); - cls.demofile.write(buf.data, 0, buf.cursize); - buf.cursize = 0; - } - - MSG.WriteByte(buf, svc_configstring); - MSG.WriteShort(buf, i); - MSG.WriteString(buf, cl.configstrings[i]); - } - - } - - // baselines - //memset( nullstate, 0, sizeof(nullstate)); - for (i = 0; i < MAX_EDICTS; i++) { - ent = cl_entities[i].baseline; - if (ent.modelindex == 0) - continue; - - if (buf.cursize + 64 > buf.maxsize) { // write it out - //len = LittleLong(buf.cursize); - //fwrite(& len, 4, 1, cls.demofile); - cls.demofile.writeInt(buf.cursize); - //fwrite(buf.data, buf.cursize, 1, cls.demofile); - cls.demofile.write(buf.data, 0, buf.cursize); - buf.cursize = 0; - } - - MSG.WriteByte(buf, svc_spawnbaseline); - MSG.WriteDeltaEntity(nullstate, cl_entities[i].baseline, buf, true, true); - } - - MSG.WriteByte(buf, svc_stufftext); - MSG.WriteString(buf, "precache\n"); - - // write it to the demo file - - //len = LittleLong(buf.cursize); - //fwrite(& len, 4, 1, cls.demofile); - cls.demofile.writeInt(buf.cursize); - //fwrite(buf.data, buf.cursize, 1, cls.demofile); - cls.demofile.write(buf.data, 0, buf.cursize); - // the rest of the demo file will be individual frames - - } - catch (IOException e) { - } - } - }; - - /* - ================== - CL_ForwardToServer_f - ================== - */ - static xcommand_t ForwardToServer_f = new xcommand_t() { - public void execute() { - if (cls.state != ca_connected && cls.state != ca_active) { - Com.Printf("Can't \"" + Cmd.Argv(0) + "\", not connected\n"); - return; - } - - // don't forward the first argument - if (Cmd.Argc() > 1) { - MSG.WriteByte(cls.netchan.message, clc_stringcmd); - SZ.Print(cls.netchan.message, Cmd.Args()); - } - } - }; - - /* - ================== - CL_Pause_f - ================== - */ - static xcommand_t Pause_f = new xcommand_t() { - public void execute() { - // never pause in multiplayer - - if (Cvar.VariableValue("maxclients") > 1 || Globals.server_state == 0) { - Cvar.SetValue("paused", 0); - return; - } - - Cvar.SetValue("paused", cl_paused.value); - } - }; - - /* - ================== - CL_Quit_f - ================== - */ - static xcommand_t Quit_f = new xcommand_t() { - public void execute() { - Disconnect(); - Com.Quit(); - } - }; - - /* - ======================= - CL_SendConnectPacket - - We have gotten a challenge from the server, so try and - connect. - ====================== - */ - static void SendConnectPacket() { - netadr_t adr = new netadr_t(); - int port; - - if (!NET.StringToAdr(cls.servername, adr)) { - Com.Printf("Bad server address\n"); - cls.connect_time = 0; - return; - } - if (adr.port == 0) - adr.port = PORT_SERVER; - // adr.port = BigShort(PORT_SERVER); - - port = (int) Cvar.VariableValue("qport"); - userinfo_modified = false; - - Netchan.OutOfBandPrint( - NS_CLIENT, - adr, - "connect " + PROTOCOL_VERSION + " " + port + " " + cls.challenge + " \"" + Cvar.Userinfo() + "\"\n"); - } - - /* - ================= - CL_CheckForResend - - Resend a connect message if the last one has timed out - ================= - */ - static void CheckForResend() { - netadr_t adr = new netadr_t(); - - // if the local server is running and we aren't - // then connect - if (cls.state == ca_disconnected && Globals.server_state != 0) { - cls.state = ca_connecting; - cls.servername = "localhost"; - // we don't need a challenge on the localhost - CL.SendConnectPacket(); - return; - } - - // resend if we haven't gotten a reply yet - if (cls.state != ca_connecting) - return; - - if (cls.realtime - cls.connect_time < 3000) - return; - - if (!NET.StringToAdr(cls.servername, adr)) { - Com.Printf("Bad server address\n"); - cls.state = ca_disconnected; - return; - } - if (adr.port == 0) - // adr.port = BigShort(PORT_SERVER); - adr.port = PORT_SERVER; - - cls.connect_time = cls.realtime; // for retransmit requests - - Com.Printf("Connecting to " + cls.servername + "...\n"); - - Netchan.OutOfBandPrint(NS_CLIENT, adr, "getchallenge\n"); - } - - /* - ================ - CL_Connect_f - - ================ - */ - static xcommand_t Connect_f = new xcommand_t() { - public void execute() { - String server; - - if (Cmd.Argc() != 2) { - Com.Printf("usage: connect <server>\n"); - return; - } - - if (Globals.server_state != 0) { - // if running a local server, kill it and reissue - SV_MAIN.SV_Shutdown("Server quit\n", false); - } else { - CL.Disconnect(); - } - - server = Cmd.Argv(1); - - NET.Config(true); // allow remote - - CL.Disconnect(); - - cls.state = ca_connecting; - //strncpy (cls.servername, server, sizeof(cls.servername)-1); - cls.servername = server; - cls.connect_time = -99999; - // CL_CheckForResend() will fire immediately - } - }; - - /* - ===================== - CL_Rcon_f - - Send the rest of the command line over as - an unconnected command. - ===================== - */ - static xcommand_t Rcon_f = new xcommand_t() { - public void execute() { - StringBuffer message = new StringBuffer(1024); - int i; - netadr_t to = new netadr_t(); - - if (rcon_client_password.string == null) { - Com.Printf("You must set 'rcon_password' before\nissuing an rcon command.\n"); - return; - } - - message.append((char)255); - message.append((char)255); - message.append((char)255); - message.append((char)255); - - NET.Config(true); // allow remote - - //strcat (message, "rcon "); - message.append("rcon "); - - //strcat (message, rcon_client_password.string); - message.append(rcon_client_password.string); - //strcat (message, " "); - message.append(" "); - - for (i = 1; i < Cmd.Argc(); i++) { - //strcat (message, Cmd.Argv(i)); - message.append(Cmd.Argv(i)); - //strcat (message, " "); - message.append(" "); - } - - if (cls.state >= ca_connected) - to = cls.netchan.remote_address; - else { - if (rcon_address.string.length() == 0) { - Com.Printf( - "You must either be connected,\nor set the 'rcon_address' cvar\nto issue rcon commands\n"); - - return; - } - NET.StringToAdr(rcon_address.string, to); - if (to.port == 0) - //to.port = BigShort (PORT_SERVER); - to.port = PORT_SERVER; - } - message.append('\0'); - String b = message.toString(); - NET.SendPacket(NS_CLIENT, b.length(), b.getBytes(), to); - } - }; - - /* - ===================== - CL_ClearState - - ===================== - */ - - static void ClearState() { - S.StopAllSounds(); - CL.ClearEffects(); - CL.ClearTEnts(); - - // wipe the entire cl structure - - cl = new client_state_t(); - for (int i = 0; i < cl_entities.length; i++) { - cl_entities[i] = new centity_t(); - } - - SZ.Clear(cls.netchan.message); - } - - /* - ===================== - CL_Disconnect - - Goes from a connected state to full screen console state - Sends a disconnect message to the server - This is also called on Com_Error, so it shouldn't cause any errors - ===================== - */ - - static void Disconnect() { - - String fin; - - if (cls.state == ca_disconnected) - return; - - if (cl_timedemo != null && cl_timedemo.value != 0.0f) { - int time; - - time = (int) (Sys.Milliseconds() - cl.timedemo_start); - if (time > 0) - Com.Printf( - "%i frames, %3.1f seconds: %3.1f fps\n", - new Vargs(3).add(cl.timedemo_frames).add(time / 1000.0).add(cl.timedemo_frames * 1000.0 / time)); - } - - VectorClear(cl.refdef.blend); - //re.CinematicSetPalette(null); - - Menu.ForceMenuOff(); - - cls.connect_time = 0; - - // SCR.StopCinematic(); - - if (cls.demorecording) - CL.Stop_f.execute(); - - // send a disconnect message to the server - fin = (char) clc_stringcmd + "disconnect"; - Netchan.Transmit(cls.netchan, fin.length(), fin.getBytes()); - Netchan.Transmit(cls.netchan, fin.length(), fin.getBytes()); - Netchan.Transmit(cls.netchan, fin.length(), fin.getBytes()); - - CL.ClearState(); - - // stop download - if (cls.download != null) { - fclose(cls.download); - cls.download = null; - // fclose(cls.download); - // cls.download = NULL; - } - - cls.state = ca_disconnected; - } - - static xcommand_t Disconnect_f = new xcommand_t() { - public void execute() { - Com.Error(ERR_DROP, "Disconnected from server"); - } - }; - - /* - ================= - CL_Changing_f - - Just sent as a hint to the client that they should - drop to full console - ================= - */ - static xcommand_t Changing_f = new xcommand_t() { - public void execute() { - //ZOID - //if we are downloading, we don't change! - // This so we don't suddenly stop downloading a map - - if (cls.download != null) - return; - - SCR.BeginLoadingPlaque(); - cls.state = ca_connected; // not active anymore, but not disconnected - Com.Printf("\nChanging map...\n"); - } - }; - - /* - ================= - CL_Reconnect_f - - The server is changing levels - ================= - */ - static xcommand_t Reconnect_f = new xcommand_t() { - public void execute() { - //ZOID - //if we are downloading, we don't change! This so we don't suddenly stop downloading a map - if (cls.download != null) - return; - - S.StopAllSounds(); - if (cls.state == ca_connected) { - Com.Printf("reconnecting...\n"); - cls.state = ca_connected; - MSG.WriteChar(cls.netchan.message, clc_stringcmd); - MSG.WriteString(cls.netchan.message, "new"); - return; - } - - if (cls.servername != null) { - if (cls.state >= ca_connected) { - CL.Disconnect(); - cls.connect_time = cls.realtime - 1500; - } else - cls.connect_time = -99999; // fire immediately - - cls.state = ca_connecting; - Com.Printf("reconnecting...\n"); - } - } - }; - - /* - ================= - CL_ParseStatusMessage - - Handle a reply from a ping - ================= - */ - static void ParseStatusMessage() { - String s; - - s = MSG.ReadString(net_message); - - Com.Printf(s + "\n"); - Menu.AddToServerList(net_from, s); - } - - /* - ================= - CL_PingServers_f - ================= - */ - static xcommand_t PingServers_f = new xcommand_t() { - public void execute() { - int i; - netadr_t adr = new netadr_t(); - //char name[32]; - String name; - String adrstring; - cvar_t noudp; - cvar_t noipx; - - NET.Config(true); // allow remote - - // send a broadcast packet - Com.Printf("pinging broadcast...\n"); - - noudp = Cvar.Get("noudp", "0", CVAR_NOSET); - if (noudp.value == 0.0f) { - adr.type = NA_BROADCAST; - adr.port = PORT_SERVER; - //adr.port = BigShort(PORT_SERVER); - Netchan.OutOfBandPrint(NS_CLIENT, adr, "info " + PROTOCOL_VERSION); - } - - // we use no IPX - noipx = Cvar.Get("noipx", "1", CVAR_NOSET); - if (noipx.value == 0.0f) { - adr.type = NA_BROADCAST_IPX; - //adr.port = BigShort(PORT_SERVER); - adr.port = PORT_SERVER; - Netchan.OutOfBandPrint(NS_CLIENT, adr, "info " + PROTOCOL_VERSION); - } - - // send a packet to each address book entry - for (i = 0; i < 16; i++) { - //Com_sprintf (name, sizeof(name), "adr%i", i); - name = "adr" + i; - adrstring = Cvar.VariableString(name); - if (adrstring == null || adrstring.length() == 0) - continue; - - Com.Printf("pinging " + adrstring + "...\n"); - if (!NET.StringToAdr(adrstring, adr)) { - Com.Printf("Bad address: " + adrstring + "\n"); - continue; - } - if (adr.port == 0) - //adr.port = BigShort(PORT_SERVER); - adr.port = PORT_SERVER; - Netchan.OutOfBandPrint(NS_CLIENT, adr, "info " + PROTOCOL_VERSION); - } - } - }; - - - /* - ================= - CL_Skins_f - - Load or download any custom player skins and models - ================= - */ - static xcommand_t Skins_f = new xcommand_t() { - public void execute() { - int i; - - for (i = 0; i < MAX_CLIENTS; i++) { - if (cl.configstrings[CS_PLAYERSKINS + i] == null) - continue; - Com.Printf("client " + i + ": " + cl.configstrings[CS_PLAYERSKINS + i] + "\n"); - SCR.UpdateScreen(); - Sys.SendKeyEvents(); // pump message loop - CL.ParseClientinfo(i); - } - } - }; - - /* - ================= - CL_ConnectionlessPacket - - Responses to broadcasts, etc - ================= - */ - static void ConnectionlessPacket() { - String s; - String c; - - MSG.BeginReading(net_message); - MSG.ReadLong(net_message); // skip the -1 - - s = MSG.ReadStringLine(net_message); - - Cmd.TokenizeString(s.toCharArray(), false); - - c = Cmd.Argv(0); - - Com.Printf(NET.AdrToString(net_from) + ": " + c + "\n"); - - // server connection - if (c.equals("client_connect")) { - if (cls.state == ca_connected) { - Com.Printf("Dup connect received. Ignored.\n"); - return; - } - Netchan.Setup(NS_CLIENT, cls.netchan, net_from, cls.quakePort); - MSG.WriteChar(cls.netchan.message, clc_stringcmd); - MSG.WriteString(cls.netchan.message, "new"); - cls.state = ca_connected; - return; - } - - // server responding to a status broadcast - if (c.equals("info")) { - CL.ParseStatusMessage(); - return; - } - - // remote command from gui front end - if (c.equals ("cmd")) { - if (!NET.IsLocalAddress(net_from)) { - Com.Printf("Command packet from remote host. Ignored.\n"); - return; - } - s = MSG.ReadString(net_message); - Cbuf.AddText(s); - Cbuf.AddText("\n"); - return; - } - // print command from somewhere - if (c.equals("print")) { - s = MSG.ReadString(net_message); - Com.Printf(s); - return; - } - - // ping from somewhere - if (c.equals("ping")) { - Netchan.OutOfBandPrint(NS_CLIENT, net_from, "ack"); - return; - } - - // challenge from the server we are connecting to - if (c.equals("challenge")) { - cls.challenge = Integer.parseInt(Cmd.Argv(1)); - CL.SendConnectPacket(); - return; - } - - // echo request from server - if (c.equals("echo")) { - Netchan.OutOfBandPrint(NS_CLIENT, net_from, Cmd.Argv(1)); - return; - } - - Com.Printf("Unknown command.\n"); - } - - /* - ================= - CL_DumpPackets - - A vain attempt to help bad TCP stacks that cause problems - when they overflow - ================= - */ - static void DumpPackets() { - while (NET.GetPacket(NS_CLIENT, net_from, net_message)) { - Com.Printf("dumping a packet\n"); - } - } - - /* - ================= - CL_ReadPackets - ================= - */ - static void ReadPackets() { - while (NET.GetPacket(NS_CLIENT, net_from, net_message)) { - - // - // remote command packet - // - if (net_message.data[0] == -1 && net_message.data[1] == -1 - && net_message.data[2] == -1 && net_message.data[3] == -1) { - // if (*(int *)net_message.data == -1) - CL.ConnectionlessPacket(); - continue; - } - - if (cls.state == ca_disconnected || cls.state == ca_connecting) - continue; // dump it if not connected - - if (net_message.cursize < 8) { - Com.Printf(NET.AdrToString(net_from) + ": Runt packet\n"); - continue; - } - - // - // packet from server - // - if (!NET.CompareAdr(net_from, cls.netchan.remote_address)) { - Com.DPrintf(NET.AdrToString(net_from) + ":sequenced packet without connection\n"); - continue; - } - if (!Netchan.Process(cls.netchan, net_message)) - continue; // wasn't accepted for some reason - ParseServerMessage(); - } - - // - // check timeout - // - if (cls.state >= ca_connected && cls.realtime - cls.netchan.last_received > cl_timeout.value * 1000) { - if (++cl.timeoutcount > 5) // timeoutcount saves debugger - { - Com.Printf("\nServer connection timed out.\n"); - CL.Disconnect(); - return; - } - } - else - cl.timeoutcount = 0; - } - - // ============================================================================= - - /* - ============== - CL_FixUpGender_f - ============== - */ - static void FixUpGender() { - - String sk; - - if (gender_auto.value != 0.0f) { - - if (gender.modified) { - // was set directly, don't override the user - gender.modified = false; - return; - } - - sk = skin.string; - if (sk.startsWith("male") || sk.startsWith("cyborg")) - Cvar.Set("gender", "male"); - else if (sk.startsWith("female") || sk.startsWith("crackhor")) - Cvar.Set("gender", "female"); - else - Cvar.Set("gender", "none"); - gender.modified = false; - } - } - - /* - ============== - CL_Userinfo_f - ============== - */ - static xcommand_t Userinfo_f = new xcommand_t() { - public void execute() { - Com.Printf("User info settings:\n"); - Info.Print(Cvar.Userinfo()); - } - }; - - /* - ================= - CL_Snd_Restart_f - - Restart the sound subsystem so it can pick up - new parameters and flush all sounds - ================= - */ - static xcommand_t Snd_Restart_f = new xcommand_t() { - public void execute() { - S.Shutdown(); - S.Init(); - CL.RegisterSounds(); - } - }; - - static int precache_check; // for autodownload of precache items - static int precache_spawncount; - static int precache_tex; - static int precache_model_skin; - - static byte precache_model[]; // used for skin checking in alias models - - public static final int PLAYER_MULT = 5; - - // ENV_CNT is map load, ENV_CNT+1 is first env map - public static final int ENV_CNT = (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT); - public static final int TEXTURE_CNT = (ENV_CNT + 13); - - static String env_suf[] = { "rt", "bk", "lf", "ft", "up", "dn" }; - - public static void RequestNextDownload() { - int map_checksum = 0; // for detecting cheater maps - //char fn[MAX_OSPATH]; - String fn; - - qfiles.dmdl_t pheader; - - if (cls.state != ca_connected) - return; - - if (SV_MAIN.allow_download.value == 0 && precache_check < ENV_CNT) - precache_check = ENV_CNT; - - // ZOID - if (precache_check == CS_MODELS) { // confirm map - precache_check = CS_MODELS + 2; // 0 isn't used - if (SV_MAIN.allow_download_maps.value != 0) - if (!CheckOrDownloadFile(cl.configstrings[CS_MODELS + 1])) - return; // started a download - } - if (precache_check >= CS_MODELS && precache_check < CS_MODELS + MAX_MODELS) { - if (SV_MAIN.allow_download_models.value != 0) { - while (precache_check < CS_MODELS + MAX_MODELS && cl.configstrings[precache_check].length() > 0) { - if (cl.configstrings[precache_check].charAt(0) == '*' || cl.configstrings[precache_check].charAt(0) == '#') { - precache_check++; - continue; - } - if (precache_model_skin == 0) { - if (!CheckOrDownloadFile(cl.configstrings[precache_check])) { - precache_model_skin = 1; - return; // started a download - } - precache_model_skin = 1; - } - - // checking for skins in the model - if (precache_model == null) { - - precache_model = FS.LoadFile(cl.configstrings[precache_check]); - if (precache_model == null) { - precache_model_skin = 0; - precache_check++; - continue; // couldn't load it - } - ByteBuffer bb = ByteBuffer.wrap(precache_model); - bb.order(ByteOrder.LITTLE_ENDIAN); - - int header = bb.getInt(); - - if (header != qfiles.IDALIASHEADER) { - // not an alias model - FS.FreeFile(precache_model); - precache_model = null; - precache_model_skin = 0; - precache_check++; - continue; - } - pheader = new qfiles.dmdl_t(ByteBuffer.wrap(precache_model).order(ByteOrder.LITTLE_ENDIAN)); - if (pheader.version != ALIAS_VERSION) { - precache_check++; - precache_model_skin = 0; - continue; // couldn't load it - } - } - - pheader = new qfiles.dmdl_t(ByteBuffer.wrap(precache_model).order(ByteOrder.LITTLE_ENDIAN)); - - int num_skins = pheader.num_skins; - - while (precache_model_skin - 1 < num_skins) { - //Com.Printf("critical code section because of endian mess!\n"); - - String name = - new String( - precache_model, - pheader.ofs_skins + (precache_model_skin - 1) * MAX_SKINNAME, - MAX_SKINNAME * num_skins); - - if (!CheckOrDownloadFile(name)) { - precache_model_skin++; - return; // started a download - } - precache_model_skin++; - } - if (precache_model != null) { - FS.FreeFile(precache_model); - precache_model = null; - } - precache_model_skin = 0; - precache_check++; - } - } - precache_check = CS_SOUNDS; - } - if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS + MAX_SOUNDS) { - if (SV_MAIN.allow_download_sounds.value != 0) { - if (precache_check == CS_SOUNDS) - precache_check++; // zero is blank - while (precache_check < CS_SOUNDS + MAX_SOUNDS && cl.configstrings[precache_check].length() > 0) { - if (cl.configstrings[precache_check].charAt(0) == '*') { - precache_check++; - continue; - } - fn = "sound/" + cl.configstrings[precache_check++]; - if (!CheckOrDownloadFile(fn)) - return; // started a download - } - } - precache_check = CS_IMAGES; - } - if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES + MAX_IMAGES) { - if (precache_check == CS_IMAGES) - precache_check++; // zero is blank - - while (precache_check < CS_IMAGES + MAX_IMAGES && cl.configstrings[precache_check].length() > 0) { - fn = "pics/" + cl.configstrings[precache_check++] + ".pcx"; - if (!CheckOrDownloadFile(fn)) - return; // started a download - } - precache_check = CS_PLAYERSKINS; - } - // skins are special, since a player has three things to download: - // model, weapon model and skin - // so precache_check is now *3 - if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) { - if (SV_MAIN.allow_download_players.value != 0) { - while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) { - - int i, n; - //char model[MAX_QPATH], skin[MAX_QPATH], * p; - String model, skin; - - i = (precache_check - CS_PLAYERSKINS) / PLAYER_MULT; - n = (precache_check - CS_PLAYERSKINS) % PLAYER_MULT; - - if (cl.configstrings[CS_PLAYERSKINS + i].length() == 0) { - precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT; - continue; - } - - int pos = cl.configstrings[CS_PLAYERSKINS + i].indexOf('\\'); - if (pos != -1) - pos++; - else - pos = 0; - - model = cl.configstrings[CS_PLAYERSKINS + i].substring(pos); - - pos = model.indexOf('/'); - - if (pos == -1) - pos = model.indexOf('\\'); - - if (pos != -1) { - skin = model.substring(pos + 1); - } - else - skin = ""; - - switch (n) { - case 0 : // model - fn = "players/" + model + "/tris.md2"; - if (!CheckOrDownloadFile(fn)) { - precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1; - return; // started a download - } - n++; - /*FALL THROUGH*/ - - case 1 : // weapon model - fn = "players/" + model + "/weapon.md2"; - if (!CheckOrDownloadFile(fn)) { - precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2; - return; // started a download - } - n++; - /*FALL THROUGH*/ - - case 2 : // weapon skin - fn = "players/" + model + "/weapon.pcx"; - if (!CheckOrDownloadFile(fn)) { - precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3; - return; // started a download - } - n++; - /*FALL THROUGH*/ - - case 3 : // skin - fn = "players/" + model + "/" + skin + ".pcx"; - if (!CheckOrDownloadFile(fn)) { - precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4; - return; // started a download - } - n++; - /*FALL THROUGH*/ - - case 4 : // skin_i - fn = "players/" + model + "/" + skin + "_i.pcx"; - if (!CheckOrDownloadFile(fn)) { - precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5; - return; // started a download - } - // move on to next model - precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT; - } - } - } - // precache phase completed - precache_check = ENV_CNT; - } - - if (precache_check == ENV_CNT) { - precache_check = ENV_CNT + 1; - - int iw[] = {map_checksum}; - - CM.CM_LoadMap(cl.configstrings[CS_MODELS + 1], true, iw); - map_checksum = iw[0]; - - if ((map_checksum ^ atoi(cl.configstrings[CS_MAPCHECKSUM])) != 0) { - Com.Error( - ERR_DROP, - "Local map version differs from server: " + map_checksum + " != '" + cl.configstrings[CS_MAPCHECKSUM] + "'\n"); - return; - } - } - - if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) { - if (SV_MAIN.allow_download.value != 0 && SV_MAIN.allow_download_maps.value != 0) { - while (precache_check < TEXTURE_CNT) { - int n = precache_check++ -ENV_CNT - 1; - - if ((n & 1) != 0) - fn = "env/" + cl.configstrings[CS_SKY] + env_suf[n / 2] + ".pcx"; - else - fn = "env/" + cl.configstrings[CS_SKY] + env_suf[n / 2] + ".tga"; - if (!CheckOrDownloadFile(fn)) - return; // started a download - } - } - precache_check = TEXTURE_CNT; - } - - if (precache_check == TEXTURE_CNT) { - precache_check = TEXTURE_CNT + 1; - precache_tex = 0; - } - - // confirm existance of textures, download any that don't exist - if (precache_check == TEXTURE_CNT + 1) { - // from qcommon/cmodel.c - // extern int numtexinfo; - // extern mapsurface_t map_surfaces[]; - - if (SV_MAIN.allow_download.value != 0 && SV_MAIN.allow_download_maps.value != 0) { - while (precache_tex < CM.numtexinfo) { - //char fn[MAX_OSPATH]; - - fn = "textures/" + CM.map_surfaces[precache_tex++].rname + ".wal"; - if (!CheckOrDownloadFile(fn)) - return; // started a download - } - } - precache_check = TEXTURE_CNT + 999; - } - - // ZOID - CL.RegisterSounds(); - PrepRefresh(); - - MSG.WriteByte(cls.netchan.message, clc_stringcmd); - MSG.WriteString(cls.netchan.message, "begin " + precache_spawncount + "\n"); - } - - /* - ================= - CL_Precache_f - - The server will send this command right - before allowing the client into the server - ================= - */ - static xcommand_t Precache_f = new xcommand_t() { - public void execute() { - /* Yet another hack to let old demos work - the old precache sequence */ - - if (Cmd.Argc() < 2) { - - int iw[] ={0};// for detecting cheater maps - - - CM.CM_LoadMap(cl.configstrings[CS_MODELS + 1], true, iw); - int mapchecksum = iw[0] ; - CL.RegisterSounds(); - CL.PrepRefresh(); - return; - } - - precache_check = CS_MODELS; - precache_spawncount = atoi(Cmd.Argv(1)); - precache_model = null; - precache_model_skin = 0; - - RequestNextDownload(); - } - }; - - /* - ================= - CL_InitLocal - ================= - */ - public static void InitLocal() { - cls.state = Defines.ca_disconnected; - cls.realtime = Sys.Milliseconds(); - - InitInput(); - - // never used !! -// adr0 = Cvar.Get("adr0", "", CVAR_ARCHIVE); -// adr1 = Cvar.Get("adr1", "", CVAR_ARCHIVE); -// adr2 = Cvar.Get("adr2", "", CVAR_ARCHIVE); -// adr3 = Cvar.Get("adr3", "", CVAR_ARCHIVE); -// adr4 = Cvar.Get("adr4", "", CVAR_ARCHIVE); -// adr5 = Cvar.Get("adr5", "", CVAR_ARCHIVE); -// adr6 = Cvar.Get("adr6", "", CVAR_ARCHIVE); -// adr7 = Cvar.Get("adr7", "", CVAR_ARCHIVE); -// adr8 = Cvar.Get("adr8", "", CVAR_ARCHIVE); - - // - // register our variables - // - cl_stereo_separation = Cvar.Get("cl_stereo_separation", "0.4", CVAR_ARCHIVE); - cl_stereo = Cvar.Get("cl_stereo", "0", 0); - - cl_add_blend = Cvar.Get("cl_blend", "1", 0); - cl_add_lights = Cvar.Get("cl_lights", "1", 0); - cl_add_particles = Cvar.Get("cl_particles", "1", 0); - cl_add_entities = Cvar.Get("cl_entities", "1", 0); - cl_gun = Cvar.Get("cl_gun", "1", 0); - cl_footsteps = Cvar.Get("cl_footsteps", "1", 0); - cl_noskins = Cvar.Get("cl_noskins", "0", 0); - cl_autoskins = Cvar.Get("cl_autoskins", "0", 0); - cl_predict = Cvar.Get("cl_predict", "1", 0); - - cl_maxfps = Cvar.Get("cl_maxfps", "90", 0); - - cl_upspeed = Cvar.Get("cl_upspeed", "200", 0); - cl_forwardspeed = Cvar.Get("cl_forwardspeed", "200", 0); - cl_sidespeed = Cvar.Get("cl_sidespeed", "200", 0); - cl_yawspeed = Cvar.Get("cl_yawspeed", "140", 0); - cl_pitchspeed = Cvar.Get("cl_pitchspeed", "150", 0); - cl_anglespeedkey = Cvar.Get("cl_anglespeedkey", "1.5", 0); - - cl_run = Cvar.Get("cl_run", "0", CVAR_ARCHIVE); - lookspring = Cvar.Get("lookspring", "0", CVAR_ARCHIVE); - lookstrafe = Cvar.Get("lookstrafe", "0", CVAR_ARCHIVE); - sensitivity = Cvar.Get("sensitivity", "3", CVAR_ARCHIVE); - - m_pitch = Cvar.Get("m_pitch", "0.022", CVAR_ARCHIVE); - m_yaw = Cvar.Get("m_yaw", "0.022", 0); - m_forward = Cvar.Get("m_forward", "1", 0); - m_side = Cvar.Get("m_side", "1", 0); - - cl_shownet = Cvar.Get("cl_shownet", "0", 0); - cl_showmiss = Cvar.Get("cl_showmiss", "0", 0); - cl_showclamp = Cvar.Get("showclamp", "0", 0); - cl_timeout = Cvar.Get("cl_timeout", "120", 0); - cl_paused = Cvar.Get("paused", "0", 0); - cl_timedemo = Cvar.Get("timedemo", "0", 0); - - rcon_client_password = Cvar.Get("rcon_password", "", 0); - rcon_address = Cvar.Get("rcon_address", "", 0); - - cl_lightlevel = Cvar.Get("r_lightlevel", "0", 0); - - // - // userinfo - // - info_password = Cvar.Get("password", "", CVAR_USERINFO); - info_spectator = Cvar.Get("spectator", "0", CVAR_USERINFO); - name = Cvar.Get("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE); - skin = Cvar.Get("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE); - rate = Cvar.Get("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE); // FIXME - msg = Cvar.Get("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE); - hand = Cvar.Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE); - fov = Cvar.Get("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE); - gender = Cvar.Get("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE); - gender_auto = Cvar.Get("gender_auto", "1", CVAR_ARCHIVE); - gender.modified = false; // clear this so we know when user sets it manually - - cl_vwep = Cvar.Get("cl_vwep", "1", CVAR_ARCHIVE); - - // - // register our commands - // - Cmd.AddCommand("cmd", ForwardToServer_f); - Cmd.AddCommand("pause", Pause_f); - Cmd.AddCommand("pingservers", PingServers_f); - Cmd.AddCommand("skins", Skins_f); - - Cmd.AddCommand("userinfo", Userinfo_f); - Cmd.AddCommand("snd_restart", Snd_Restart_f); - - Cmd.AddCommand("changing", Changing_f); - Cmd.AddCommand("disconnect", Disconnect_f); - Cmd.AddCommand("record", Record_f); - Cmd.AddCommand("stop", Stop_f); - - Cmd.AddCommand("quit", Quit_f); - - Cmd.AddCommand("connect", Connect_f); - Cmd.AddCommand("reconnect", Reconnect_f); - - Cmd.AddCommand("rcon", Rcon_f); - - Cmd.AddCommand("precache", Precache_f); - - Cmd.AddCommand("download", Download_f); - - // - // forward to server commands - // - // the only thing this does is allow command completion - // to work -- all unknown commands are automatically - // forwarded to the server - Cmd.AddCommand("wave", null); - Cmd.AddCommand("inven", null); - Cmd.AddCommand("kill", null); - Cmd.AddCommand("use", null); - Cmd.AddCommand("drop", null); - Cmd.AddCommand("say", null); - Cmd.AddCommand("say_team", null); - Cmd.AddCommand("info", null); - Cmd.AddCommand("prog", null); - Cmd.AddCommand("give", null); - Cmd.AddCommand("god", null); - Cmd.AddCommand("notarget", null); - Cmd.AddCommand("noclip", null); - Cmd.AddCommand("invuse", null); - Cmd.AddCommand("invprev", null); - Cmd.AddCommand("invnext", null); - Cmd.AddCommand("invdrop", null); - Cmd.AddCommand("weapnext", null); - Cmd.AddCommand("weapprev", null); - - } - - /* - =============== - CL_WriteConfiguration - - Writes key bindings and archived cvars to config.cfg - =============== - */ - static void WriteConfiguration() { - RandomAccessFile f; - String path; - - if (cls.state == ca_uninitialized) - return; - - path = FS.Gamedir() + "/config.cfg"; - f = fopen(path, "rw"); - if (f == null) { - Com.Printf("Couldn't write config.cfg.\n"); - return; - } - try - { - f.seek(0); - f.setLength(0); - } - catch (IOException e1) - {} - try { - f.writeBytes("// generated by quake, do not modify\n"); - } - catch (IOException e) {} - - Key.WriteBindings(f); - fclose(f); - Cvar.WriteVariables(path); - } - - /* - ================== - CL_FixCvarCheats - - ================== - */ - public static class cheatvar_t { - String name; - String value; - cvar_t var; - } - - public static String cheatvarsinfo[][] = { { "timescale", "1" }, { - "timedemo", "0" }, { - "r_drawworld", "1" }, { - "cl_testlights", "0" }, { - "r_fullbright", "0" }, { - "r_drawflat", "0" }, { - "paused", "0" }, { - "fixedtime", "0" }, { - "sw_draworder", "0" }, { - "gl_lightmap", "0" }, { - "gl_saturatelighting", "0" }, { - null, null } - }; - public static cheatvar_t cheatvars[]; - - static { - cheatvars = new cheatvar_t[cheatvarsinfo.length]; - for (int n = 0; n < cheatvarsinfo.length; n++) { - cheatvars[n] = new cheatvar_t(); - cheatvars[n].name = cheatvarsinfo[n][0]; - cheatvars[n].value = cheatvarsinfo[n][1]; - } - } - - static int numcheatvars; - - public static void FixCvarCheats() { - int i; - cheatvar_t var; - - if ("1".equals(cl.configstrings[CS_MAXCLIENTS]) || 0 == cl.configstrings[CS_MAXCLIENTS].length()) - return; // single player can cheat - - // find all the cvars if we haven't done it yet - if (0 == numcheatvars) { - while (cheatvars[numcheatvars].name != null) { - cheatvars[numcheatvars].var = Cvar.Get(cheatvars[numcheatvars].name, cheatvars[numcheatvars].value, 0); - numcheatvars++; - } - } - - // make sure they are all set to the proper values - for (i = 0; i < numcheatvars; i++) { - var = cheatvars[i]; - if (!var.var.string.equals(var.value)) { - Cvar.Set(var.name, var.value); - } - } - } - - // ============================================================================ - - /* - ================== - CL_SendCommand - - ================== - */ - public static void SendCommand() { - // get new key events - Sys.SendKeyEvents(); - - // allow mice or other external controllers to add commands - IN.Commands(); - - // process console commands - Cbuf.Execute(); - - // fix any cheating cvars - FixCvarCheats(); - - // send intentions now - SendCmd(); - - // resend a connection request if necessary - CheckForResend(); - } - - /* - ================== - CL_Frame - - ================== - */ - private static int extratime; -// private static int lasttimecalled; - - public static void Frame(int msec) { - - extratime += msec; - - if (cl_timedemo.value == 0.0f) { - if (cls.state == ca_connected && extratime < 100) { - return; // don't flood packets out while connecting - } - if (extratime < 1000 / cl_maxfps.value) { - return; // framerate is too high - } - } - - // let the mouse activate or deactivate - IN.Frame(); - - // decide the simulation time - cls.frametime = extratime / 1000.0f; - cl.time += extratime; - cls.realtime = curtime; - - extratime = 0; - - if (cls.frametime > (1.0f / 5)) - cls.frametime = (1.0f / 5); - - // if in the debugger last frame, don't timeout - if (msec > 5000) - cls.netchan.last_received = Sys.Milliseconds(); - - // fetch results from server - CL.ReadPackets(); - - // send a new command message to the server - SendCommand(); - - // predict all unacknowledged movements - CL.PredictMovement(); - - // allow rendering DLL change - VID.CheckChanges(); - if (!cl.refresh_prepped && cls.state == ca_active) { - CL.PrepRefresh(); - // force GC after level loading - System.gc(); - } - - SCR.UpdateScreen(); - - // update audio - S.Update(cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up); - - // advance local effects for next frame - CL.RunDLights(); - CL.RunLightStyles(); - - SCR.RunConsole(); - - cls.framecount++; - if (cls.state != ca_active || cls.key_dest != key_game) { - try { - Thread.sleep(20); - } catch (InterruptedException e) {} - } - } - - // ============================================================================ +public final class CL { + + static int precache_check; // for autodownload of precache items + + static int precache_spawncount; + + static int precache_tex; + + static int precache_model_skin; + + static byte precache_model[]; // used for skin checking in alias models + + public static final int PLAYER_MULT = 5; + + /* + * ================== CL_FixCvarCheats + * + * ================== + */ + public static class cheatvar_t { + String name; + + String value; + + cvar_t var; + } + + public static String cheatvarsinfo[][] = { { "timescale", "1" }, + { "timedemo", "0" }, { "r_drawworld", "1" }, + { "cl_testlights", "0" }, { "r_fullbright", "0" }, + { "r_drawflat", "0" }, { "paused", "0" }, { "fixedtime", "0" }, + { "sw_draworder", "0" }, { "gl_lightmap", "0" }, + { "gl_saturatelighting", "0" }, { null, null } }; + + public static cheatvar_t cheatvars[]; + + static { + cheatvars = new cheatvar_t[cheatvarsinfo.length]; + for (int n = 0; n < cheatvarsinfo.length; n++) { + cheatvars[n] = new cheatvar_t(); + cheatvars[n].name = cheatvarsinfo[n][0]; + cheatvars[n].value = cheatvarsinfo[n][1]; + } + } + + static int numcheatvars; + + /* + * ==================== CL_Stop_f + * + * stop recording a demo ==================== + */ + static xcommand_t Stop_f = new xcommand_t() { + public void execute() { + try { + + int len; + + if (!Globals.cls.demorecording) { + Com.Printf("Not recording a demo.\n"); + return; + } + + // finish up + len = -1; + Globals.cls.demofile.writeInt(len); + Globals.cls.demofile.close(); + Globals.cls.demofile = null; + Globals.cls.demorecording = false; + Com.Printf("Stopped demo.\n"); + } catch (IOException e) { + } + } + }; + + /* + * ==================== CL_Record_f + * + * record <demoname> + * + * Begins recording a demo from the current position ==================== + */ + static entity_state_t nullstate = new entity_state_t(null); + + static xcommand_t Record_f = new xcommand_t() { + public void execute() { + try { + String name; + byte buf_data[] = new byte[Defines.MAX_MSGLEN]; + sizebuf_t buf = new sizebuf_t(); + int i; + entity_state_t ent; + + if (Cmd.Argc() != 2) { + Com.Printf("record <demoname>\n"); + return; + } + + if (Globals.cls.demorecording) { + Com.Printf("Already recording.\n"); + return; + } + + if (Globals.cls.state != Defines.ca_active) { + Com.Printf("You must be in a level to record.\n"); + return; + } + + // + // open the demo file + // + name = FS.Gamedir() + "/demos/" + Cmd.Argv(1) + ".dm2"; + + Com.Printf("recording to " + name + ".\n"); + FS.CreatePath(name); + Globals.cls.demofile = new RandomAccessFile(name, "rw"); + if (Globals.cls.demofile == null) { + Com.Printf("ERROR: couldn't open.\n"); + return; + } + Globals.cls.demorecording = true; + + // don't start saving messages until a non-delta compressed + // message is received + Globals.cls.demowaiting = true; + + // + // write out messages to hold the startup information + // + SZ.Init(buf, buf_data, Defines.MAX_MSGLEN); + + // send the serverdata + MSG.WriteByte(buf, Defines.svc_serverdata); + MSG.WriteInt(buf, Defines.PROTOCOL_VERSION); + MSG.WriteInt(buf, 0x10000 + Globals.cl.servercount); + MSG.WriteByte(buf, 1); // demos are always attract loops + MSG.WriteString(buf, Globals.cl.gamedir); + MSG.WriteShort(buf, Globals.cl.playernum); + + MSG.WriteString(buf, Globals.cl.configstrings[Defines.CS_NAME]); + + // configstrings + for (i = 0; i < Defines.MAX_CONFIGSTRINGS; i++) { + if (Globals.cl.configstrings[i].length() > 0) { + if (buf.cursize + Globals.cl.configstrings[i].length() + + 32 > buf.maxsize) { // write it out + //len = LittleLong(buf.cursize); + //fwrite(& len, 4, 1, cls.demofile); + Globals.cls.demofile.writeInt(buf.cursize); + //fwrite(buf.data, buf.cursize, 1, cls.demofile); + Globals.cls.demofile + .write(buf.data, 0, buf.cursize); + buf.cursize = 0; + } + + MSG.WriteByte(buf, Defines.svc_configstring); + MSG.WriteShort(buf, i); + MSG.WriteString(buf, Globals.cl.configstrings[i]); + } + + } + + // baselines + //memset( nullstate, 0, sizeof(nullstate)); + for (i = 0; i < Defines.MAX_EDICTS; i++) { + ent = Globals.cl_entities[i].baseline; + if (ent.modelindex == 0) + continue; + + if (buf.cursize + 64 > buf.maxsize) { // write it out + //len = LittleLong(buf.cursize); + //fwrite(& len, 4, 1, cls.demofile); + Globals.cls.demofile.writeInt(buf.cursize); + //fwrite(buf.data, buf.cursize, 1, cls.demofile); + Globals.cls.demofile.write(buf.data, 0, buf.cursize); + buf.cursize = 0; + } + + MSG.WriteByte(buf, Defines.svc_spawnbaseline); + MSG.WriteDeltaEntity(nullstate, + Globals.cl_entities[i].baseline, buf, true, true); + } + + MSG.WriteByte(buf, Defines.svc_stufftext); + MSG.WriteString(buf, "precache\n"); + + // write it to the demo file + + //len = LittleLong(buf.cursize); + //fwrite(& len, 4, 1, cls.demofile); + Globals.cls.demofile.writeInt(buf.cursize); + //fwrite(buf.data, buf.cursize, 1, cls.demofile); + Globals.cls.demofile.write(buf.data, 0, buf.cursize); + // the rest of the demo file will be individual frames + + } catch (IOException e) { + } + } + }; + + /* + * ================== CL_ForwardToServer_f ================== + */ + static xcommand_t ForwardToServer_f = new xcommand_t() { + public void execute() { + if (Globals.cls.state != Defines.ca_connected + && Globals.cls.state != Defines.ca_active) { + Com.Printf("Can't \"" + Cmd.Argv(0) + "\", not connected\n"); + return; + } + + // don't forward the first argument + if (Cmd.Argc() > 1) { + MSG.WriteByte(Globals.cls.netchan.message, + Defines.clc_stringcmd); + SZ.Print(Globals.cls.netchan.message, Cmd.Args()); + } + } + }; + + /* + * ================== CL_Pause_f ================== + */ + static xcommand_t Pause_f = new xcommand_t() { + public void execute() { + // never pause in multiplayer + + if (Cvar.VariableValue("maxclients") > 1 + || Globals.server_state == 0) { + Cvar.SetValue("paused", 0); + return; + } + + Cvar.SetValue("paused", Globals.cl_paused.value); + } + }; + + /* + * ================== CL_Quit_f ================== + */ + static xcommand_t Quit_f = new xcommand_t() { + public void execute() { + Disconnect(); + Com.Quit(); + } + }; + + /* + * ================ CL_Connect_f + * + * ================ + */ + static xcommand_t Connect_f = new xcommand_t() { + public void execute() { + String server; + + if (Cmd.Argc() != 2) { + Com.Printf("usage: connect <server>\n"); + return; + } + + if (Globals.server_state != 0) { + // if running a local server, kill it and reissue + SV_MAIN.SV_Shutdown("Server quit\n", false); + } else { + Disconnect(); + } + + server = Cmd.Argv(1); + + NET.Config(true); // allow remote + + Disconnect(); + + Globals.cls.state = Defines.ca_connecting; + //strncpy (cls.servername, server, sizeof(cls.servername)-1); + Globals.cls.servername = server; + Globals.cls.connect_time = -99999; + // CL_CheckForResend() will fire immediately + } + }; + + /* + * ===================== CL_Rcon_f + * + * Send the rest of the command line over as an unconnected command. + * ===================== + */ + static xcommand_t Rcon_f = new xcommand_t() { + public void execute() { + StringBuffer message = new StringBuffer(1024); + int i; + netadr_t to = new netadr_t(); + + if (Globals.rcon_client_password.string == null) { + Com + .Printf("You must set 'rcon_password' before\nissuing an rcon command.\n"); + return; + } + + message.append((char) 255); + message.append((char) 255); + message.append((char) 255); + message.append((char) 255); + + NET.Config(true); // allow remote + + //strcat (message, "rcon "); + message.append("rcon "); + + //strcat (message, rcon_client_password.string); + message.append(Globals.rcon_client_password.string); + //strcat (message, " "); + message.append(" "); + + for (i = 1; i < Cmd.Argc(); i++) { + //strcat (message, Cmd.Argv(i)); + message.append(Cmd.Argv(i)); + //strcat (message, " "); + message.append(" "); + } + + if (Globals.cls.state >= Defines.ca_connected) + to = Globals.cls.netchan.remote_address; + else { + if (Globals.rcon_address.string.length() == 0) { + Com + .Printf("You must either be connected,\nor set the 'rcon_address' cvar\nto issue rcon commands\n"); + + return; + } + NET.StringToAdr(Globals.rcon_address.string, to); + if (to.port == 0) + //to.port = BigShort (PORT_SERVER); + to.port = Defines.PORT_SERVER; + } + message.append('\0'); + String b = message.toString(); + NET.SendPacket(Defines.NS_CLIENT, b.length(), b.getBytes(), to); + } + }; + + static xcommand_t Disconnect_f = new xcommand_t() { + public void execute() { + Com.Error(Defines.ERR_DROP, "Disconnected from server"); + } + }; + + /* + * ================= CL_Changing_f + * + * Just sent as a hint to the client that they should drop to full console + * ================= + */ + static xcommand_t Changing_f = new xcommand_t() { + public void execute() { + //ZOID + //if we are downloading, we don't change! + // This so we don't suddenly stop downloading a map + + if (Globals.cls.download != null) + return; + + SCR.BeginLoadingPlaque(); + Globals.cls.state = Defines.ca_connected; // not active anymore, but + // not disconnected + Com.Printf("\nChanging map...\n"); + } + }; + + /* + * ================= CL_Reconnect_f + * + * The server is changing levels ================= + */ + static xcommand_t Reconnect_f = new xcommand_t() { + public void execute() { + //ZOID + //if we are downloading, we don't change! This so we don't suddenly + // stop downloading a map + if (Globals.cls.download != null) + return; + + S.StopAllSounds(); + if (Globals.cls.state == Defines.ca_connected) { + Com.Printf("reconnecting...\n"); + Globals.cls.state = Defines.ca_connected; + MSG.WriteChar(Globals.cls.netchan.message, + Defines.clc_stringcmd); + MSG.WriteString(Globals.cls.netchan.message, "new"); + return; + } + + if (Globals.cls.servername != null) { + if (Globals.cls.state >= Defines.ca_connected) { + Disconnect(); + Globals.cls.connect_time = Globals.cls.realtime - 1500; + } else + Globals.cls.connect_time = -99999; // fire immediately + + Globals.cls.state = Defines.ca_connecting; + Com.Printf("reconnecting...\n"); + } + } + }; + + /* + * ================= CL_PingServers_f ================= + */ + static xcommand_t PingServers_f = new xcommand_t() { + public void execute() { + int i; + netadr_t adr = new netadr_t(); + //char name[32]; + String name; + String adrstring; + cvar_t noudp; + cvar_t noipx; + + NET.Config(true); // allow remote + + // send a broadcast packet + Com.Printf("pinging broadcast...\n"); + + noudp = Cvar.Get("noudp", "0", Defines.CVAR_NOSET); + if (noudp.value == 0.0f) { + adr.type = Defines.NA_BROADCAST; + adr.port = Defines.PORT_SERVER; + //adr.port = BigShort(PORT_SERVER); + Netchan.OutOfBandPrint(Defines.NS_CLIENT, adr, "info " + + Defines.PROTOCOL_VERSION); + } + + // we use no IPX + noipx = Cvar.Get("noipx", "1", Defines.CVAR_NOSET); + if (noipx.value == 0.0f) { + adr.type = Defines.NA_BROADCAST_IPX; + //adr.port = BigShort(PORT_SERVER); + adr.port = Defines.PORT_SERVER; + Netchan.OutOfBandPrint(Defines.NS_CLIENT, adr, "info " + + Defines.PROTOCOL_VERSION); + } + + // send a packet to each address book entry + for (i = 0; i < 16; i++) { + //Com_sprintf (name, sizeof(name), "adr%i", i); + name = "adr" + i; + adrstring = Cvar.VariableString(name); + if (adrstring == null || adrstring.length() == 0) + continue; + + Com.Printf("pinging " + adrstring + "...\n"); + if (!NET.StringToAdr(adrstring, adr)) { + Com.Printf("Bad address: " + adrstring + "\n"); + continue; + } + if (adr.port == 0) + //adr.port = BigShort(PORT_SERVER); + adr.port = Defines.PORT_SERVER; + Netchan.OutOfBandPrint(Defines.NS_CLIENT, adr, "info " + + Defines.PROTOCOL_VERSION); + } + } + }; + + /* + * ================= CL_Skins_f + * + * Load or download any custom player skins and models ================= + */ + static xcommand_t Skins_f = new xcommand_t() { + public void execute() { + int i; + + for (i = 0; i < Defines.MAX_CLIENTS; i++) { + if (Globals.cl.configstrings[Defines.CS_PLAYERSKINS + i] == null) + continue; + Com.Printf("client " + i + ": " + + Globals.cl.configstrings[Defines.CS_PLAYERSKINS + i] + + "\n"); + SCR.UpdateScreen(); + Sys.SendKeyEvents(); // pump message loop + CL_parse.ParseClientinfo(i); + } + } + }; + + /* + * ============== CL_Userinfo_f ============== + */ + static xcommand_t Userinfo_f = new xcommand_t() { + public void execute() { + Com.Printf("User info settings:\n"); + Info.Print(Cvar.Userinfo()); + } + }; + + /* + * ================= CL_Snd_Restart_f + * + * Restart the sound subsystem so it can pick up new parameters and flush + * all sounds ================= + */ + static xcommand_t Snd_Restart_f = new xcommand_t() { + public void execute() { + S.Shutdown(); + S.Init(); + CL_parse.RegisterSounds(); + } + }; + + // ENV_CNT is map load, ENV_CNT+1 is first env map + public static final int ENV_CNT = (Defines.CS_PLAYERSKINS + Defines.MAX_CLIENTS + * CL.PLAYER_MULT); + + public static final int TEXTURE_CNT = (ENV_CNT + 13); + + static String env_suf[] = { "rt", "bk", "lf", "ft", "up", "dn" }; + + /* + * ================= CL_Precache_f + * + * The server will send this command right before allowing the client into + * the server ================= + */ + static xcommand_t Precache_f = new xcommand_t() { + public void execute() { + /* + * Yet another hack to let old demos work the old precache sequence + */ + + if (Cmd.Argc() < 2) { + + int iw[] = { 0 }; // for detecting cheater maps + + CM.CM_LoadMap(Globals.cl.configstrings[Defines.CS_MODELS + 1], + true, iw); + int mapchecksum = iw[0]; + CL_parse.RegisterSounds(); + CL_view.PrepRefresh(); + return; + } + + CL.precache_check = Defines.CS_MODELS; + CL.precache_spawncount = Lib.atoi(Cmd.Argv(1)); + CL.precache_model = null; + CL.precache_model_skin = 0; + + RequestNextDownload(); + } + }; + + /* + * ================== CL_Frame + * + * ================== + */ + private static int extratime; + + // ============================================================================ + + /* + * =============== CL_Shutdown + * + * FIXME: this is a callback from Sys_Quit and Com_Error. It would be better + * to run quit through here before the final handoff to the sys code. + * =============== + */ + static boolean isdown = false; + + /* + * ==================== CL_WriteDemoMessage + * + * Dumps the current net message, prefixed by the length + * ==================== + */ + static void WriteDemoMessage() { + int swlen; + + // the first eight bytes are just packet sequencing stuff + swlen = Globals.net_message.cursize - 8; + + try { + Globals.cls.demofile.writeInt(swlen); + //fwrite (&swlen, 4, 1, cls.demofile); + Globals.cls.demofile.write(Globals.net_message.data, 8, swlen); + //fwrite (net_message.data+8, len, 1, cls.demofile); + } catch (IOException e) { + } + + } + + /* + * ======================= CL_SendConnectPacket + * + * We have gotten a challenge from the server, so try and connect. + * ====================== + */ + static void SendConnectPacket() { + netadr_t adr = new netadr_t(); + int port; + + if (!NET.StringToAdr(Globals.cls.servername, adr)) { + Com.Printf("Bad server address\n"); + Globals.cls.connect_time = 0; + return; + } + if (adr.port == 0) + adr.port = Defines.PORT_SERVER; + // adr.port = BigShort(PORT_SERVER); + + port = (int) Cvar.VariableValue("qport"); + Globals.userinfo_modified = false; + + Netchan.OutOfBandPrint(Defines.NS_CLIENT, adr, "connect " + + Defines.PROTOCOL_VERSION + " " + port + " " + + Globals.cls.challenge + " \"" + Cvar.Userinfo() + "\"\n"); + } + + /* + * ================= CL_CheckForResend + * + * Resend a connect message if the last one has timed out ================= + */ + static void CheckForResend() { + netadr_t adr = new netadr_t(); + + // if the local server is running and we aren't + // then connect + if (Globals.cls.state == Defines.ca_disconnected + && Globals.server_state != 0) { + Globals.cls.state = Defines.ca_connecting; + Globals.cls.servername = "localhost"; + // we don't need a challenge on the localhost + SendConnectPacket(); + return; + } + + // resend if we haven't gotten a reply yet + if (Globals.cls.state != Defines.ca_connecting) + return; + + if (Globals.cls.realtime - Globals.cls.connect_time < 3000) + return; + + if (!NET.StringToAdr(Globals.cls.servername, adr)) { + Com.Printf("Bad server address\n"); + Globals.cls.state = Defines.ca_disconnected; + return; + } + if (adr.port == 0) + // adr.port = BigShort(PORT_SERVER); + adr.port = Defines.PORT_SERVER; + + Globals.cls.connect_time = Globals.cls.realtime; // for retransmit + // requests + + Com.Printf("Connecting to " + Globals.cls.servername + "...\n"); + + Netchan.OutOfBandPrint(Defines.NS_CLIENT, adr, "getchallenge\n"); + } + + /* + * ===================== CL_ClearState + * + * ===================== + */ + + static void ClearState() { + S.StopAllSounds(); + CL_fx.ClearEffects(); + CL_tent.ClearTEnts(); + + // wipe the entire cl structure + + Globals.cl = new client_state_t(); + for (int i = 0; i < Globals.cl_entities.length; i++) { + Globals.cl_entities[i] = new centity_t(); + } + + SZ.Clear(Globals.cls.netchan.message); + } + + /* + * ===================== CL_Disconnect + * + * Goes from a connected state to full screen console state Sends a + * disconnect message to the server This is also called on Com_Error, so it + * shouldn't cause any errors ===================== + */ + + static void Disconnect() { + + String fin; + + if (Globals.cls.state == Defines.ca_disconnected) + return; + + if (Globals.cl_timedemo != null && Globals.cl_timedemo.value != 0.0f) { + int time; + + time = (int) (Sys.Milliseconds() - Globals.cl.timedemo_start); + if (time > 0) + Com.Printf("%i frames, %3.1f seconds: %3.1f fps\n", + new Vargs(3).add(Globals.cl.timedemo_frames).add( + time / 1000.0).add( + Globals.cl.timedemo_frames * 1000.0 / time)); + } + + Math3D.VectorClear(Globals.cl.refdef.blend); + //re.CinematicSetPalette(null); + + Menu.ForceMenuOff(); + + Globals.cls.connect_time = 0; + + // SCR.StopCinematic(); + + if (Globals.cls.demorecording) + Stop_f.execute(); + + // send a disconnect message to the server + fin = (char) Defines.clc_stringcmd + "disconnect"; + Netchan.Transmit(Globals.cls.netchan, fin.length(), fin.getBytes()); + Netchan.Transmit(Globals.cls.netchan, fin.length(), fin.getBytes()); + Netchan.Transmit(Globals.cls.netchan, fin.length(), fin.getBytes()); + + ClearState(); + + // stop download + if (Globals.cls.download != null) { + Lib.fclose(Globals.cls.download); + Globals.cls.download = null; + // fclose(cls.download); + // cls.download = NULL; + } + + Globals.cls.state = Defines.ca_disconnected; + } + + /* + * ================= CL_ParseStatusMessage + * + * Handle a reply from a ping ================= + */ + static void ParseStatusMessage() { + String s; + + s = MSG.ReadString(Globals.net_message); + + Com.Printf(s + "\n"); + Menu.AddToServerList(Globals.net_from, s); + } + + /* + * ================= CL_ConnectionlessPacket + * + * Responses to broadcasts, etc ================= + */ + static void ConnectionlessPacket() { + String s; + String c; + + MSG.BeginReading(Globals.net_message); + MSG.ReadLong(Globals.net_message); // skip the -1 + + s = MSG.ReadStringLine(Globals.net_message); + + Cmd.TokenizeString(s.toCharArray(), false); + + c = Cmd.Argv(0); + + Com.Printf(NET.AdrToString(Globals.net_from) + ": " + c + "\n"); + + // server connection + if (c.equals("client_connect")) { + if (Globals.cls.state == Defines.ca_connected) { + Com.Printf("Dup connect received. Ignored.\n"); + return; + } + Netchan.Setup(Defines.NS_CLIENT, Globals.cls.netchan, + Globals.net_from, Globals.cls.quakePort); + MSG.WriteChar(Globals.cls.netchan.message, Defines.clc_stringcmd); + MSG.WriteString(Globals.cls.netchan.message, "new"); + Globals.cls.state = Defines.ca_connected; + return; + } + + // server responding to a status broadcast + if (c.equals("info")) { + ParseStatusMessage(); + return; + } + + // remote command from gui front end + if (c.equals("cmd")) { + if (!NET.IsLocalAddress(Globals.net_from)) { + Com.Printf("Command packet from remote host. Ignored.\n"); + return; + } + s = MSG.ReadString(Globals.net_message); + Cbuf.AddText(s); + Cbuf.AddText("\n"); + return; + } + // print command from somewhere + if (c.equals("print")) { + s = MSG.ReadString(Globals.net_message); + Com.Printf(s); + return; + } + + // ping from somewhere + if (c.equals("ping")) { + Netchan.OutOfBandPrint(Defines.NS_CLIENT, Globals.net_from, "ack"); + return; + } + + // challenge from the server we are connecting to + if (c.equals("challenge")) { + Globals.cls.challenge = Integer.parseInt(Cmd.Argv(1)); + SendConnectPacket(); + return; + } + + // echo request from server + if (c.equals("echo")) { + Netchan.OutOfBandPrint(Defines.NS_CLIENT, Globals.net_from, Cmd + .Argv(1)); + return; + } + + Com.Printf("Unknown command.\n"); + } + + /* + * ================= CL_DumpPackets + * + * A vain attempt to help bad TCP stacks that cause problems when they + * overflow ================= + */ + static void DumpPackets() { + while (NET.GetPacket(Defines.NS_CLIENT, Globals.net_from, + Globals.net_message)) { + Com.Printf("dumping a packet\n"); + } + } + + /* + * ================= CL_ReadPackets ================= + */ + static void ReadPackets() { + while (NET.GetPacket(Defines.NS_CLIENT, Globals.net_from, + Globals.net_message)) { + + // + // remote command packet + // + if (Globals.net_message.data[0] == -1 + && Globals.net_message.data[1] == -1 + && Globals.net_message.data[2] == -1 + && Globals.net_message.data[3] == -1) { + // if (*(int *)net_message.data == -1) + ConnectionlessPacket(); + continue; + } + + if (Globals.cls.state == Defines.ca_disconnected + || Globals.cls.state == Defines.ca_connecting) + continue; // dump it if not connected + + if (Globals.net_message.cursize < 8) { + Com.Printf(NET.AdrToString(Globals.net_from) + + ": Runt packet\n"); + continue; + } + + // + // packet from server + // + if (!NET.CompareAdr(Globals.net_from, + Globals.cls.netchan.remote_address)) { + Com.DPrintf(NET.AdrToString(Globals.net_from) + + ":sequenced packet without connection\n"); + continue; + } + if (!Netchan.Process(Globals.cls.netchan, Globals.net_message)) + continue; // wasn't accepted for some reason + CL_parse.ParseServerMessage(); + } + + // + // check timeout + // + if (Globals.cls.state >= Defines.ca_connected + && Globals.cls.realtime - Globals.cls.netchan.last_received > Globals.cl_timeout.value * 1000) { + if (++Globals.cl.timeoutcount > 5) // timeoutcount saves debugger + { + Com.Printf("\nServer connection timed out.\n"); + Disconnect(); + return; + } + } else + Globals.cl.timeoutcount = 0; + } + + // ============================================================================= + + /* + * ============== CL_FixUpGender_f ============== + */ + static void FixUpGender() { + + String sk; + + if (Globals.gender_auto.value != 0.0f) { + + if (Globals.gender.modified) { + // was set directly, don't override the user + Globals.gender.modified = false; + return; + } + + sk = Globals.skin.string; + if (sk.startsWith("male") || sk.startsWith("cyborg")) + Cvar.Set("gender", "male"); + else if (sk.startsWith("female") || sk.startsWith("crackhor")) + Cvar.Set("gender", "female"); + else + Cvar.Set("gender", "none"); + Globals.gender.modified = false; + } + } + + public static void RequestNextDownload() { + int map_checksum = 0; // for detecting cheater maps + //char fn[MAX_OSPATH]; + String fn; + + qfiles.dmdl_t pheader; + + if (Globals.cls.state != Defines.ca_connected) + return; + + if (SV_MAIN.allow_download.value == 0 && CL.precache_check < ENV_CNT) + CL.precache_check = ENV_CNT; + + // ZOID + if (CL.precache_check == Defines.CS_MODELS) { // confirm map + CL.precache_check = Defines.CS_MODELS + 2; // 0 isn't used + if (SV_MAIN.allow_download_maps.value != 0) + if (!CL_parse + .CheckOrDownloadFile(Globals.cl.configstrings[Defines.CS_MODELS + 1])) + return; // started a download + } + if (CL.precache_check >= Defines.CS_MODELS + && CL.precache_check < Defines.CS_MODELS + Defines.MAX_MODELS) { + if (SV_MAIN.allow_download_models.value != 0) { + while (CL.precache_check < Defines.CS_MODELS + + Defines.MAX_MODELS + && Globals.cl.configstrings[CL.precache_check].length() > 0) { + if (Globals.cl.configstrings[CL.precache_check].charAt(0) == '*' + || Globals.cl.configstrings[CL.precache_check] + .charAt(0) == '#') { + CL.precache_check++; + continue; + } + if (CL.precache_model_skin == 0) { + if (!CL_parse + .CheckOrDownloadFile(Globals.cl.configstrings[CL.precache_check])) { + CL.precache_model_skin = 1; + return; // started a download + } + CL.precache_model_skin = 1; + } + + // checking for skins in the model + if (CL.precache_model == null) { + + CL.precache_model = FS + .LoadFile(Globals.cl.configstrings[CL.precache_check]); + if (CL.precache_model == null) { + CL.precache_model_skin = 0; + CL.precache_check++; + continue; // couldn't load it + } + ByteBuffer bb = ByteBuffer.wrap(CL.precache_model); + bb.order(ByteOrder.LITTLE_ENDIAN); + + int header = bb.getInt(); + + if (header != qfiles.IDALIASHEADER) { + // not an alias model + FS.FreeFile(CL.precache_model); + CL.precache_model = null; + CL.precache_model_skin = 0; + CL.precache_check++; + continue; + } + pheader = new qfiles.dmdl_t(ByteBuffer.wrap( + CL.precache_model).order( + ByteOrder.LITTLE_ENDIAN)); + if (pheader.version != Defines.ALIAS_VERSION) { + CL.precache_check++; + CL.precache_model_skin = 0; + continue; // couldn't load it + } + } + + pheader = new qfiles.dmdl_t(ByteBuffer.wrap( + CL.precache_model).order(ByteOrder.LITTLE_ENDIAN)); + + int num_skins = pheader.num_skins; + + while (CL.precache_model_skin - 1 < num_skins) { + //Com.Printf("critical code section because of endian + // mess!\n"); + + String name = new String(CL.precache_model, + pheader.ofs_skins + + (CL.precache_model_skin - 1) + * Defines.MAX_SKINNAME, + Defines.MAX_SKINNAME * num_skins); + + if (!CL_parse.CheckOrDownloadFile(name)) { + CL.precache_model_skin++; + return; // started a download + } + CL.precache_model_skin++; + } + if (CL.precache_model != null) { + FS.FreeFile(CL.precache_model); + CL.precache_model = null; + } + CL.precache_model_skin = 0; + CL.precache_check++; + } + } + CL.precache_check = Defines.CS_SOUNDS; + } + if (CL.precache_check >= Defines.CS_SOUNDS + && CL.precache_check < Defines.CS_SOUNDS + Defines.MAX_SOUNDS) { + if (SV_MAIN.allow_download_sounds.value != 0) { + if (CL.precache_check == Defines.CS_SOUNDS) + CL.precache_check++; // zero is blank + while (CL.precache_check < Defines.CS_SOUNDS + + Defines.MAX_SOUNDS + && Globals.cl.configstrings[CL.precache_check].length() > 0) { + if (Globals.cl.configstrings[CL.precache_check].charAt(0) == '*') { + CL.precache_check++; + continue; + } + fn = "sound/" + + Globals.cl.configstrings[CL.precache_check++]; + if (!CL_parse.CheckOrDownloadFile(fn)) + return; // started a download + } + } + CL.precache_check = Defines.CS_IMAGES; + } + if (CL.precache_check >= Defines.CS_IMAGES + && CL.precache_check < Defines.CS_IMAGES + Defines.MAX_IMAGES) { + if (CL.precache_check == Defines.CS_IMAGES) + CL.precache_check++; // zero is blank + + while (CL.precache_check < Defines.CS_IMAGES + Defines.MAX_IMAGES + && Globals.cl.configstrings[CL.precache_check].length() > 0) { + fn = "pics/" + Globals.cl.configstrings[CL.precache_check++] + + ".pcx"; + if (!CL_parse.CheckOrDownloadFile(fn)) + return; // started a download + } + CL.precache_check = Defines.CS_PLAYERSKINS; + } + // skins are special, since a player has three things to download: + // model, weapon model and skin + // so precache_check is now *3 + if (CL.precache_check >= Defines.CS_PLAYERSKINS + && CL.precache_check < Defines.CS_PLAYERSKINS + + Defines.MAX_CLIENTS * CL.PLAYER_MULT) { + if (SV_MAIN.allow_download_players.value != 0) { + while (CL.precache_check < Defines.CS_PLAYERSKINS + + Defines.MAX_CLIENTS * CL.PLAYER_MULT) { + + int i, n; + //char model[MAX_QPATH], skin[MAX_QPATH], * p; + String model, skin; + + i = (CL.precache_check - Defines.CS_PLAYERSKINS) + / CL.PLAYER_MULT; + n = (CL.precache_check - Defines.CS_PLAYERSKINS) + % CL.PLAYER_MULT; + + if (Globals.cl.configstrings[Defines.CS_PLAYERSKINS + i] + .length() == 0) { + CL.precache_check = Defines.CS_PLAYERSKINS + (i + 1) + * CL.PLAYER_MULT; + continue; + } + + int pos = Globals.cl.configstrings[Defines.CS_PLAYERSKINS + + i].indexOf('\\'); + if (pos != -1) + pos++; + else + pos = 0; + + model = Globals.cl.configstrings[Defines.CS_PLAYERSKINS + i] + .substring(pos); + + pos = model.indexOf('/'); + + if (pos == -1) + pos = model.indexOf('\\'); + + if (pos != -1) { + skin = model.substring(pos + 1); + } else + skin = ""; + + switch (n) { + case 0: // model + fn = "players/" + model + "/tris.md2"; + if (!CL_parse.CheckOrDownloadFile(fn)) { + CL.precache_check = Defines.CS_PLAYERSKINS + i + * CL.PLAYER_MULT + 1; + return; // started a download + } + n++; + /* FALL THROUGH */ + + case 1: // weapon model + fn = "players/" + model + "/weapon.md2"; + if (!CL_parse.CheckOrDownloadFile(fn)) { + CL.precache_check = Defines.CS_PLAYERSKINS + i + * CL.PLAYER_MULT + 2; + return; // started a download + } + n++; + /* FALL THROUGH */ + + case 2: // weapon skin + fn = "players/" + model + "/weapon.pcx"; + if (!CL_parse.CheckOrDownloadFile(fn)) { + CL.precache_check = Defines.CS_PLAYERSKINS + i + * CL.PLAYER_MULT + 3; + return; // started a download + } + n++; + /* FALL THROUGH */ + + case 3: // skin + fn = "players/" + model + "/" + skin + ".pcx"; + if (!CL_parse.CheckOrDownloadFile(fn)) { + CL.precache_check = Defines.CS_PLAYERSKINS + i + * CL.PLAYER_MULT + 4; + return; // started a download + } + n++; + /* FALL THROUGH */ + + case 4: // skin_i + fn = "players/" + model + "/" + skin + "_i.pcx"; + if (!CL_parse.CheckOrDownloadFile(fn)) { + CL.precache_check = Defines.CS_PLAYERSKINS + i + * CL.PLAYER_MULT + 5; + return; // started a download + } + // move on to next model + CL.precache_check = Defines.CS_PLAYERSKINS + (i + 1) + * CL.PLAYER_MULT; + } + } + } + // precache phase completed + CL.precache_check = ENV_CNT; + } + + if (CL.precache_check == ENV_CNT) { + CL.precache_check = ENV_CNT + 1; + + int iw[] = { map_checksum }; + + CM.CM_LoadMap(Globals.cl.configstrings[Defines.CS_MODELS + 1], + true, iw); + map_checksum = iw[0]; + + if ((map_checksum ^ Lib + .atoi(Globals.cl.configstrings[Defines.CS_MAPCHECKSUM])) != 0) { + Com + .Error( + Defines.ERR_DROP, + "Local map version differs from server: " + + map_checksum + + " != '" + + Globals.cl.configstrings[Defines.CS_MAPCHECKSUM] + + "'\n"); + return; + } + } + + if (CL.precache_check > ENV_CNT && CL.precache_check < TEXTURE_CNT) { + if (SV_MAIN.allow_download.value != 0 + && SV_MAIN.allow_download_maps.value != 0) { + while (CL.precache_check < TEXTURE_CNT) { + int n = CL.precache_check++ - ENV_CNT - 1; + + if ((n & 1) != 0) + fn = "env/" + Globals.cl.configstrings[Defines.CS_SKY] + + env_suf[n / 2] + ".pcx"; + else + fn = "env/" + Globals.cl.configstrings[Defines.CS_SKY] + + env_suf[n / 2] + ".tga"; + if (!CL_parse.CheckOrDownloadFile(fn)) + return; // started a download + } + } + CL.precache_check = TEXTURE_CNT; + } + + if (CL.precache_check == TEXTURE_CNT) { + CL.precache_check = TEXTURE_CNT + 1; + CL.precache_tex = 0; + } + + // confirm existance of textures, download any that don't exist + if (CL.precache_check == TEXTURE_CNT + 1) { + // from qcommon/cmodel.c + // extern int numtexinfo; + // extern mapsurface_t map_surfaces[]; + + if (SV_MAIN.allow_download.value != 0 + && SV_MAIN.allow_download_maps.value != 0) { + while (CL.precache_tex < CM.numtexinfo) { + //char fn[MAX_OSPATH]; + + fn = "textures/" + CM.map_surfaces[CL.precache_tex++].rname + + ".wal"; + if (!CL_parse.CheckOrDownloadFile(fn)) + return; // started a download + } + } + CL.precache_check = TEXTURE_CNT + 999; + } + + // ZOID + CL_parse.RegisterSounds(); + CL_view.PrepRefresh(); + + MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_stringcmd); + MSG.WriteString(Globals.cls.netchan.message, "begin " + + CL.precache_spawncount + "\n"); + } + + /* + * ================= CL_InitLocal ================= + */ + public static void InitLocal() { + Globals.cls.state = Defines.ca_disconnected; + Globals.cls.realtime = Sys.Milliseconds(); + + CL_input.InitInput(); + + // never used !! + // adr0 = Cvar.Get("adr0", "", CVAR_ARCHIVE); + // adr1 = Cvar.Get("adr1", "", CVAR_ARCHIVE); + // adr2 = Cvar.Get("adr2", "", CVAR_ARCHIVE); + // adr3 = Cvar.Get("adr3", "", CVAR_ARCHIVE); + // adr4 = Cvar.Get("adr4", "", CVAR_ARCHIVE); + // adr5 = Cvar.Get("adr5", "", CVAR_ARCHIVE); + // adr6 = Cvar.Get("adr6", "", CVAR_ARCHIVE); + // adr7 = Cvar.Get("adr7", "", CVAR_ARCHIVE); + // adr8 = Cvar.Get("adr8", "", CVAR_ARCHIVE); + + // + // register our variables + // + Globals.cl_stereo_separation = Cvar.Get("cl_stereo_separation", "0.4", + Defines.CVAR_ARCHIVE); + Globals.cl_stereo = Cvar.Get("cl_stereo", "0", 0); + + Globals.cl_add_blend = Cvar.Get("cl_blend", "1", 0); + Globals.cl_add_lights = Cvar.Get("cl_lights", "1", 0); + Globals.cl_add_particles = Cvar.Get("cl_particles", "1", 0); + Globals.cl_add_entities = Cvar.Get("cl_entities", "1", 0); + Globals.cl_gun = Cvar.Get("cl_gun", "1", 0); + Globals.cl_footsteps = Cvar.Get("cl_footsteps", "1", 0); + Globals.cl_noskins = Cvar.Get("cl_noskins", "0", 0); + Globals.cl_autoskins = Cvar.Get("cl_autoskins", "0", 0); + Globals.cl_predict = Cvar.Get("cl_predict", "1", 0); + + Globals.cl_maxfps = Cvar.Get("cl_maxfps", "90", 0); + + Globals.cl_upspeed = Cvar.Get("cl_upspeed", "200", 0); + Globals.cl_forwardspeed = Cvar.Get("cl_forwardspeed", "200", 0); + Globals.cl_sidespeed = Cvar.Get("cl_sidespeed", "200", 0); + Globals.cl_yawspeed = Cvar.Get("cl_yawspeed", "140", 0); + Globals.cl_pitchspeed = Cvar.Get("cl_pitchspeed", "150", 0); + Globals.cl_anglespeedkey = Cvar.Get("cl_anglespeedkey", "1.5", 0); + + Globals.cl_run = Cvar.Get("cl_run", "0", Defines.CVAR_ARCHIVE); + Globals.lookspring = Cvar.Get("lookspring", "0", Defines.CVAR_ARCHIVE); + Globals.lookstrafe = Cvar.Get("lookstrafe", "0", Defines.CVAR_ARCHIVE); + Globals.sensitivity = Cvar + .Get("sensitivity", "3", Defines.CVAR_ARCHIVE); + + Globals.m_pitch = Cvar.Get("m_pitch", "0.022", Defines.CVAR_ARCHIVE); + Globals.m_yaw = Cvar.Get("m_yaw", "0.022", 0); + Globals.m_forward = Cvar.Get("m_forward", "1", 0); + Globals.m_side = Cvar.Get("m_side", "1", 0); + + Globals.cl_shownet = Cvar.Get("cl_shownet", "0", 0); + Globals.cl_showmiss = Cvar.Get("cl_showmiss", "0", 0); + Globals.cl_showclamp = Cvar.Get("showclamp", "0", 0); + Globals.cl_timeout = Cvar.Get("cl_timeout", "120", 0); + Globals.cl_paused = Cvar.Get("paused", "0", 0); + Globals.cl_timedemo = Cvar.Get("timedemo", "0", 0); + + Globals.rcon_client_password = Cvar.Get("rcon_password", "", 0); + Globals.rcon_address = Cvar.Get("rcon_address", "", 0); + + Globals.cl_lightlevel = Cvar.Get("r_lightlevel", "0", 0); + + // + // userinfo + // + Globals.info_password = Cvar.Get("password", "", Defines.CVAR_USERINFO); + Globals.info_spectator = Cvar.Get("spectator", "0", + Defines.CVAR_USERINFO); + Globals.name = Cvar.Get("name", "unnamed", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.skin = Cvar.Get("skin", "male/grunt", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.rate = Cvar.Get("rate", "25000", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); // FIXME + Globals.msg = Cvar.Get("msg", "1", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.hand = Cvar.Get("hand", "0", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.fov = Cvar.Get("fov", "90", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.gender = Cvar.Get("gender", "male", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.gender_auto = Cvar + .Get("gender_auto", "1", Defines.CVAR_ARCHIVE); + Globals.gender.modified = false; // clear this so we know when user sets + // it manually + + Globals.cl_vwep = Cvar.Get("cl_vwep", "1", Defines.CVAR_ARCHIVE); + + // + // register our commands + // + Cmd.AddCommand("cmd", ForwardToServer_f); + Cmd.AddCommand("pause", Pause_f); + Cmd.AddCommand("pingservers", PingServers_f); + Cmd.AddCommand("skins", Skins_f); + + Cmd.AddCommand("userinfo", Userinfo_f); + Cmd.AddCommand("snd_restart", Snd_Restart_f); + + Cmd.AddCommand("changing", Changing_f); + Cmd.AddCommand("disconnect", Disconnect_f); + Cmd.AddCommand("record", Record_f); + Cmd.AddCommand("stop", Stop_f); + + Cmd.AddCommand("quit", Quit_f); + + Cmd.AddCommand("connect", Connect_f); + Cmd.AddCommand("reconnect", Reconnect_f); + + Cmd.AddCommand("rcon", Rcon_f); + + Cmd.AddCommand("precache", Precache_f); + + Cmd.AddCommand("download", CL_parse.Download_f); + + // + // forward to server commands + // + // the only thing this does is allow command completion + // to work -- all unknown commands are automatically + // forwarded to the server + Cmd.AddCommand("wave", null); + Cmd.AddCommand("inven", null); + Cmd.AddCommand("kill", null); + Cmd.AddCommand("use", null); + Cmd.AddCommand("drop", null); + Cmd.AddCommand("say", null); + Cmd.AddCommand("say_team", null); + Cmd.AddCommand("info", null); + Cmd.AddCommand("prog", null); + Cmd.AddCommand("give", null); + Cmd.AddCommand("god", null); + Cmd.AddCommand("notarget", null); + Cmd.AddCommand("noclip", null); + Cmd.AddCommand("invuse", null); + Cmd.AddCommand("invprev", null); + Cmd.AddCommand("invnext", null); + Cmd.AddCommand("invdrop", null); + Cmd.AddCommand("weapnext", null); + Cmd.AddCommand("weapprev", null); + + } + + /* + * =============== CL_WriteConfiguration + * + * Writes key bindings and archived cvars to config.cfg =============== + */ + static void WriteConfiguration() { + RandomAccessFile f; + String path; + + if (Globals.cls.state == Defines.ca_uninitialized) + return; + + path = FS.Gamedir() + "/config.cfg"; + f = Lib.fopen(path, "rw"); + if (f == null) { + Com.Printf("Couldn't write config.cfg.\n"); + return; + } + try { + f.seek(0); + f.setLength(0); + } catch (IOException e1) { + } + try { + f.writeBytes("// generated by quake, do not modify\n"); + } catch (IOException e) { + } + + Key.WriteBindings(f); + Lib.fclose(f); + Cvar.WriteVariables(path); + } + + public static void FixCvarCheats() { + int i; + CL.cheatvar_t var; + + if ("1".equals(Globals.cl.configstrings[Defines.CS_MAXCLIENTS]) + || 0 == Globals.cl.configstrings[Defines.CS_MAXCLIENTS] + .length()) + return; // single player can cheat + + // find all the cvars if we haven't done it yet + if (0 == CL.numcheatvars) { + while (CL.cheatvars[CL.numcheatvars].name != null) { + CL.cheatvars[CL.numcheatvars].var = Cvar.Get( + CL.cheatvars[CL.numcheatvars].name, + CL.cheatvars[CL.numcheatvars].value, 0); + CL.numcheatvars++; + } + } + + // make sure they are all set to the proper values + for (i = 0; i < CL.numcheatvars; i++) { + var = CL.cheatvars[i]; + if (!var.var.string.equals(var.value)) { + Cvar.Set(var.name, var.value); + } + } + } + + // ============================================================================ + + /* + * ================== CL_SendCommand + * + * ================== + */ + public static void SendCommand() { + // get new key events + Sys.SendKeyEvents(); + + // allow mice or other external controllers to add commands + IN.Commands(); + + // process console commands + Cbuf.Execute(); + + // fix any cheating cvars + FixCvarCheats(); + + // send intentions now + CL_input.SendCmd(); + + // resend a connection request if necessary + CheckForResend(); + } + + // private static int lasttimecalled; + + public static void Frame(int msec) { + + extratime += msec; + + if (Globals.cl_timedemo.value == 0.0f) { + if (Globals.cls.state == Defines.ca_connected && extratime < 100) { + return; // don't flood packets out while connecting + } + if (extratime < 1000 / Globals.cl_maxfps.value) { + return; // framerate is too high + } + } + + // let the mouse activate or deactivate + IN.Frame(); + + // decide the simulation time + Globals.cls.frametime = extratime / 1000.0f; + Globals.cl.time += extratime; + Globals.cls.realtime = Globals.curtime; + + extratime = 0; + + if (Globals.cls.frametime > (1.0f / 5)) + Globals.cls.frametime = (1.0f / 5); + + // if in the debugger last frame, don't timeout + if (msec > 5000) + Globals.cls.netchan.last_received = Sys.Milliseconds(); + + // fetch results from server + ReadPackets(); + + // send a new command message to the server + SendCommand(); + + // predict all unacknowledged movements + CL_pred.PredictMovement(); + + // allow rendering DLL change + VID.CheckChanges(); + if (!Globals.cl.refresh_prepped + && Globals.cls.state == Defines.ca_active) { + CL_view.PrepRefresh(); + // force GC after level loading + System.gc(); + } + + SCR.UpdateScreen(); + + // update audio + S.Update(Globals.cl.refdef.vieworg, Globals.cl.v_forward, + Globals.cl.v_right, Globals.cl.v_up); + + // advance local effects for next frame + CL_fx.RunDLights(); + CL_fx.RunLightStyles(); - /* - =============== - CL_Shutdown + SCR.RunConsole(); - FIXME: this is a callback from Sys_Quit and Com_Error. It would be better - to run quit through here before the final handoff to the sys code. - =============== - */ - static boolean isdown = false; - public static void Shutdown() { + Globals.cls.framecount++; + if (Globals.cls.state != Defines.ca_active + || Globals.cls.key_dest != Defines.key_game) { + try { + Thread.sleep(20); + } catch (InterruptedException e) { + } + } + } - if (isdown) { - System.out.print("recursive shutdown\n"); - return; - } - isdown = true; + public static void Shutdown() { - WriteConfiguration(); + if (isdown) { + System.out.print("recursive shutdown\n"); + return; + } + isdown = true; - S.Shutdown(); - IN.Shutdown(); - VID.Shutdown(); - } + WriteConfiguration(); - /** - * initialize client subsystem - */ - public static void Init() { - if (Globals.dedicated.value != 0.0f) - return; // nothing running on the client + S.Shutdown(); + IN.Shutdown(); + VID.Shutdown(); + } - // all archived variables will now be loaded + /** + * initialize client subsystem + */ + public static void Init() { + if (Globals.dedicated.value != 0.0f) + return; // nothing running on the client - Console.Init(); //ok + // all archived variables will now be loaded - S.Init(); //empty - VID.Init(); + Console.Init(); //ok - V.Init(); + S.Init(); //empty + VID.Init(); - Globals.net_message.data = Globals.net_message_buffer; - Globals.net_message.maxsize = Globals.net_message_buffer.length; + V.Init(); - Menu.Init(); + Globals.net_message.data = Globals.net_message_buffer; + Globals.net_message.maxsize = Globals.net_message_buffer.length; - SCR.Init(); - //Globals.cls.disable_screen = 1.0f; // don't draw yet + Menu.Init(); - CL.InitLocal(); - IN.Init(); + SCR.Init(); + //Globals.cls.disable_screen = 1.0f; // don't draw yet - FS.ExecAutoexec(); - Cbuf.Execute(); - } + InitLocal(); + IN.Init(); - /** - * Called after an ERR_DROP was thrown. - */ - public static void Drop() { - if (Globals.cls.state == Defines.ca_uninitialized) - return; - if (Globals.cls.state == Defines.ca_disconnected) - return; + FS.ExecAutoexec(); + Cbuf.Execute(); + } - CL.Disconnect(); + /** + * Called after an ERR_DROP was thrown. + */ + public static void Drop() { + if (Globals.cls.state == Defines.ca_uninitialized) + return; + if (Globals.cls.state == Defines.ca_disconnected) + return; - // drop loading plaque unless this is the initial game start - if (Globals.cls.disable_servercount != -1) - SCR.EndLoadingPlaque(); // get rid of loading plaque - } + Disconnect(); -} + // drop loading plaque unless this is the initial game start + if (Globals.cls.disable_servercount != -1) + SCR.EndLoadingPlaque(); // get rid of loading plaque + } +}
\ No newline at end of file |