diff options
author | Rene Stoeckel <[email protected]> | 2004-09-22 19:22:16 +0000 |
---|---|---|
committer | Rene Stoeckel <[email protected]> | 2004-09-22 19:22:16 +0000 |
commit | c4fcffe436fbfb5b0f3b7be2e5ee103ec74932f7 (patch) | |
tree | 7c9439ab1d9f5a4fd61bd57c755069007b23e0b6 /src/jake2/qcommon | |
parent | bcb4ac6eefb425d5b0a90009da506361d5739e75 (diff) |
major refactoring in game, server and client package
Diffstat (limited to 'src/jake2/qcommon')
-rw-r--r-- | src/jake2/qcommon/CM.java | 3779 | ||||
-rw-r--r-- | src/jake2/qcommon/Cbuf.java | 452 | ||||
-rw-r--r-- | src/jake2/qcommon/Cvar.java | 854 | ||||
-rw-r--r-- | src/jake2/qcommon/MSG.java | 1105 | ||||
-rw-r--r-- | src/jake2/qcommon/Netchan.java | 707 | ||||
-rw-r--r-- | src/jake2/qcommon/PMove.java | 2421 | ||||
-rw-r--r-- | src/jake2/qcommon/Q2DataDialog.java | 854 | ||||
-rw-r--r-- | src/jake2/qcommon/netchan_t.java | 122 |
8 files changed, 5084 insertions, 5210 deletions
diff --git a/src/jake2/qcommon/CM.java b/src/jake2/qcommon/CM.java index 5978f88..52495db 100644 --- a/src/jake2/qcommon/CM.java +++ b/src/jake2/qcommon/CM.java @@ -1,29 +1,29 @@ /* -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 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. - -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. - -*/ + * 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 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. + * + * 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. + * + */ // Created on 02.01.2004 by RST. -// $Id: CM.java,v 1.5 2004-07-28 12:01:27 hzi Exp $ - +// $Id: CM.java,v 1.6 2004-09-22 19:22:09 salomo Exp $ package jake2.qcommon; import jake2.Defines; +import jake2.Globals; import jake2.game.*; import jake2.util.*; @@ -31,1889 +31,1866 @@ import java.io.RandomAccessFile; import java.nio.*; import java.util.Arrays; -public class CM extends Game { - - public static class cnode_t { - cplane_t plane; // ptr - int children[] = { 0, 0 }; // negative numbers are leafs - } - - public static class cbrushside_t { - cplane_t plane; // ptr - mapsurface_t surface; // ptr - } - - public static class cleaf_t { - int contents; - int cluster; - int area; - - // was unsigned short, but is ok (rst) - short firstleafbrush; - // was unsigned short, but is ok (rst) - short numleafbrushes; - } - - public static class cbrush_t { - int contents; - int numsides; - int firstbrushside; - int checkcount; // to avoid repeated testings - } - - public static class carea_t { - int numareaportals; - int firstareaportal; - int floodnum; // if two areas have equal floodnums, they are connected - int floodvalid; - } +public class CM { + + public static class cnode_t { + cplane_t plane; // ptr + + int children[] = { 0, 0 }; // negative numbers are leafs + } + + public static class cbrushside_t { + cplane_t plane; // ptr + + mapsurface_t surface; // ptr + } + + public static class cleaf_t { + int contents; + + int cluster; + + int area; + + // was unsigned short, but is ok (rst) + short firstleafbrush; + + // was unsigned short, but is ok (rst) + short numleafbrushes; + } + + public static class cbrush_t { + int contents; + + int numsides; + + int firstbrushside; + + int checkcount; // to avoid repeated testings + } + + public static class carea_t { + int numareaportals; + + int firstareaportal; + + int floodnum; // if two areas have equal floodnums, they are connected + + int floodvalid; + } + + static int checkcount; + + static String map_name = ""; + + static int numbrushsides; + + static cbrushside_t map_brushsides[] = new cbrushside_t[Defines.MAX_MAP_BRUSHSIDES]; + static { + for (int n = 0; n < Defines.MAX_MAP_BRUSHSIDES; n++) + map_brushsides[n] = new cbrushside_t(); + } + + public static int numtexinfo; + + public static mapsurface_t map_surfaces[] = new mapsurface_t[Defines.MAX_MAP_TEXINFO]; + static { + for (int n = 0; n < Defines.MAX_MAP_TEXINFO; n++) + map_surfaces[n] = new mapsurface_t(); + } + + static int numplanes; + + // extra for box hull ( +6) + static cplane_t map_planes[] = new cplane_t[Defines.MAX_MAP_PLANES + 6]; + + static { + for (int n = 0; n < Defines.MAX_MAP_PLANES + 6; n++) + map_planes[n] = new cplane_t(); + } + + static int numnodes; + + // extra for box hull ( +6) + static cnode_t map_nodes[] = new cnode_t[Defines.MAX_MAP_NODES + 6]; + + static { + for (int n = 0; n < Defines.MAX_MAP_NODES + 6; n++) + map_nodes[n] = new cnode_t(); + } + + static int numleafs = 1; // allow leaf funcs to be called without a map + + static cleaf_t map_leafs[] = new cleaf_t[Defines.MAX_MAP_LEAFS]; + static { + for (int n = 0; n < Defines.MAX_MAP_LEAFS; n++) + map_leafs[n] = new cleaf_t(); + } + + static int emptyleaf, solidleaf; + + static int numleafbrushes; + + //static unsigned short map_leafbrushes[Defines.MAX_MAP_LEAFBRUSHES]; + public static int map_leafbrushes[] = new int[Defines.MAX_MAP_LEAFBRUSHES]; + + public static int numcmodels; + + public static cmodel_t map_cmodels[] = new cmodel_t[Defines.MAX_MAP_MODELS]; + static { + for (int n = 0; n < Defines.MAX_MAP_MODELS; n++) + map_cmodels[n] = new cmodel_t(); + + } + + public static int numbrushes; + + public static cbrush_t map_brushes[] = new cbrush_t[Defines.MAX_MAP_BRUSHES]; + static { + for (int n = 0; n < Defines.MAX_MAP_BRUSHES; n++) + map_brushes[n] = new cbrush_t(); + + } + + public static int numvisibility; + + public static byte map_visibility[] = new byte[Defines.MAX_MAP_VISIBILITY]; + + // main visibility data. rst + // was: static dvis_t *map_vis = (dvis_t *)map_visibility; + public static qfiles.dvis_t map_vis = new qfiles.dvis_t(ByteBuffer + .wrap(map_visibility)); + + public static int numentitychars; + + public static String map_entitystring; + + public static int numareas = 1; + + public static carea_t map_areas[] = new carea_t[Defines.MAX_MAP_AREAS]; + static { + for (int n = 0; n < Defines.MAX_MAP_AREAS; n++) + map_areas[n] = new carea_t(); + + } + + public static int numareaportals; + + public static qfiles.dareaportal_t map_areaportals[] = new qfiles.dareaportal_t[Defines.MAX_MAP_AREAPORTALS]; + + static { + for (int n = 0; n < Defines.MAX_MAP_AREAPORTALS; n++) + map_areaportals[n] = new qfiles.dareaportal_t(); + + } + + public static int numclusters = 1; + + public static mapsurface_t nullsurface = new mapsurface_t(); + + public static int floodvalid; + + public static boolean portalopen[] = new boolean[Defines.MAX_MAP_AREAPORTALS]; + + public static cvar_t map_noareas; + + /* + * =============================================================================== + * + * MAP LOADING + * + * =============================================================================== + */ + + public static byte cmod_base[]; + + // is that right (rst) ? + public static int checksum; + + public static int last_checksum; + + /* + * ================== CM_LoadMap + * + * Loads in the map and all submodels ================== + */ + public static cmodel_t CM_LoadMap(String name, boolean clientload, + int checksum[]) { + Com.DPrintf("CM_LoadMap...\n"); + byte buf[]; + int i; + qfiles.dheader_t header; + int length; + + map_noareas = Cvar.Get("map_noareas", "0", 0); + + if (map_name.equals(name) + && (clientload || 0 == Cvar.VariableValue("flushmap"))) { + + checksum[0] = last_checksum; + + if (!clientload) { + Arrays.fill(portalopen, false); + FloodAreaConnections(); + } + return map_cmodels[0]; // still have the right version + } + + // free old stuff + numnodes = 0; + numleafs = 0; + numcmodels = 0; + numvisibility = 0; + numentitychars = 0; + map_entitystring = ""; + map_name = ""; + + if (name == null || name.length() == 0) { + numleafs = 1; + numclusters = 1; + numareas = 1; + checksum[0] = 0; + return map_cmodels[0]; + // cinematic servers won't have anything at all + } + + // + // load the file + // + buf = FS.LoadFile(name); + + if (buf == null) + Com.Error(Defines.ERR_DROP, "Couldn't load " + name); + + length = buf.length; + + ByteBuffer bbuf = ByteBuffer.wrap(buf); + + last_checksum = MD4.Com_BlockChecksum(buf, length); + checksum[0] = last_checksum; + + header = new qfiles.dheader_t(bbuf.slice()); + + if (header.version != Defines.BSPVERSION) + Com.Error(Defines.ERR_DROP, "CMod_LoadBrushModel: " + name + + " has wrong version number (" + header.version + + " should be " + Defines.BSPVERSION + ")"); + + cmod_base = buf; + + // load into heap + CMod_LoadSurfaces(header.lumps[Defines.LUMP_TEXINFO]); // ok. + CMod_LoadLeafs(header.lumps[Defines.LUMP_LEAFS]); + CMod_LoadLeafBrushes(header.lumps[Defines.LUMP_LEAFBRUSHES]); + CMod_LoadPlanes(header.lumps[Defines.LUMP_PLANES]); + CMod_LoadBrushes(header.lumps[Defines.LUMP_BRUSHES]); + CMod_LoadBrushSides(header.lumps[Defines.LUMP_BRUSHSIDES]); + CMod_LoadSubmodels(header.lumps[Defines.LUMP_MODELS]); + + CMod_LoadNodes(header.lumps[Defines.LUMP_NODES]); + CMod_LoadAreas(header.lumps[Defines.LUMP_AREAS]); + CMod_LoadAreaPortals(header.lumps[Defines.LUMP_AREAPORTALS]); + CMod_LoadVisibility(header.lumps[Defines.LUMP_VISIBILITY]); + CMod_LoadEntityString(header.lumps[Defines.LUMP_ENTITIES]); + + FS.FreeFile(buf); + + CM_InitBoxHull(); + + Arrays.fill(portalopen, false); + + FloodAreaConnections(); + + map_name = name; + + // debug (rst) + /* + * Com.p("Testing pointleafes:"); for (int n = 0; n < 20; n++) { float + * pos[] = new float[] {(float) (Math.random() * 1000), (float) + * (Math.random() * 1000), 0 }; int x = CM_PointLeafnum(pos); + * Com.p(Lib.vtofsbeaty(pos) + " ---> leaf=" + x + " area = " + * +map_leafs[x].area); } + */ + return map_cmodels[0]; + } + + /* + * ================= CMod_LoadSubmodels ================= + */ + public static void CMod_LoadSubmodels(lump_t l) { + Com.DPrintf("CMod_LoadSubmodels...\n"); + qfiles.dmodel_t in; + cmodel_t out; + int i, j, count; + + if ((l.filelen % qfiles.dmodel_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dmodel_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no models"); + if (count > Defines.MAX_MAP_MODELS) + Com.Error(Defines.ERR_DROP, "Map has too many models"); + + Com.DPrintf(" numcmodels=" + count + "\n"); + numcmodels = count; + + if (debugloadmap) { + Com.DPrintf("submodles(headnode, <origin>, <mins>, <maxs>)\n"); + } + for (i = 0; i < count; i++) { + in = new qfiles.dmodel_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dmodel_t.SIZE + l.fileofs, qfiles.dmodel_t.SIZE)); + out = map_cmodels[i]; + + for (j = 0; j < 3; j++) { // spread the mins / maxs by a pixel + out.mins[j] = in.mins[j] - 1; + out.maxs[j] = in.maxs[j] + 1; + out.origin[j] = in.origin[j]; + } + out.headnode = in.headnode; + if (debugloadmap) { + Com + .DPrintf( + "|%6i|%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n", + new Vargs().add(out.headnode) + .add(out.origin[0]).add(out.origin[1]) + .add(out.origin[2]).add(out.mins[0]) + .add(out.mins[1]).add(out.mins[2]).add( + out.maxs[0]).add(out.maxs[1]) + .add(out.maxs[2])); + } + } + } + + static boolean debugloadmap = false; + + /* + * ================= CMod_LoadSurfaces ================= + */ + public static void CMod_LoadSurfaces(lump_t l) { + Com.DPrintf("CMod_LoadSurfaces...\n"); + texinfo_t in; + mapsurface_t out; + int i, count; + + if ((l.filelen % texinfo_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / texinfo_t.SIZE; + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no surfaces"); + if (count > Defines.MAX_MAP_TEXINFO) + Com.Error(Defines.ERR_DROP, "Map has too many surfaces"); + + numtexinfo = count; + Com.DPrintf("numtexinfo=" + count + "\n"); + if (debugloadmap) + Com.DPrintf("surfaces:\n"); + + for (i = 0; i < count; i++) { + out = map_surfaces[i] = new mapsurface_t(); + in = new texinfo_t(cmod_base, l.fileofs + i * texinfo_t.SIZE, + texinfo_t.SIZE); + + out.c.name = in.texture; + out.rname = in.texture; + out.c.flags = in.flags; + out.c.value = in.value; + + if (debugloadmap) { + Com.DPrintf("|%20s|%20s|%6i|%6i|\n", new Vargs() + .add(out.c.name).add(out.rname).add(out.c.value).add( + out.c.flags)); + } + + } + } + + /* + * ================= CMod_LoadNodes + * + * ================= + */ + public static void CMod_LoadNodes(lump_t l) { + Com.DPrintf("CMod_LoadNodes...\n"); + qfiles.dnode_t in; + int child; + cnode_t out; + int i, j, count; + + if ((l.filelen % qfiles.dnode_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size:" + + l.fileofs + "," + qfiles.dnode_t.SIZE); + count = l.filelen / qfiles.dnode_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map has no nodes"); + if (count > Defines.MAX_MAP_NODES) + Com.Error(Defines.ERR_DROP, "Map has too many nodes"); + + numnodes = count; + Com.DPrintf(" numnodes=" + count + "\n"); + + if (debugloadmap) { + Com.DPrintf("nodes(planenum, child[0], child[1])\n"); + } + + for (i = 0; i < count; i++) { + in = new qfiles.dnode_t(ByteBuffer.wrap(cmod_base, + qfiles.dnode_t.SIZE * i + l.fileofs, qfiles.dnode_t.SIZE)); + out = map_nodes[i]; + + out.plane = map_planes[in.planenum]; + for (j = 0; j < 2; j++) { + child = in.children[j]; + out.children[j] = child; + } + if (debugloadmap) { + Com.DPrintf("|%6i| %6i| %6i|\n", new Vargs().add(in.planenum) + .add(out.children[0]).add(out.children[1])); + } + } + } + + /* + * ================= CMod_LoadBrushes + * + * ================= + */ + public static void CMod_LoadBrushes(lump_t l) { + Com.DPrintf("CMod_LoadBrushes...\n"); + qfiles.dbrush_t in; + cbrush_t out; + int i, count; + + if ((l.filelen % qfiles.dbrush_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dbrush_t.SIZE; + + if (count > Defines.MAX_MAP_BRUSHES) + Com.Error(Defines.ERR_DROP, "Map has too many brushes"); + + numbrushes = count; + Com.DPrintf(" numbrushes=" + count + "\n"); + if (debugloadmap) { + Com.DPrintf("brushes:(firstbrushside, numsides, contents)\n"); + } + for (i = 0; i < count; i++) { + in = new qfiles.dbrush_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dbrush_t.SIZE + l.fileofs, qfiles.dbrush_t.SIZE)); + out = map_brushes[i]; + out.firstbrushside = in.firstside; + out.numsides = in.numsides; + out.contents = in.contents; + + if (debugloadmap) { + Com + .DPrintf("| %6i| %6i| %8X|\n", new Vargs().add( + out.firstbrushside).add(out.numsides).add( + out.contents)); + } + } + } + + /* + * ================= CMod_LoadLeafs ================= + */ + public static void CMod_LoadLeafs(lump_t l) { + Com.DPrintf("CMod_LoadLeafs...\n"); + int i; + cleaf_t out; + qfiles.dleaf_t in; + int count; + + if ((l.filelen % qfiles.dleaf_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dleaf_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no leafs"); + + // need to save space for box planes + if (count > Defines.MAX_MAP_PLANES) + Com.Error(Defines.ERR_DROP, "Map has too many planes"); + + Com.DPrintf(" numleafes=" + count + "\n"); + + numleafs = count; + numclusters = 0; + if (debugloadmap) + Com + .DPrintf("cleaf-list:(contents, cluster, area, firstleafbrush, numleafbrushes)\n"); + for (i = 0; i < count; i++) { + in = new qfiles.dleaf_t(cmod_base, i * qfiles.dleaf_t.SIZE + + l.fileofs, qfiles.dleaf_t.SIZE); + + out = map_leafs[i]; + + out.contents = in.contents; + out.cluster = in.cluster; + out.area = in.area; + out.firstleafbrush = (short) in.firstleafbrush; + out.numleafbrushes = (short) in.numleafbrushes; + + if (out.cluster >= numclusters) + numclusters = out.cluster + 1; + + if (debugloadmap) { + Com.DPrintf("|%8x|%6i|%6i|%6i|\n", new Vargs() + .add(out.contents).add(out.cluster).add(out.area).add( + out.firstleafbrush).add(out.numleafbrushes)); + } + + } + + Com.DPrintf(" numclusters=" + numclusters + "\n"); + + if (map_leafs[0].contents != Defines.CONTENTS_SOLID) + Com.Error(Defines.ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID"); + + solidleaf = 0; + emptyleaf = -1; + + for (i = 1; i < numleafs; i++) { + if (map_leafs[i].contents == 0) { + emptyleaf = i; + break; + } + } + + if (emptyleaf == -1) + Com.Error(Defines.ERR_DROP, "Map does not have an empty leaf"); + } + + /* + * ================= CMod_LoadPlanes ================= + */ + public static void CMod_LoadPlanes(lump_t l) { + Com.DPrintf("CMod_LoadPlanes...\n"); + int i, j; + cplane_t out; + qfiles.dplane_t in; + int count; + int bits; + + if ((l.filelen % qfiles.dplane_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dplane_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no planes"); + + // need to save space for box planes + if (count > Defines.MAX_MAP_PLANES) + Com.Error(Defines.ERR_DROP, "Map has too many planes"); + + Com.DPrintf(" numplanes=" + count + "\n"); + + numplanes = count; + if (debugloadmap) { + Com + .DPrintf("cplanes(normal[0],normal[1],normal[2], dist, type, signbits)\n"); + } + + for (i = 0; i < count; i++) { + in = new qfiles.dplane_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dplane_t.SIZE + l.fileofs, qfiles.dplane_t.SIZE)); + + out = map_planes[i]; + + bits = 0; + for (j = 0; j < 3; j++) { + out.normal[j] = in.normal[j]; + + if (out.normal[j] < 0) + bits |= 1 << j; + } + + out.dist = in.dist; + out.type = (byte) in.type; + out.signbits = (byte) bits; + + if (debugloadmap) { + Com.DPrintf("|%6.2f|%6.2f|%6.2f| %10.2f|%3i| %1i|\n", + new Vargs().add(out.normal[0]).add(out.normal[1]).add( + out.normal[2]).add(out.dist).add(out.type).add( + out.signbits)); + } + } + } + + /* + * ================= CMod_LoadLeafBrushes ================= + */ + public static void CMod_LoadLeafBrushes(lump_t l) { + Com.DPrintf("CMod_LoadLeafBrushes...\n"); + int i; + int out[]; + short in[]; + int count; + + if ((l.filelen % 2) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / 2; + + Com.DPrintf(" numbrushes=" + count + "\n"); + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no planes"); + + // need to save space for box planes + if (count > Defines.MAX_MAP_LEAFBRUSHES) + Com.Error(Defines.ERR_DROP, "Map has too many leafbrushes"); + + out = map_leafbrushes; + numleafbrushes = count; + + ByteBuffer bb = ByteBuffer.wrap(cmod_base, l.fileofs, count * 2).order( + ByteOrder.LITTLE_ENDIAN); + + if (debugloadmap) { + Com.DPrintf("map_brushes:\n"); + } + + for (i = 0; i < count; i++) { + out[i] = bb.getShort(); + if (debugloadmap) { + Com.DPrintf("|%6i|%6i|\n", new Vargs().add(i).add(out[i])); + } + } + } + + /* + * ================= CMod_LoadBrushSides ================= + */ + public static void CMod_LoadBrushSides(lump_t l) { + Com.DPrintf("CMod_LoadBrushSides...\n"); + int i, j; + cbrushside_t out; + qfiles.dbrushside_t in; + int count; + int num; + + if ((l.filelen % qfiles.dbrushside_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l.filelen / qfiles.dbrushside_t.SIZE; + + // need to save space for box planes + if (count > Defines.MAX_MAP_BRUSHSIDES) + Com.Error(Defines.ERR_DROP, "Map has too many planes"); + + numbrushsides = count; + + Com.DPrintf(" numbrushsides=" + count + "\n"); + + if (debugloadmap) { + Com.DPrintf("brushside(planenum, surfacenum):\n"); + } + for (i = 0; i < count; i++) { + + in = new qfiles.dbrushside_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dbrushside_t.SIZE + l.fileofs, + qfiles.dbrushside_t.SIZE)); + + out = map_brushsides[i]; + + num = in.planenum; + + out.plane = map_planes[num]; // pointer + + j = in.texinfo; + + if (j >= numtexinfo) + Com.Error(Defines.ERR_DROP, "Bad brushside texinfo"); + + // rst: some mysterious happens here, even in the original code ???, + // texinfo is -1!!! + // hoz: checked against c version: ok. + if (j == -1) + out.surface = new mapsurface_t(); // just for safety + else + out.surface = map_surfaces[j]; + + if (debugloadmap) { + Com.DPrintf("| %6i| %6i|\n", new Vargs().add(num).add(j)); + } + } + } + + /* + * ================= CMod_LoadAreas ================= + */ + public static void CMod_LoadAreas(lump_t l) { + Com.DPrintf("CMod_LoadAreas...\n"); + int i; + carea_t out; + qfiles.darea_t in; + int count; + + if ((l.filelen % qfiles.darea_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.darea_t.SIZE; + + if (count > Defines.MAX_MAP_AREAS) + Com.Error(Defines.ERR_DROP, "Map has too many areas"); + + Com.DPrintf(" numareas=" + count + "\n"); + numareas = count; + + if (debugloadmap) { + Com.DPrintf("areas(numportals, firstportal)\n"); + } + + for (i = 0; i < count; i++) { + + in = new qfiles.darea_t(ByteBuffer.wrap(cmod_base, i + * qfiles.darea_t.SIZE + l.fileofs, qfiles.darea_t.SIZE)); + out = map_areas[i]; + + out.numareaportals = in.numareaportals; + out.firstareaportal = in.firstareaportal; + out.floodvalid = 0; + out.floodnum = 0; + if (debugloadmap) { + Com.DPrintf("| %6i| %6i|\n", new Vargs() + .add(out.numareaportals).add(out.firstareaportal)); + } + } + } + + /* + * ================= CMod_LoadAreaPortals ================= + */ + public static void CMod_LoadAreaPortals(lump_t l) { + Com.DPrintf("CMod_LoadAreaPortals...\n"); + int i; + qfiles.dareaportal_t out; + qfiles.dareaportal_t in; + int count; + + if ((l.filelen % qfiles.dareaportal_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l.filelen / qfiles.dareaportal_t.SIZE; - static int checkcount; - - static String map_name = ""; - - static int numbrushsides; - static cbrushside_t map_brushsides[] = new cbrushside_t[MAX_MAP_BRUSHSIDES]; - static { - for (int n = 0; n < MAX_MAP_BRUSHSIDES; n++) - map_brushsides[n] = new cbrushside_t(); - } - - public static int numtexinfo; - public static mapsurface_t map_surfaces[] = new mapsurface_t[MAX_MAP_TEXINFO]; - static { - for (int n = 0; n < MAX_MAP_TEXINFO; n++) - map_surfaces[n] = new mapsurface_t(); - } - - static int numplanes; - // extra for box hull ( +6) - static cplane_t map_planes[] = new cplane_t[MAX_MAP_PLANES + 6]; - - static { - for (int n = 0; n < MAX_MAP_PLANES + 6; n++) - map_planes[n] = new cplane_t(); - } - - static int numnodes; - // extra for box hull ( +6) - static cnode_t map_nodes[] = new cnode_t[MAX_MAP_NODES + 6]; - - static { - for (int n = 0; n < MAX_MAP_NODES + 6; n++) - map_nodes[n] = new cnode_t(); - } - - static int numleafs = 1; // allow leaf funcs to be called without a map - static cleaf_t map_leafs[] = new cleaf_t[MAX_MAP_LEAFS]; - static { - for (int n = 0; n < MAX_MAP_LEAFS; n++) - map_leafs[n] = new cleaf_t(); - } - - static int emptyleaf, solidleaf; - - static int numleafbrushes; - //static unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES]; - public static int map_leafbrushes[] = new int[MAX_MAP_LEAFBRUSHES]; - public static int numcmodels; - public static cmodel_t map_cmodels[] = new cmodel_t[MAX_MAP_MODELS]; - static { - for (int n = 0; n < MAX_MAP_MODELS; n++) - map_cmodels[n] = new cmodel_t(); - - } - - public static int numbrushes; - public static cbrush_t map_brushes[] = new cbrush_t[MAX_MAP_BRUSHES]; - static { - for (int n = 0; n < MAX_MAP_BRUSHES; n++) - map_brushes[n] = new cbrush_t(); - - } - - public static int numvisibility; - public static byte map_visibility[] = new byte[MAX_MAP_VISIBILITY]; - - // main visibility data. rst - // was: static dvis_t *map_vis = (dvis_t *)map_visibility; - public static qfiles.dvis_t map_vis = new qfiles.dvis_t(ByteBuffer.wrap(map_visibility)); - - public static int numentitychars; - public static String map_entitystring; - - public static int numareas = 1; - public static carea_t map_areas[] = new carea_t[MAX_MAP_AREAS]; - static { - for (int n = 0; n < MAX_MAP_AREAS; n++) - map_areas[n] = new carea_t(); - - } - public static int numareaportals; - public static qfiles.dareaportal_t map_areaportals[] = new qfiles.dareaportal_t[MAX_MAP_AREAPORTALS]; - - static { - for (int n = 0; n < MAX_MAP_AREAPORTALS; n++) - map_areaportals[n] = new qfiles.dareaportal_t(); - - } - - public static int numclusters = 1; - - public static mapsurface_t nullsurface = new mapsurface_t(); - - public static int floodvalid; - - public static boolean portalopen[] = new boolean[MAX_MAP_AREAPORTALS]; - - public static cvar_t map_noareas; - - /* - =============================================================================== - - MAP LOADING - - =============================================================================== - */ - - public static byte cmod_base[]; - - // is that right (rst) ? - public static int checksum; - public static int last_checksum; - - /* - ================== - CM_LoadMap - - Loads in the map and all submodels - ================== - */ - public static cmodel_t CM_LoadMap(String name, boolean clientload, int checksum[]) { - Com.DPrintf("CM_LoadMap...\n"); - byte buf[]; - int i; - qfiles.dheader_t header; - int length; - - map_noareas = Cvar.Get("map_noareas", "0", 0); - - if (map_name.equals(name) && (clientload || 0 == Cvar.VariableValue("flushmap"))) { - - checksum[0] = last_checksum; - - if (!clientload) { - Arrays.fill(portalopen, false); - FloodAreaConnections(); - } - return map_cmodels[0]; // still have the right version - } - - // free old stuff - numnodes = 0; - numleafs = 0; - numcmodels = 0; - numvisibility = 0; - numentitychars = 0; - map_entitystring = ""; - map_name = ""; - - if (name == null || name.length() == 0) { - numleafs = 1; - numclusters = 1; - numareas = 1; - checksum[0] = 0; - return map_cmodels[0]; - // cinematic servers won't have anything at all - } - - // - // load the file - // - buf = FS.LoadFile(name); - - if (buf == null) - Com.Error(ERR_DROP, "Couldn't load " + name); - - length = buf.length; - - ByteBuffer bbuf = ByteBuffer.wrap(buf); - - last_checksum = MD4.Com_BlockChecksum(buf, length); - checksum[0] = last_checksum; - - header = new qfiles.dheader_t(bbuf.slice()); - - if (header.version != BSPVERSION) - Com.Error( - ERR_DROP, - "CMod_LoadBrushModel: " + name + " has wrong version number (" + header.version + " should be " + BSPVERSION + ")"); - - cmod_base = buf; - - // load into heap - CMod_LoadSurfaces(header.lumps[LUMP_TEXINFO]); // ok. - CMod_LoadLeafs(header.lumps[LUMP_LEAFS]); - CMod_LoadLeafBrushes(header.lumps[LUMP_LEAFBRUSHES]); - CMod_LoadPlanes(header.lumps[LUMP_PLANES]); - CMod_LoadBrushes(header.lumps[LUMP_BRUSHES]); - CMod_LoadBrushSides(header.lumps[LUMP_BRUSHSIDES]); - CMod_LoadSubmodels(header.lumps[LUMP_MODELS]); - - CMod_LoadNodes(header.lumps[LUMP_NODES]); - CMod_LoadAreas(header.lumps[LUMP_AREAS]); - CMod_LoadAreaPortals(header.lumps[LUMP_AREAPORTALS]); - CMod_LoadVisibility(header.lumps[LUMP_VISIBILITY]); - CMod_LoadEntityString(header.lumps[LUMP_ENTITIES]); - - FS.FreeFile(buf); - - CM_InitBoxHull(); - - Arrays.fill(portalopen, false); - - FloodAreaConnections(); - - map_name = name; - - // debug (rst) - /* - Com.p("Testing pointleafes:"); - for (int n = 0; n < 20; n++) { - float pos[] = new float[] {(float) (Math.random() * 1000), (float) (Math.random() * 1000), 0 }; - int x = CM_PointLeafnum(pos); - Com.p(Lib.vtofsbeaty(pos) + " ---> leaf=" + x + " area = " +map_leafs[x].area); - } - */ - return map_cmodels[0]; - } - - /* - ================= - CMod_LoadSubmodels - ================= - */ - public static void CMod_LoadSubmodels(lump_t l) { - Com.DPrintf("CMod_LoadSubmodels...\n"); - qfiles.dmodel_t in; - cmodel_t out; - int i, j, count; - - if ((l.filelen % qfiles.dmodel_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dmodel_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map with no models"); - if (count > MAX_MAP_MODELS) - Com.Error(ERR_DROP, "Map has too many models"); - - Com.DPrintf(" numcmodels=" + count + "\n"); - numcmodels = count; - - if (debugloadmap) { - Com.DPrintf("submodles(headnode, <origin>, <mins>, <maxs>)\n"); - } - for (i = 0; i < count; i++) { - in = new qfiles.dmodel_t(ByteBuffer.wrap(cmod_base, i * qfiles.dmodel_t.SIZE + l.fileofs, qfiles.dmodel_t.SIZE)); - out = map_cmodels[i]; - - for (j = 0; j < 3; j++) { // spread the mins / maxs by a pixel - out.mins[j] = in.mins[j] - 1; - out.maxs[j] = in.maxs[j] + 1; - out.origin[j] = in.origin[j]; - } - out.headnode = in.headnode; - if (debugloadmap) { - Com.DPrintf( - "|%6i|%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n", - new Vargs() - .add(out.headnode) - .add(out.origin[0]) - .add(out.origin[1]) - .add(out.origin[2]) - .add(out.mins[0]) - .add(out.mins[1]) - .add(out.mins[2]) - .add(out.maxs[0]) - .add(out.maxs[1]) - .add(out.maxs[2])); - } - } - } - static boolean debugloadmap = false; - - /* - ================= - CMod_LoadSurfaces - ================= - */ - public static void CMod_LoadSurfaces(lump_t l) { - Com.DPrintf("CMod_LoadSurfaces...\n"); - texinfo_t in; - mapsurface_t out; - int i, count; - - if ((l.filelen % texinfo_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / texinfo_t.SIZE; - if (count < 1) - Com.Error(ERR_DROP, "Map with no surfaces"); - if (count > MAX_MAP_TEXINFO) - Com.Error(ERR_DROP, "Map has too many surfaces"); - - numtexinfo = count; - Com.DPrintf("numtexinfo=" + count + "\n"); - if (debugloadmap) - Com.DPrintf("surfaces:\n"); - - for (i = 0; i < count; i++) { - out = map_surfaces[i] = new mapsurface_t(); - in = new texinfo_t(cmod_base, l.fileofs + i * texinfo_t.SIZE, texinfo_t.SIZE); - - out.c.name = in.texture; - out.rname = in.texture; - out.c.flags = in.flags; - out.c.value = in.value; - - if (debugloadmap) { - Com.DPrintf("|%20s|%20s|%6i|%6i|\n", new Vargs().add(out.c.name).add(out.rname).add(out.c.value).add(out.c.flags)); - } - - } - } - - /* - ================= - CMod_LoadNodes - - ================= - */ - public static void CMod_LoadNodes(lump_t l) { - Com.DPrintf("CMod_LoadNodes...\n"); - qfiles.dnode_t in; - int child; - cnode_t out; - int i, j, count; - - if ((l.filelen % qfiles.dnode_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size:" + l.fileofs + "," + qfiles.dnode_t.SIZE); - count = l.filelen / qfiles.dnode_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map has no nodes"); - if (count > MAX_MAP_NODES) - Com.Error(ERR_DROP, "Map has too many nodes"); - - numnodes = count; - Com.DPrintf(" numnodes=" + count + "\n"); - - if (debugloadmap) { - Com.DPrintf("nodes(planenum, child[0], child[1])\n"); - } - - for (i = 0; i < count; i++) { - in = new qfiles.dnode_t(ByteBuffer.wrap(cmod_base, qfiles.dnode_t.SIZE * i + l.fileofs, qfiles.dnode_t.SIZE)); - out = map_nodes[i]; - - out.plane = map_planes[in.planenum]; - for (j = 0; j < 2; j++) { - child = in.children[j]; - out.children[j] = child; - } - if (debugloadmap) { - Com.DPrintf("|%6i| %6i| %6i|\n", new Vargs().add(in.planenum).add(out.children[0]).add(out.children[1])); - } - } - } - - /* - ================= - CMod_LoadBrushes - - ================= - */ - public static void CMod_LoadBrushes(lump_t l) { - Com.DPrintf("CMod_LoadBrushes...\n"); - qfiles.dbrush_t in; - cbrush_t out; - int i, count; - - if ((l.filelen % qfiles.dbrush_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dbrush_t.SIZE; - - if (count > MAX_MAP_BRUSHES) - Com.Error(ERR_DROP, "Map has too many brushes"); - - numbrushes = count; - Com.DPrintf(" numbrushes=" + count + "\n"); - if (debugloadmap) { - Com.DPrintf("brushes:(firstbrushside, numsides, contents)\n"); - } - for (i = 0; i < count; i++) { - in = new qfiles.dbrush_t(ByteBuffer.wrap(cmod_base, i * qfiles.dbrush_t.SIZE + l.fileofs, qfiles.dbrush_t.SIZE)); - out = map_brushes[i]; - out.firstbrushside = in.firstside; - out.numsides = in.numsides; - out.contents = in.contents; - - if (debugloadmap) { - Com.DPrintf("| %6i| %6i| %8X|\n", new Vargs().add(out.firstbrushside).add(out.numsides).add(out.contents)); - } - } - } - - /* - ================= - CMod_LoadLeafs - ================= - */ - public static void CMod_LoadLeafs(lump_t l) { - Com.DPrintf("CMod_LoadLeafs...\n"); - int i; - cleaf_t out; - qfiles.dleaf_t in; - int count; - - if ((l.filelen % qfiles.dleaf_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dleaf_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map with no leafs"); - - // need to save space for box planes - if (count > MAX_MAP_PLANES) - Com.Error(ERR_DROP, "Map has too many planes"); - - Com.DPrintf(" numleafes=" + count + "\n"); - - numleafs = count; - numclusters = 0; - if (debugloadmap) - Com.DPrintf("cleaf-list:(contents, cluster, area, firstleafbrush, numleafbrushes)\n"); - for (i = 0; i < count; i++) { - in = new qfiles.dleaf_t(cmod_base, i * qfiles.dleaf_t.SIZE + l.fileofs, qfiles.dleaf_t.SIZE); - - out = map_leafs[i]; - - out.contents = in.contents; - out.cluster = in.cluster; - out.area = in.area; - out.firstleafbrush = (short) in.firstleafbrush; - out.numleafbrushes = (short) in.numleafbrushes; - - if (out.cluster >= numclusters) - numclusters = out.cluster + 1; - - if (debugloadmap) { - Com.DPrintf( - "|%8x|%6i|%6i|%6i|\n", - new Vargs().add(out.contents).add(out.cluster).add(out.area).add(out.firstleafbrush).add(out.numleafbrushes)); - } - - } - - Com.DPrintf(" numclusters=" + numclusters + "\n"); - - if (map_leafs[0].contents != CONTENTS_SOLID) - Com.Error(ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID"); - - solidleaf = 0; - emptyleaf = -1; - - for (i = 1; i < numleafs; i++) { - if (map_leafs[i].contents == 0) { - emptyleaf = i; - break; - } - } - - if (emptyleaf == -1) - Com.Error(ERR_DROP, "Map does not have an empty leaf"); - } - - /* - ================= - CMod_LoadPlanes - ================= - */ - public static void CMod_LoadPlanes(lump_t l) { - Com.DPrintf("CMod_LoadPlanes...\n"); - int i, j; - cplane_t out; - qfiles.dplane_t in; - int count; - int bits; - - if ((l.filelen % qfiles.dplane_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dplane_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map with no planes"); - - // need to save space for box planes - if (count > MAX_MAP_PLANES) - Com.Error(ERR_DROP, "Map has too many planes"); - - Com.DPrintf(" numplanes=" + count + "\n"); - - numplanes = count; - if (debugloadmap) { - Com.DPrintf("cplanes(normal[0],normal[1],normal[2], dist, type, signbits)\n"); - } - - for (i = 0; i < count; i++) { - in = new qfiles.dplane_t(ByteBuffer.wrap(cmod_base, i * qfiles.dplane_t.SIZE + l.fileofs, qfiles.dplane_t.SIZE)); - - out = map_planes[i]; - - bits = 0; - for (j = 0; j < 3; j++) { - out.normal[j] = in.normal[j]; + if (count > Defines.MAX_MAP_AREAS) + Com.Error(Defines.ERR_DROP, "Map has too many areas"); - if (out.normal[j] < 0) - bits |= 1 << j; - } - - out.dist = in.dist; - out.type = (byte) in.type; - out.signbits = (byte) bits; - - if (debugloadmap) { - Com.DPrintf( - "|%6.2f|%6.2f|%6.2f| %10.2f|%3i| %1i|\n", - new Vargs().add(out.normal[0]).add(out.normal[1]).add(out.normal[2]).add(out.dist).add(out.type).add( - out.signbits)); - } - } - } - - /* - ================= - CMod_LoadLeafBrushes - ================= - */ - public static void CMod_LoadLeafBrushes(lump_t l) { - Com.DPrintf("CMod_LoadLeafBrushes...\n"); - int i; - int out[]; - short in[]; - int count; - - if ((l.filelen % 2) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / 2; - - Com.DPrintf(" numbrushes=" + count + "\n"); - - if (count < 1) - Com.Error(ERR_DROP, "Map with no planes"); - - // need to save space for box planes - if (count > MAX_MAP_LEAFBRUSHES) - Com.Error(ERR_DROP, "Map has too many leafbrushes"); - - out = map_leafbrushes; - numleafbrushes = count; - - ByteBuffer bb = ByteBuffer.wrap(cmod_base, l.fileofs, count * 2).order(ByteOrder.LITTLE_ENDIAN); - - if (debugloadmap) { - Com.DPrintf("map_brushes:\n"); - } - - for (i = 0; i < count; i++) { - out[i] = bb.getShort(); - if (debugloadmap) { - Com.DPrintf("|%6i|%6i|\n", new Vargs().add(i).add(out[i])); - } - } - } - - /* - ================= - CMod_LoadBrushSides - ================= - */ - public static void CMod_LoadBrushSides(lump_t l) { - Com.DPrintf("CMod_LoadBrushSides...\n"); - int i, j; - cbrushside_t out; - qfiles.dbrushside_t in; - int count; - int num; - - if ((l.filelen % qfiles.dbrushside_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - count = l.filelen / qfiles.dbrushside_t.SIZE; - - // need to save space for box planes - if (count > MAX_MAP_BRUSHSIDES) - Com.Error(ERR_DROP, "Map has too many planes"); - - numbrushsides = count; - - Com.DPrintf(" numbrushsides=" + count + "\n"); - - if (debugloadmap) { - Com.DPrintf("brushside(planenum, surfacenum):\n"); - } - for (i = 0; i < count; i++) { - - in = - new qfiles.dbrushside_t( - ByteBuffer.wrap(cmod_base, i * qfiles.dbrushside_t.SIZE + l.fileofs, qfiles.dbrushside_t.SIZE)); - - out = map_brushsides[i]; - - num = in.planenum; - - out.plane = map_planes[num]; // pointer - - j = in.texinfo; - - if (j >= numtexinfo) - Com.Error(ERR_DROP, "Bad brushside texinfo"); - - // rst: some mysterious happens here, even in the original code ???, texinfo is -1!!! - // hoz: checked against c version: ok. - if (j == -1) - out.surface = new mapsurface_t(); // just for safety - else - out.surface = map_surfaces[j]; - - if (debugloadmap) { - Com.DPrintf("| %6i| %6i|\n", new Vargs().add(num).add(j)); - } - } - } - - /* - ================= - CMod_LoadAreas - ================= - */ - public static void CMod_LoadAreas(lump_t l) { - Com.DPrintf("CMod_LoadAreas...\n"); - int i; - carea_t out; - qfiles.darea_t in; - int count; - - if ((l.filelen % qfiles.darea_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.darea_t.SIZE; - - if (count > MAX_MAP_AREAS) - Com.Error(ERR_DROP, "Map has too many areas"); - - Com.DPrintf(" numareas=" + count + "\n"); - numareas = count; - - if (debugloadmap) { - Com.DPrintf("areas(numportals, firstportal)\n"); - } - - for (i = 0; i < count; i++) { - - in = new qfiles.darea_t(ByteBuffer.wrap(cmod_base, i * qfiles.darea_t.SIZE + l.fileofs, qfiles.darea_t.SIZE)); - out = map_areas[i]; - - out.numareaportals = in.numareaportals; - out.firstareaportal = in.firstareaportal; - out.floodvalid = 0; - out.floodnum = 0; - if (debugloadmap) { - Com.DPrintf("| %6i| %6i|\n", new Vargs().add(out.numareaportals).add(out.firstareaportal)); - } - } - } - - /* - ================= - CMod_LoadAreaPortals - ================= - */ - public static void CMod_LoadAreaPortals(lump_t l) { - Com.DPrintf("CMod_LoadAreaPortals...\n"); - int i; - qfiles.dareaportal_t out; - qfiles.dareaportal_t in; - int count; + numareaportals = count; + Com.DPrintf(" numareaportals=" + count + "\n"); + if (debugloadmap) { + Com.DPrintf("areaportals(portalnum, otherarea)\n"); + } + for (i = 0; i < count; i++) { + in = new qfiles.dareaportal_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dareaportal_t.SIZE + l.fileofs, + qfiles.dareaportal_t.SIZE)); + + out = map_areaportals[i]; - if ((l.filelen % qfiles.dareaportal_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - count = l.filelen / qfiles.dareaportal_t.SIZE; + out.portalnum = in.portalnum; + out.otherarea = in.otherarea; - if (count > MAX_MAP_AREAS) - Com.Error(ERR_DROP, "Map has too many areas"); + if (debugloadmap) { + Com.DPrintf("|%6i|%6i|\n", new Vargs().add(out.portalnum).add( + out.otherarea)); + } + } + } - numareaportals = count; - Com.DPrintf(" numareaportals=" + count + "\n"); - if (debugloadmap) { - Com.DPrintf("areaportals(portalnum, otherarea)\n"); - } - for (i = 0; i < count; i++) { - in = - new qfiles.dareaportal_t( - ByteBuffer.wrap(cmod_base, i * qfiles.dareaportal_t.SIZE + l.fileofs, qfiles.dareaportal_t.SIZE)); - - out = map_areaportals[i]; - - out.portalnum = in.portalnum; - out.otherarea = in.otherarea; - - if (debugloadmap) { - Com.DPrintf("|%6i|%6i|\n", new Vargs().add(out.portalnum).add(out.otherarea)); - } - } - } - - - /* - ================= - CMod_LoadVisibility - ================= - */ - public static void CMod_LoadVisibility(lump_t l) { - Com.DPrintf("CMod_LoadVisibility...\n"); - int i; - - numvisibility = l.filelen; - - Com.DPrintf(" numvisibility=" + numvisibility + "\n"); - - if (l.filelen > MAX_MAP_VISIBILITY) - Com.Error(ERR_DROP, "Map has too large visibility lump"); - - System.arraycopy(cmod_base, l.fileofs, map_visibility, 0, l.filelen); - - ByteBuffer bb = ByteBuffer.wrap(map_visibility, 0, l.filelen); - bb.order(ByteOrder.LITTLE_ENDIAN); - - map_vis = new qfiles.dvis_t(bb); - - } - - /* - ================= - CMod_LoadEntityString - ================= - */ - public static void CMod_LoadEntityString(lump_t l) { - Com.DPrintf("CMod_LoadEntityString...\n"); - - numentitychars = l.filelen; - - if (l.filelen > MAX_MAP_ENTSTRING) - Com.Error(ERR_DROP, "Map has too large entity lump"); - - int x = 0; - for (; x < l.filelen && cmod_base[x + l.fileofs] != 0; x++); - - map_entitystring = new String(cmod_base, l.fileofs, x).trim(); - } - - /* - ================== - CM_InlineModel - ================== - */ - - // works fine - public static cmodel_t InlineModel(String name) { - int num; - - if (name == null || name.charAt(0) != '*') - Com.Error(ERR_DROP, "CM_InlineModel: bad name"); - - num = atoi(name.substring(1)); - - if (num < 1 || num >= numcmodels) - Com.Error(ERR_DROP, "CM_InlineModel: bad number"); - - return map_cmodels[num]; - } - - public static int CM_NumClusters() { - return numclusters; - } - - public static int CM_NumInlineModels() { - return numcmodels; - } - - public static String CM_EntityString() { - return map_entitystring; - } - - public static int CM_LeafContents(int leafnum) { - if (leafnum < 0 || leafnum >= numleafs) - Com.Error(ERR_DROP, "CM_LeafContents: bad number"); - return map_leafs[leafnum].contents; - } - - public static int CM_LeafCluster(int leafnum) { - if (leafnum < 0 || leafnum >= numleafs) - Com.Error(ERR_DROP, "CM_LeafCluster: bad number"); - return map_leafs[leafnum].cluster; - } - - public static int CM_LeafArea(int leafnum) { - if (leafnum < 0 || leafnum >= numleafs) - Com.Error(ERR_DROP, "CM_LeafArea: bad number"); - return map_leafs[leafnum].area; - } - - //======================================================================= - - static cplane_t box_planes[]; - static int box_headnode; - static cbrush_t box_brush; - static cleaf_t box_leaf; - - /* - =================== - CM_InitBoxHull - - Set up the planes and nodes so that the six floats of a bounding box - can just be stored out and get a proper clipping hull structure. - =================== - */ - public static void CM_InitBoxHull() { - int i; - int side; - cnode_t c; - cplane_t p; - cbrushside_t s; - - box_headnode = numnodes; // noch platz f?r 6 brushes - - box_planes = - new cplane_t[] { - map_planes[numplanes], - map_planes[numplanes + 1], - map_planes[numplanes + 2], - map_planes[numplanes + 3], - map_planes[numplanes + 4], - map_planes[numplanes + 5], - map_planes[numplanes + 6], - map_planes[numplanes + 7], - map_planes[numplanes + 8], - map_planes[numplanes + 9], - map_planes[numplanes + 10], - map_planes[numplanes + 11], - map_planes[numplanes + 12] }; - - if (numnodes + 6 > MAX_MAP_NODES - || numbrushes + 1 > MAX_MAP_BRUSHES - || numleafbrushes + 1 > MAX_MAP_LEAFBRUSHES - || numbrushsides + 6 > MAX_MAP_BRUSHSIDES - || numplanes + 12 > MAX_MAP_PLANES) - Com.Error(ERR_DROP, "Not enough room for box tree"); - - box_brush = map_brushes[numbrushes]; - box_brush.numsides = 6; - box_brush.firstbrushside = numbrushsides; - box_brush.contents = CONTENTS_MONSTER; - - box_leaf = map_leafs[numleafs]; - box_leaf.contents = CONTENTS_MONSTER; - box_leaf.firstleafbrush = (short) numleafbrushes; - box_leaf.numleafbrushes = 1; - - map_leafbrushes[numleafbrushes] = numbrushes; - - for (i = 0; i < 6; i++) { - side = i & 1; - - // brush sides - s = map_brushsides[numbrushsides + i]; - s.plane = map_planes[(numplanes + i * 2 + side)]; - s.surface = nullsurface; - - // nodes - c = map_nodes[box_headnode + i]; - c.plane = map_planes[(numplanes + i * 2)]; - c.children[side] = -1 - emptyleaf; - if (i != 5) - c.children[side ^ 1] = box_headnode + i + 1; - else - c.children[side ^ 1] = -1 - numleafs; - - // planes - p = box_planes[i * 2]; - p.type = (byte) (i >> 1); - p.signbits = 0; - VectorClear(p.normal); - p.normal[i >> 1] = 1; - - p = box_planes[i * 2 + 1]; - p.type = (byte) (3 + (i >> 1)); - p.signbits = 0; - VectorClear(p.normal); - p.normal[i >> 1] = -1; - } - } - - /* - =================== - CM_HeadnodeForBox - - To keep everything totally uniform, bounding boxes are turned into small - BSP trees instead of being compared directly. - =================== - */ - public static int HeadnodeForBox(float[] mins, float[] maxs) { - box_planes[0].dist = maxs[0]; - box_planes[1].dist = -maxs[0]; - box_planes[2].dist = mins[0]; - box_planes[3].dist = -mins[0]; - box_planes[4].dist = maxs[1]; - box_planes[5].dist = -maxs[1]; - box_planes[6].dist = mins[1]; - box_planes[7].dist = -mins[1]; - box_planes[8].dist = maxs[2]; - box_planes[9].dist = -maxs[2]; - box_planes[10].dist = mins[2]; - box_planes[11].dist = -mins[2]; - - return box_headnode; - } - - /* - ================== - CM_PointLeafnum_r - ================== - */ - public static int CM_PointLeafnum_r(float[] p, int num) { - float d; - cnode_t node; - cplane_t plane; - - while (num >= 0) { - node = map_nodes[num]; - plane = node.plane; - - if (plane.type < 3) - d = p[plane.type] - plane.dist; - else - d = DotProduct(plane.normal, p) - plane.dist; - if (d < 0) - num = node.children[1]; - else - num = node.children[0]; - } - - c_pointcontents++; // optimize counter - - return -1 - num; - } - - public static int CM_PointLeafnum(float[] p) { - if (numplanes == 0) - return 0; // sound may call this without map loaded - return CM_PointLeafnum_r(p, 0); - } - - /* - ============= - CM_BoxLeafnums - - Fills in a list of all the leafs touched - ============= - */ - static int leaf_count, leaf_maxcount; - static int leaf_list[]; - static float leaf_mins[], leaf_maxs[]; - static int leaf_topnode; - - public static void CM_BoxLeafnums_r(int nodenum) { - cplane_t plane; - cnode_t node; - int s; - - while (true) { - if (nodenum < 0) { - if (leaf_count >= leaf_maxcount) { - //TODO: here is still an error. - //Com.DPrintf("CM_BoxLeafnums_r: overflow\n"); - return; - } - leaf_list[leaf_count++] = -1 - nodenum; - return; - } - - node = map_nodes[nodenum]; - plane = node.plane; - - s = Math3D.BoxOnPlaneSide(leaf_mins, leaf_maxs, plane); - - if (s == 1) - nodenum = node.children[0]; - else if (s == 2) - nodenum = node.children[1]; - else { - // go down both - if (leaf_topnode == -1) - leaf_topnode = nodenum; - CM_BoxLeafnums_r(node.children[0]); - nodenum = node.children[1]; - } - } - } - - public static int CM_BoxLeafnums_headnode(float[] mins, float[] maxs, int list[], int listsize, int headnode, int topnode[]) { - leaf_list = list; - leaf_count = 0; - leaf_maxcount = listsize; - leaf_mins = mins; - leaf_maxs = maxs; - - leaf_topnode = -1; - - CM_BoxLeafnums_r(headnode); - - if (topnode != null) - topnode[0] = leaf_topnode; - - return leaf_count; - } - - public static int CM_BoxLeafnums(float[] mins, float[] maxs, int list[], int listsize, int topnode[]) { - return CM_BoxLeafnums_headnode(mins, maxs, list, listsize, map_cmodels[0].headnode, topnode); - } - - /* - public static class intwrap1 { - public intwrap(int i) { - this.i = i; - } - public int i; - } - */ - /* - ================== - CM_PointContents - ================== - */ - public static int PointContents(float[] p, int headnode) { - int l; - - if (numnodes == 0) // map not loaded - return 0; - - l = CM_PointLeafnum_r(p, headnode); - - return map_leafs[l].contents; - } - - /* - ================== - CM_TransformedPointContents - - Handles offseting and rotation of the end points for moving and - rotating entities - ================== - */ - public static int TransformedPointContents(float[] p, int headnode, float[] origin, float[] angles) { - float[] p_l = { 0, 0, 0 }; - float[] temp = { 0, 0, 0 }; - float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; - int l; - - // subtract origin offset - VectorSubtract(p, origin, p_l); - - // rotate start and end into the models frame of reference - if (headnode != box_headnode && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) { - AngleVectors(angles, forward, right, up); - - VectorCopy(p_l, temp); - p_l[0] = DotProduct(temp, forward); - p_l[1] = -DotProduct(temp, right); - p_l[2] = DotProduct(temp, up); - } - - l = CM_PointLeafnum_r(p_l, headnode); - - return map_leafs[l].contents; - } - - /* - =============================================================================== - - BOX TRACING - - =============================================================================== - */ - - // 1/32 epsilon to keep floating point happy - private static final float DIST_EPSILON = 0.03125f; - - private static float[] trace_start = { 0, 0, 0 }, trace_end = { 0, 0, 0 }; - private static float[] trace_mins = { 0, 0, 0 }, trace_maxs = { 0, 0, 0 }; - private static float[] trace_extents = { 0, 0, 0 }; - - private static trace_t trace_trace = new trace_t(); - private static int trace_contents; - private static boolean trace_ispoint; // optimized case - - /* - ================ - CM_ClipBoxToBrush - ================ - */ - public static void CM_ClipBoxToBrush(float[] mins, float[] maxs, float[] p1, float[] p2, trace_t trace, cbrush_t brush) { - int i, j; - cplane_t plane, clipplane; - float dist; - float enterfrac, leavefrac; - float[] ofs = { 0, 0, 0 }; - float d1, d2; - boolean getout, startout; - float f; - cbrushside_t side, leadside; - - enterfrac = -1; - leavefrac = 1; - clipplane = null; - - if (brush.numsides == 0) - return; - - c_brush_traces++; - - getout = false; - startout = false; - leadside = null; - - for (i = 0; i < brush.numsides; i++) { - side = map_brushsides[brush.firstbrushside + i]; - plane = side.plane; - - // FIXME: special case for axial - - if (!trace_ispoint) { // general box case - - // push the plane out apropriately for mins/maxs - - // FIXME: use signbits into 8 way lookup for each mins/maxs - for (j = 0; j < 3; j++) { - if (plane.normal[j] < 0) - ofs[j] = maxs[j]; - else - ofs[j] = mins[j]; - } - dist = DotProduct(ofs, plane.normal); - dist = plane.dist - dist; - } - else { // special point case - dist = plane.dist; - } - - d1 = DotProduct(p1, plane.normal) - dist; - d2 = DotProduct(p2, plane.normal) - dist; - - if (d2 > 0) - getout = true; // endpoint is not in solid - if (d1 > 0) - startout = true; - - // if completely in front of face, no intersection - if (d1 > 0 && d2 >= d1) - return; - - if (d1 <= 0 && d2 <= 0) - continue; - - // crosses face - if (d1 > d2) { // enter - f = (d1 - DIST_EPSILON) / (d1 - d2); - if (f > enterfrac) { - enterfrac = f; - clipplane = plane; - leadside = side; - } - } - else { // leave - f = (d1 + DIST_EPSILON) / (d1 - d2); - if (f < leavefrac) - leavefrac = f; - } - } - - if (!startout) { // original point was inside brush - trace.startsolid = true; - if (!getout) - trace.allsolid = true; - return; - } - if (enterfrac < leavefrac) { - if (enterfrac > -1 && enterfrac < trace.fraction) { - if (enterfrac < 0) - enterfrac = 0; - trace.fraction = enterfrac; - // copy - trace.plane.set(clipplane); - trace.surface = leadside.surface.c; - trace.contents = brush.contents; - } - } - } - - /* - ================ - CM_TestBoxInBrush - ================ - */ - public static void CM_TestBoxInBrush(float[] mins, float[] maxs, float[] p1, trace_t trace, cbrush_t brush) { - int i, j; - cplane_t plane; - float dist; - float[] ofs = { 0, 0, 0 }; - float d1; - cbrushside_t side; - - if (brush.numsides == 0) - return; - - for (i = 0; i < brush.numsides; i++) { - side = map_brushsides[brush.firstbrushside + i]; - plane = side.plane; - - // FIXME: special case for axial - // general box case - // push the plane out apropriately for mins/maxs - // FIXME: use signbits into 8 way lookup for each mins/maxs - - for (j = 0; j < 3; j++) { - if (plane.normal[j] < 0) - ofs[j] = maxs[j]; - else - ofs[j] = mins[j]; - } - dist = DotProduct(ofs, plane.normal); - dist = plane.dist - dist; - - d1 = DotProduct(p1, plane.normal) - dist; - - // if completely in front of face, no intersection - if (d1 > 0) - return; - - } - - // inside this brush - trace.startsolid = trace.allsolid = true; - trace.fraction = 0; - trace.contents = brush.contents; - } - - /* - ================ - CM_TraceToLeaf - ================ - */ - public static void CM_TraceToLeaf(int leafnum) { - int k; - int brushnum; - cleaf_t leaf; - cbrush_t b; - - leaf = map_leafs[leafnum]; - if (0 == (leaf.contents & trace_contents)) - return; - - // trace line against all brushes in the leaf - for (k = 0; k < leaf.numleafbrushes; k++) { - - brushnum = map_leafbrushes[leaf.firstleafbrush + k]; - b = map_brushes[brushnum]; - if (b.checkcount == checkcount) - continue; // already checked this brush in another leaf - b.checkcount = checkcount; - - if (0 == (b.contents & trace_contents)) - continue; - CM_ClipBoxToBrush(trace_mins, trace_maxs, trace_start, trace_end, trace_trace, b); - if (0 == trace_trace.fraction) - return; - } - - } - - /* - ================ - CM_TestInLeaf - ================ - */ - public static void CM_TestInLeaf(int leafnum) { - int k; - int brushnum; - cleaf_t leaf; - cbrush_t b; - - leaf = map_leafs[leafnum]; - if (0 == (leaf.contents & trace_contents)) - return; - // trace line against all brushes in the leaf - for (k = 0; k < leaf.numleafbrushes; k++) { - brushnum = map_leafbrushes[leaf.firstleafbrush + k]; - b = map_brushes[brushnum]; - if (b.checkcount == checkcount) - continue; // already checked this brush in another leaf - b.checkcount = checkcount; - - if (0 == (b.contents & trace_contents)) - continue; - CM_TestBoxInBrush(trace_mins, trace_maxs, trace_start, trace_trace, b); - if (0 == trace_trace.fraction) - return; - } - - } - - /* - ================== - CM_RecursiveHullCheck - ================== - */ - public static void CM_RecursiveHullCheck(int num, float p1f, float p2f, float[] p1, float[] p2) { - cnode_t node; - cplane_t plane; - float t1, t2, offset; - float frac, frac2; - float idist; - int i; - float[] mid = { 0, 0, 0 }; - int side; - float midf; - - if (trace_trace.fraction <= p1f) - return; // already hit something nearer - - // if < 0, we are in a leaf node - if (num < 0) { - CM_TraceToLeaf(-1 - num); - return; - } - - // - // find the point distances to the seperating plane - // and the offset for the size of the box - // - node = map_nodes[num]; - plane = node.plane; - - if (plane.type < 3) { - t1 = p1[plane.type] - plane.dist; - t2 = p2[plane.type] - plane.dist; - offset = trace_extents[plane.type]; - } - else { - t1 = DotProduct(plane.normal, p1) - plane.dist; - t2 = DotProduct(plane.normal, p2) - plane.dist; - if (trace_ispoint) - offset = 0; - else - offset = - Math.abs(trace_extents[0] * plane.normal[0]) - + Math.abs(trace_extents[1] * plane.normal[1]) - + Math.abs(trace_extents[2] * plane.normal[2]); - } - - // see which sides we need to consider - if (t1 >= offset && t2 >= offset) { - CM_RecursiveHullCheck(node.children[0], p1f, p2f, p1, p2); - return; - } - if (t1 < -offset && t2 < -offset) { - CM_RecursiveHullCheck(node.children[1], p1f, p2f, p1, p2); - return; - } - - // put the crosspoint DIST_EPSILON pixels on the near side - if (t1 < t2) { - idist = 1.0f / (t1 - t2); - side = 1; - frac2 = (t1 + offset + DIST_EPSILON) * idist; - frac = (t1 - offset + DIST_EPSILON) * idist; - } - else if (t1 > t2) { - idist = 1.0f / (t1 - t2); - side = 0; - frac2 = (t1 - offset - DIST_EPSILON) * idist; - frac = (t1 + offset + DIST_EPSILON) * idist; - } - else { - side = 0; - frac = 1; - frac2 = 0; - } - - // move up to the node - if (frac < 0) - frac = 0; - if (frac > 1) - frac = 1; - - midf = p1f + (p2f - p1f) * frac; - for (i = 0; i < 3; i++) - mid[i] = p1[i] + frac * (p2[i] - p1[i]); - - CM_RecursiveHullCheck(node.children[side], p1f, midf, p1, mid); - - // go past the node - if (frac2 < 0) - frac2 = 0; - if (frac2 > 1) - frac2 = 1; - - midf = p1f + (p2f - p1f) * frac2; - for (i = 0; i < 3; i++) - mid[i] = p1[i] + frac2 * (p2[i] - p1[i]); - - CM_RecursiveHullCheck(node.children[side ^ 1], midf, p2f, mid, p2); - } - - //====================================================================== - - /* - ================== - CM_BoxTrace - ================== - */ - public static trace_t BoxTrace(float[] start, float[] end, float[] mins, float[] maxs, int headnode, int brushmask) { - - // for multi-check avoidance - checkcount++; - - // for statistics, may be zeroed - c_traces++; - - // fill in a default trace - //was: memset(& trace_trace, 0, sizeof(trace_trace)); - trace_trace = new trace_t(); - - trace_trace.fraction = 1; - trace_trace.surface = nullsurface.c; - - if (numnodes == 0) // map not loaded - { - Com.DPrintf("dummy trace zurueck, da map not loaded!\n"); - return trace_trace; - } - - trace_contents = brushmask; - VectorCopy(start, trace_start); - VectorCopy(end, trace_end); - VectorCopy(mins, trace_mins); - VectorCopy(maxs, trace_maxs); - - // - // check for position test special case - // - if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) { - - int leafs[] = new int[1024]; - int i, numleafs; - float[] c1 = { 0, 0, 0 }, c2 = { 0, 0, 0 }; - int topnode = 0; - - VectorAdd(start, mins, c1); - VectorAdd(start, maxs, c2); - - for (i = 0; i < 3; i++) { - c1[i] -= 1; - c2[i] += 1; - } - - int tn[] = {topnode}; - - numleafs = CM_BoxLeafnums_headnode(c1, c2, leafs, 1024, headnode, tn); - topnode = tn[0]; - for (i = 0; i < numleafs; i++) { - CM_TestInLeaf(leafs[i]); - if (trace_trace.allsolid) - break; - } - VectorCopy(start, trace_trace.endpos); - return trace_trace; - } - - // - // check for point special case - // - if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0 && maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0) { - trace_ispoint = true; - VectorClear(trace_extents); - } - else { - trace_ispoint = false; - trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0]; - trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1]; - trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2]; - } - - // - // general sweeping through world - // - CM_RecursiveHullCheck(headnode, 0, 1, start, end); - - if (trace_trace.fraction == 1) { - VectorCopy(end, trace_trace.endpos); - } - else { - for (int i = 0; i < 3; i++) - trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]); - } - return trace_trace; - } - - /* - ================== - CM_TransformedBoxTrace - - Handles offseting and rotation of the end points for moving and - rotating entities - ================== - */ - public static trace_t TransformedBoxTrace( - float[] start, - float[] end, - float[] mins, - float[] maxs, - int headnode, - int brushmask, - float[] origin, - float[] angles) { - trace_t trace; - float[] start_l = { 0, 0, 0 }, end_l = { 0, 0, 0 }; - float[] a = { 0, 0, 0 }; - float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; - float[] temp = { 0, 0, 0 }; - boolean rotated; - - // subtract origin offset - VectorSubtract(start, origin, start_l); - VectorSubtract(end, origin, end_l); - - // rotate start and end into the models frame of reference - if (headnode != box_headnode && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) - rotated = true; - else - rotated = false; - - if (rotated) { - AngleVectors(angles, forward, right, up); - - VectorCopy(start_l, temp); - start_l[0] = DotProduct(temp, forward); - start_l[1] = -DotProduct(temp, right); - start_l[2] = DotProduct(temp, up); - - VectorCopy(end_l, temp); - end_l[0] = DotProduct(temp, forward); - end_l[1] = -DotProduct(temp, right); - end_l[2] = DotProduct(temp, up); - } - - // sweep the box through the model - trace = BoxTrace(start_l, end_l, mins, maxs, headnode, brushmask); - - if (rotated && trace.fraction != 1.0) { - // FIXME: figure out how to do this with existing angles - VectorNegate(angles, a); - AngleVectors(a, forward, right, up); - - VectorCopy(trace.plane.normal, temp); - trace.plane.normal[0] = DotProduct(temp, forward); - trace.plane.normal[1] = -DotProduct(temp, right); - trace.plane.normal[2] = DotProduct(temp, up); - } - - trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]); - trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]); - trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]); - - return trace; - } - - /* - =============================================================================== - PVS / PHS - =============================================================================== - */ - - /* - =================== - CM_DecompressVis - =================== - */ - public static void CM_DecompressVis(byte in[], int offset, byte out[]) { - int c; - - int row; - - row = (numclusters + 7) >> 3; - int outp = 0; - int inp = offset; - - if (in == null || numvisibility == 0) { // no vis info, so make all visible - while (row != 0) { - out[outp++] = (byte) 0xFF; - row--; - } - return; - } - - do { - if (in[inp] != 0) { - out[outp++] = in[inp++]; - continue; - } - - c = in[inp + 1] & 0xFF; - inp += 2; - if (outp + c > row) { - c = row - (outp); - Com.DPrintf("warning: Vis decompression overrun\n"); - } - while (c != 0) { - out[outp++] = 0; - c--; - } - } - while (outp < row); - } - - public static byte pvsrow[] = new byte[MAX_MAP_LEAFS / 8]; - public static byte phsrow[] = new byte[MAX_MAP_LEAFS / 8]; - - public static byte[] CM_ClusterPVS(int cluster) { - if (cluster == -1) - Arrays.fill(pvsrow, 0, (numclusters + 7) >> 3, (byte)0); - else - CM_DecompressVis(map_visibility, map_vis.bitofs[cluster][DVIS_PVS], pvsrow); - return pvsrow; - } - - public static byte[] CM_ClusterPHS(int cluster) { - if (cluster == -1) - Arrays.fill(phsrow, 0, (numclusters + 7) >> 3, (byte)0); - else - CM_DecompressVis(map_visibility, map_vis.bitofs[cluster][Defines.DVIS_PHS], phsrow); - return phsrow; - } - - /* - =============================================================================== - AREAPORTALS - =============================================================================== - */ - - public static void FloodArea_r(carea_t area, int floodnum) { - //Com.Printf("FloodArea_r(" + floodnum + ")...\n"); - int i; - qfiles.dareaportal_t p; - - if (area.floodvalid == floodvalid) { - if (area.floodnum == floodnum) - return; - Com.Error(ERR_DROP, "FloodArea_r: reflooded"); - } - - area.floodnum = floodnum; - area.floodvalid = floodvalid; - - for (i = 0; i < area.numareaportals; i++) { - p = map_areaportals[area.firstareaportal + i]; - if (portalopen[p.portalnum]) - FloodArea_r(map_areas[p.otherarea], floodnum); - } - } - - /* - ==================== - FloodAreaConnections - ==================== - */ - public static void FloodAreaConnections() { - Com.DPrintf("FloodAreaConnections...\n"); - - int i; - carea_t area; - int floodnum; - - // all current floods are now invalid - floodvalid++; - floodnum = 0; - - // area 0 is not used - for (i = 1; i < numareas; i++) { - - area = map_areas[i]; - - if (area.floodvalid == floodvalid) - continue; // already flooded into - floodnum++; - FloodArea_r(area, floodnum); - } - } - - /* - ================= - CM_SetAreaPortalState - ================= - */ - public static void CM_SetAreaPortalState(int portalnum, boolean open) { - if (portalnum > numareaportals) - Com.Error(ERR_DROP, "areaportal > numareaportals"); - - portalopen[portalnum] = open; - FloodAreaConnections(); - } - - /* - ================= - CM_AreasConnected - ================= - */ - - public static boolean CM_AreasConnected(int area1, int area2) { - if (map_noareas.value != 0) - return true; - - if (area1 > numareas || area2 > numareas) - Com.Error(ERR_DROP, "area > numareas"); - - if (map_areas[area1].floodnum == map_areas[area2].floodnum) - return true; - - return false; - } - - /* - ================= - CM_WriteAreaBits - - Writes a length byte followed by a bit vector of all the areas - that area in the same flood as the area parameter - - This is used by the client refreshes to cull visibility - ================= - */ - public static int CM_WriteAreaBits(byte buffer[], int area) { - int i; - int floodnum; - int bytes; - - bytes = (numareas + 7) >> 3; - - if (map_noareas.value != 0) { // for debugging, send everything - Arrays.fill(buffer, 0, bytes, (byte)255); - } - else { - Arrays.fill(buffer, 0, bytes, (byte)0); - floodnum = map_areas[area].floodnum; - for (i = 0; i < numareas; i++) { - if (map_areas[i].floodnum == floodnum || area == 0) - buffer[i >> 3] |= 1 << (i & 7); - } - } - - return bytes; - } - - /* - =================== - CM_WritePortalState - - Writes the portal state to a savegame file - =================== - */ - - public static void CM_WritePortalState(RandomAccessFile os) { - - //was: fwrite(portalopen, sizeof(portalopen), 1, f); - try { - - for (int n = 0; n < portalopen.length; n++) - if (portalopen[n]) - os.writeInt(1); - else - os.writeInt(0); - } - catch (Exception e) { - Com.Printf("ERROR:" + e); - e.printStackTrace(); - } - } - - /* - =================== - CM_ReadPortalState - - Reads the portal state from a savegame file - and recalculates the area connections - =================== - */ - public static void CM_ReadPortalState(RandomAccessFile f) { - - //was: FS_Read(portalopen, sizeof(portalopen), f); - int len = portalopen.length * 4; - - byte buf[] = new byte[len]; - - - FS.Read(buf, len, f); - - ByteBuffer bb = ByteBuffer.wrap(buf); - IntBuffer ib = bb.asIntBuffer(); - - for (int n = 0; n < portalopen.length; n++) - portalopen[n] = ib.get() != 0; - - FloodAreaConnections(); - } - - /* - ============= - CM_HeadnodeVisible - - Returns true if any leaf under headnode has a cluster that - is potentially visible - ============= - */ - public static boolean CM_HeadnodeVisible(int nodenum, byte visbits[]) { - int leafnum; - int cluster; - cnode_t node; - - if (nodenum < 0) { - leafnum = -1 - nodenum; - cluster = map_leafs[leafnum].cluster; - if (cluster == -1) - return false; - if (0 != (visbits[cluster >>> 3] & (1 << (cluster & 7)))) - return true; - return false; - } - - node = map_nodes[nodenum]; - if (CM_HeadnodeVisible(node.children[0], visbits)) - return true; - return CM_HeadnodeVisible(node.children[1], visbits); - } -} + /* + * ================= CMod_LoadVisibility ================= + */ + public static void CMod_LoadVisibility(lump_t l) { + Com.DPrintf("CMod_LoadVisibility...\n"); + int i; + + numvisibility = l.filelen; + + Com.DPrintf(" numvisibility=" + numvisibility + "\n"); + + if (l.filelen > Defines.MAX_MAP_VISIBILITY) + Com.Error(Defines.ERR_DROP, "Map has too large visibility lump"); + + System.arraycopy(cmod_base, l.fileofs, map_visibility, 0, l.filelen); + + ByteBuffer bb = ByteBuffer.wrap(map_visibility, 0, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + map_vis = new qfiles.dvis_t(bb); + + } + + /* + * ================= CMod_LoadEntityString ================= + */ + public static void CMod_LoadEntityString(lump_t l) { + Com.DPrintf("CMod_LoadEntityString...\n"); + + numentitychars = l.filelen; + + if (l.filelen > Defines.MAX_MAP_ENTSTRING) + Com.Error(Defines.ERR_DROP, "Map has too large entity lump"); + + int x = 0; + for (; x < l.filelen && cmod_base[x + l.fileofs] != 0; x++) + ; + + map_entitystring = new String(cmod_base, l.fileofs, x).trim(); + } + + /* + * ================== CM_InlineModel ================== + */ + + // works fine + public static cmodel_t InlineModel(String name) { + int num; + + if (name == null || name.charAt(0) != '*') + Com.Error(Defines.ERR_DROP, "CM_InlineModel: bad name"); + + num = Lib.atoi(name.substring(1)); + + if (num < 1 || num >= numcmodels) + Com.Error(Defines.ERR_DROP, "CM_InlineModel: bad number"); + + return map_cmodels[num]; + } + + public static int CM_NumClusters() { + return numclusters; + } + + public static int CM_NumInlineModels() { + return numcmodels; + } + + public static String CM_EntityString() { + return map_entitystring; + } + + public static int CM_LeafContents(int leafnum) { + if (leafnum < 0 || leafnum >= numleafs) + Com.Error(Defines.ERR_DROP, "CM_LeafContents: bad number"); + return map_leafs[leafnum].contents; + } + + public static int CM_LeafCluster(int leafnum) { + if (leafnum < 0 || leafnum >= numleafs) + Com.Error(Defines.ERR_DROP, "CM_LeafCluster: bad number"); + return map_leafs[leafnum].cluster; + } + + public static int CM_LeafArea(int leafnum) { + if (leafnum < 0 || leafnum >= numleafs) + Com.Error(Defines.ERR_DROP, "CM_LeafArea: bad number"); + return map_leafs[leafnum].area; + } + + //======================================================================= + + static cplane_t box_planes[]; + + static int box_headnode; + + static cbrush_t box_brush; + + static cleaf_t box_leaf; + + /* + * =================== CM_InitBoxHull + * + * Set up the planes and nodes so that the six floats of a bounding box can + * just be stored out and get a proper clipping hull structure. + * =================== + */ + public static void CM_InitBoxHull() { + int i; + int side; + cnode_t c; + cplane_t p; + cbrushside_t s; + + box_headnode = numnodes; // noch platz f?r 6 brushes + + box_planes = new cplane_t[] { map_planes[numplanes], + map_planes[numplanes + 1], map_planes[numplanes + 2], + map_planes[numplanes + 3], map_planes[numplanes + 4], + map_planes[numplanes + 5], map_planes[numplanes + 6], + map_planes[numplanes + 7], map_planes[numplanes + 8], + map_planes[numplanes + 9], map_planes[numplanes + 10], + map_planes[numplanes + 11], map_planes[numplanes + 12] }; + + if (numnodes + 6 > Defines.MAX_MAP_NODES + || numbrushes + 1 > Defines.MAX_MAP_BRUSHES + || numleafbrushes + 1 > Defines.MAX_MAP_LEAFBRUSHES + || numbrushsides + 6 > Defines.MAX_MAP_BRUSHSIDES + || numplanes + 12 > Defines.MAX_MAP_PLANES) + Com.Error(Defines.ERR_DROP, "Not enough room for box tree"); + + box_brush = map_brushes[numbrushes]; + box_brush.numsides = 6; + box_brush.firstbrushside = numbrushsides; + box_brush.contents = Defines.CONTENTS_MONSTER; + + box_leaf = map_leafs[numleafs]; + box_leaf.contents = Defines.CONTENTS_MONSTER; + box_leaf.firstleafbrush = (short) numleafbrushes; + box_leaf.numleafbrushes = 1; + + map_leafbrushes[numleafbrushes] = numbrushes; + + for (i = 0; i < 6; i++) { + side = i & 1; + + // brush sides + s = map_brushsides[numbrushsides + i]; + s.plane = map_planes[(numplanes + i * 2 + side)]; + s.surface = nullsurface; + + // nodes + c = map_nodes[box_headnode + i]; + c.plane = map_planes[(numplanes + i * 2)]; + c.children[side] = -1 - emptyleaf; + if (i != 5) + c.children[side ^ 1] = box_headnode + i + 1; + else + c.children[side ^ 1] = -1 - numleafs; + + // planes + p = box_planes[i * 2]; + p.type = (byte) (i >> 1); + p.signbits = 0; + Math3D.VectorClear(p.normal); + p.normal[i >> 1] = 1; + + p = box_planes[i * 2 + 1]; + p.type = (byte) (3 + (i >> 1)); + p.signbits = 0; + Math3D.VectorClear(p.normal); + p.normal[i >> 1] = -1; + } + } + + /* + * =================== CM_HeadnodeForBox + * + * To keep everything totally uniform, bounding boxes are turned into small + * BSP trees instead of being compared directly. =================== + */ + public static int HeadnodeForBox(float[] mins, float[] maxs) { + box_planes[0].dist = maxs[0]; + box_planes[1].dist = -maxs[0]; + box_planes[2].dist = mins[0]; + box_planes[3].dist = -mins[0]; + box_planes[4].dist = maxs[1]; + box_planes[5].dist = -maxs[1]; + box_planes[6].dist = mins[1]; + box_planes[7].dist = -mins[1]; + box_planes[8].dist = maxs[2]; + box_planes[9].dist = -maxs[2]; + box_planes[10].dist = mins[2]; + box_planes[11].dist = -mins[2]; + + return box_headnode; + } + + /* + * ================== CM_PointLeafnum_r ================== + */ + public static int CM_PointLeafnum_r(float[] p, int num) { + float d; + cnode_t node; + cplane_t plane; + + while (num >= 0) { + node = map_nodes[num]; + plane = node.plane; + + if (plane.type < 3) + d = p[plane.type] - plane.dist; + else + d = Math3D.DotProduct(plane.normal, p) - plane.dist; + if (d < 0) + num = node.children[1]; + else + num = node.children[0]; + } + + Globals.c_pointcontents++; // optimize counter + + return -1 - num; + } + + public static int CM_PointLeafnum(float[] p) { + if (numplanes == 0) + return 0; // sound may call this without map loaded + return CM_PointLeafnum_r(p, 0); + } + + /* + * ============= CM_BoxLeafnums + * + * Fills in a list of all the leafs touched ============= + */ + static int leaf_count, leaf_maxcount; + + static int leaf_list[]; + + static float leaf_mins[], leaf_maxs[]; + + static int leaf_topnode; + + public static void CM_BoxLeafnums_r(int nodenum) { + cplane_t plane; + cnode_t node; + int s; + + while (true) { + if (nodenum < 0) { + if (leaf_count >= leaf_maxcount) { + //TODO: here is still an error. + //Com.DPrintf("CM_BoxLeafnums_r: overflow\n"); + return; + } + leaf_list[leaf_count++] = -1 - nodenum; + return; + } + + node = map_nodes[nodenum]; + plane = node.plane; + + s = Math3D.BoxOnPlaneSide(leaf_mins, leaf_maxs, plane); + + if (s == 1) + nodenum = node.children[0]; + else if (s == 2) + nodenum = node.children[1]; + else { + // go down both + if (leaf_topnode == -1) + leaf_topnode = nodenum; + CM_BoxLeafnums_r(node.children[0]); + nodenum = node.children[1]; + } + } + } + + public static int CM_BoxLeafnums_headnode(float[] mins, float[] maxs, + int list[], int listsize, int headnode, int topnode[]) { + leaf_list = list; + leaf_count = 0; + leaf_maxcount = listsize; + leaf_mins = mins; + leaf_maxs = maxs; + + leaf_topnode = -1; + + CM_BoxLeafnums_r(headnode); + + if (topnode != null) + topnode[0] = leaf_topnode; + + return leaf_count; + } + + public static int CM_BoxLeafnums(float[] mins, float[] maxs, int list[], + int listsize, int topnode[]) { + return CM_BoxLeafnums_headnode(mins, maxs, list, listsize, + map_cmodels[0].headnode, topnode); + } + + /* + * public static class intwrap1 { public intwrap(int i) { this.i = i; } + * public int i; } + */ + /* + * ================== CM_PointContents ================== + */ + public static int PointContents(float[] p, int headnode) { + int l; + + if (numnodes == 0) // map not loaded + return 0; + + l = CM_PointLeafnum_r(p, headnode); + + return map_leafs[l].contents; + } + + /* + * ================== CM_TransformedPointContents + * + * Handles offseting and rotation of the end points for moving and rotating + * entities ================== + */ + public static int TransformedPointContents(float[] p, int headnode, + float[] origin, float[] angles) { + float[] p_l = { 0, 0, 0 }; + float[] temp = { 0, 0, 0 }; + float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; + int l; + + // subtract origin offset + Math3D.VectorSubtract(p, origin, p_l); + + // rotate start and end into the models frame of reference + if (headnode != box_headnode + && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) { + Math3D.AngleVectors(angles, forward, right, up); + + Math3D.VectorCopy(p_l, temp); + p_l[0] = Math3D.DotProduct(temp, forward); + p_l[1] = -Math3D.DotProduct(temp, right); + p_l[2] = Math3D.DotProduct(temp, up); + } + + l = CM_PointLeafnum_r(p_l, headnode); + + return map_leafs[l].contents; + } + + /* + * =============================================================================== + * + * BOX TRACING + * + * =============================================================================== + */ + + // 1/32 epsilon to keep floating point happy + private static final float DIST_EPSILON = 0.03125f; + + private static float[] trace_start = { 0, 0, 0 }, trace_end = { 0, 0, 0 }; + + private static float[] trace_mins = { 0, 0, 0 }, trace_maxs = { 0, 0, 0 }; + + private static float[] trace_extents = { 0, 0, 0 }; + + private static trace_t trace_trace = new trace_t(); + + private static int trace_contents; + + private static boolean trace_ispoint; // optimized case + + /* + * ================ CM_ClipBoxToBrush ================ + */ + public static void CM_ClipBoxToBrush(float[] mins, float[] maxs, + float[] p1, float[] p2, trace_t trace, cbrush_t brush) { + int i, j; + cplane_t plane, clipplane; + float dist; + float enterfrac, leavefrac; + float[] ofs = { 0, 0, 0 }; + float d1, d2; + boolean getout, startout; + float f; + cbrushside_t side, leadside; + + enterfrac = -1; + leavefrac = 1; + clipplane = null; + + if (brush.numsides == 0) + return; + + Globals.c_brush_traces++; + + getout = false; + startout = false; + leadside = null; + + for (i = 0; i < brush.numsides; i++) { + side = map_brushsides[brush.firstbrushside + i]; + plane = side.plane; + + // FIXME: special case for axial + + if (!trace_ispoint) { // general box case + + // push the plane out apropriately for mins/maxs + + // FIXME: use signbits into 8 way lookup for each mins/maxs + for (j = 0; j < 3; j++) { + if (plane.normal[j] < 0) + ofs[j] = maxs[j]; + else + ofs[j] = mins[j]; + } + dist = Math3D.DotProduct(ofs, plane.normal); + dist = plane.dist - dist; + } else { // special point case + dist = plane.dist; + } + + d1 = Math3D.DotProduct(p1, plane.normal) - dist; + d2 = Math3D.DotProduct(p2, plane.normal) - dist; + + if (d2 > 0) + getout = true; // endpoint is not in solid + if (d1 > 0) + startout = true; + + // if completely in front of face, no intersection + if (d1 > 0 && d2 >= d1) + return; + + if (d1 <= 0 && d2 <= 0) + continue; + + // crosses face + if (d1 > d2) { // enter + f = (d1 - DIST_EPSILON) / (d1 - d2); + if (f > enterfrac) { + enterfrac = f; + clipplane = plane; + leadside = side; + } + } else { // leave + f = (d1 + DIST_EPSILON) / (d1 - d2); + if (f < leavefrac) + leavefrac = f; + } + } + + if (!startout) { // original point was inside brush + trace.startsolid = true; + if (!getout) + trace.allsolid = true; + return; + } + if (enterfrac < leavefrac) { + if (enterfrac > -1 && enterfrac < trace.fraction) { + if (enterfrac < 0) + enterfrac = 0; + trace.fraction = enterfrac; + // copy + trace.plane.set(clipplane); + trace.surface = leadside.surface.c; + trace.contents = brush.contents; + } + } + } + + /* + * ================ CM_TestBoxInBrush ================ + */ + public static void CM_TestBoxInBrush(float[] mins, float[] maxs, + float[] p1, trace_t trace, cbrush_t brush) { + int i, j; + cplane_t plane; + float dist; + float[] ofs = { 0, 0, 0 }; + float d1; + cbrushside_t side; + + if (brush.numsides == 0) + return; + + for (i = 0; i < brush.numsides; i++) { + side = map_brushsides[brush.firstbrushside + i]; + plane = side.plane; + + // FIXME: special case for axial + // general box case + // push the plane out apropriately for mins/maxs + // FIXME: use signbits into 8 way lookup for each mins/maxs + + for (j = 0; j < 3; j++) { + if (plane.normal[j] < 0) + ofs[j] = maxs[j]; + else + ofs[j] = mins[j]; + } + dist = Math3D.DotProduct(ofs, plane.normal); + dist = plane.dist - dist; + + d1 = Math3D.DotProduct(p1, plane.normal) - dist; + + // if completely in front of face, no intersection + if (d1 > 0) + return; + + } + + // inside this brush + trace.startsolid = trace.allsolid = true; + trace.fraction = 0; + trace.contents = brush.contents; + } + + /* + * ================ CM_TraceToLeaf ================ + */ + public static void CM_TraceToLeaf(int leafnum) { + int k; + int brushnum; + cleaf_t leaf; + cbrush_t b; + + leaf = map_leafs[leafnum]; + if (0 == (leaf.contents & trace_contents)) + return; + + // trace line against all brushes in the leaf + for (k = 0; k < leaf.numleafbrushes; k++) { + + brushnum = map_leafbrushes[leaf.firstleafbrush + k]; + b = map_brushes[brushnum]; + if (b.checkcount == checkcount) + continue; // already checked this brush in another leaf + b.checkcount = checkcount; + + if (0 == (b.contents & trace_contents)) + continue; + CM_ClipBoxToBrush(trace_mins, trace_maxs, trace_start, trace_end, + trace_trace, b); + if (0 == trace_trace.fraction) + return; + } + + } + + /* + * ================ CM_TestInLeaf ================ + */ + public static void CM_TestInLeaf(int leafnum) { + int k; + int brushnum; + cleaf_t leaf; + cbrush_t b; + + leaf = map_leafs[leafnum]; + if (0 == (leaf.contents & trace_contents)) + return; + // trace line against all brushes in the leaf + for (k = 0; k < leaf.numleafbrushes; k++) { + brushnum = map_leafbrushes[leaf.firstleafbrush + k]; + b = map_brushes[brushnum]; + if (b.checkcount == checkcount) + continue; // already checked this brush in another leaf + b.checkcount = checkcount; + + if (0 == (b.contents & trace_contents)) + continue; + CM_TestBoxInBrush(trace_mins, trace_maxs, trace_start, trace_trace, + b); + if (0 == trace_trace.fraction) + return; + } + + } + + /* + * ================== CM_RecursiveHullCheck ================== + */ + public static void CM_RecursiveHullCheck(int num, float p1f, float p2f, + float[] p1, float[] p2) { + cnode_t node; + cplane_t plane; + float t1, t2, offset; + float frac, frac2; + float idist; + int i; + float[] mid = { 0, 0, 0 }; + int side; + float midf; + + if (trace_trace.fraction <= p1f) + return; // already hit something nearer + + // if < 0, we are in a leaf node + if (num < 0) { + CM_TraceToLeaf(-1 - num); + return; + } + + // + // find the point distances to the seperating plane + // and the offset for the size of the box + // + node = map_nodes[num]; + plane = node.plane; + + if (plane.type < 3) { + t1 = p1[plane.type] - plane.dist; + t2 = p2[plane.type] - plane.dist; + offset = trace_extents[plane.type]; + } else { + t1 = Math3D.DotProduct(plane.normal, p1) - plane.dist; + t2 = Math3D.DotProduct(plane.normal, p2) - plane.dist; + if (trace_ispoint) + offset = 0; + else + offset = Math.abs(trace_extents[0] * plane.normal[0]) + + Math.abs(trace_extents[1] * plane.normal[1]) + + Math.abs(trace_extents[2] * plane.normal[2]); + } + + // see which sides we need to consider + if (t1 >= offset && t2 >= offset) { + CM_RecursiveHullCheck(node.children[0], p1f, p2f, p1, p2); + return; + } + if (t1 < -offset && t2 < -offset) { + CM_RecursiveHullCheck(node.children[1], p1f, p2f, p1, p2); + return; + } + + // put the crosspoint DIST_EPSILON pixels on the near side + if (t1 < t2) { + idist = 1.0f / (t1 - t2); + side = 1; + frac2 = (t1 + offset + DIST_EPSILON) * idist; + frac = (t1 - offset + DIST_EPSILON) * idist; + } else if (t1 > t2) { + idist = 1.0f / (t1 - t2); + side = 0; + frac2 = (t1 - offset - DIST_EPSILON) * idist; + frac = (t1 + offset + DIST_EPSILON) * idist; + } else { + side = 0; + frac = 1; + frac2 = 0; + } + + // move up to the node + if (frac < 0) + frac = 0; + if (frac > 1) + frac = 1; + + midf = p1f + (p2f - p1f) * frac; + for (i = 0; i < 3; i++) + mid[i] = p1[i] + frac * (p2[i] - p1[i]); + + CM_RecursiveHullCheck(node.children[side], p1f, midf, p1, mid); + + // go past the node + if (frac2 < 0) + frac2 = 0; + if (frac2 > 1) + frac2 = 1; + + midf = p1f + (p2f - p1f) * frac2; + for (i = 0; i < 3; i++) + mid[i] = p1[i] + frac2 * (p2[i] - p1[i]); + + CM_RecursiveHullCheck(node.children[side ^ 1], midf, p2f, mid, p2); + } + + //====================================================================== + + /* + * ================== CM_BoxTrace ================== + */ + public static trace_t BoxTrace(float[] start, float[] end, float[] mins, + float[] maxs, int headnode, int brushmask) { + + // for multi-check avoidance + checkcount++; + + // for statistics, may be zeroed + Globals.c_traces++; + + // fill in a default trace + //was: memset(& trace_trace, 0, sizeof(trace_trace)); + trace_trace = new trace_t(); + + trace_trace.fraction = 1; + trace_trace.surface = nullsurface.c; + + if (numnodes == 0) // map not loaded + { + Com.DPrintf("dummy trace zurueck, da map not loaded!\n"); + return trace_trace; + } + + trace_contents = brushmask; + Math3D.VectorCopy(start, trace_start); + Math3D.VectorCopy(end, trace_end); + Math3D.VectorCopy(mins, trace_mins); + Math3D.VectorCopy(maxs, trace_maxs); + + // + // check for position test special case + // + if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) { + + int leafs[] = new int[1024]; + int i, numleafs; + float[] c1 = { 0, 0, 0 }, c2 = { 0, 0, 0 }; + int topnode = 0; + + Math3D.VectorAdd(start, mins, c1); + Math3D.VectorAdd(start, maxs, c2); + + for (i = 0; i < 3; i++) { + c1[i] -= 1; + c2[i] += 1; + } + + int tn[] = { topnode }; + + numleafs = CM_BoxLeafnums_headnode(c1, c2, leafs, 1024, headnode, + tn); + topnode = tn[0]; + for (i = 0; i < numleafs; i++) { + CM_TestInLeaf(leafs[i]); + if (trace_trace.allsolid) + break; + } + Math3D.VectorCopy(start, trace_trace.endpos); + return trace_trace; + } + + // + // check for point special case + // + if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0 && maxs[0] == 0 + && maxs[1] == 0 && maxs[2] == 0) { + trace_ispoint = true; + Math3D.VectorClear(trace_extents); + } else { + trace_ispoint = false; + trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0]; + trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1]; + trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2]; + } + + // + // general sweeping through world + // + CM_RecursiveHullCheck(headnode, 0, 1, start, end); + + if (trace_trace.fraction == 1) { + Math3D.VectorCopy(end, trace_trace.endpos); + } else { + for (int i = 0; i < 3; i++) + trace_trace.endpos[i] = start[i] + trace_trace.fraction + * (end[i] - start[i]); + } + return trace_trace; + } + + /* + * ================== CM_TransformedBoxTrace + * + * Handles offseting and rotation of the end points for moving and rotating + * entities ================== + */ + public static trace_t TransformedBoxTrace(float[] start, float[] end, + float[] mins, float[] maxs, int headnode, int brushmask, + float[] origin, float[] angles) { + trace_t trace; + float[] start_l = { 0, 0, 0 }, end_l = { 0, 0, 0 }; + float[] a = { 0, 0, 0 }; + float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; + float[] temp = { 0, 0, 0 }; + boolean rotated; + + // subtract origin offset + Math3D.VectorSubtract(start, origin, start_l); + Math3D.VectorSubtract(end, origin, end_l); + + // rotate start and end into the models frame of reference + if (headnode != box_headnode + && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) + rotated = true; + else + rotated = false; + + if (rotated) { + Math3D.AngleVectors(angles, forward, right, up); + + Math3D.VectorCopy(start_l, temp); + start_l[0] = Math3D.DotProduct(temp, forward); + start_l[1] = -Math3D.DotProduct(temp, right); + start_l[2] = Math3D.DotProduct(temp, up); + + Math3D.VectorCopy(end_l, temp); + end_l[0] = Math3D.DotProduct(temp, forward); + end_l[1] = -Math3D.DotProduct(temp, right); + end_l[2] = Math3D.DotProduct(temp, up); + } + + // sweep the box through the model + trace = BoxTrace(start_l, end_l, mins, maxs, headnode, brushmask); + + if (rotated && trace.fraction != 1.0) { + // FIXME: figure out how to do this with existing angles + Math3D.VectorNegate(angles, a); + Math3D.AngleVectors(a, forward, right, up); + + Math3D.VectorCopy(trace.plane.normal, temp); + trace.plane.normal[0] = Math3D.DotProduct(temp, forward); + trace.plane.normal[1] = -Math3D.DotProduct(temp, right); + trace.plane.normal[2] = Math3D.DotProduct(temp, up); + } + + trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]); + trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]); + trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]); + + return trace; + } + + /* + * =============================================================================== + * PVS / PHS + * =============================================================================== + */ + + /* + * =================== CM_DecompressVis =================== + */ + public static void CM_DecompressVis(byte in[], int offset, byte out[]) { + int c; + + int row; + + row = (numclusters + 7) >> 3; + int outp = 0; + int inp = offset; + + if (in == null || numvisibility == 0) { // no vis info, so make all + // visible + while (row != 0) { + out[outp++] = (byte) 0xFF; + row--; + } + return; + } + + do { + if (in[inp] != 0) { + out[outp++] = in[inp++]; + continue; + } + + c = in[inp + 1] & 0xFF; + inp += 2; + if (outp + c > row) { + c = row - (outp); + Com.DPrintf("warning: Vis decompression overrun\n"); + } + while (c != 0) { + out[outp++] = 0; + c--; + } + } while (outp < row); + } + + public static byte pvsrow[] = new byte[Defines.MAX_MAP_LEAFS / 8]; + + public static byte phsrow[] = new byte[Defines.MAX_MAP_LEAFS / 8]; + + public static byte[] CM_ClusterPVS(int cluster) { + if (cluster == -1) + Arrays.fill(pvsrow, 0, (numclusters + 7) >> 3, (byte) 0); + else + CM_DecompressVis(map_visibility, + map_vis.bitofs[cluster][Defines.DVIS_PVS], pvsrow); + return pvsrow; + } + + public static byte[] CM_ClusterPHS(int cluster) { + if (cluster == -1) + Arrays.fill(phsrow, 0, (numclusters + 7) >> 3, (byte) 0); + else + CM_DecompressVis(map_visibility, + map_vis.bitofs[cluster][Defines.DVIS_PHS], phsrow); + return phsrow; + } + + /* + * =============================================================================== + * AREAPORTALS + * =============================================================================== + */ + + public static void FloodArea_r(carea_t area, int floodnum) { + //Com.Printf("FloodArea_r(" + floodnum + ")...\n"); + int i; + qfiles.dareaportal_t p; + + if (area.floodvalid == floodvalid) { + if (area.floodnum == floodnum) + return; + Com.Error(Defines.ERR_DROP, "FloodArea_r: reflooded"); + } + + area.floodnum = floodnum; + area.floodvalid = floodvalid; + + for (i = 0; i < area.numareaportals; i++) { + p = map_areaportals[area.firstareaportal + i]; + if (portalopen[p.portalnum]) + FloodArea_r(map_areas[p.otherarea], floodnum); + } + } + + /* + * ==================== FloodAreaConnections ==================== + */ + public static void FloodAreaConnections() { + Com.DPrintf("FloodAreaConnections...\n"); + + int i; + carea_t area; + int floodnum; + + // all current floods are now invalid + floodvalid++; + floodnum = 0; + + // area 0 is not used + for (i = 1; i < numareas; i++) { + + area = map_areas[i]; + + if (area.floodvalid == floodvalid) + continue; // already flooded into + floodnum++; + FloodArea_r(area, floodnum); + } + } + + /* + * ================= CM_SetAreaPortalState ================= + */ + public static void CM_SetAreaPortalState(int portalnum, boolean open) { + if (portalnum > numareaportals) + Com.Error(Defines.ERR_DROP, "areaportal > numareaportals"); + + portalopen[portalnum] = open; + FloodAreaConnections(); + } + + /* + * ================= CM_AreasConnected ================= + */ + + public static boolean CM_AreasConnected(int area1, int area2) { + if (map_noareas.value != 0) + return true; + + if (area1 > numareas || area2 > numareas) + Com.Error(Defines.ERR_DROP, "area > numareas"); + + if (map_areas[area1].floodnum == map_areas[area2].floodnum) + return true; + + return false; + } + + /* + * ================= CM_WriteAreaBits + * + * Writes a length byte followed by a bit vector of all the areas that area + * in the same flood as the area parameter + * + * This is used by the client refreshes to cull visibility ================= + */ + public static int CM_WriteAreaBits(byte buffer[], int area) { + int i; + int floodnum; + int bytes; + + bytes = (numareas + 7) >> 3; + + if (map_noareas.value != 0) { // for debugging, send everything + Arrays.fill(buffer, 0, bytes, (byte) 255); + } else { + Arrays.fill(buffer, 0, bytes, (byte) 0); + floodnum = map_areas[area].floodnum; + for (i = 0; i < numareas; i++) { + if (map_areas[i].floodnum == floodnum || area == 0) + buffer[i >> 3] |= 1 << (i & 7); + } + } + + return bytes; + } + + /* + * =================== CM_WritePortalState + * + * Writes the portal state to a savegame file =================== + */ + + public static void CM_WritePortalState(RandomAccessFile os) { + + //was: fwrite(portalopen, sizeof(portalopen), 1, f); + try { + + for (int n = 0; n < portalopen.length; n++) + if (portalopen[n]) + os.writeInt(1); + else + os.writeInt(0); + } catch (Exception e) { + Com.Printf("ERROR:" + e); + e.printStackTrace(); + } + } + + /* + * =================== CM_ReadPortalState + * + * Reads the portal state from a savegame file and recalculates the area + * connections =================== + */ + public static void CM_ReadPortalState(RandomAccessFile f) { + + //was: FS_Read(portalopen, sizeof(portalopen), f); + int len = portalopen.length * 4; + + byte buf[] = new byte[len]; + + FS.Read(buf, len, f); + + ByteBuffer bb = ByteBuffer.wrap(buf); + IntBuffer ib = bb.asIntBuffer(); + + for (int n = 0; n < portalopen.length; n++) + portalopen[n] = ib.get() != 0; + + FloodAreaConnections(); + } + + /* + * ============= CM_HeadnodeVisible + * + * Returns true if any leaf under headnode has a cluster that is potentially + * visible ============= + */ + public static boolean CM_HeadnodeVisible(int nodenum, byte visbits[]) { + int leafnum; + int cluster; + cnode_t node; + + if (nodenum < 0) { + leafnum = -1 - nodenum; + cluster = map_leafs[leafnum].cluster; + if (cluster == -1) + return false; + if (0 != (visbits[cluster >>> 3] & (1 << (cluster & 7)))) + return true; + return false; + } + + node = map_nodes[nodenum]; + if (CM_HeadnodeVisible(node.children[0], visbits)) + return true; + return CM_HeadnodeVisible(node.children[1], visbits); + } +}
\ No newline at end of file diff --git a/src/jake2/qcommon/Cbuf.java b/src/jake2/qcommon/Cbuf.java index f78577b..baa7090 100644 --- a/src/jake2/qcommon/Cbuf.java +++ b/src/jake2/qcommon/Cbuf.java @@ -2,245 +2,249 @@ * Cbuf.java * Copyright (C) 2003 * - * $Id: Cbuf.java,v 1.4 2004-09-18 13:07:46 hzi Exp $ + * $Id: Cbuf.java,v 1.5 2004-09-22 19:22:09 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.qcommon; import jake2.Defines; import jake2.Globals; import jake2.game.Cmd; +import jake2.util.Lib; /** * Cbuf */ public final class Cbuf { - /** - * - */ - public static void Init() { - SZ.Init(Globals.cmd_text, Globals.cmd_text_buf, Globals.cmd_text_buf.length); - } - - public static void InsertText(String text) { - - byte[] temp = null; - int templen = 0; - - // copy off any commands still remaining in the exec buffer - templen = Globals.cmd_text.cursize; - if (templen != 0) { - temp = new byte[templen]; - System.arraycopy(Globals.cmd_text.data, 0, temp, 0, templen); - SZ.Clear(Globals.cmd_text); - } - - // add the entire text of the file - Cbuf.AddText(text); - - // add the copied off data - if (templen != 0) { - SZ.Write(Globals.cmd_text, temp, templen); - temp = null; - } - } - - /** - * @param clear - */ - static void AddEarlyCommands(boolean clear) { - - for (int i = 0; i < Com.Argc(); i++) { - String s = Com.Argv(i); - if (!s.equals("+set")) - continue; - Cbuf.AddText("set " + Com.Argv(i + 1) + " " + Com.Argv(i + 2) + "\n"); - if (clear) { - Com.ClearArgv(i); - Com.ClearArgv(i + 1); - Com.ClearArgv(i + 2); - } - i += 2; - } - } - - /** - * @return - */ - static boolean AddLateCommands() { - int i; - int j; - boolean ret = false; - - // build the combined string to parse from - int s = 0; - int argc = Com.Argc(); - for (i = 1; i < argc; i++) { - s += Com.Argv(i).length(); - } - if (s == 0) - return false; - - String text = ""; - for (i = 1; i < argc; i++) { - text += Com.Argv(i); - if (i != argc - 1) - text += " "; - } - - // pull out the commands - String build = ""; - for (i = 0; i < text.length(); i++) { - if (text.charAt(i) == '+') { - i++; - - for (j = i;(text.charAt(j) != '+') && (text.charAt(j) != '-') && j < text.length(); j++); - - build += text.substring(i, j - 1); - build += "\n"; - - i = j - 1; - } - } - - ret = (build.length() != 0); - if (ret) - Cbuf.AddText(build); - - text = null; - build = null; - - return ret; - } - - /** - * @param text - */ - public static void AddText(String text) { - int l = text.length(); - - if (Globals.cmd_text.cursize + l >= Globals.cmd_text.maxsize) { - Com.Printf("Cbuf_AddText: overflow\n"); - return; - } - SZ.Write(Globals.cmd_text, text.getBytes(), l); - } - - /** - * - */ - public static void Execute() { - - byte[] text = null; - byte[] line = new byte[1024]; - - Globals.alias_count = 0; // don't allow infinite alias loops - - while (Globals.cmd_text.cursize != 0) { - // find a \n or ; line break - text = Globals.cmd_text.data; - - int quotes = 0; - int i; - - for (i = 0; i < Globals.cmd_text.cursize; i++) { - if (text[i] == '"') - quotes++; - if (!(quotes % 2 != 0) && text[i] == ';') - break; // don't break if inside a quoted string - if (text[i] == '\n') - break; - } - - System.arraycopy(text, 0, line, 0, i); - line[i] = 0; - - // delete the text from the command buffer and move remaining commands down - // this is necessary because commands (exec, alias) can insert data at the - // beginning of the text buffer - - if (i == Globals.cmd_text.cursize) - Globals.cmd_text.cursize = 0; - else { - i++; - Globals.cmd_text.cursize -= i; - byte[] tmp = new byte[Globals.cmd_text.cursize]; - - System.arraycopy(text, i, tmp, 0, Globals.cmd_text.cursize); - System.arraycopy(tmp, 0, text, 0, Globals.cmd_text.cursize); - text[Globals.cmd_text.cursize] = '\0'; - - } - - // execute the command line - int len = jake2.util.Lib.strlen(line); - - String cmd = new String(line, 0, len); - Cmd.ExecuteString(cmd); - - if (Globals.cmd_wait) { - // skip out while text still remains in buffer, leaving it - // for next frame - Globals.cmd_wait = false; - break; - } - } - } - - public static void ExecuteText(int exec_when, String text) { - switch(exec_when) { - case Defines.EXEC_NOW: - Cmd.ExecuteString(text); - break; - case Defines.EXEC_INSERT: - Cbuf.InsertText(text); - break; - case Defines.EXEC_APPEND: - Cbuf.AddText(text); - break; - default: - Com.Error(Defines.ERR_FATAL, "Cbuf_ExecuteText: bad exec_when"); - } - } - - /* - ============ - Cbuf_CopyToDefer - ============ - */ - public static void CopyToDefer() { - System.arraycopy(Globals.cmd_text_buf, 0, Globals.defer_text_buf, 0, Globals.cmd_text.cursize); - Globals.defer_text_buf[Globals.cmd_text.cursize] = 0; - Globals.cmd_text.cursize = 0; - } - - /* - ============ - Cbuf_InsertFromDefer - ============ - */ - public static void InsertFromDefer() { - InsertText(new String(Globals.defer_text_buf).trim()); - Globals.defer_text_buf[0] = 0; - } - -} + /** + * + */ + public static void Init() { + SZ.Init(Globals.cmd_text, Globals.cmd_text_buf, + Globals.cmd_text_buf.length); + } + + public static void InsertText(String text) { + + byte[] temp = null; + int templen = 0; + + // copy off any commands still remaining in the exec buffer + templen = Globals.cmd_text.cursize; + if (templen != 0) { + temp = new byte[templen]; + System.arraycopy(Globals.cmd_text.data, 0, temp, 0, templen); + SZ.Clear(Globals.cmd_text); + } + + // add the entire text of the file + Cbuf.AddText(text); + + // add the copied off data + if (templen != 0) { + SZ.Write(Globals.cmd_text, temp, templen); + temp = null; + } + } + + /** + * @param clear + */ + static void AddEarlyCommands(boolean clear) { + + for (int i = 0; i < Com.Argc(); i++) { + String s = Com.Argv(i); + if (!s.equals("+set")) + continue; + Cbuf.AddText("set " + Com.Argv(i + 1) + " " + Com.Argv(i + 2) + + "\n"); + if (clear) { + Com.ClearArgv(i); + Com.ClearArgv(i + 1); + Com.ClearArgv(i + 2); + } + i += 2; + } + } + + /** + * @return + */ + static boolean AddLateCommands() { + int i; + int j; + boolean ret = false; + + // build the combined string to parse from + int s = 0; + int argc = Com.Argc(); + for (i = 1; i < argc; i++) { + s += Com.Argv(i).length(); + } + if (s == 0) + return false; + + String text = ""; + for (i = 1; i < argc; i++) { + text += Com.Argv(i); + if (i != argc - 1) + text += " "; + } + + // pull out the commands + String build = ""; + for (i = 0; i < text.length(); i++) { + if (text.charAt(i) == '+') { + i++; + + for (j = i; (text.charAt(j) != '+') && (text.charAt(j) != '-') + && j < text.length(); j++) + ; + + build += text.substring(i, j - 1); + build += "\n"; + + i = j - 1; + } + } + + ret = (build.length() != 0); + if (ret) + Cbuf.AddText(build); + + text = null; + build = null; + + return ret; + } + + /** + * @param text + */ + public static void AddText(String text) { + int l = text.length(); + + if (Globals.cmd_text.cursize + l >= Globals.cmd_text.maxsize) { + Com.Printf("Cbuf_AddText: overflow\n"); + return; + } + SZ.Write(Globals.cmd_text, text.getBytes(), l); + } + + /** + * + */ + public static void Execute() { + + byte[] text = null; + byte[] line = new byte[1024]; + + Globals.alias_count = 0; // don't allow infinite alias loops + + while (Globals.cmd_text.cursize != 0) { + // find a \n or ; line break + text = Globals.cmd_text.data; + + int quotes = 0; + int i; + + for (i = 0; i < Globals.cmd_text.cursize; i++) { + if (text[i] == '"') + quotes++; + if (!(quotes % 2 != 0) && text[i] == ';') + break; // don't break if inside a quoted string + if (text[i] == '\n') + break; + } + + System.arraycopy(text, 0, line, 0, i); + line[i] = 0; + + // delete the text from the command buffer and move remaining + // commands down + // this is necessary because commands (exec, alias) can insert data + // at the + // beginning of the text buffer + + if (i == Globals.cmd_text.cursize) + Globals.cmd_text.cursize = 0; + else { + i++; + Globals.cmd_text.cursize -= i; + byte[] tmp = new byte[Globals.cmd_text.cursize]; + + System.arraycopy(text, i, tmp, 0, Globals.cmd_text.cursize); + System.arraycopy(tmp, 0, text, 0, Globals.cmd_text.cursize); + text[Globals.cmd_text.cursize] = '\0'; + + } + + // execute the command line + int len = Lib.strlen(line); + + String cmd = new String(line, 0, len); + Cmd.ExecuteString(cmd); + + if (Globals.cmd_wait) { + // skip out while text still remains in buffer, leaving it + // for next frame + Globals.cmd_wait = false; + break; + } + } + } + + public static void ExecuteText(int exec_when, String text) { + switch (exec_when) { + case Defines.EXEC_NOW: + Cmd.ExecuteString(text); + break; + case Defines.EXEC_INSERT: + Cbuf.InsertText(text); + break; + case Defines.EXEC_APPEND: + Cbuf.AddText(text); + break; + default: + Com.Error(Defines.ERR_FATAL, "Cbuf_ExecuteText: bad exec_when"); + } + } + + /* + * ============ Cbuf_CopyToDefer ============ + */ + public static void CopyToDefer() { + System.arraycopy(Globals.cmd_text_buf, 0, Globals.defer_text_buf, 0, + Globals.cmd_text.cursize); + Globals.defer_text_buf[Globals.cmd_text.cursize] = 0; + Globals.cmd_text.cursize = 0; + } + + /* + * ============ Cbuf_InsertFromDefer ============ + */ + public static void InsertFromDefer() { + InsertText(new String(Globals.defer_text_buf).trim()); + Globals.defer_text_buf[0] = 0; + } + +}
\ No newline at end of file diff --git a/src/jake2/qcommon/Cvar.java b/src/jake2/qcommon/Cvar.java index a43464b..7255afd 100644 --- a/src/jake2/qcommon/Cvar.java +++ b/src/jake2/qcommon/Cvar.java @@ -2,459 +2,437 @@ * Cvar.java * Copyright (C) 2003 * - * $Id: Cvar.java,v 1.4 2004-08-19 20:56:41 hzi Exp $ + * $Id: Cvar.java,v 1.5 2004-09-22 19:22:09 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.qcommon; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.Vector; - import jake2.Defines; import jake2.Globals; -import jake2.game.*; +import jake2.game.Cmd; +import jake2.game.Info; +import jake2.game.cvar_t; import jake2.util.Lib; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Vector; + /** - * Cvar implements console variables. The original code is - * located in cvar.c + * Cvar implements console variables. The original code is located in cvar.c */ public class Cvar extends Globals { - /** - * @param var_name - * @param var_value - * @param flags - * @return - */ - public static cvar_t Get(String var_name, String var_value, int flags) { - cvar_t var; - - if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { - if (!Info.Info_Validate(var_name)) { - Com.Printf("invalid info cvar name\n"); - return null; - } - } - - var = Cvar.FindVar(var_name); - if (var != null) { - var.flags |= flags; - return var; - } - - if (var_value == null) - return null; - - if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { - if (!InfoValidate(var_value)) { - Com.Printf("invalid info cvar value\n"); - return null; - } - } - var = new cvar_t(); - var.name = new String(var_name); - var.string = new String(var_value); - var.modified = true; - // handles atof(var.string) - try { - var.value = Float.parseFloat(var.string); - } - catch (NumberFormatException e) { - var.value = 0.0f; - } - // link the variable in - var.next = Globals.cvar_vars; - Globals.cvar_vars = var; - - var.flags = flags; - - return var; - } - - static void Init() { - Cmd.AddCommand("set", Set_f); - Cmd.AddCommand("cvarlist", List_f); - } - - public static String VariableString(String var_name) { - cvar_t var; - var = FindVar(var_name); - return (var == null) ? "" : var.string; - } - - static cvar_t FindVar(String var_name) { - cvar_t var; - - for (var = Globals.cvar_vars; var != null; var = var.next) { - if (var_name.equals(var.name)) - return var; - } - - return null; - } - - /* - ============ - Cvar_FullSet - ============ - */ - public static cvar_t FullSet(String var_name, String value, int flags) { - cvar_t var; - - var = Cvar.FindVar(var_name); - if (null == var) { // create it - return Cvar.Get(var_name, value, flags); - } - - var.modified = true; - - if ((var.flags & CVAR_USERINFO) != 0) - Globals.userinfo_modified = true; // transmit at next oportunity - - var.string = value; - try { - var.value = Float.parseFloat(var.string); - } catch (Exception e) { - var.value = 0.0f; - } - - var.flags = flags; - - return var; - } - - /* - ============ - Cvar_Set - ============ - */ - public static cvar_t Set(String var_name, String value) { - return Set2(var_name, value, false); - } - - /* - ============ - Cvar_Set2 - ============ - */ - static cvar_t Set2(String var_name, String value, boolean force) { - - cvar_t var = Cvar.FindVar(var_name); - if (var == null) { // create it - return Cvar.Get(var_name, value, 0); - } - - if ((var.flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { - if (!InfoValidate(value)) { - Com.Printf("invalid info cvar value\n"); - return var; - } - } - - if (!force) { - if ((var.flags & CVAR_NOSET) != 0) { - Com.Printf(var_name + " is write protected.\n"); - return var; - } - - if ((var.flags & CVAR_LATCH) != 0) { - if (var.latched_string != null) { - if (value.equals(var.latched_string)) - return var; - //Z_Free (var.latched_string); - var.latched_string = null; - } - else { - if (value.equals(var.string)) - return var; - } - - if (Globals.server_state != 0) { - Com.Printf(var_name + " will be changed for next game.\n"); - var.latched_string = value; - } - else { - var.string = value; - try { - var.value = Float.parseFloat(var.string); - } catch (Exception e) { - var.value = 0.0f; - } - if (var.name.equals("game")) { - FS.SetGamedir(var.string); - FS.ExecAutoexec(); - } - } - return var; - } - } - else { - if (var.latched_string != null) { - //Z_Free(var.latched_string); - var.latched_string = null; - } - } - - if (value.equals(var.string)) - return var; // not changed - - var.modified = true; - - if ((var.flags & CVAR_USERINFO) != 0) - Globals.userinfo_modified = true; // transmit at next oportunity - - var.string = value; - try { - var.value = Float.parseFloat(var.string); - } catch (Exception e) { - var.value = 0.0f; - } - - return var; - } - - static xcommand_t Set_f = new xcommand_t() { - public void execute() { - int c; - int flags; - - c = Cmd.Argc(); - if (c != 3 && c != 4) { - Com.Printf("usage: set <variable> <value> [u / s]\n"); - return; - } - - if (c == 4) { - if (Cmd.Argv(3).equals("u")) - flags = CVAR_USERINFO; - else if (Cmd.Argv(3).equals("s")) - flags = CVAR_SERVERINFO; - else { - Com.Printf("flags can only be 'u' or 's'\n"); - return; - } - Cvar.FullSet(Cmd.Argv(1), Cmd.Argv(2), flags); - } - else - Cvar.Set(Cmd.Argv(1), Cmd.Argv(2)); - - } - - }; - - static xcommand_t List_f = new xcommand_t() { - public void execute() { - cvar_t var; - int i; - - i = 0; - for (var = Globals.cvar_vars; var != null; var = var.next, i++) { - if ((var.flags & CVAR_ARCHIVE) != 0) - Com.Printf("*"); - else - Com.Printf(" "); - if ((var.flags & CVAR_USERINFO) != 0) - Com.Printf("U"); - else - Com.Printf(" "); - if ((var.flags & CVAR_SERVERINFO) != 0) - Com.Printf("S"); - else - Com.Printf(" "); - if ((var.flags & CVAR_NOSET) != 0) - Com.Printf("-"); - else if ((var.flags & CVAR_LATCH) != 0) - Com.Printf("L"); - else - Com.Printf(" "); - Com.Printf(" " + var.name + " \"" + var.string + "\"\n"); - } - Com.Printf(i + " cvars\n"); - } - }; - - /* - ============ - Cvar_ForceSet - ============ - */ - public static cvar_t ForceSet(String var_name, String value) { - return Cvar.Set2(var_name, value, true); - } - /* - ============ - Cvar_SetValue - ============ - */ - public static void SetValue(String var_name, float value) { - Cvar.Set(var_name, "" + value); - } - - /* - ============ - Cvar_VariableValue - ============ - */ - public static float VariableValue(String var_name) { - cvar_t var = Cvar.FindVar(var_name); - if (var == null) - return 0; - float val = 0.0f; - try { - val = Float.parseFloat(var.string); - } catch (Exception e) {} - return val; - } - - /* - ============ - Cvar_Command - - Handles variable inspection and changing from the console - ============ - */ - public static boolean Command() { - cvar_t v; - - // check variables - v = Cvar.FindVar(Cmd.Argv(0)); - if (v == null) - return false; - - // perform a variable print or set - if (Cmd.Argc() == 1) { - Com.Printf("\"" + v.name + "\" is \"" + v.string + "\"\n"); - return true; - } - - Cvar.Set(v.name, Cmd.Argv(1)); - return true; - } - - public static String BitInfo(int bit) { - String info; - cvar_t var; - - info = ""; - - for (var = Globals.cvar_vars; var != null; var = var.next) { - if ((var.flags & bit) != 0) - info = Info.Info_SetValueForKey1(info, var.name, var.string); - } - return info; - } - - // returns an info string containing all the CVAR_SERVERINFO cvars - public static String Serverinfo() { - return BitInfo(Defines.CVAR_SERVERINFO); - } - - public static void GetLatchedVars() { - cvar_t var; - - for (var = Globals.cvar_vars; var != null; var = var.next) { - if (var.latched_string == null || var.latched_string == "") - continue; - var.string = var.latched_string; - var.latched_string = null; - try { - var.value = Float.parseFloat(var.string); - } - catch (NumberFormatException e) { - var.value = 0.0f; - } - if (var.name.equals("game")) { - FS.SetGamedir(var.string); - FS.ExecAutoexec(); - } - } - } - - /** - * returns an info string containing all the CVAR_USERINFO cvars. - */ - public static String Userinfo() { - return BitInfo(CVAR_USERINFO); - } - - public static void WriteVariables(String path) { - cvar_t var; - RandomAccessFile f; - String buffer; - - f = Lib.fopen(path, "rw"); - if (f == null) - return; - - try { - f.seek(f.length()); - } catch (IOException e1) { - fclose(f); - return; - } - for (var = cvar_vars; var != null; var = var.next) { - if ((var.flags & CVAR_ARCHIVE) != 0) { - buffer = "set " + var.name + " \"" + var.string + "\"\n"; - try { - f.writeBytes(buffer); - } - catch (IOException e) { - } - } - } - fclose(f); - } - - /* - ============ - Cvar_CompleteVariable - ============ - */ - public static Vector CompleteVariable(String partial) { - - Vector vars = new Vector(); - - // check match - for (cvar_t cvar = Globals.cvar_vars; cvar != null; cvar = cvar.next) - if (cvar.name.startsWith(partial)) - vars.add(cvar.name); - - return vars; - } - - /* - ============ - Cvar_InfoValidate - ============ - */ - static boolean InfoValidate(String s) { - if (s.indexOf("\\") != -1) - return false; - if (s.indexOf("\"") != -1) - return false; - if (s.indexOf(";") != -1) - return false; - return true; - } -} + /** + * @param var_name + * @param var_value + * @param flags + * @return + */ + public static cvar_t Get(String var_name, String var_value, int flags) { + cvar_t var; + + if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { + if (!Info.Info_Validate(var_name)) { + Com.Printf("invalid info cvar name\n"); + return null; + } + } + + var = Cvar.FindVar(var_name); + if (var != null) { + var.flags |= flags; + return var; + } + + if (var_value == null) + return null; + + if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { + if (!InfoValidate(var_value)) { + Com.Printf("invalid info cvar value\n"); + return null; + } + } + var = new cvar_t(); + var.name = new String(var_name); + var.string = new String(var_value); + var.modified = true; + // handles atof(var.string) + try { + var.value = Float.parseFloat(var.string); + } catch (NumberFormatException e) { + var.value = 0.0f; + } + // link the variable in + var.next = Globals.cvar_vars; + Globals.cvar_vars = var; + + var.flags = flags; + + return var; + } + + static void Init() { + Cmd.AddCommand("set", Set_f); + Cmd.AddCommand("cvarlist", List_f); + } + + public static String VariableString(String var_name) { + cvar_t var; + var = FindVar(var_name); + return (var == null) ? "" : var.string; + } + + static cvar_t FindVar(String var_name) { + cvar_t var; + + for (var = Globals.cvar_vars; var != null; var = var.next) { + if (var_name.equals(var.name)) + return var; + } + + return null; + } + + /* + * ============ Cvar_FullSet ============ + */ + public static cvar_t FullSet(String var_name, String value, int flags) { + cvar_t var; + + var = Cvar.FindVar(var_name); + if (null == var) { // create it + return Cvar.Get(var_name, value, flags); + } + + var.modified = true; + + if ((var.flags & CVAR_USERINFO) != 0) + Globals.userinfo_modified = true; // transmit at next oportunity + + var.string = value; + try { + var.value = Float.parseFloat(var.string); + } catch (Exception e) { + var.value = 0.0f; + } + + var.flags = flags; + + return var; + } + + /* + * ============ Cvar_Set ============ + */ + public static cvar_t Set(String var_name, String value) { + return Set2(var_name, value, false); + } + + /* + * ============ Cvar_Set2 ============ + */ + static cvar_t Set2(String var_name, String value, boolean force) { + + cvar_t var = Cvar.FindVar(var_name); + if (var == null) { // create it + return Cvar.Get(var_name, value, 0); + } + + if ((var.flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { + if (!InfoValidate(value)) { + Com.Printf("invalid info cvar value\n"); + return var; + } + } + + if (!force) { + if ((var.flags & CVAR_NOSET) != 0) { + Com.Printf(var_name + " is write protected.\n"); + return var; + } + + if ((var.flags & CVAR_LATCH) != 0) { + if (var.latched_string != null) { + if (value.equals(var.latched_string)) + return var; + //Z_Free (var.latched_string); + var.latched_string = null; + } else { + if (value.equals(var.string)) + return var; + } + + if (Globals.server_state != 0) { + Com.Printf(var_name + " will be changed for next game.\n"); + var.latched_string = value; + } else { + var.string = value; + try { + var.value = Float.parseFloat(var.string); + } catch (Exception e) { + var.value = 0.0f; + } + if (var.name.equals("game")) { + FS.SetGamedir(var.string); + FS.ExecAutoexec(); + } + } + return var; + } + } else { + if (var.latched_string != null) { + //Z_Free(var.latched_string); + var.latched_string = null; + } + } + + if (value.equals(var.string)) + return var; // not changed + + var.modified = true; + + if ((var.flags & CVAR_USERINFO) != 0) + Globals.userinfo_modified = true; // transmit at next oportunity + + var.string = value; + try { + var.value = Float.parseFloat(var.string); + } catch (Exception e) { + var.value = 0.0f; + } + + return var; + } + + static xcommand_t Set_f = new xcommand_t() { + public void execute() { + int c; + int flags; + + c = Cmd.Argc(); + if (c != 3 && c != 4) { + Com.Printf("usage: set <variable> <value> [u / s]\n"); + return; + } + + if (c == 4) { + if (Cmd.Argv(3).equals("u")) + flags = CVAR_USERINFO; + else if (Cmd.Argv(3).equals("s")) + flags = CVAR_SERVERINFO; + else { + Com.Printf("flags can only be 'u' or 's'\n"); + return; + } + Cvar.FullSet(Cmd.Argv(1), Cmd.Argv(2), flags); + } else + Cvar.Set(Cmd.Argv(1), Cmd.Argv(2)); + + } + + }; + + static xcommand_t List_f = new xcommand_t() { + public void execute() { + cvar_t var; + int i; + + i = 0; + for (var = Globals.cvar_vars; var != null; var = var.next, i++) { + if ((var.flags & CVAR_ARCHIVE) != 0) + Com.Printf("*"); + else + Com.Printf(" "); + if ((var.flags & CVAR_USERINFO) != 0) + Com.Printf("U"); + else + Com.Printf(" "); + if ((var.flags & CVAR_SERVERINFO) != 0) + Com.Printf("S"); + else + Com.Printf(" "); + if ((var.flags & CVAR_NOSET) != 0) + Com.Printf("-"); + else if ((var.flags & CVAR_LATCH) != 0) + Com.Printf("L"); + else + Com.Printf(" "); + Com.Printf(" " + var.name + " \"" + var.string + "\"\n"); + } + Com.Printf(i + " cvars\n"); + } + }; + + /* + * ============ Cvar_ForceSet ============ + */ + public static cvar_t ForceSet(String var_name, String value) { + return Cvar.Set2(var_name, value, true); + } + + /* + * ============ Cvar_SetValue ============ + */ + public static void SetValue(String var_name, float value) { + Cvar.Set(var_name, "" + value); + } + + /* + * ============ Cvar_VariableValue ============ + */ + public static float VariableValue(String var_name) { + cvar_t var = Cvar.FindVar(var_name); + if (var == null) + return 0; + float val = 0.0f; + try { + val = Float.parseFloat(var.string); + } catch (Exception e) { + } + return val; + } + + /* + * ============ Cvar_Command + * + * Handles variable inspection and changing from the console ============ + */ + public static boolean Command() { + cvar_t v; + + // check variables + v = Cvar.FindVar(Cmd.Argv(0)); + if (v == null) + return false; + + // perform a variable print or set + if (Cmd.Argc() == 1) { + Com.Printf("\"" + v.name + "\" is \"" + v.string + "\"\n"); + return true; + } + + Cvar.Set(v.name, Cmd.Argv(1)); + return true; + } + + public static String BitInfo(int bit) { + String info; + cvar_t var; + + info = ""; + + for (var = Globals.cvar_vars; var != null; var = var.next) { + if ((var.flags & bit) != 0) + info = Info.Info_SetValueForKey1(info, var.name, var.string); + } + return info; + } + + // returns an info string containing all the CVAR_SERVERINFO cvars + public static String Serverinfo() { + return BitInfo(Defines.CVAR_SERVERINFO); + } + + public static void GetLatchedVars() { + cvar_t var; + + for (var = Globals.cvar_vars; var != null; var = var.next) { + if (var.latched_string == null || var.latched_string == "") + continue; + var.string = var.latched_string; + var.latched_string = null; + try { + var.value = Float.parseFloat(var.string); + } catch (NumberFormatException e) { + var.value = 0.0f; + } + if (var.name.equals("game")) { + FS.SetGamedir(var.string); + FS.ExecAutoexec(); + } + } + } + + /** + * returns an info string containing all the CVAR_USERINFO cvars. + */ + public static String Userinfo() { + return BitInfo(CVAR_USERINFO); + } + + public static void WriteVariables(String path) { + cvar_t var; + RandomAccessFile f; + String buffer; + + f = Lib.fopen(path, "rw"); + if (f == null) + return; + + try { + f.seek(f.length()); + } catch (IOException e1) { + Lib.fclose(f); + return; + } + for (var = cvar_vars; var != null; var = var.next) { + if ((var.flags & CVAR_ARCHIVE) != 0) { + buffer = "set " + var.name + " \"" + var.string + "\"\n"; + try { + f.writeBytes(buffer); + } catch (IOException e) { + } + } + } + Lib.fclose(f); + } + + /* + * ============ Cvar_CompleteVariable ============ + */ + public static Vector CompleteVariable(String partial) { + + Vector vars = new Vector(); + + // check match + for (cvar_t cvar = Globals.cvar_vars; cvar != null; cvar = cvar.next) + if (cvar.name.startsWith(partial)) + vars.add(cvar.name); + + return vars; + } + + /* + * ============ Cvar_InfoValidate ============ + */ + static boolean InfoValidate(String s) { + if (s.indexOf("\\") != -1) + return false; + if (s.indexOf("\"") != -1) + return false; + if (s.indexOf(";") != -1) + return false; + return true; + } +}
\ No newline at end of file diff --git a/src/jake2/qcommon/MSG.java b/src/jake2/qcommon/MSG.java index 4396ac3..ee2a089 100644 --- a/src/jake2/qcommon/MSG.java +++ b/src/jake2/qcommon/MSG.java @@ -1,562 +1,559 @@ /* -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 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. - -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. - -*/ + * 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 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. + * + * 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. + * + */ // Created on 29.11.2003 by RST. -// $Id: MSG.java,v 1.4 2004-07-28 11:58:10 hzi Exp $ - +// $Id: MSG.java,v 1.5 2004-09-22 19:22:09 salomo Exp $ package jake2.qcommon; +import jake2.Globals; import jake2.game.*; import jake2.util.*; -public class MSG extends GameBase { - - // - // writing functions - // - - //ok. - public static void WriteChar(sizebuf_t sb, int c) { - sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF); - } - - //ok. - public static void WriteChar(sizebuf_t sb, float c) { - - WriteChar(sb, (int) c); - } - - //ok. - public static void WriteByte(sizebuf_t sb, int c) { - sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF); - } - - //ok. - public static void WriteByte(sizebuf_t sb, float c) { - WriteByte(sb, (int) c); - } - - - public static void WriteShort(sizebuf_t sb, int c) { - int i = SZ.GetSpace(sb, 2); - sb.data[i++] = (byte) (c & 0xff); - sb.data[i] = (byte) ((c >>> 8) & 0xFF); - } - - //ok. - public static void WriteInt(sizebuf_t sb, int c) { - int i = SZ.GetSpace(sb, 4); - sb.data[i++] = (byte) ((c & 0xff)); - sb.data[i++] = (byte) ((c >>> 8) & 0xff); - sb.data[i++] = (byte) ((c >>> 16) & 0xff); - sb.data[i++] = (byte) ((c >>> 24) & 0xff); - } - - //ok. - public static void WriteLong(sizebuf_t sb, int c) { - WriteInt(sb, c); - } - - //ok. - public static void WriteFloat(sizebuf_t sb, float f) { - WriteInt(sb, Float.floatToIntBits(f)); - } - - // had a bug, now its ok. - public static void WriteString(sizebuf_t sb, String s) { - String x = s; - - if (s == null) - x = ""; - - SZ.Write(sb, x.getBytes()); - WriteByte(sb, 0); - } - - //ok. - public static void WriteString(sizebuf_t sb, byte s[]) { - WriteString(sb, new String(s).trim()); - } - - public static void WriteCoord(sizebuf_t sb, float f) { - WriteShort(sb, (int) (f * 8)); - } - - public static void WritePos(sizebuf_t sb, float[] pos) { - assert(pos.length == 3) : "vec3_t bug"; - WriteShort(sb, (int) (pos[0] * 8)); - WriteShort(sb, (int) (pos[1] * 8)); - WriteShort(sb, (int) (pos[2] * 8)); - } - - public static void WriteAngle(sizebuf_t sb, float f) { - WriteByte(sb, (int) (f * 256 / 360) & 255); - } - - public static void WriteAngle16(sizebuf_t sb, float f) { - WriteShort(sb, Math3D.ANGLE2SHORT(f)); - } - - public static void WriteDeltaUsercmd(sizebuf_t buf, usercmd_t from, usercmd_t cmd) { - int bits; - - // - // send the movement message - // - bits = 0; - if (cmd.angles[0] != from.angles[0]) - bits |= CM_ANGLE1; - if (cmd.angles[1] != from.angles[1]) - bits |= CM_ANGLE2; - if (cmd.angles[2] != from.angles[2]) - bits |= CM_ANGLE3; - if (cmd.forwardmove != from.forwardmove) - bits |= CM_FORWARD; - if (cmd.sidemove != from.sidemove) - bits |= CM_SIDE; - if (cmd.upmove != from.upmove) - bits |= CM_UP; - if (cmd.buttons != from.buttons) - bits |= CM_BUTTONS; - if (cmd.impulse != from.impulse) - bits |= CM_IMPULSE; - - WriteByte(buf, bits); - - if ((bits & CM_ANGLE1) != 0) - WriteShort(buf, cmd.angles[0]); - if ((bits & CM_ANGLE2) != 0) - WriteShort(buf, cmd.angles[1]); - if ((bits & CM_ANGLE3) != 0) - WriteShort(buf, cmd.angles[2]); - - if ((bits & CM_FORWARD) != 0) - WriteShort(buf, cmd.forwardmove); - if ((bits & CM_SIDE) != 0) - WriteShort(buf, cmd.sidemove); - if ((bits & CM_UP) != 0) - WriteShort(buf, cmd.upmove); - - if ((bits & CM_BUTTONS) != 0) - WriteByte(buf, cmd.buttons); - if ((bits & CM_IMPULSE) != 0) - WriteByte(buf, cmd.impulse); - - WriteByte(buf, cmd.msec); - WriteByte(buf, cmd.lightlevel); - } - - //should be ok. - public static void WriteDir(sizebuf_t sb, float[] dir) { - int i, best; - float d, bestd; - - if (dir == null) { - WriteByte(sb, 0); - return; - } - - bestd = 0; - best = 0; - for (i = 0; i < NUMVERTEXNORMALS; i++) { - d = Math3D.DotProduct(dir, bytedirs[i]); - if (d > bestd) { - bestd = d; - best = i; - } - } - WriteByte(sb, best); - } - - //should be ok. - public static void ReadDir(sizebuf_t sb, float[] dir) { - int b; - - b = ReadByte(sb); - if (b >= NUMVERTEXNORMALS) - Com.Error(ERR_DROP, "MSF_ReadDir: out of range"); - Math3D.VectorCopy(bytedirs[b], dir); - } - - /* - ================== - WriteDeltaEntity - - Writes part of a packetentities message. - Can delta from either a baseline or a previous packet_entity - ================== - */ - public static void WriteDeltaEntity(entity_state_t from, entity_state_t to, sizebuf_t msg, boolean force, boolean newentity) { - int bits; - - if (0 == to.number) - Com.Error(ERR_FATAL, "Unset entity number"); - if (to.number >= MAX_EDICTS) - Com.Error(ERR_FATAL, "Entity number >= MAX_EDICTS"); - - // send an update - bits = 0; - - if (to.number >= 256) - bits |= U_NUMBER16; // number8 is implicit otherwise - - if (to.origin[0] != from.origin[0]) - bits |= U_ORIGIN1; - if (to.origin[1] != from.origin[1]) - bits |= U_ORIGIN2; - if (to.origin[2] != from.origin[2]) - bits |= U_ORIGIN3; - - if (to.angles[0] != from.angles[0]) - bits |= U_ANGLE1; - if (to.angles[1] != from.angles[1]) - bits |= U_ANGLE2; - if (to.angles[2] != from.angles[2]) - bits |= U_ANGLE3; - - if (to.skinnum != from.skinnum) { - if (to.skinnum < 256) - bits |= U_SKIN8; - else if (to.skinnum < 0x10000) - bits |= U_SKIN16; - else - bits |= (U_SKIN8 | U_SKIN16); - } - - if (to.frame != from.frame) { - if (to.frame < 256) - bits |= U_FRAME8; - else - bits |= U_FRAME16; - } - - if (to.effects != from.effects) { - if (to.effects < 256) - bits |= U_EFFECTS8; - else if (to.effects < 0x8000) - bits |= U_EFFECTS16; - else - bits |= U_EFFECTS8 | U_EFFECTS16; - } - - if (to.renderfx != from.renderfx) { - if (to.renderfx < 256) - bits |= U_RENDERFX8; - else if (to.renderfx < 0x8000) - bits |= U_RENDERFX16; - else - bits |= U_RENDERFX8 | U_RENDERFX16; - } - - if (to.solid != from.solid) - bits |= U_SOLID; - - // event is not delta compressed, just 0 compressed - if (to.event != 0) - bits |= U_EVENT; - - if (to.modelindex != from.modelindex) - bits |= U_MODEL; - if (to.modelindex2 != from.modelindex2) - bits |= U_MODEL2; - if (to.modelindex3 != from.modelindex3) - bits |= U_MODEL3; - if (to.modelindex4 != from.modelindex4) - bits |= U_MODEL4; - - if (to.sound != from.sound) - bits |= U_SOUND; - - if (newentity || (to.renderfx & RF_BEAM) != 0) - bits |= U_OLDORIGIN; - - // - // write the message - // - if (bits == 0 && !force) - return; // nothing to send! - - //---------- - - if ((bits & 0xff000000) != 0) - bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1; - else if ((bits & 0x00ff0000) != 0) - bits |= U_MOREBITS2 | U_MOREBITS1; - else if ((bits & 0x0000ff00) != 0) - bits |= U_MOREBITS1; - - WriteByte(msg, bits & 255); - - if ((bits & 0xff000000) != 0) { - WriteByte(msg, (bits >>> 8) & 255); - WriteByte(msg, (bits >>> 16) & 255); - WriteByte(msg, (bits >>> 24) & 255); - } - else if ((bits & 0x00ff0000) != 0) { - WriteByte(msg, (bits >>> 8) & 255); - WriteByte(msg, (bits >>> 16) & 255); - } - else if ((bits & 0x0000ff00) != 0) { - WriteByte(msg, (bits >>> 8) & 255); - } - - //---------- - - if ((bits & U_NUMBER16) != 0) - WriteShort(msg, to.number); - else - WriteByte(msg, to.number); - - if ((bits & U_MODEL) != 0) - WriteByte(msg, to.modelindex); - if ((bits & U_MODEL2) != 0) - WriteByte(msg, to.modelindex2); - if ((bits & U_MODEL3) != 0) - WriteByte(msg, to.modelindex3); - if ((bits & U_MODEL4) != 0) - WriteByte(msg, to.modelindex4); - - if ((bits & U_FRAME8) != 0) - WriteByte(msg, to.frame); - if ((bits & U_FRAME16) != 0) - WriteShort(msg, to.frame); - - if ((bits & U_SKIN8) != 0 && (bits & U_SKIN16) != 0) //used for laser colors - WriteInt(msg, to.skinnum); - else if ((bits & U_SKIN8) != 0) - WriteByte(msg, to.skinnum); - else if ((bits & U_SKIN16) != 0) - WriteShort(msg, to.skinnum); - - if ((bits & (U_EFFECTS8 | U_EFFECTS16)) == (U_EFFECTS8 | U_EFFECTS16)) - WriteInt(msg, to.effects); - else if ((bits & U_EFFECTS8) != 0) - WriteByte(msg, to.effects); - else if ((bits & U_EFFECTS16) != 0) - WriteShort(msg, to.effects); - - if ((bits & (U_RENDERFX8 | U_RENDERFX16)) == (U_RENDERFX8 | U_RENDERFX16)) - WriteInt(msg, to.renderfx); - else if ((bits & U_RENDERFX8) != 0) - WriteByte(msg, to.renderfx); - else if ((bits & U_RENDERFX16) != 0) - WriteShort(msg, to.renderfx); - - if ((bits & U_ORIGIN1) != 0) - WriteCoord(msg, to.origin[0]); - if ((bits & U_ORIGIN2) != 0) - WriteCoord(msg, to.origin[1]); - if ((bits & U_ORIGIN3) != 0) - WriteCoord(msg, to.origin[2]); - - if ((bits & U_ANGLE1) != 0) - WriteAngle(msg, to.angles[0]); - if ((bits & U_ANGLE2) != 0) - WriteAngle(msg, to.angles[1]); - if ((bits & U_ANGLE3) != 0) - WriteAngle(msg, to.angles[2]); - - if ((bits & U_OLDORIGIN) != 0) { - WriteCoord(msg, to.old_origin[0]); - WriteCoord(msg, to.old_origin[1]); - WriteCoord(msg, to.old_origin[2]); - } - - if ((bits & U_SOUND) != 0) - WriteByte(msg, to.sound); - if ((bits & U_EVENT) != 0) - WriteByte(msg, to.event); - if ((bits & U_SOLID) != 0) - WriteShort(msg, to.solid); - } - - //============================================================ - - // - // reading functions - // - - public static void BeginReading(sizebuf_t msg) { - msg.readcount = 0; - } - - // returns -1 if no more characters are available, but also [-128 , 127] - public static int ReadChar(sizebuf_t msg_read) { - int c; - - if (msg_read.readcount + 1 > msg_read.cursize) - c = -1; - else - c = msg_read.data[msg_read.readcount]; - msg_read.readcount++; - // kickangles bugfix (rst) - return c; - } - - public static int ReadByte(sizebuf_t msg_read) { - int c; - - if (msg_read.readcount + 1 > msg_read.cursize) - c = -1; - else - c = msg_read.data[msg_read.readcount] & 0xff; - msg_read.readcount++; - - return c; - } - - public static short ReadShort(sizebuf_t msg_read) { - int c; - - if (msg_read.readcount + 2 > msg_read.cursize) - c = -1; - else - c = (short) ((msg_read.data[msg_read.readcount] & 0xff) + (msg_read.data[msg_read.readcount + 1] << 8)); - - msg_read.readcount += 2; - - return (short) c; - } - - public static int ReadLong(sizebuf_t msg_read) { - int c; - - if (msg_read.readcount + 4 > msg_read.cursize) - { - Com.Printf("buffer underrun in ReadLong!"); - c = -1; - } - - else - c = - (msg_read.data[msg_read.readcount] & 0xff) - | ((msg_read.data[msg_read.readcount + 1] & 0xff) << 8) - | ((msg_read.data[msg_read.readcount + 2] & 0xff) << 16) - | ((msg_read.data[msg_read.readcount + 3] & 0xff) << 24); - - msg_read.readcount += 4; - - return c; - } - - public static float ReadFloat(sizebuf_t msg_read) { - int n = ReadLong(msg_read); - return Float.intBitsToFloat(n); - } - - // 2k read buffer. - public static byte readbuf[] = new byte[2048]; - - public static String ReadString(sizebuf_t msg_read) { - - byte c; - int l = 0; - do { - c = (byte)ReadByte(msg_read); - if (c == -1 || c == 0) - break; - - readbuf[l] = c; - l++; - } while (l < 2047); - - return new String(readbuf, 0, l); - } - - public static String ReadStringLine(sizebuf_t msg_read) { - - int l; - byte c; - - l = 0; - do { - c = (byte) ReadChar(msg_read); - if (c == -1 || c == 0 || c == 0x0a) - break; - readbuf[l] = c; - l++; - } while (l < 2047); - - return new String(readbuf, 0, l).trim(); - } - - public static float ReadCoord(sizebuf_t msg_read) { - return ReadShort(msg_read) * (1.0f / 8); - } - - public static void ReadPos(sizebuf_t msg_read, float pos[]) { - assert(pos.length == 3) : "vec3_t bug"; - pos[0] = ReadShort(msg_read) * (1.0f / 8); - pos[1] = ReadShort(msg_read) * (1.0f / 8); - pos[2] = ReadShort(msg_read) * (1.0f / 8); - } - - public static float ReadAngle(sizebuf_t msg_read) { - return ReadChar(msg_read) * (360.0f / 256); - } - - public static float ReadAngle16(sizebuf_t msg_read) { - return Math3D.SHORT2ANGLE(ReadShort(msg_read)); - } - - public static void ReadDeltaUsercmd(sizebuf_t msg_read, usercmd_t from, usercmd_t move) { - int bits; - - //memcpy(move, from, sizeof(* move)); - // IMPORTANT!! copy without new - move.set(from); - bits = ReadByte(msg_read); - - // read current angles - if ((bits & CM_ANGLE1) != 0) - move.angles[0] = ReadShort(msg_read); - if ((bits & CM_ANGLE2) != 0) - move.angles[1] = ReadShort(msg_read); - if ((bits & CM_ANGLE3) != 0) - move.angles[2] = ReadShort(msg_read); - - // read movement - if ((bits & CM_FORWARD) != 0) - move.forwardmove = ReadShort(msg_read); - if ((bits & CM_SIDE) != 0) - move.sidemove = ReadShort(msg_read); - if ((bits & CM_UP) != 0) - move.upmove = ReadShort(msg_read); - - // read buttons - if ((bits & CM_BUTTONS) != 0) - move.buttons = (byte) ReadByte(msg_read); - - if ((bits & CM_IMPULSE) != 0) - move.impulse = (byte) ReadByte(msg_read); - - // read time to run command - move.msec = (byte) ReadByte(msg_read); - - // read the light level - move.lightlevel = (byte) ReadByte(msg_read); - - } - - public static void ReadData(sizebuf_t msg_read, byte data[], int len) { - for (int i = 0; i < len; i++) - data[i] = (byte) ReadByte(msg_read); - } -} +public class MSG extends Globals { + + // + // writing functions + // + + //ok. + public static void WriteChar(sizebuf_t sb, int c) { + sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF); + } + + //ok. + public static void WriteChar(sizebuf_t sb, float c) { + + WriteChar(sb, (int) c); + } + + //ok. + public static void WriteByte(sizebuf_t sb, int c) { + sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF); + } + + //ok. + public static void WriteByte(sizebuf_t sb, float c) { + WriteByte(sb, (int) c); + } + + public static void WriteShort(sizebuf_t sb, int c) { + int i = SZ.GetSpace(sb, 2); + sb.data[i++] = (byte) (c & 0xff); + sb.data[i] = (byte) ((c >>> 8) & 0xFF); + } + + //ok. + public static void WriteInt(sizebuf_t sb, int c) { + int i = SZ.GetSpace(sb, 4); + sb.data[i++] = (byte) ((c & 0xff)); + sb.data[i++] = (byte) ((c >>> 8) & 0xff); + sb.data[i++] = (byte) ((c >>> 16) & 0xff); + sb.data[i++] = (byte) ((c >>> 24) & 0xff); + } + + //ok. + public static void WriteLong(sizebuf_t sb, int c) { + WriteInt(sb, c); + } + + //ok. + public static void WriteFloat(sizebuf_t sb, float f) { + WriteInt(sb, Float.floatToIntBits(f)); + } + + // had a bug, now its ok. + public static void WriteString(sizebuf_t sb, String s) { + String x = s; + + if (s == null) + x = ""; + + SZ.Write(sb, x.getBytes()); + WriteByte(sb, 0); + } + + //ok. + public static void WriteString(sizebuf_t sb, byte s[]) { + WriteString(sb, new String(s).trim()); + } + + public static void WriteCoord(sizebuf_t sb, float f) { + WriteShort(sb, (int) (f * 8)); + } + + public static void WritePos(sizebuf_t sb, float[] pos) { + assert (pos.length == 3) : "vec3_t bug"; + WriteShort(sb, (int) (pos[0] * 8)); + WriteShort(sb, (int) (pos[1] * 8)); + WriteShort(sb, (int) (pos[2] * 8)); + } + + public static void WriteAngle(sizebuf_t sb, float f) { + WriteByte(sb, (int) (f * 256 / 360) & 255); + } + + public static void WriteAngle16(sizebuf_t sb, float f) { + WriteShort(sb, Math3D.ANGLE2SHORT(f)); + } + + public static void WriteDeltaUsercmd(sizebuf_t buf, usercmd_t from, + usercmd_t cmd) { + int bits; + + // + // send the movement message + // + bits = 0; + if (cmd.angles[0] != from.angles[0]) + bits |= CM_ANGLE1; + if (cmd.angles[1] != from.angles[1]) + bits |= CM_ANGLE2; + if (cmd.angles[2] != from.angles[2]) + bits |= CM_ANGLE3; + if (cmd.forwardmove != from.forwardmove) + bits |= CM_FORWARD; + if (cmd.sidemove != from.sidemove) + bits |= CM_SIDE; + if (cmd.upmove != from.upmove) + bits |= CM_UP; + if (cmd.buttons != from.buttons) + bits |= CM_BUTTONS; + if (cmd.impulse != from.impulse) + bits |= CM_IMPULSE; + + WriteByte(buf, bits); + + if ((bits & CM_ANGLE1) != 0) + WriteShort(buf, cmd.angles[0]); + if ((bits & CM_ANGLE2) != 0) + WriteShort(buf, cmd.angles[1]); + if ((bits & CM_ANGLE3) != 0) + WriteShort(buf, cmd.angles[2]); + + if ((bits & CM_FORWARD) != 0) + WriteShort(buf, cmd.forwardmove); + if ((bits & CM_SIDE) != 0) + WriteShort(buf, cmd.sidemove); + if ((bits & CM_UP) != 0) + WriteShort(buf, cmd.upmove); + + if ((bits & CM_BUTTONS) != 0) + WriteByte(buf, cmd.buttons); + if ((bits & CM_IMPULSE) != 0) + WriteByte(buf, cmd.impulse); + + WriteByte(buf, cmd.msec); + WriteByte(buf, cmd.lightlevel); + } + + //should be ok. + public static void WriteDir(sizebuf_t sb, float[] dir) { + int i, best; + float d, bestd; + + if (dir == null) { + WriteByte(sb, 0); + return; + } + + bestd = 0; + best = 0; + for (i = 0; i < NUMVERTEXNORMALS; i++) { + d = Math3D.DotProduct(dir, bytedirs[i]); + if (d > bestd) { + bestd = d; + best = i; + } + } + WriteByte(sb, best); + } + + //should be ok. + public static void ReadDir(sizebuf_t sb, float[] dir) { + int b; + + b = ReadByte(sb); + if (b >= NUMVERTEXNORMALS) + Com.Error(ERR_DROP, "MSF_ReadDir: out of range"); + Math3D.VectorCopy(bytedirs[b], dir); + } + + /* + * ================== WriteDeltaEntity + * + * Writes part of a packetentities message. Can delta from either a baseline + * or a previous packet_entity ================== + */ + public static void WriteDeltaEntity(entity_state_t from, entity_state_t to, + sizebuf_t msg, boolean force, boolean newentity) { + int bits; + + if (0 == to.number) + Com.Error(ERR_FATAL, "Unset entity number"); + if (to.number >= MAX_EDICTS) + Com.Error(ERR_FATAL, "Entity number >= MAX_EDICTS"); + + // send an update + bits = 0; + + if (to.number >= 256) + bits |= U_NUMBER16; // number8 is implicit otherwise + + if (to.origin[0] != from.origin[0]) + bits |= U_ORIGIN1; + if (to.origin[1] != from.origin[1]) + bits |= U_ORIGIN2; + if (to.origin[2] != from.origin[2]) + bits |= U_ORIGIN3; + + if (to.angles[0] != from.angles[0]) + bits |= U_ANGLE1; + if (to.angles[1] != from.angles[1]) + bits |= U_ANGLE2; + if (to.angles[2] != from.angles[2]) + bits |= U_ANGLE3; + + if (to.skinnum != from.skinnum) { + if (to.skinnum < 256) + bits |= U_SKIN8; + else if (to.skinnum < 0x10000) + bits |= U_SKIN16; + else + bits |= (U_SKIN8 | U_SKIN16); + } + + if (to.frame != from.frame) { + if (to.frame < 256) + bits |= U_FRAME8; + else + bits |= U_FRAME16; + } + + if (to.effects != from.effects) { + if (to.effects < 256) + bits |= U_EFFECTS8; + else if (to.effects < 0x8000) + bits |= U_EFFECTS16; + else + bits |= U_EFFECTS8 | U_EFFECTS16; + } + + if (to.renderfx != from.renderfx) { + if (to.renderfx < 256) + bits |= U_RENDERFX8; + else if (to.renderfx < 0x8000) + bits |= U_RENDERFX16; + else + bits |= U_RENDERFX8 | U_RENDERFX16; + } + + if (to.solid != from.solid) + bits |= U_SOLID; + + // event is not delta compressed, just 0 compressed + if (to.event != 0) + bits |= U_EVENT; + + if (to.modelindex != from.modelindex) + bits |= U_MODEL; + if (to.modelindex2 != from.modelindex2) + bits |= U_MODEL2; + if (to.modelindex3 != from.modelindex3) + bits |= U_MODEL3; + if (to.modelindex4 != from.modelindex4) + bits |= U_MODEL4; + + if (to.sound != from.sound) + bits |= U_SOUND; + + if (newentity || (to.renderfx & RF_BEAM) != 0) + bits |= U_OLDORIGIN; + + // + // write the message + // + if (bits == 0 && !force) + return; // nothing to send! + + //---------- + + if ((bits & 0xff000000) != 0) + bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1; + else if ((bits & 0x00ff0000) != 0) + bits |= U_MOREBITS2 | U_MOREBITS1; + else if ((bits & 0x0000ff00) != 0) + bits |= U_MOREBITS1; + + WriteByte(msg, bits & 255); + + if ((bits & 0xff000000) != 0) { + WriteByte(msg, (bits >>> 8) & 255); + WriteByte(msg, (bits >>> 16) & 255); + WriteByte(msg, (bits >>> 24) & 255); + } else if ((bits & 0x00ff0000) != 0) { + WriteByte(msg, (bits >>> 8) & 255); + WriteByte(msg, (bits >>> 16) & 255); + } else if ((bits & 0x0000ff00) != 0) { + WriteByte(msg, (bits >>> 8) & 255); + } + + //---------- + + if ((bits & U_NUMBER16) != 0) + WriteShort(msg, to.number); + else + WriteByte(msg, to.number); + + if ((bits & U_MODEL) != 0) + WriteByte(msg, to.modelindex); + if ((bits & U_MODEL2) != 0) + WriteByte(msg, to.modelindex2); + if ((bits & U_MODEL3) != 0) + WriteByte(msg, to.modelindex3); + if ((bits & U_MODEL4) != 0) + WriteByte(msg, to.modelindex4); + + if ((bits & U_FRAME8) != 0) + WriteByte(msg, to.frame); + if ((bits & U_FRAME16) != 0) + WriteShort(msg, to.frame); + + if ((bits & U_SKIN8) != 0 && (bits & U_SKIN16) != 0) //used for laser + // colors + WriteInt(msg, to.skinnum); + else if ((bits & U_SKIN8) != 0) + WriteByte(msg, to.skinnum); + else if ((bits & U_SKIN16) != 0) + WriteShort(msg, to.skinnum); + + if ((bits & (U_EFFECTS8 | U_EFFECTS16)) == (U_EFFECTS8 | U_EFFECTS16)) + WriteInt(msg, to.effects); + else if ((bits & U_EFFECTS8) != 0) + WriteByte(msg, to.effects); + else if ((bits & U_EFFECTS16) != 0) + WriteShort(msg, to.effects); + + if ((bits & (U_RENDERFX8 | U_RENDERFX16)) == (U_RENDERFX8 | U_RENDERFX16)) + WriteInt(msg, to.renderfx); + else if ((bits & U_RENDERFX8) != 0) + WriteByte(msg, to.renderfx); + else if ((bits & U_RENDERFX16) != 0) + WriteShort(msg, to.renderfx); + + if ((bits & U_ORIGIN1) != 0) + WriteCoord(msg, to.origin[0]); + if ((bits & U_ORIGIN2) != 0) + WriteCoord(msg, to.origin[1]); + if ((bits & U_ORIGIN3) != 0) + WriteCoord(msg, to.origin[2]); + + if ((bits & U_ANGLE1) != 0) + WriteAngle(msg, to.angles[0]); + if ((bits & U_ANGLE2) != 0) + WriteAngle(msg, to.angles[1]); + if ((bits & U_ANGLE3) != 0) + WriteAngle(msg, to.angles[2]); + + if ((bits & U_OLDORIGIN) != 0) { + WriteCoord(msg, to.old_origin[0]); + WriteCoord(msg, to.old_origin[1]); + WriteCoord(msg, to.old_origin[2]); + } + + if ((bits & U_SOUND) != 0) + WriteByte(msg, to.sound); + if ((bits & U_EVENT) != 0) + WriteByte(msg, to.event); + if ((bits & U_SOLID) != 0) + WriteShort(msg, to.solid); + } + + //============================================================ + + // + // reading functions + // + + public static void BeginReading(sizebuf_t msg) { + msg.readcount = 0; + } + + // returns -1 if no more characters are available, but also [-128 , 127] + public static int ReadChar(sizebuf_t msg_read) { + int c; + + if (msg_read.readcount + 1 > msg_read.cursize) + c = -1; + else + c = msg_read.data[msg_read.readcount]; + msg_read.readcount++; + // kickangles bugfix (rst) + return c; + } + + public static int ReadByte(sizebuf_t msg_read) { + int c; + + if (msg_read.readcount + 1 > msg_read.cursize) + c = -1; + else + c = msg_read.data[msg_read.readcount] & 0xff; + msg_read.readcount++; + + return c; + } + + public static short ReadShort(sizebuf_t msg_read) { + int c; + + if (msg_read.readcount + 2 > msg_read.cursize) + c = -1; + else + c = (short) ((msg_read.data[msg_read.readcount] & 0xff) + (msg_read.data[msg_read.readcount + 1] << 8)); + + msg_read.readcount += 2; + + return (short) c; + } + + public static int ReadLong(sizebuf_t msg_read) { + int c; + + if (msg_read.readcount + 4 > msg_read.cursize) { + Com.Printf("buffer underrun in ReadLong!"); + c = -1; + } + + else + c = (msg_read.data[msg_read.readcount] & 0xff) + | ((msg_read.data[msg_read.readcount + 1] & 0xff) << 8) + | ((msg_read.data[msg_read.readcount + 2] & 0xff) << 16) + | ((msg_read.data[msg_read.readcount + 3] & 0xff) << 24); + + msg_read.readcount += 4; + + return c; + } + + public static float ReadFloat(sizebuf_t msg_read) { + int n = ReadLong(msg_read); + return Float.intBitsToFloat(n); + } + + // 2k read buffer. + public static byte readbuf[] = new byte[2048]; + + public static String ReadString(sizebuf_t msg_read) { + + byte c; + int l = 0; + do { + c = (byte) ReadByte(msg_read); + if (c == -1 || c == 0) + break; + + readbuf[l] = c; + l++; + } while (l < 2047); + + return new String(readbuf, 0, l); + } + + public static String ReadStringLine(sizebuf_t msg_read) { + + int l; + byte c; + + l = 0; + do { + c = (byte) ReadChar(msg_read); + if (c == -1 || c == 0 || c == 0x0a) + break; + readbuf[l] = c; + l++; + } while (l < 2047); + + return new String(readbuf, 0, l).trim(); + } + + public static float ReadCoord(sizebuf_t msg_read) { + return ReadShort(msg_read) * (1.0f / 8); + } + + public static void ReadPos(sizebuf_t msg_read, float pos[]) { + assert (pos.length == 3) : "vec3_t bug"; + pos[0] = ReadShort(msg_read) * (1.0f / 8); + pos[1] = ReadShort(msg_read) * (1.0f / 8); + pos[2] = ReadShort(msg_read) * (1.0f / 8); + } + + public static float ReadAngle(sizebuf_t msg_read) { + return ReadChar(msg_read) * (360.0f / 256); + } + + public static float ReadAngle16(sizebuf_t msg_read) { + return Math3D.SHORT2ANGLE(ReadShort(msg_read)); + } + + public static void ReadDeltaUsercmd(sizebuf_t msg_read, usercmd_t from, + usercmd_t move) { + int bits; + + //memcpy(move, from, sizeof(* move)); + // IMPORTANT!! copy without new + move.set(from); + bits = ReadByte(msg_read); + + // read current angles + if ((bits & CM_ANGLE1) != 0) + move.angles[0] = ReadShort(msg_read); + if ((bits & CM_ANGLE2) != 0) + move.angles[1] = ReadShort(msg_read); + if ((bits & CM_ANGLE3) != 0) + move.angles[2] = ReadShort(msg_read); + + // read movement + if ((bits & CM_FORWARD) != 0) + move.forwardmove = ReadShort(msg_read); + if ((bits & CM_SIDE) != 0) + move.sidemove = ReadShort(msg_read); + if ((bits & CM_UP) != 0) + move.upmove = ReadShort(msg_read); + + // read buttons + if ((bits & CM_BUTTONS) != 0) + move.buttons = (byte) ReadByte(msg_read); + + if ((bits & CM_IMPULSE) != 0) + move.impulse = (byte) ReadByte(msg_read); + + // read time to run command + move.msec = (byte) ReadByte(msg_read); + + // read the light level + move.lightlevel = (byte) ReadByte(msg_read); + + } + + public static void ReadData(sizebuf_t msg_read, byte data[], int len) { + for (int i = 0; i < len; i++) + data[i] = (byte) ReadByte(msg_read); + } +}
\ No newline at end of file diff --git a/src/jake2/qcommon/Netchan.java b/src/jake2/qcommon/Netchan.java index 3331646..458bcbd 100644 --- a/src/jake2/qcommon/Netchan.java +++ b/src/jake2/qcommon/Netchan.java @@ -2,27 +2,27 @@ * NetChannel.java * Copyright (C) 2003 * - * $Id: Netchan.java,v 1.3 2004-07-12 20:47:00 hzi Exp $ + * $Id: Netchan.java,v 1.4 2004-09-22 19:22:09 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.qcommon; import jake2.Defines; @@ -37,350 +37,335 @@ import jake2.sys.Sys; */ public final class Netchan extends SV_MAIN { - /* - - packet header - ------------- - 31 sequence - 1 does this message contains a reliable payload - 31 acknowledge sequence - 1 acknowledge receipt of even/odd message - 16 qport - - The remote connection never knows if it missed a reliable message, the - local side detects that it has been dropped by seeing a sequence acknowledge - higher thatn the last reliable sequence, but without the correct evon/odd - bit for the reliable set. - - If the sender notices that a reliable message has been dropped, it will be - retransmitted. It will not be retransmitted again until a message after - the retransmit has been acknowledged and the reliable still failed to get there. - - if the sequence number is -1, the packet should be handled without a netcon - - The reliable message can be added to at any time by doing - MSG_Write* (&netchan.message, <data>). - - If the message buffer is overflowed, either by a single message, or by - multiple frames worth piling up while the last reliable transmit goes - unacknowledged, the netchan signals a fatal error. - - Reliable messages are always placed first in a packet, then the unreliable - message is included if there is sufficient room. - - To the receiver, there is no distinction between the reliable and unreliable - parts of the message, they are just processed out as a single larger message. - - Illogical packet sequence numbers cause the packet to be dropped, but do - not kill the connection. This, combined with the tight window of valid - reliable acknowledgement numbers provides protection against malicious - address spoofing. - - - The qport field is a workaround for bad address translating routers that - sometimes remap the client's source port on a packet during gameplay. - - If the base part of the net address matches and the qport matches, then the - channel matches even if the IP port differs. The IP port should be updated - to the new value before sending out any replies. - - - If there is no information that needs to be transfered on a given frame, - such as during the connection stage while waiting for the client to load, - then a packet only needs to be delivered if there is something in the - unacknowledged reliable - */ - - public static cvar_t showpackets; - public static cvar_t showdrop; - public static cvar_t qport; - - //public static netadr_t net_from = new netadr_t(); - public static sizebuf_t net_message = new sizebuf_t(); - public static byte net_message_buffer[] = new byte[Defines.MAX_MSGLEN]; - - /* - =============== - Netchan_Init - - =============== - */ - //ok. - public static void Netchan_Init() { - long port; - - // pick a port value that should be nice and random - port = Sys.Milliseconds() & 0xffff; - - showpackets = Cvar.Get("showpackets", "0", 0); - showdrop = Cvar.Get("showdrop", "0", 0); - qport = Cvar.Get("qport", "" + port, Defines.CVAR_NOSET); - } - - /* - =============== - Netchan_OutOfBand - - Sends an out-of-band datagram - ================ - */ - //ok. - public static void Netchan_OutOfBand(int net_socket, netadr_t adr, int length, byte data[]) { - sizebuf_t send = new sizebuf_t(); - byte send_buf[] = new byte[Defines.MAX_MSGLEN]; - - // write the packet header - SZ.Init(send, send_buf, Defines.MAX_MSGLEN); - - MSG.WriteInt(send, -1); // -1 sequence means out of band - SZ.Write(send, data, length); - - // send the datagram - NET.SendPacket(net_socket, send.cursize, send.data, adr); - } - - public static void OutOfBandPrint(int net_socket, netadr_t adr, String s) { - Netchan_OutOfBand(net_socket, adr, s.length(), s.getBytes()); - } - - /* - ============== - Netchan_Setup - - called to open a channel to a remote system - ============== - */ - public static void Setup(int sock, netchan_t chan, netadr_t adr, int qport) { - //memset (chan, 0, sizeof(*chan)); - - chan.clear(); - chan.sock = sock; - chan.remote_address.set(adr); - chan.qport = qport; - chan.last_received = Globals.curtime; - chan.incoming_sequence = 0; - chan.outgoing_sequence = 1; - - SZ.Init(chan.message, chan.message_buf, chan.message_buf.length); - chan.message.allowoverflow = true; - } - - /* - =============== - Netchan_CanReliable - - Returns true if the last reliable message has acked - ================ - */ - public static boolean Netchan_CanReliable(netchan_t chan) { - if (chan.reliable_length != 0) - return false; // waiting for ack - return true; - } - // das ist richtig !!! - public static boolean Netchan_NeedReliable(netchan_t chan) { - boolean send_reliable; - - // if the remote side dropped the last reliable message, resend it - send_reliable = false; - - if (chan.incoming_acknowledged > chan.last_reliable_sequence && chan.incoming_reliable_acknowledged != chan.reliable_sequence) - send_reliable = true; - - // if the reliable transmit buffer is empty, copy the current message out - if (0 == chan.reliable_length && chan.message.cursize != 0) { - send_reliable = true; - } - - return send_reliable; - } - - /* - =============== - Netchan_Transmit - - tries to send an unreliable message to a connection, and handles the - transmition / retransmition of the reliable messages. - - A 0 length will still generate a packet and deal with the reliable messages. - ================ - */ - public static void Transmit(netchan_t chan, int length, byte data[]) { - sizebuf_t send = new sizebuf_t(); - byte send_buf[] = new byte[MAX_MSGLEN]; - int send_reliable; - int w1, w2; - - // check for message overflow - if (chan.message.overflowed) { - chan.fatal_error = true; - Com.Printf(NET.AdrToString(chan.remote_address) + ":Outgoing message overflow\n"); - return; - } - - send_reliable = Netchan_NeedReliable(chan) ? 1 : 0; - - if (chan.reliable_length == 0 && chan.message.cursize != 0) { - System.arraycopy(chan.message_buf, 0, chan.reliable_buf, 0, chan.message.cursize); - chan.reliable_length = chan.message.cursize; - chan.message.cursize = 0; - chan.reliable_sequence ^= 1; - } - - // write the packet header - SZ.Init(send, send_buf, send_buf.length); - - w1 = (chan.outgoing_sequence & ~(1 << 31)) | (send_reliable << 31); - w2 = (chan.incoming_sequence & ~(1 << 31)) | (chan.incoming_reliable_sequence << 31); - - chan.outgoing_sequence++; - chan.last_sent = (int) Globals.curtime; - - MSG.WriteInt(send, w1); - MSG.WriteInt(send, w2); - - // send the qport if we are a client - if (chan.sock == Defines.NS_CLIENT) - MSG.WriteShort(send, (int) qport.value); - - // copy the reliable message to the packet first - if (send_reliable != 0) { - SZ.Write(send, chan.reliable_buf, chan.reliable_length); - chan.last_reliable_sequence = chan.outgoing_sequence; - } - - // add the unreliable part if space is available - if (send.maxsize - send.cursize >= length) - SZ.Write(send, data, length); - else - Com.Printf("Netchan_Transmit: dumped unreliable\n"); - - // send the datagram - NET.SendPacket(chan.sock, send.cursize, send.data, chan.remote_address); - - if (showpackets.value != 0) { - if (send_reliable != 0) - Com.Printf(//"send %4i : s=%i reliable=%i ack=%i rack=%i\n" - "send " - + send.cursize - + " : s=" - + (chan.outgoing_sequence - 1) - + " reliable=" - + chan.reliable_sequence - + " ack=" - + chan.incoming_sequence - + " rack=" - + chan.incoming_reliable_sequence - + "\n"); - else - Com.Printf(//"send %4i : s=%i ack=%i rack=%i\n" - "send " - + send.cursize - + " : s=" - + (chan.outgoing_sequence - 1) - + " ack=" - + chan.incoming_sequence - + " rack=" - + chan.incoming_reliable_sequence - + "\n"); - } - } - - /* - ================= - Netchan_Process - - called when the current net_message is from remote_address - modifies net_message so that it points to the packet payload - ================= - */ - public static boolean Process(netchan_t chan, sizebuf_t msg) { - int sequence, sequence_ack; - int reliable_ack, reliable_message; - int qport; - - // get sequence numbers - MSG.BeginReading(msg); - sequence = MSG.ReadLong(msg); - sequence_ack = MSG.ReadLong(msg); - - // read the qport if we are a server - if (chan.sock == NS_SERVER) - qport = MSG.ReadShort(msg); - - // achtung unsigned int - reliable_message = sequence >>> 31; - reliable_ack = sequence_ack >>> 31; - - sequence &= ~(1 << 31); - sequence_ack &= ~(1 << 31); - - if (showpackets.value != 0) { - if (reliable_message != 0) - Com.Printf(//"recv %4i : s=%i reliable=%i ack=%i rack=%i\n" - "recv " - + msg.cursize - + " : s=" - + sequence - + " reliable=" - + (chan.incoming_reliable_sequence ^ 1) - + " ack=" - + sequence_ack - + " rack=" - + reliable_ack - + "\n"); - else - Com.Printf(//"recv %4i : s=%i ack=%i rack=%i\n" - "recv " + msg.cursize + " : s=" + sequence + " ack=" + sequence_ack + " rack=" + reliable_ack + "\n"); - } - - // - // discard stale or duplicated packets - // - if (sequence <= chan.incoming_sequence) { - if (showdrop.value != 0) - Com.Printf( - NET.AdrToString(chan.remote_address) - + ":Out of order packet " - + sequence - + " at " - + chan.incoming_sequence - + "\n"); - return false; - } - - // - // dropped packets don't keep the message from being used - // - chan.dropped = sequence - (chan.incoming_sequence + 1); - if (chan.dropped > 0) { - if (showdrop.value != 0) - Com.Printf(NET.AdrToString(chan.remote_address) + ":Dropped " + chan.dropped + " packets at " + sequence + "\n"); - } - - // - // if the current outgoing reliable message has been acknowledged - // clear the buffer to make way for the next - // - if (reliable_ack == chan.reliable_sequence) - chan.reliable_length = 0; // it has been received - - // - // if this message contains a reliable message, bump incoming_reliable_sequence - // - chan.incoming_sequence = sequence; - chan.incoming_acknowledged = sequence_ack; - chan.incoming_reliable_acknowledged = reliable_ack; - if (reliable_message != 0) { - chan.incoming_reliable_sequence ^= 1; - } - - // - // the message can now be read from the current message pointer - // - chan.last_received = (int) Globals.curtime; - - return true; - } - -} + /* + * + * packet header ------------- 31 sequence 1 does this message contains a + * reliable payload 31 acknowledge sequence 1 acknowledge receipt of + * even/odd message 16 qport + * + * The remote connection never knows if it missed a reliable message, the + * local side detects that it has been dropped by seeing a sequence + * acknowledge higher thatn the last reliable sequence, but without the + * correct evon/odd bit for the reliable set. + * + * If the sender notices that a reliable message has been dropped, it will + * be retransmitted. It will not be retransmitted again until a message + * after the retransmit has been acknowledged and the reliable still failed + * to get there. + * + * if the sequence number is -1, the packet should be handled without a + * netcon + * + * The reliable message can be added to at any time by doing MSG_Write* + * (&netchan.message, <data>). + * + * If the message buffer is overflowed, either by a single message, or by + * multiple frames worth piling up while the last reliable transmit goes + * unacknowledged, the netchan signals a fatal error. + * + * Reliable messages are always placed first in a packet, then the + * unreliable message is included if there is sufficient room. + * + * To the receiver, there is no distinction between the reliable and + * unreliable parts of the message, they are just processed out as a single + * larger message. + * + * Illogical packet sequence numbers cause the packet to be dropped, but do + * not kill the connection. This, combined with the tight window of valid + * reliable acknowledgement numbers provides protection against malicious + * address spoofing. + * + * + * The qport field is a workaround for bad address translating routers that + * sometimes remap the client's source port on a packet during gameplay. + * + * If the base part of the net address matches and the qport matches, then + * the channel matches even if the IP port differs. The IP port should be + * updated to the new value before sending out any replies. + * + * + * If there is no information that needs to be transfered on a given frame, + * such as during the connection stage while waiting for the client to load, + * then a packet only needs to be delivered if there is something in the + * unacknowledged reliable + */ + + public static cvar_t showpackets; + + public static cvar_t showdrop; + + public static cvar_t qport; + + //public static netadr_t net_from = new netadr_t(); + public static sizebuf_t net_message = new sizebuf_t(); + + public static byte net_message_buffer[] = new byte[Defines.MAX_MSGLEN]; + + /* + * =============== Netchan_Init + * + * =============== + */ + //ok. + public static void Netchan_Init() { + long port; + + // pick a port value that should be nice and random + port = Sys.Milliseconds() & 0xffff; + + showpackets = Cvar.Get("showpackets", "0", 0); + showdrop = Cvar.Get("showdrop", "0", 0); + qport = Cvar.Get("qport", "" + port, Defines.CVAR_NOSET); + } + + /* + * =============== Netchan_OutOfBand + * + * Sends an out-of-band datagram ================ + */ + //ok. + public static void Netchan_OutOfBand(int net_socket, netadr_t adr, + int length, byte data[]) { + sizebuf_t send = new sizebuf_t(); + byte send_buf[] = new byte[Defines.MAX_MSGLEN]; + + // write the packet header + SZ.Init(send, send_buf, Defines.MAX_MSGLEN); + + MSG.WriteInt(send, -1); // -1 sequence means out of band + SZ.Write(send, data, length); + + // send the datagram + NET.SendPacket(net_socket, send.cursize, send.data, adr); + } + + public static void OutOfBandPrint(int net_socket, netadr_t adr, String s) { + Netchan_OutOfBand(net_socket, adr, s.length(), s.getBytes()); + } + + /* + * ============== Netchan_Setup + * + * called to open a channel to a remote system ============== + */ + public static void Setup(int sock, netchan_t chan, netadr_t adr, int qport) { + //memset (chan, 0, sizeof(*chan)); + + chan.clear(); + chan.sock = sock; + chan.remote_address.set(adr); + chan.qport = qport; + chan.last_received = Globals.curtime; + chan.incoming_sequence = 0; + chan.outgoing_sequence = 1; + + SZ.Init(chan.message, chan.message_buf, chan.message_buf.length); + chan.message.allowoverflow = true; + } + + /* + * =============== Netchan_CanReliable + * + * Returns true if the last reliable message has acked ================ + */ + public static boolean Netchan_CanReliable(netchan_t chan) { + if (chan.reliable_length != 0) + return false; // waiting for ack + return true; + } + + // das ist richtig !!! + public static boolean Netchan_NeedReliable(netchan_t chan) { + boolean send_reliable; + + // if the remote side dropped the last reliable message, resend it + send_reliable = false; + + if (chan.incoming_acknowledged > chan.last_reliable_sequence + && chan.incoming_reliable_acknowledged != chan.reliable_sequence) + send_reliable = true; + + // if the reliable transmit buffer is empty, copy the current message + // out + if (0 == chan.reliable_length && chan.message.cursize != 0) { + send_reliable = true; + } + + return send_reliable; + } + + /* + * =============== Netchan_Transmit + * + * tries to send an unreliable message to a connection, and handles the + * transmition / retransmition of the reliable messages. + * + * A 0 length will still generate a packet and deal with the reliable + * messages. ================ + */ + public static void Transmit(netchan_t chan, int length, byte data[]) { + sizebuf_t send = new sizebuf_t(); + byte send_buf[] = new byte[Defines.MAX_MSGLEN]; + int send_reliable; + int w1, w2; + + // check for message overflow + if (chan.message.overflowed) { + chan.fatal_error = true; + Com.Printf(NET.AdrToString(chan.remote_address) + + ":Outgoing message overflow\n"); + return; + } + + send_reliable = Netchan_NeedReliable(chan) ? 1 : 0; + + if (chan.reliable_length == 0 && chan.message.cursize != 0) { + System.arraycopy(chan.message_buf, 0, chan.reliable_buf, 0, + chan.message.cursize); + chan.reliable_length = chan.message.cursize; + chan.message.cursize = 0; + chan.reliable_sequence ^= 1; + } + + // write the packet header + SZ.Init(send, send_buf, send_buf.length); + + w1 = (chan.outgoing_sequence & ~(1 << 31)) | (send_reliable << 31); + w2 = (chan.incoming_sequence & ~(1 << 31)) + | (chan.incoming_reliable_sequence << 31); + + chan.outgoing_sequence++; + chan.last_sent = (int) Globals.curtime; + + MSG.WriteInt(send, w1); + MSG.WriteInt(send, w2); + + // send the qport if we are a client + if (chan.sock == Defines.NS_CLIENT) + MSG.WriteShort(send, (int) qport.value); + + // copy the reliable message to the packet first + if (send_reliable != 0) { + SZ.Write(send, chan.reliable_buf, chan.reliable_length); + chan.last_reliable_sequence = chan.outgoing_sequence; + } + + // add the unreliable part if space is available + if (send.maxsize - send.cursize >= length) + SZ.Write(send, data, length); + else + Com.Printf("Netchan_Transmit: dumped unreliable\n"); + + // send the datagram + NET.SendPacket(chan.sock, send.cursize, send.data, chan.remote_address); + + if (showpackets.value != 0) { + if (send_reliable != 0) + Com.Printf( + //"send %4i : s=%i reliable=%i ack=%i rack=%i\n" + "send " + send.cursize + " : s=" + + (chan.outgoing_sequence - 1) + " reliable=" + + chan.reliable_sequence + " ack=" + + chan.incoming_sequence + " rack=" + + chan.incoming_reliable_sequence + "\n"); + else + Com.Printf( + //"send %4i : s=%i ack=%i rack=%i\n" + "send " + send.cursize + " : s=" + + (chan.outgoing_sequence - 1) + " ack=" + + chan.incoming_sequence + " rack=" + + chan.incoming_reliable_sequence + "\n"); + } + } + + /* + * ================= Netchan_Process + * + * called when the current net_message is from remote_address modifies + * net_message so that it points to the packet payload ================= + */ + public static boolean Process(netchan_t chan, sizebuf_t msg) { + int sequence, sequence_ack; + int reliable_ack, reliable_message; + int qport; + + // get sequence numbers + MSG.BeginReading(msg); + sequence = MSG.ReadLong(msg); + sequence_ack = MSG.ReadLong(msg); + + // read the qport if we are a server + if (chan.sock == Defines.NS_SERVER) + qport = MSG.ReadShort(msg); + + // achtung unsigned int + reliable_message = sequence >>> 31; + reliable_ack = sequence_ack >>> 31; + + sequence &= ~(1 << 31); + sequence_ack &= ~(1 << 31); + + if (showpackets.value != 0) { + if (reliable_message != 0) + Com.Printf( + //"recv %4i : s=%i reliable=%i ack=%i rack=%i\n" + "recv " + msg.cursize + " : s=" + sequence + + " reliable=" + + (chan.incoming_reliable_sequence ^ 1) + + " ack=" + sequence_ack + " rack=" + + reliable_ack + "\n"); + else + Com + .Printf( + //"recv %4i : s=%i ack=%i rack=%i\n" + "recv " + msg.cursize + " : s=" + sequence + " ack=" + + sequence_ack + " rack=" + reliable_ack + "\n"); + } + + // + // discard stale or duplicated packets + // + if (sequence <= chan.incoming_sequence) { + if (showdrop.value != 0) + Com.Printf(NET.AdrToString(chan.remote_address) + + ":Out of order packet " + sequence + " at " + + chan.incoming_sequence + "\n"); + return false; + } + + // + // dropped packets don't keep the message from being used + // + chan.dropped = sequence - (chan.incoming_sequence + 1); + if (chan.dropped > 0) { + if (showdrop.value != 0) + Com.Printf(NET.AdrToString(chan.remote_address) + ":Dropped " + + chan.dropped + " packets at " + sequence + "\n"); + } + + // + // if the current outgoing reliable message has been acknowledged + // clear the buffer to make way for the next + // + if (reliable_ack == chan.reliable_sequence) + chan.reliable_length = 0; // it has been received + + // + // if this message contains a reliable message, bump + // incoming_reliable_sequence + // + chan.incoming_sequence = sequence; + chan.incoming_acknowledged = sequence_ack; + chan.incoming_reliable_acknowledged = reliable_ack; + if (reliable_message != 0) { + chan.incoming_reliable_sequence ^= 1; + } + + // + // the message can now be read from the current message pointer + // + chan.last_received = (int) Globals.curtime; + + return true; + } +}
\ No newline at end of file diff --git a/src/jake2/qcommon/PMove.java b/src/jake2/qcommon/PMove.java index 2043c8a..f4e92c3 100644 --- a/src/jake2/qcommon/PMove.java +++ b/src/jake2/qcommon/PMove.java @@ -1,1259 +1,1184 @@ /* -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 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. - -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. - -*/ + * 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 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. + * + * 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. + * + */ // Created on 25.01.2004 by RST. -// $Id: PMove.java,v 1.4 2004-09-10 19:02:53 salomo Exp $ - +// $Id: PMove.java,v 1.5 2004-09-22 19:22:09 salomo Exp $ package jake2.qcommon; import jake2.*; import jake2.client.*; import jake2.game.*; -import jake2.qcommon.*; import jake2.render.*; import jake2.server.*; +import jake2.util.Math3D; + +public class PMove { + + // all of the locals will be zeroed before each + // pmove, just to make damn sure we don't have + // any differences when running on client or server + + public static class pml_t { + public float[] origin = { 0, 0, 0 }; // full float precision + + public float[] velocity = { 0, 0, 0 }; // full float precision + + public float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, + 0 }; + + public float frametime; + + public csurface_t groundsurface; + + public cplane_t groundplane = new cplane_t(); + + public int groundcontents; + + public float[] previous_origin = { 0, 0, 0 }; + + public boolean ladder; + } + + public static pmove_t pm; + + public static PMove.pml_t pml = new PMove.pml_t(); + + // movement parameters + public static float pm_stopspeed = 100; + + public static float pm_maxspeed = 300; + + public static float pm_duckspeed = 100; + + public static float pm_accelerate = 10; + + public static float pm_airaccelerate = 0; + + public static float pm_wateraccelerate = 10; + + public static float pm_friction = 6; + + public static float pm_waterfriction = 1; + + public static float pm_waterspeed = 400; + + /* + * ================ PM_SnapPosition + * + * On exit, the origin will have a value that is pre-quantized to the 0.125 + * precision of the network channel and in a valid position. + * ================ + */ + // try all single bits first + public static int jitterbits[] = { 0, 4, 1, 2, 3, 5, 6, 7 }; + + /* + * ================ PM_InitialSnapPosition + * + * ================ + */ + public static int offset[] = { 0, -1, 1 }; + + /* + * + * walking up a step should kill some velocity + * + */ + + /* + * ================== PM_ClipVelocity + * + * Slide off of the impacting object returns the blocked flags (1 = floor, 2 = + * step / wall) ================== + */ -public class PMove extends Game -{ - - public final static int STEPSIZE = 18; - - // all of the locals will be zeroed before each - // pmove, just to make damn sure we don't have - // any differences when running on client or server - - public static class pml_t - { - float[] origin = { 0, 0, 0 }; // full float precision - float[] velocity = { 0, 0, 0 }; // full float precision - - float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; - float frametime; - - csurface_t groundsurface; - cplane_t groundplane = new cplane_t(); - int groundcontents; - - float[] previous_origin = { 0, 0, 0 }; - boolean ladder; - } - - public static pmove_t pm; - public static pml_t pml = new pml_t(); - - // movement parameters - public static float pm_stopspeed = 100; - public static float pm_maxspeed = 300; - public static float pm_duckspeed = 100; - public static float pm_accelerate = 10; - public static float pm_airaccelerate = 0; - public static float pm_wateraccelerate = 10; - public static float pm_friction = 6; - public static float pm_waterfriction = 1; - public static float pm_waterspeed = 400; - - /* - - walking up a step should kill some velocity - - */ - - /* - ================== - PM_ClipVelocity - - Slide off of the impacting object - returns the blocked flags (1 = floor, 2 = step / wall) - ================== - */ - public static final float STOP_EPSILON = 0.1f; - - public static void PM_ClipVelocity(float[] in, float[] normal, float[] out, float overbounce) - { - float backoff; - float change; - int i; - - backoff = DotProduct(in, normal) * overbounce; - - for (i = 0; i < 3; i++) - { - change = normal[i] * backoff; - out[i] = in[i] - change; - if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) - out[i] = 0; - } - } - - /* - ================== - PM_StepSlideMove - - Each intersection will try to step over the obstruction instead of - sliding along it. - - Returns a new origin, velocity, and contact entity - Does not modify any world state? - ================== - */ - public final static float MIN_STEP_NORMAL = 0.7f; // can't step up onto very steep slopes - - public static void PM_StepSlideMove_() - { - int bumpcount, numbumps; - float[] dir = { 0, 0, 0 }; - float d; - int numplanes; - float[] planes[] = new float[MAX_CLIP_PLANES][3]; - float[] primal_velocity = { 0, 0, 0 }; - int i, j; - trace_t trace; - float[] end = { 0, 0, 0 }; - float time_left; - - numbumps = 4; - - VectorCopy(pml.velocity, primal_velocity); - numplanes = 0; - - time_left = pml.frametime; - - for (bumpcount = 0; bumpcount < numbumps; bumpcount++) - { - for (i = 0; i < 3; i++) - end[i] = pml.origin[i] + time_left * pml.velocity[i]; - - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, end); - - if (trace.allsolid) - { // entity is trapped in another solid - pml.velocity[2] = 0; // don't build up falling damage - return; - } - - if (trace.fraction > 0) - { // actually covered some distance - VectorCopy(trace.endpos, pml.origin); - numplanes = 0; - } - - if (trace.fraction == 1) - break; // moved the entire distance - - // save entity for contact - if (pm.numtouch < MAXTOUCH && trace.ent != null) - { - //rst: just for debugging touches. - //if (trace.ent.index != -1 && trace.ent.index != 0) - //Com.p("touch: " + trace.ent.classname + " (" + trace.ent.index + ")" ); - - pm.touchents[pm.numtouch] = trace.ent; - pm.numtouch++; - } - - time_left -= time_left * trace.fraction; - - // slide along this plane - if (numplanes >= MAX_CLIP_PLANES) - { // this shouldn't really happen - VectorCopy(vec3_origin, pml.velocity); - break; - } - - VectorCopy(trace.plane.normal, planes[numplanes]); - numplanes++; - - // - // modify original_velocity so it parallels all of the clip planes - // - - for (i = 0; i < numplanes; i++) - { - PM_ClipVelocity(pml.velocity, planes[i], pml.velocity, 1.01f); - for (j = 0; j < numplanes; j++) - if (j != i) - { - if (DotProduct(pml.velocity, planes[j]) < 0) - break; // not ok - } - if (j == numplanes) - break; - } - - if (i != numplanes) - { // go along this plane - } - else - { // go along the crease - if (numplanes != 2) - { - // Con_Printf ("clip velocity, numplanes == %i\n",numplanes); - VectorCopy(vec3_origin, pml.velocity); - break; - } - CrossProduct(planes[0], planes[1], dir); - d = DotProduct(dir, pml.velocity); - VectorScale(dir, d, pml.velocity); - } - - // - // if velocity is against the original velocity, stop dead - // to avoid tiny occilations in sloping corners - // - if (DotProduct(pml.velocity, primal_velocity) <= 0) - { - VectorCopy(vec3_origin, pml.velocity); - break; - } - } - - if (pm.s.pm_time != 0) - { - VectorCopy(primal_velocity, pml.velocity); - } - } - - /* - ================== - PM_StepSlideMove - - ================== - */ - public static void PM_StepSlideMove() - { - float[] start_o = { 0, 0, 0 }, start_v = { 0, 0, 0 }; - float[] down_o = { 0, 0, 0 }, down_v = { 0, 0, 0 }; - trace_t trace; - float down_dist, up_dist; - // float [] delta; - float[] up = { 0, 0, 0 }, down = { 0, 0, 0 }; - - VectorCopy(pml.origin, start_o); - VectorCopy(pml.velocity, start_v); - - PM_StepSlideMove_(); - - VectorCopy(pml.origin, down_o); - VectorCopy(pml.velocity, down_v); - - VectorCopy(start_o, up); - up[2] += STEPSIZE; - - trace = pm.trace.trace(up, pm.mins, pm.maxs, up); - if (trace.allsolid) - return; // can't step up - - // try sliding above - VectorCopy(up, pml.origin); - VectorCopy(start_v, pml.velocity); - - PM_StepSlideMove_(); - - // push down the final amount - VectorCopy(pml.origin, down); - down[2] -= STEPSIZE; - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, down); - if (!trace.allsolid) - { - VectorCopy(trace.endpos, pml.origin); - } - - VectorCopy(pml.origin, up); - - // decide which one went farther - down_dist = (down_o[0] - start_o[0]) * (down_o[0] - start_o[0]) + (down_o[1] - start_o[1]) * (down_o[1] - start_o[1]); - up_dist = (up[0] - start_o[0]) * (up[0] - start_o[0]) + (up[1] - start_o[1]) * (up[1] - start_o[1]); - - if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL) - { - VectorCopy(down_o, pml.origin); - VectorCopy(down_v, pml.velocity); - return; - } - //!! Special case - // if we were walking along a plane, then we need to copy the Z over - pml.velocity[2] = down_v[2]; - } - - /* - ================== - PM_Friction - - Handles both ground friction and water friction - ================== - */ - public static void PM_Friction() - { - float vel[]; - float speed, newspeed, control; - float friction; - float drop; - - vel = pml.velocity; - - speed = (float) (Math.sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2])); - if (speed < 1) - { - vel[0] = 0; - vel[1] = 0; - return; - } - - drop = 0; - - // apply ground friction - if ((pm.groundentity != null && pml.groundsurface != null && 0 == (pml.groundsurface.flags & SURF_SLICK)) || (pml.ladder)) - { - friction = pm_friction; - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control * friction * pml.frametime; - } - - // apply water friction - if (pm.waterlevel != 0 && !pml.ladder) - drop += speed * pm_waterfriction * pm.waterlevel * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - { - newspeed = 0; - } - newspeed /= speed; - - vel[0] = vel[0] * newspeed; - vel[1] = vel[1] * newspeed; - vel[2] = vel[2] * newspeed; - } - - /* - ============== - PM_Accelerate - - Handles user intended acceleration - ============== - */ - public static void PM_Accelerate(float[] wishdir, float wishspeed, float accel) - { - int i; - float addspeed, accelspeed, currentspeed; - - currentspeed = DotProduct(pml.velocity, wishdir); - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) - return; - accelspeed = accel * pml.frametime * wishspeed; - if (accelspeed > addspeed) - accelspeed = addspeed; - - for (i = 0; i < 3; i++) - pml.velocity[i] += accelspeed * wishdir[i]; - } - - public static void PM_AirAccelerate(float[] wishdir, float wishspeed, float accel) - { - int i; - float addspeed, accelspeed, currentspeed, wishspd = wishspeed; - - if (wishspd > 30) - wishspd = 30; - currentspeed = DotProduct(pml.velocity, wishdir); - addspeed = wishspd - currentspeed; - if (addspeed <= 0) - return; - accelspeed = accel * wishspeed * pml.frametime; - if (accelspeed > addspeed) - accelspeed = addspeed; - - for (i = 0; i < 3; i++) - pml.velocity[i] += accelspeed * wishdir[i]; - } - - /* - ============= - PM_AddCurrents - ============= - */ - public static void PM_AddCurrents(float[] wishvel) - { - float[] v = { 0, 0, 0 }; - float s; - - // - // account for ladders - // - - if (pml.ladder && Math.abs(pml.velocity[2]) <= 200) - { - if ((pm.viewangles[PITCH] <= -15) && (pm.cmd.forwardmove > 0)) - wishvel[2] = 200; - else if ((pm.viewangles[PITCH] >= 15) && (pm.cmd.forwardmove > 0)) - wishvel[2] = -200; - else if (pm.cmd.upmove > 0) - wishvel[2] = 200; - else if (pm.cmd.upmove < 0) - wishvel[2] = -200; - else - wishvel[2] = 0; - - // limit horizontal speed when on a ladder - if (wishvel[0] < -25) - wishvel[0] = -25; - else if (wishvel[0] > 25) - wishvel[0] = 25; - - if (wishvel[1] < -25) - wishvel[1] = -25; - else if (wishvel[1] > 25) - wishvel[1] = 25; - } - - // - // add water currents - // - - if ((pm.watertype & MASK_CURRENT) != 0) - { - VectorClear(v); - - if ((pm.watertype & CONTENTS_CURRENT_0) != 0) - v[0] += 1; - if ((pm.watertype & CONTENTS_CURRENT_90) != 0) - v[1] += 1; - if ((pm.watertype & CONTENTS_CURRENT_180) != 0) - v[0] -= 1; - if ((pm.watertype & CONTENTS_CURRENT_270) != 0) - v[1] -= 1; - if ((pm.watertype & CONTENTS_CURRENT_UP) != 0) - v[2] += 1; - if ((pm.watertype & CONTENTS_CURRENT_DOWN) != 0) - v[2] -= 1; - - s = pm_waterspeed; - if ((pm.waterlevel == 1) && (pm.groundentity != null)) - s /= 2; - - VectorMA(wishvel, s, v, wishvel); - } - - // - // add conveyor belt velocities - // - - if (pm.groundentity != null) - { - VectorClear(v); - - if ((pml.groundcontents & CONTENTS_CURRENT_0) != 0) - v[0] += 1; - if ((pml.groundcontents & CONTENTS_CURRENT_90) != 0) - v[1] += 1; - if ((pml.groundcontents & CONTENTS_CURRENT_180) != 0) - v[0] -= 1; - if ((pml.groundcontents & CONTENTS_CURRENT_270) != 0) - v[1] -= 1; - if ((pml.groundcontents & CONTENTS_CURRENT_UP) != 0) - v[2] += 1; - if ((pml.groundcontents & CONTENTS_CURRENT_DOWN) != 0) - v[2] -= 1; - - VectorMA(wishvel, 100 /* pm.groundentity.speed */ - , v, wishvel); - } - } - - /* - =================== - PM_WaterMove - - =================== - */ - public static void PM_WaterMove() - { - int i; - float[] wishvel = { 0, 0, 0 }; - float wishspeed; - float[] wishdir = { 0, 0, 0 }; - - // - // user intentions - // - for (i = 0; i < 3; i++) - wishvel[i] = pml.forward[i] * pm.cmd.forwardmove + pml.right[i] * pm.cmd.sidemove; - - if (0 == pm.cmd.forwardmove && 0 == pm.cmd.sidemove && 0 == pm.cmd.upmove) - wishvel[2] -= 60; // drift towards bottom - else - wishvel[2] += pm.cmd.upmove; - - PM_AddCurrents(wishvel); - - VectorCopy(wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - if (wishspeed > pm_maxspeed) - { - VectorScale(wishvel, pm_maxspeed / wishspeed, wishvel); - wishspeed = pm_maxspeed; - } - wishspeed *= 0.5; - - PM_Accelerate(wishdir, wishspeed, pm_wateraccelerate); - - PM_StepSlideMove(); - } - - /* - =================== - PM_AirMove - - =================== - */ - public static void PM_AirMove() - { - int i; - float[] wishvel = { 0, 0, 0 }; - float fmove, smove; - float[] wishdir = { 0, 0, 0 }; - float wishspeed; - float maxspeed; - - fmove = pm.cmd.forwardmove; - smove = pm.cmd.sidemove; - - for (i = 0; i < 2; i++) - wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel[2] = 0; - - PM_AddCurrents(wishvel); - - VectorCopy(wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - // - // clamp to server defined max speed - // - maxspeed = (pm.s.pm_flags & PMF_DUCKED) != 0 ? pm_duckspeed : pm_maxspeed; - - if (wishspeed > maxspeed) - { - VectorScale(wishvel, maxspeed / wishspeed, wishvel); - wishspeed = maxspeed; - } - - if (pml.ladder) - { - PM_Accelerate(wishdir, wishspeed, pm_accelerate); - if (0 == wishvel[2]) - { - if (pml.velocity[2] > 0) - { - pml.velocity[2] -= pm.s.gravity * pml.frametime; - if (pml.velocity[2] < 0) - pml.velocity[2] = 0; - } - else - { - pml.velocity[2] += pm.s.gravity * pml.frametime; - if (pml.velocity[2] > 0) - pml.velocity[2] = 0; - } - } - PM_StepSlideMove(); - } - else if (pm.groundentity != null) - { // walking on ground - pml.velocity[2] = 0; //!!! this is before the accel - PM_Accelerate(wishdir, wishspeed, pm_accelerate); - - // PGM -- fix for negative trigger_gravity fields - // pml.velocity[2] = 0; - if (pm.s.gravity > 0) - pml.velocity[2] = 0; - else - pml.velocity[2] -= pm.s.gravity * pml.frametime; - // PGM - - if (0 == pml.velocity[0] && 0 == pml.velocity[1]) - return; - PM_StepSlideMove(); - } - else - { // not on ground, so little effect on velocity - if (pm_airaccelerate != 0) - PM_AirAccelerate(wishdir, wishspeed, pm_accelerate); - else - PM_Accelerate(wishdir, wishspeed, 1); - // add gravity - pml.velocity[2] -= pm.s.gravity * pml.frametime; - PM_StepSlideMove(); - } - } - - /* - ============= - PM_CatagorizePosition - ============= - */ - public static void PM_CatagorizePosition() - { - float[] point = { 0, 0, 0 }; - int cont; - trace_t trace; - int sample1; - int sample2; - - // if the player hull point one unit down is solid, the player - // is on ground - - // see if standing on something solid - point[0] = pml.origin[0]; - point[1] = pml.origin[1]; - point[2] = pml.origin[2] - 0.25f; - if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel) - { - pm.s.pm_flags &= ~PMF_ON_GROUND; - pm.groundentity = null; - } - else - { - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, point); - pml.groundplane = trace.plane; - pml.groundsurface = trace.surface; - pml.groundcontents = trace.contents; - - if (null == trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid)) - { - pm.groundentity = null; - pm.s.pm_flags &= ~PMF_ON_GROUND; - } - else - { - pm.groundentity = trace.ent; - // hitting solid ground will end a waterjump - if ((pm.s.pm_flags & PMF_TIME_WATERJUMP) != 0) - { - pm.s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); - pm.s.pm_time = 0; - } - - if (0 == (pm.s.pm_flags & PMF_ON_GROUND)) - { // just hit the ground - pm.s.pm_flags |= PMF_ON_GROUND; - // don't do landing time if we were just going down a slope - if (pml.velocity[2] < -200) - { - pm.s.pm_flags |= PMF_TIME_LAND; - // don't allow another jump for a little while - if (pml.velocity[2] < -400) - pm.s.pm_time = 25; - else - pm.s.pm_time = 18; - } - } - } - - if (pm.numtouch < MAXTOUCH && trace.ent != null) - { - pm.touchents[pm.numtouch] = trace.ent; - pm.numtouch++; - } - } - - // - // get waterlevel, accounting for ducking - // - pm.waterlevel = 0; - pm.watertype = 0; - - sample2 = (int) (pm.viewheight - pm.mins[2]); - sample1 = sample2 / 2; - - point[2] = pml.origin[2] + pm.mins[2] + 1; - cont = pm.pointcontents.pointcontents(point); - - if ((cont & MASK_WATER) != 0) - { - pm.watertype = cont; - pm.waterlevel = 1; - point[2] = pml.origin[2] + pm.mins[2] + sample1; - cont = pm.pointcontents.pointcontents(point); - if ((cont & MASK_WATER) != 0) - { - pm.waterlevel = 2; - point[2] = pml.origin[2] + pm.mins[2] + sample2; - cont = pm.pointcontents.pointcontents(point); - if ((cont & MASK_WATER) != 0) - pm.waterlevel = 3; - } - } - - } - - /* - ============= - PM_CheckJump - ============= - */ - public static void PM_CheckJump() - { - if ((pm.s.pm_flags & PMF_TIME_LAND) != 0) - { // hasn't been long enough since landing to jump again - return; - } - - if (pm.cmd.upmove < 10) - { // not holding jump - pm.s.pm_flags &= ~PMF_JUMP_HELD; - return; - } - - // must wait for jump to be released - if ((pm.s.pm_flags & PMF_JUMP_HELD) != 0) - return; - - if (pm.s.pm_type == PM_DEAD) - return; - - if (pm.waterlevel >= 2) - { // swimming, not jumping - pm.groundentity = null; - - if (pml.velocity[2] <= -300) - return; - - if (pm.watertype == CONTENTS_WATER) - pml.velocity[2] = 100; - else if (pm.watertype == CONTENTS_SLIME) - pml.velocity[2] = 80; - else - pml.velocity[2] = 50; - return; - } - - if (pm.groundentity == null) - return; // in air, so no effect - - pm.s.pm_flags |= PMF_JUMP_HELD; - - pm.groundentity = null; - pml.velocity[2] += 270; - if (pml.velocity[2] < 270) - pml.velocity[2] = 270; - } - - /* - ============= - PM_CheckSpecialMovement - ============= - */ - public static void PM_CheckSpecialMovement() - { - float[] spot = { 0, 0, 0 }; - int cont; - float[] flatforward = { 0, 0, 0 }; - trace_t trace; - - if (pm.s.pm_time != 0) - return; - - pml.ladder = false; - - // check for ladder - flatforward[0] = pml.forward[0]; - flatforward[1] = pml.forward[1]; - flatforward[2] = 0; - VectorNormalize(flatforward); - - VectorMA(pml.origin, 1, flatforward, spot); - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, spot); - if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER) != 0) - pml.ladder = true; - - // check for water jump - if (pm.waterlevel != 2) - return; - - VectorMA(pml.origin, 30, flatforward, spot); - spot[2] += 4; - cont = pm.pointcontents.pointcontents(spot); - if (0 == (cont & CONTENTS_SOLID)) - return; - - spot[2] += 16; - cont = pm.pointcontents.pointcontents(spot); - if (cont != 0) - return; - // jump out of water - VectorScale(flatforward, 50, pml.velocity); - pml.velocity[2] = 350; - - pm.s.pm_flags |= PMF_TIME_WATERJUMP; - pm.s.pm_time = -1; // was 255 - } - - /* - =============== - PM_FlyMove - =============== - */ - public static void PM_FlyMove(boolean doclip) - { - float speed, drop, friction, control, newspeed; - float currentspeed, addspeed, accelspeed; - int i; - float[] wishvel = { 0, 0, 0 }; - float fmove, smove; - float[] wishdir = { 0, 0, 0 }; - float wishspeed; - float[] end = { 0, 0, 0 }; - trace_t trace; - - pm.viewheight = 22; - - // friction - - speed = VectorLength(pml.velocity); - if (speed < 1) - { - VectorCopy(vec3_origin, pml.velocity); - } - else - { - drop = 0; - - friction = pm_friction * 1.5f; // extra friction - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control * friction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - newspeed /= speed; - - VectorScale(pml.velocity, newspeed, pml.velocity); - } - - // accelerate - fmove = pm.cmd.forwardmove; - smove = pm.cmd.sidemove; - - VectorNormalize(pml.forward); - VectorNormalize(pml.right); - - for (i = 0; i < 3; i++) - wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel[2] += pm.cmd.upmove; - - VectorCopy(wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - // - // clamp to server defined max speed - // - if (wishspeed > pm_maxspeed) - { - VectorScale(wishvel, pm_maxspeed / wishspeed, wishvel); - wishspeed = pm_maxspeed; - } - - currentspeed = DotProduct(pml.velocity, wishdir); - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) - return; - accelspeed = pm_accelerate * pml.frametime * wishspeed; - if (accelspeed > addspeed) - accelspeed = addspeed; - - for (i = 0; i < 3; i++) - pml.velocity[i] += accelspeed * wishdir[i]; - - if (doclip) - { - for (i = 0; i < 3; i++) - end[i] = pml.origin[i] + pml.frametime * pml.velocity[i]; - - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, end); - - VectorCopy(trace.endpos, pml.origin); - } - else - { - // move - VectorMA(pml.origin, pml.frametime, pml.velocity, pml.origin); - } - } - - /* - ============== - PM_CheckDuck - - Sets mins, maxs, and pm.viewheight - ============== - */ - public static void PM_CheckDuck() - { - trace_t trace; - - pm.mins[0] = -16; - pm.mins[1] = -16; - - pm.maxs[0] = 16; - pm.maxs[1] = 16; - - if (pm.s.pm_type == PM_GIB) - { - pm.mins[2] = 0; - pm.maxs[2] = 16; - pm.viewheight = 8; - return; - } - - pm.mins[2] = -24; - - if (pm.s.pm_type == PM_DEAD) - { - pm.s.pm_flags |= PMF_DUCKED; - } - else if (pm.cmd.upmove < 0 && (pm.s.pm_flags & PMF_ON_GROUND) != 0) - { // duck - pm.s.pm_flags |= PMF_DUCKED; - } - else - { // stand up if possible - if ((pm.s.pm_flags & PMF_DUCKED) != 0) - { - // try to stand up - pm.maxs[2] = 32; - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, pml.origin); - if (!trace.allsolid) - pm.s.pm_flags &= ~PMF_DUCKED; - } - } - - if ((pm.s.pm_flags & PMF_DUCKED) != 0) - { - pm.maxs[2] = 4; - pm.viewheight = -2; - } - else - { - pm.maxs[2] = 32; - pm.viewheight = 22; - } - } - - /* - ============== - PM_DeadMove - ============== - */ - public static void PM_DeadMove() - { - float forward; - - if (null == pm.groundentity) - return; - - // extra friction - - forward = VectorLength(pml.velocity); - forward -= 20; - if (forward <= 0) - { - VectorClear(pml.velocity); - } - else - { - VectorNormalize(pml.velocity); - VectorScale(pml.velocity, forward, pml.velocity); - } - } - - public static boolean PM_GoodPosition() - { - trace_t trace; - float[] origin = { 0, 0, 0 }, end = { 0, 0, 0 }; - int i; - - if (pm.s.pm_type == PM_SPECTATOR) - return true; - - for (i = 0; i < 3; i++) - origin[i] = end[i] = pm.s.origin[i] * 0.125f; - trace = pm.trace.trace(origin, pm.mins, pm.maxs, end); - - return !trace.allsolid; - } - - /* - ================ - PM_SnapPosition - - On exit, the origin will have a value that is pre-quantized to the 0.125 - precision of the network channel and in a valid position. - ================ - */ - // try all single bits first - static int jitterbits[] = { 0, 4, 1, 2, 3, 5, 6, 7 }; - public static void PM_SnapPosition() - { - int sign[] = { 0, 0, 0 }; - int i, j, bits; - short base[] = { 0, 0, 0 }; - - // snap velocity to eigths - for (i = 0; i < 3; i++) - pm.s.velocity[i] = (short) (pml.velocity[i] * 8); - - for (i = 0; i < 3; i++) - { - if (pml.origin[i] >= 0) - sign[i] = 1; - else - sign[i] = -1; - pm.s.origin[i] = (short) (pml.origin[i] * 8); - if (pm.s.origin[i] * 0.125 == pml.origin[i]) - sign[i] = 0; - } - VectorCopy(pm.s.origin, base); - - // try all combinations - for (j = 0; j < 8; j++) - { - bits = jitterbits[j]; - VectorCopy(base, pm.s.origin); - for (i = 0; i < 3; i++) - if ((bits & (1 << i)) != 0) - pm.s.origin[i] += sign[i]; - - if (PM_GoodPosition()) - return; - } - - // go back to the last position - VectorCopy(pml.previous_origin, pm.s.origin); - // Com_DPrintf ("using previous_origin\n"); - } - - /* - ================ - PM_InitialSnapPosition - - ================ - */ - static int offset[] = { 0, -1, 1 }; - public static void PM_InitialSnapPosition() - { - int x, y, z; - short base[] = { 0, 0, 0 }; - - VectorCopy(pm.s.origin, base); - - for (z = 0; z < 3; z++) - { - pm.s.origin[2] = (short) (base[2] + offset[z]); - for (y = 0; y < 3; y++) - { - pm.s.origin[1] = (short) (base[1] + offset[y]); - for (x = 0; x < 3; x++) - { - pm.s.origin[0] = (short) (base[0] + offset[x]); - if (PM_GoodPosition()) - { - pml.origin[0] = pm.s.origin[0] * 0.125f; - pml.origin[1] = pm.s.origin[1] * 0.125f; - pml.origin[2] = pm.s.origin[2] * 0.125f; - VectorCopy(pm.s.origin, pml.previous_origin); - return; - } - } - } - } - - Com.DPrintf("Bad InitialSnapPosition\n"); - } - - /* - ================ - PM_ClampAngles - - ================ - */ - public static void PM_ClampAngles() - { - short temp; - int i; - - if ((pm.s.pm_flags & PMF_TIME_TELEPORT) != 0) - { - pm.viewangles[YAW] = SHORT2ANGLE(pm.cmd.angles[YAW] + pm.s.delta_angles[YAW]); - pm.viewangles[PITCH] = 0; - pm.viewangles[ROLL] = 0; - } - else - { - // circularly clamp the angles with deltas - for (i = 0; i < 3; i++) - { - temp = (short) (pm.cmd.angles[i] + pm.s.delta_angles[i]); - pm.viewangles[i] = SHORT2ANGLE(temp); - } - - // don't let the player look up or down more than 90 degrees - if (pm.viewangles[PITCH] > 89 && pm.viewangles[PITCH] < 180) - pm.viewangles[PITCH] = 89; - else if (pm.viewangles[PITCH] < 271 && pm.viewangles[PITCH] >= 180) - pm.viewangles[PITCH] = 271; - } - AngleVectors(pm.viewangles, pml.forward, pml.right, pml.up); - } - - /* - ================ - Pmove - - Can be called by either the server or the client - ================ - */ - public static void Pmove(pmove_t pmove) - { - pm = pmove; - - // clear results - pm.numtouch = 0; - VectorClear(pm.viewangles); - pm.viewheight = 0; - pm.groundentity = null; - pm.watertype = 0; - pm.waterlevel = 0; - - // clear all pmove local vars - pml = new pml_t(); - - // convert origin and velocity to float values - pml.origin[0] = pm.s.origin[0] * 0.125f; - pml.origin[1] = pm.s.origin[1] * 0.125f; - pml.origin[2] = pm.s.origin[2] * 0.125f; - - pml.velocity[0] = pm.s.velocity[0] * 0.125f; - pml.velocity[1] = pm.s.velocity[1] * 0.125f; - pml.velocity[2] = pm.s.velocity[2] * 0.125f; - - // save old org in case we get stuck - VectorCopy(pm.s.origin, pml.previous_origin); - - pml.frametime = (pm.cmd.msec & 0xFF) * 0.001f; - - PM_ClampAngles(); - - if (pm.s.pm_type == PM_SPECTATOR) - { - PM_FlyMove(false); - PM_SnapPosition(); - return; - } - - if (pm.s.pm_type >= PM_DEAD) - { - pm.cmd.forwardmove = 0; - pm.cmd.sidemove = 0; - pm.cmd.upmove = 0; - } - - if (pm.s.pm_type == PM_FREEZE) - return; // no movement at all - - // set mins, maxs, and viewheight - PM_CheckDuck(); - - if (pm.snapinitial) - PM_InitialSnapPosition(); - - // set groundentity, watertype, and waterlevel - PM_CatagorizePosition(); - - if (pm.s.pm_type == PM_DEAD) - PM_DeadMove(); - - PM_CheckSpecialMovement(); - - // drop timing counter - if (pm.s.pm_time != 0) - { - int msec; - - // TOD o bugfix cwei - msec = pm.cmd.msec >>> 3; - if (msec == 0) - msec = 1; - if (msec >= (pm.s.pm_time & 0xFF)) - { - pm.s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); - pm.s.pm_time = 0; - } - else - pm.s.pm_time = (byte)((pm.s.pm_time & 0xFF) - msec); - } - - if ((pm.s.pm_flags & PMF_TIME_TELEPORT) != 0) - { // teleport pause stays exactly in place - } - else if ((pm.s.pm_flags & PMF_TIME_WATERJUMP) != 0) - { // waterjump has no control, but falls - pml.velocity[2] -= pm.s.gravity * pml.frametime; - if (pml.velocity[2] < 0) - { // cancel as soon as we are falling down again - pm.s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); - pm.s.pm_time = 0; - } - - PM_StepSlideMove(); - } - else - { - PM_CheckJump(); - - PM_Friction(); - - if (pm.waterlevel >= 2) - PM_WaterMove(); - else - { - float[] angles={0,0,0}; - - VectorCopy(pm.viewangles, angles); - if (angles[PITCH] > 180) - angles[PITCH] = angles[PITCH] - 360; - angles[PITCH] /= 3; - - AngleVectors(angles, pml.forward, pml.right, pml.up); - - PM_AirMove(); - } - } - - // set groundentity, watertype, and waterlevel for final spot - PM_CatagorizePosition(); - - PM_SnapPosition(); - } -} + public static void PM_ClipVelocity(float[] in, float[] normal, float[] out, + float overbounce) { + float backoff; + float change; + int i; + + backoff = Math3D.DotProduct(in, normal) * overbounce; + + for (i = 0; i < 3; i++) { + change = normal[i] * backoff; + out[i] = in[i] - change; + if (out[i] > -Defines.MOVE_STOP_EPSILON + && out[i] < Defines.MOVE_STOP_EPSILON) + out[i] = 0; + } + } + + public static void PM_StepSlideMove_() { + int bumpcount, numbumps; + float[] dir = { 0, 0, 0 }; + float d; + int numplanes; + float[] planes[] = new float[GameBase.MAX_CLIP_PLANES][3]; + float[] primal_velocity = { 0, 0, 0 }; + int i, j; + trace_t trace; + float[] end = { 0, 0, 0 }; + float time_left; + + numbumps = 4; + + Math3D.VectorCopy(PMove.pml.velocity, primal_velocity); + numplanes = 0; + + time_left = PMove.pml.frametime; + + for (bumpcount = 0; bumpcount < numbumps; bumpcount++) { + for (i = 0; i < 3; i++) + end[i] = PMove.pml.origin[i] + time_left + * PMove.pml.velocity[i]; + + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, end); + + if (trace.allsolid) { // entity is trapped in another solid + PMove.pml.velocity[2] = 0; // don't build up falling damage + return; + } + + if (trace.fraction > 0) { // actually covered some distance + Math3D.VectorCopy(trace.endpos, PMove.pml.origin); + numplanes = 0; + } + + if (trace.fraction == 1) + break; // moved the entire distance + + // save entity for contact + if (PMove.pm.numtouch < Defines.MAXTOUCH && trace.ent != null) { + //rst: just for debugging touches. + //if (trace.ent.index != -1 && trace.ent.index != 0) + //Com.p("touch: " + trace.ent.classname + " (" + + // trace.ent.index + ")" ); + + PMove.pm.touchents[PMove.pm.numtouch] = trace.ent; + PMove.pm.numtouch++; + } + + time_left -= time_left * trace.fraction; + + // slide along this plane + if (numplanes >= GameBase.MAX_CLIP_PLANES) { // this shouldn't + // really happen + Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity); + break; + } + + Math3D.VectorCopy(trace.plane.normal, planes[numplanes]); + numplanes++; + + // + // modify original_velocity so it parallels all of the clip planes + // + + for (i = 0; i < numplanes; i++) { + PMove.PM_ClipVelocity(PMove.pml.velocity, planes[i], + PMove.pml.velocity, 1.01f); + for (j = 0; j < numplanes; j++) + if (j != i) { + if (Math3D.DotProduct(PMove.pml.velocity, planes[j]) < 0) + break; // not ok + } + if (j == numplanes) + break; + } + + if (i != numplanes) { // go along this plane + } else { // go along the crease + if (numplanes != 2) { + // Con_Printf ("clip velocity, numplanes == + // %i\n",numplanes); + Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity); + break; + } + Math3D.CrossProduct(planes[0], planes[1], dir); + d = Math3D.DotProduct(dir, PMove.pml.velocity); + Math3D.VectorScale(dir, d, PMove.pml.velocity); + } + + // + // if velocity is against the original velocity, stop dead + // to avoid tiny occilations in sloping corners + // + if (Math3D.DotProduct(PMove.pml.velocity, primal_velocity) <= 0) { + Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity); + break; + } + } + + if (PMove.pm.s.pm_time != 0) { + Math3D.VectorCopy(primal_velocity, PMove.pml.velocity); + } + } + + /* + * ================== PM_StepSlideMove + * + * ================== + */ + public static void PM_StepSlideMove() { + float[] start_o = { 0, 0, 0 }, start_v = { 0, 0, 0 }; + float[] down_o = { 0, 0, 0 }, down_v = { 0, 0, 0 }; + trace_t trace; + float down_dist, up_dist; + // float [] delta; + float[] up = { 0, 0, 0 }, down = { 0, 0, 0 }; + + Math3D.VectorCopy(PMove.pml.origin, start_o); + Math3D.VectorCopy(PMove.pml.velocity, start_v); + + PM_StepSlideMove_(); + + Math3D.VectorCopy(PMove.pml.origin, down_o); + Math3D.VectorCopy(PMove.pml.velocity, down_v); + + Math3D.VectorCopy(start_o, up); + up[2] += Defines.STEPSIZE; + + trace = PMove.pm.trace.trace(up, PMove.pm.mins, PMove.pm.maxs, up); + if (trace.allsolid) + return; // can't step up + + // try sliding above + Math3D.VectorCopy(up, PMove.pml.origin); + Math3D.VectorCopy(start_v, PMove.pml.velocity); + + PM_StepSlideMove_(); + + // push down the final amount + Math3D.VectorCopy(PMove.pml.origin, down); + down[2] -= Defines.STEPSIZE; + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, down); + if (!trace.allsolid) { + Math3D.VectorCopy(trace.endpos, PMove.pml.origin); + } + + Math3D.VectorCopy(PMove.pml.origin, up); + + // decide which one went farther + down_dist = (down_o[0] - start_o[0]) * (down_o[0] - start_o[0]) + + (down_o[1] - start_o[1]) * (down_o[1] - start_o[1]); + up_dist = (up[0] - start_o[0]) * (up[0] - start_o[0]) + + (up[1] - start_o[1]) * (up[1] - start_o[1]); + + if (down_dist > up_dist + || trace.plane.normal[2] < Defines.MIN_STEP_NORMAL) { + Math3D.VectorCopy(down_o, PMove.pml.origin); + Math3D.VectorCopy(down_v, PMove.pml.velocity); + return; + } + //!! Special case + // if we were walking along a plane, then we need to copy the Z over + PMove.pml.velocity[2] = down_v[2]; + } + + /* + * ================== PM_Friction + * + * Handles both ground friction and water friction ================== + */ + public static void PM_Friction() { + float vel[]; + float speed, newspeed, control; + float friction; + float drop; + + vel = PMove.pml.velocity; + + speed = (float) (Math.sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] + * vel[2])); + if (speed < 1) { + vel[0] = 0; + vel[1] = 0; + return; + } + + drop = 0; + + // apply ground friction + if ((PMove.pm.groundentity != null && PMove.pml.groundsurface != null && 0 == (PMove.pml.groundsurface.flags & Defines.SURF_SLICK)) + || (PMove.pml.ladder)) { + friction = PMove.pm_friction; + control = speed < PMove.pm_stopspeed ? PMove.pm_stopspeed : speed; + drop += control * friction * PMove.pml.frametime; + } + + // apply water friction + if (PMove.pm.waterlevel != 0 && !PMove.pml.ladder) + drop += speed * PMove.pm_waterfriction * PMove.pm.waterlevel + * PMove.pml.frametime; + + // scale the velocity + newspeed = speed - drop; + if (newspeed < 0) { + newspeed = 0; + } + newspeed /= speed; + + vel[0] = vel[0] * newspeed; + vel[1] = vel[1] * newspeed; + vel[2] = vel[2] * newspeed; + } + + /* + * ============== PM_Accelerate + * + * Handles user intended acceleration ============== + */ + public static void PM_Accelerate(float[] wishdir, float wishspeed, + float accel) { + int i; + float addspeed, accelspeed, currentspeed; + + currentspeed = Math3D.DotProduct(PMove.pml.velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = accel * PMove.pml.frametime * wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i = 0; i < 3; i++) + PMove.pml.velocity[i] += accelspeed * wishdir[i]; + } + + public static void PM_AirAccelerate(float[] wishdir, float wishspeed, + float accel) { + int i; + float addspeed, accelspeed, currentspeed, wishspd = wishspeed; + + if (wishspd > 30) + wishspd = 30; + currentspeed = Math3D.DotProduct(PMove.pml.velocity, wishdir); + addspeed = wishspd - currentspeed; + if (addspeed <= 0) + return; + accelspeed = accel * wishspeed * PMove.pml.frametime; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i = 0; i < 3; i++) + PMove.pml.velocity[i] += accelspeed * wishdir[i]; + } + + /* + * ============= PM_AddCurrents ============= + */ + public static void PM_AddCurrents(float[] wishvel) { + float[] v = { 0, 0, 0 }; + float s; + + // + // account for ladders + // + + if (PMove.pml.ladder && Math.abs(PMove.pml.velocity[2]) <= 200) { + if ((PMove.pm.viewangles[Defines.PITCH] <= -15) + && (PMove.pm.cmd.forwardmove > 0)) + wishvel[2] = 200; + else if ((PMove.pm.viewangles[Defines.PITCH] >= 15) + && (PMove.pm.cmd.forwardmove > 0)) + wishvel[2] = -200; + else if (PMove.pm.cmd.upmove > 0) + wishvel[2] = 200; + else if (PMove.pm.cmd.upmove < 0) + wishvel[2] = -200; + else + wishvel[2] = 0; + + // limit horizontal speed when on a ladder + if (wishvel[0] < -25) + wishvel[0] = -25; + else if (wishvel[0] > 25) + wishvel[0] = 25; + + if (wishvel[1] < -25) + wishvel[1] = -25; + else if (wishvel[1] > 25) + wishvel[1] = 25; + } + + // + // add water currents + // + + if ((PMove.pm.watertype & Defines.MASK_CURRENT) != 0) { + Math3D.VectorClear(v); + + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_0) != 0) + v[0] += 1; + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_90) != 0) + v[1] += 1; + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_180) != 0) + v[0] -= 1; + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_270) != 0) + v[1] -= 1; + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_UP) != 0) + v[2] += 1; + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_DOWN) != 0) + v[2] -= 1; + + s = PMove.pm_waterspeed; + if ((PMove.pm.waterlevel == 1) && (PMove.pm.groundentity != null)) + s /= 2; + + Math3D.VectorMA(wishvel, s, v, wishvel); + } + + // + // add conveyor belt velocities + // + + if (PMove.pm.groundentity != null) { + Math3D.VectorClear(v); + + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_0) != 0) + v[0] += 1; + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_90) != 0) + v[1] += 1; + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_180) != 0) + v[0] -= 1; + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_270) != 0) + v[1] -= 1; + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_UP) != 0) + v[2] += 1; + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_DOWN) != 0) + v[2] -= 1; + + Math3D.VectorMA(wishvel, 100 /* pm.groundentity.speed */ + , v, wishvel); + } + } + + /* + * =================== PM_WaterMove + * + * =================== + */ + public static void PM_WaterMove() { + int i; + float[] wishvel = { 0, 0, 0 }; + float wishspeed; + float[] wishdir = { 0, 0, 0 }; + + // + // user intentions + // + for (i = 0; i < 3; i++) + wishvel[i] = PMove.pml.forward[i] * PMove.pm.cmd.forwardmove + + PMove.pml.right[i] * PMove.pm.cmd.sidemove; + + if (0 == PMove.pm.cmd.forwardmove && 0 == PMove.pm.cmd.sidemove + && 0 == PMove.pm.cmd.upmove) + wishvel[2] -= 60; // drift towards bottom + else + wishvel[2] += PMove.pm.cmd.upmove; + + PM_AddCurrents(wishvel); + + Math3D.VectorCopy(wishvel, wishdir); + wishspeed = Math3D.VectorNormalize(wishdir); + + if (wishspeed > PMove.pm_maxspeed) { + Math3D.VectorScale(wishvel, PMove.pm_maxspeed / wishspeed, wishvel); + wishspeed = PMove.pm_maxspeed; + } + wishspeed *= 0.5; + + PM_Accelerate(wishdir, wishspeed, PMove.pm_wateraccelerate); + + PM_StepSlideMove(); + } + + /* + * =================== PM_AirMove + * + * =================== + */ + public static void PM_AirMove() { + int i; + float[] wishvel = { 0, 0, 0 }; + float fmove, smove; + float[] wishdir = { 0, 0, 0 }; + float wishspeed; + float maxspeed; + + fmove = PMove.pm.cmd.forwardmove; + smove = PMove.pm.cmd.sidemove; + + for (i = 0; i < 2; i++) + wishvel[i] = PMove.pml.forward[i] * fmove + PMove.pml.right[i] + * smove; + wishvel[2] = 0; + + PM_AddCurrents(wishvel); + + Math3D.VectorCopy(wishvel, wishdir); + wishspeed = Math3D.VectorNormalize(wishdir); + + // + // clamp to server defined max speed + // + maxspeed = (PMove.pm.s.pm_flags & pmove_t.PMF_DUCKED) != 0 ? PMove.pm_duckspeed + : PMove.pm_maxspeed; + + if (wishspeed > maxspeed) { + Math3D.VectorScale(wishvel, maxspeed / wishspeed, wishvel); + wishspeed = maxspeed; + } + + if (PMove.pml.ladder) { + PM_Accelerate(wishdir, wishspeed, PMove.pm_accelerate); + if (0 == wishvel[2]) { + if (PMove.pml.velocity[2] > 0) { + PMove.pml.velocity[2] -= PMove.pm.s.gravity + * PMove.pml.frametime; + if (PMove.pml.velocity[2] < 0) + PMove.pml.velocity[2] = 0; + } else { + PMove.pml.velocity[2] += PMove.pm.s.gravity + * PMove.pml.frametime; + if (PMove.pml.velocity[2] > 0) + PMove.pml.velocity[2] = 0; + } + } + PM_StepSlideMove(); + } else if (PMove.pm.groundentity != null) { // walking on ground + PMove.pml.velocity[2] = 0; //!!! this is before the accel + PM_Accelerate(wishdir, wishspeed, PMove.pm_accelerate); + + // PGM -- fix for negative trigger_gravity fields + // pml.velocity[2] = 0; + if (PMove.pm.s.gravity > 0) + PMove.pml.velocity[2] = 0; + else + PMove.pml.velocity[2] -= PMove.pm.s.gravity + * PMove.pml.frametime; + // PGM + + if (0 == PMove.pml.velocity[0] && 0 == PMove.pml.velocity[1]) + return; + PM_StepSlideMove(); + } else { // not on ground, so little effect on velocity + if (PMove.pm_airaccelerate != 0) + PM_AirAccelerate(wishdir, wishspeed, PMove.pm_accelerate); + else + PM_Accelerate(wishdir, wishspeed, 1); + // add gravity + PMove.pml.velocity[2] -= PMove.pm.s.gravity * PMove.pml.frametime; + PM_StepSlideMove(); + } + } + + /* + * ============= PM_CatagorizePosition ============= + */ + public static void PM_CatagorizePosition() { + float[] point = { 0, 0, 0 }; + int cont; + trace_t trace; + int sample1; + int sample2; + + // if the player hull point one unit down is solid, the player + // is on ground + + // see if standing on something solid + point[0] = PMove.pml.origin[0]; + point[1] = PMove.pml.origin[1]; + point[2] = PMove.pml.origin[2] - 0.25f; + if (PMove.pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp + // accel) + { + PMove.pm.s.pm_flags &= ~pmove_t.PMF_ON_GROUND; + PMove.pm.groundentity = null; + } else { + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, point); + PMove.pml.groundplane = trace.plane; + PMove.pml.groundsurface = trace.surface; + PMove.pml.groundcontents = trace.contents; + + if (null == trace.ent + || (trace.plane.normal[2] < 0.7 && !trace.startsolid)) { + PMove.pm.groundentity = null; + PMove.pm.s.pm_flags &= ~pmove_t.PMF_ON_GROUND; + } else { + PMove.pm.groundentity = trace.ent; + // hitting solid ground will end a waterjump + if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_WATERJUMP) != 0) { + PMove.pm.s.pm_flags &= ~(pmove_t.PMF_TIME_WATERJUMP + | pmove_t.PMF_TIME_LAND | pmove_t.PMF_TIME_TELEPORT); + PMove.pm.s.pm_time = 0; + } + + if (0 == (PMove.pm.s.pm_flags & pmove_t.PMF_ON_GROUND)) { // just + // hit + // the + // ground + PMove.pm.s.pm_flags |= pmove_t.PMF_ON_GROUND; + // don't do landing time if we were just going down a slope + if (PMove.pml.velocity[2] < -200) { + PMove.pm.s.pm_flags |= pmove_t.PMF_TIME_LAND; + // don't allow another jump for a little while + if (PMove.pml.velocity[2] < -400) + PMove.pm.s.pm_time = 25; + else + PMove.pm.s.pm_time = 18; + } + } + } + + if (PMove.pm.numtouch < Defines.MAXTOUCH && trace.ent != null) { + PMove.pm.touchents[PMove.pm.numtouch] = trace.ent; + PMove.pm.numtouch++; + } + } + + // + // get waterlevel, accounting for ducking + // + PMove.pm.waterlevel = 0; + PMove.pm.watertype = 0; + + sample2 = (int) (PMove.pm.viewheight - PMove.pm.mins[2]); + sample1 = sample2 / 2; + + point[2] = PMove.pml.origin[2] + PMove.pm.mins[2] + 1; + cont = PMove.pm.pointcontents.pointcontents(point); + + if ((cont & Defines.MASK_WATER) != 0) { + PMove.pm.watertype = cont; + PMove.pm.waterlevel = 1; + point[2] = PMove.pml.origin[2] + PMove.pm.mins[2] + sample1; + cont = PMove.pm.pointcontents.pointcontents(point); + if ((cont & Defines.MASK_WATER) != 0) { + PMove.pm.waterlevel = 2; + point[2] = PMove.pml.origin[2] + PMove.pm.mins[2] + sample2; + cont = PMove.pm.pointcontents.pointcontents(point); + if ((cont & Defines.MASK_WATER) != 0) + PMove.pm.waterlevel = 3; + } + } + + } + + /* + * ============= PM_CheckJump ============= + */ + public static void PM_CheckJump() { + if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_LAND) != 0) { + // hasn't been long enough since landing to jump again + return; + } + + if (PMove.pm.cmd.upmove < 10) { // not holding jump + PMove.pm.s.pm_flags &= ~pmove_t.PMF_JUMP_HELD; + return; + } + + // must wait for jump to be released + if ((PMove.pm.s.pm_flags & pmove_t.PMF_JUMP_HELD) != 0) + return; + + if (PMove.pm.s.pm_type == Defines.PM_DEAD) + return; + + if (PMove.pm.waterlevel >= 2) { // swimming, not jumping + PMove.pm.groundentity = null; + + if (PMove.pml.velocity[2] <= -300) + return; + + if (PMove.pm.watertype == Defines.CONTENTS_WATER) + PMove.pml.velocity[2] = 100; + else if (PMove.pm.watertype == Defines.CONTENTS_SLIME) + PMove.pml.velocity[2] = 80; + else + PMove.pml.velocity[2] = 50; + return; + } + + if (PMove.pm.groundentity == null) + return; // in air, so no effect + + PMove.pm.s.pm_flags |= pmove_t.PMF_JUMP_HELD; + + PMove.pm.groundentity = null; + PMove.pml.velocity[2] += 270; + if (PMove.pml.velocity[2] < 270) + PMove.pml.velocity[2] = 270; + } + + /* + * ============= PM_CheckSpecialMovement ============= + */ + public static void PM_CheckSpecialMovement() { + float[] spot = { 0, 0, 0 }; + int cont; + float[] flatforward = { 0, 0, 0 }; + trace_t trace; + + if (PMove.pm.s.pm_time != 0) + return; + + PMove.pml.ladder = false; + + // check for ladder + flatforward[0] = PMove.pml.forward[0]; + flatforward[1] = PMove.pml.forward[1]; + flatforward[2] = 0; + Math3D.VectorNormalize(flatforward); + + Math3D.VectorMA(PMove.pml.origin, 1, flatforward, spot); + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, spot); + if ((trace.fraction < 1) + && (trace.contents & Defines.CONTENTS_LADDER) != 0) + PMove.pml.ladder = true; + + // check for water jump + if (PMove.pm.waterlevel != 2) + return; + + Math3D.VectorMA(PMove.pml.origin, 30, flatforward, spot); + spot[2] += 4; + cont = PMove.pm.pointcontents.pointcontents(spot); + if (0 == (cont & Defines.CONTENTS_SOLID)) + return; + + spot[2] += 16; + cont = PMove.pm.pointcontents.pointcontents(spot); + if (cont != 0) + return; + // jump out of water + Math3D.VectorScale(flatforward, 50, PMove.pml.velocity); + PMove.pml.velocity[2] = 350; + + PMove.pm.s.pm_flags |= pmove_t.PMF_TIME_WATERJUMP; + PMove.pm.s.pm_time = -1; // was 255 + } + + /* + * =============== PM_FlyMove =============== + */ + public static void PM_FlyMove(boolean doclip) { + float speed, drop, friction, control, newspeed; + float currentspeed, addspeed, accelspeed; + int i; + float[] wishvel = { 0, 0, 0 }; + float fmove, smove; + float[] wishdir = { 0, 0, 0 }; + float wishspeed; + float[] end = { 0, 0, 0 }; + trace_t trace; + + PMove.pm.viewheight = 22; + + // friction + + speed = Math3D.VectorLength(PMove.pml.velocity); + if (speed < 1) { + Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity); + } else { + drop = 0; + + friction = PMove.pm_friction * 1.5f; // extra friction + control = speed < PMove.pm_stopspeed ? PMove.pm_stopspeed : speed; + drop += control * friction * PMove.pml.frametime; + + // scale the velocity + newspeed = speed - drop; + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + + Math3D + .VectorScale(PMove.pml.velocity, newspeed, + PMove.pml.velocity); + } + + // accelerate + fmove = PMove.pm.cmd.forwardmove; + smove = PMove.pm.cmd.sidemove; + + Math3D.VectorNormalize(PMove.pml.forward); + Math3D.VectorNormalize(PMove.pml.right); + + for (i = 0; i < 3; i++) + wishvel[i] = PMove.pml.forward[i] * fmove + PMove.pml.right[i] + * smove; + wishvel[2] += PMove.pm.cmd.upmove; + + Math3D.VectorCopy(wishvel, wishdir); + wishspeed = Math3D.VectorNormalize(wishdir); + + // + // clamp to server defined max speed + // + if (wishspeed > PMove.pm_maxspeed) { + Math3D.VectorScale(wishvel, PMove.pm_maxspeed / wishspeed, wishvel); + wishspeed = PMove.pm_maxspeed; + } + + currentspeed = Math3D.DotProduct(PMove.pml.velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = PMove.pm_accelerate * PMove.pml.frametime * wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i = 0; i < 3; i++) + PMove.pml.velocity[i] += accelspeed * wishdir[i]; + + if (doclip) { + for (i = 0; i < 3; i++) + end[i] = PMove.pml.origin[i] + PMove.pml.frametime + * PMove.pml.velocity[i]; + + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, end); + + Math3D.VectorCopy(trace.endpos, PMove.pml.origin); + } else { + // move + Math3D.VectorMA(PMove.pml.origin, PMove.pml.frametime, + PMove.pml.velocity, PMove.pml.origin); + } + } + + /* + * ============== PM_CheckDuck + * + * Sets mins, maxs, and pm.viewheight ============== + */ + public static void PM_CheckDuck() { + trace_t trace; + + PMove.pm.mins[0] = -16; + PMove.pm.mins[1] = -16; + + PMove.pm.maxs[0] = 16; + PMove.pm.maxs[1] = 16; + + if (PMove.pm.s.pm_type == Defines.PM_GIB) { + PMove.pm.mins[2] = 0; + PMove.pm.maxs[2] = 16; + PMove.pm.viewheight = 8; + return; + } + + PMove.pm.mins[2] = -24; + + if (PMove.pm.s.pm_type == Defines.PM_DEAD) { + PMove.pm.s.pm_flags |= pmove_t.PMF_DUCKED; + } else if (PMove.pm.cmd.upmove < 0 + && (PMove.pm.s.pm_flags & pmove_t.PMF_ON_GROUND) != 0) { // duck + PMove.pm.s.pm_flags |= pmove_t.PMF_DUCKED; + } else { // stand up if possible + if ((PMove.pm.s.pm_flags & pmove_t.PMF_DUCKED) != 0) { + // try to stand up + PMove.pm.maxs[2] = 32; + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, PMove.pml.origin); + if (!trace.allsolid) + PMove.pm.s.pm_flags &= ~pmove_t.PMF_DUCKED; + } + } + + if ((PMove.pm.s.pm_flags & pmove_t.PMF_DUCKED) != 0) { + PMove.pm.maxs[2] = 4; + PMove.pm.viewheight = -2; + } else { + PMove.pm.maxs[2] = 32; + PMove.pm.viewheight = 22; + } + } + + /* + * ============== PM_DeadMove ============== + */ + public static void PM_DeadMove() { + float forward; + + if (null == PMove.pm.groundentity) + return; + + // extra friction + + forward = Math3D.VectorLength(PMove.pml.velocity); + forward -= 20; + if (forward <= 0) { + Math3D.VectorClear(PMove.pml.velocity); + } else { + Math3D.VectorNormalize(PMove.pml.velocity); + Math3D.VectorScale(PMove.pml.velocity, forward, PMove.pml.velocity); + } + } + + public static boolean PM_GoodPosition() { + trace_t trace; + float[] origin = { 0, 0, 0 }, end = { 0, 0, 0 }; + int i; + + if (PMove.pm.s.pm_type == Defines.PM_SPECTATOR) + return true; + + for (i = 0; i < 3; i++) + origin[i] = end[i] = PMove.pm.s.origin[i] * 0.125f; + trace = PMove.pm.trace.trace(origin, PMove.pm.mins, PMove.pm.maxs, end); + + return !trace.allsolid; + } + + public static void PM_SnapPosition() { + int sign[] = { 0, 0, 0 }; + int i, j, bits; + short base[] = { 0, 0, 0 }; + + // snap velocity to eigths + for (i = 0; i < 3; i++) + PMove.pm.s.velocity[i] = (short) (PMove.pml.velocity[i] * 8); + + for (i = 0; i < 3; i++) { + if (PMove.pml.origin[i] >= 0) + sign[i] = 1; + else + sign[i] = -1; + PMove.pm.s.origin[i] = (short) (PMove.pml.origin[i] * 8); + if (PMove.pm.s.origin[i] * 0.125 == PMove.pml.origin[i]) + sign[i] = 0; + } + Math3D.VectorCopy(PMove.pm.s.origin, base); + + // try all combinations + for (j = 0; j < 8; j++) { + bits = jitterbits[j]; + Math3D.VectorCopy(base, PMove.pm.s.origin); + for (i = 0; i < 3; i++) + if ((bits & (1 << i)) != 0) + PMove.pm.s.origin[i] += sign[i]; + + if (PMove.PM_GoodPosition()) + return; + } + + // go back to the last position + Math3D.VectorCopy(PMove.pml.previous_origin, PMove.pm.s.origin); + // Com_DPrintf ("using previous_origin\n"); + } + + public static void PM_InitialSnapPosition() { + int x, y, z; + short base[] = { 0, 0, 0 }; + + Math3D.VectorCopy(PMove.pm.s.origin, base); + + for (z = 0; z < 3; z++) { + PMove.pm.s.origin[2] = (short) (base[2] + offset[z]); + for (y = 0; y < 3; y++) { + PMove.pm.s.origin[1] = (short) (base[1] + offset[y]); + for (x = 0; x < 3; x++) { + PMove.pm.s.origin[0] = (short) (base[0] + offset[x]); + if (PMove.PM_GoodPosition()) { + PMove.pml.origin[0] = PMove.pm.s.origin[0] * 0.125f; + PMove.pml.origin[1] = PMove.pm.s.origin[1] * 0.125f; + PMove.pml.origin[2] = PMove.pm.s.origin[2] * 0.125f; + Math3D.VectorCopy(PMove.pm.s.origin, + PMove.pml.previous_origin); + return; + } + } + } + } + + Com.DPrintf("Bad InitialSnapPosition\n"); + } + + /* + * ================ PM_ClampAngles + * + * ================ + */ + public static void PM_ClampAngles() { + short temp; + int i; + + if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_TELEPORT) != 0) { + PMove.pm.viewangles[Defines.YAW] = Math3D + .SHORT2ANGLE(PMove.pm.cmd.angles[Defines.YAW] + + PMove.pm.s.delta_angles[Defines.YAW]); + PMove.pm.viewangles[Defines.PITCH] = 0; + PMove.pm.viewangles[Defines.ROLL] = 0; + } else { + // circularly clamp the angles with deltas + for (i = 0; i < 3; i++) { + temp = (short) (PMove.pm.cmd.angles[i] + PMove.pm.s.delta_angles[i]); + PMove.pm.viewangles[i] = Math3D.SHORT2ANGLE(temp); + } + + // don't let the player look up or down more than 90 degrees + if (PMove.pm.viewangles[Defines.PITCH] > 89 + && PMove.pm.viewangles[Defines.PITCH] < 180) + PMove.pm.viewangles[Defines.PITCH] = 89; + else if (PMove.pm.viewangles[Defines.PITCH] < 271 + && PMove.pm.viewangles[Defines.PITCH] >= 180) + PMove.pm.viewangles[Defines.PITCH] = 271; + } + Math3D.AngleVectors(PMove.pm.viewangles, PMove.pml.forward, + PMove.pml.right, PMove.pml.up); + } + + /* + * ================ Pmove + * + * Can be called by either the server or the client ================ + */ + public static void Pmove(pmove_t pmove) { + PMove.pm = pmove; + + // clear results + PMove.pm.numtouch = 0; + Math3D.VectorClear(PMove.pm.viewangles); + PMove.pm.viewheight = 0; + PMove.pm.groundentity = null; + PMove.pm.watertype = 0; + PMove.pm.waterlevel = 0; + + // clear all pmove local vars + PMove.pml = new PMove.pml_t(); + + // convert origin and velocity to float values + PMove.pml.origin[0] = PMove.pm.s.origin[0] * 0.125f; + PMove.pml.origin[1] = PMove.pm.s.origin[1] * 0.125f; + PMove.pml.origin[2] = PMove.pm.s.origin[2] * 0.125f; + + PMove.pml.velocity[0] = PMove.pm.s.velocity[0] * 0.125f; + PMove.pml.velocity[1] = PMove.pm.s.velocity[1] * 0.125f; + PMove.pml.velocity[2] = PMove.pm.s.velocity[2] * 0.125f; + + // save old org in case we get stuck + Math3D.VectorCopy(PMove.pm.s.origin, PMove.pml.previous_origin); + + PMove.pml.frametime = (PMove.pm.cmd.msec & 0xFF) * 0.001f; + + PM_ClampAngles(); + + if (PMove.pm.s.pm_type == Defines.PM_SPECTATOR) { + PMove.PM_FlyMove(false); + PM_SnapPosition(); + return; + } + + if (PMove.pm.s.pm_type >= Defines.PM_DEAD) { + PMove.pm.cmd.forwardmove = 0; + PMove.pm.cmd.sidemove = 0; + PMove.pm.cmd.upmove = 0; + } + + if (PMove.pm.s.pm_type == Defines.PM_FREEZE) + return; // no movement at all + + // set mins, maxs, and viewheight + PMove.PM_CheckDuck(); + + if (PMove.pm.snapinitial) + PM_InitialSnapPosition(); + + // set groundentity, watertype, and waterlevel + PMove.PM_CatagorizePosition(); + + if (PMove.pm.s.pm_type == Defines.PM_DEAD) + PMove.PM_DeadMove(); + + PMove.PM_CheckSpecialMovement(); + + // drop timing counter + if (PMove.pm.s.pm_time != 0) { + int msec; + + // TOD o bugfix cwei + msec = PMove.pm.cmd.msec >>> 3; + if (msec == 0) + msec = 1; + if (msec >= (PMove.pm.s.pm_time & 0xFF)) { + PMove.pm.s.pm_flags &= ~(pmove_t.PMF_TIME_WATERJUMP + | pmove_t.PMF_TIME_LAND | pmove_t.PMF_TIME_TELEPORT); + PMove.pm.s.pm_time = 0; + } else + PMove.pm.s.pm_time = (byte) ((PMove.pm.s.pm_time & 0xFF) - msec); + } + + if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_TELEPORT) != 0) { // teleport + // pause + // stays + // exactly + // in + // place + } else if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_WATERJUMP) != 0) { // waterjump + // has + // no + // control, + // but + // falls + PMove.pml.velocity[2] -= PMove.pm.s.gravity * PMove.pml.frametime; + if (PMove.pml.velocity[2] < 0) { // cancel as soon as we are falling + // down again + PMove.pm.s.pm_flags &= ~(pmove_t.PMF_TIME_WATERJUMP + | pmove_t.PMF_TIME_LAND | pmove_t.PMF_TIME_TELEPORT); + PMove.pm.s.pm_time = 0; + } + + PMove.PM_StepSlideMove(); + } else { + PMove.PM_CheckJump(); + + PMove.PM_Friction(); + + if (PMove.pm.waterlevel >= 2) + PMove.PM_WaterMove(); + else { + float[] angles = { 0, 0, 0 }; + + Math3D.VectorCopy(PMove.pm.viewangles, angles); + if (angles[Defines.PITCH] > 180) + angles[Defines.PITCH] = angles[Defines.PITCH] - 360; + angles[Defines.PITCH] /= 3; + + Math3D.AngleVectors(angles, PMove.pml.forward, PMove.pml.right, + PMove.pml.up); + + PMove.PM_AirMove(); + } + } + + // set groundentity, watertype, and waterlevel for final spot + PMove.PM_CatagorizePosition(); + + PM_SnapPosition(); + } +}
\ No newline at end of file diff --git a/src/jake2/qcommon/Q2DataDialog.java b/src/jake2/qcommon/Q2DataDialog.java index cb7dc62..d139000 100644 --- a/src/jake2/qcommon/Q2DataDialog.java +++ b/src/jake2/qcommon/Q2DataDialog.java @@ -1,427 +1,427 @@ -/*
- * Q2DataDialog.java
- *
- * Created on 17. September 2004, 20:13
- */
-
-package jake2.qcommon;
-
-import java.awt.*;
-import java.io.*;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.Enumeration;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-import javax.swing.*;
-
-/**
- *
- * @author hoz
- */
-public class Q2DataDialog extends javax.swing.JDialog {
-
- /** Creates new form Q2DataDialog */
- public Q2DataDialog() {
- super();
- initComponents();
-
- DisplayMode mode = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode();
- int x = (mode.getWidth() - getWidth()) / 2;
- int y = (mode.getHeight() - getHeight()) / 2;
- setLocation(x, y);
- dir = System.getProperty("user.home") + "/jake2";
- jTextField1.setText(dir);
- }
-
- /** This method is called from within the constructor to
- * initialize the form.
- * WARNING: Do NOT modify this code. The content of this method is
- * always regenerated by the Form Editor.
- */
- private void initComponents() {//GEN-BEGIN:initComponents
- java.awt.GridBagConstraints gridBagConstraints;
-
- choosePanel = new javax.swing.JPanel();
- statusPanel = new JPanel();
- status = new JLabel("initializing Jake2...");
- jTextField1 = new javax.swing.JTextField();
- changeButton = new javax.swing.JButton();
- installButton = new javax.swing.JButton();
- exitButton = new javax.swing.JButton();
- okButton = new javax.swing.JButton();
-
- setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
- setTitle("Jake2 - Bytonic Software");
-
- setResizable(false);
- addWindowListener(new java.awt.event.WindowAdapter() {
- public void windowClosing(java.awt.event.WindowEvent evt) {
- formWindowClosing(evt);
- }
- });
-
- choosePanel.setLayout(new java.awt.GridBagLayout());
-
- choosePanel.setMaximumSize(new java.awt.Dimension(400, 100));
- choosePanel.setMinimumSize(new java.awt.Dimension(400, 100));
- choosePanel.setPreferredSize(new java.awt.Dimension(400, 100));
- jTextField1.setPreferredSize(null);
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 0;
- gridBagConstraints.gridwidth = 2;
- gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.weightx = 1.0;
- choosePanel.add(jTextField1, gridBagConstraints);
-
- changeButton.setText("change");
- changeButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- changeButtonActionPerformed(evt);
- }
- });
-
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 2;
- gridBagConstraints.gridy = 0;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
- choosePanel.add(changeButton, gridBagConstraints);
-
- installButton.setText("Install");
- installButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- installButtonActionPerformed(evt);
- }
- });
-
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 1;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
- choosePanel.add(installButton, gridBagConstraints);
-
- exitButton.setText("Exit");
- exitButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- exitButtonActionPerformed(evt);
- }
- });
-
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 1;
- gridBagConstraints.gridy = 1;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- choosePanel.add(exitButton, gridBagConstraints);
-
- okButton.setText("OK");
- okButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- okButtonActionPerformed(evt);
- }
- });
-
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 2;
- gridBagConstraints.gridy = 1;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
- choosePanel.add(okButton, gridBagConstraints);
-
- //getContentPane().add(choosePanel, java.awt.BorderLayout.SOUTH);
-
- Jake2Canvas c = new Jake2Canvas();
- getContentPane().add(c, BorderLayout.CENTER);
-
- statusPanel.setLayout(new java.awt.GridBagLayout());
- statusPanel.setMaximumSize(new java.awt.Dimension(400, 100));
- statusPanel.setMinimumSize(new java.awt.Dimension(400, 100));
- statusPanel.setPreferredSize(new java.awt.Dimension(400, 100));
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 0;
- gridBagConstraints.gridwidth = 1;
- gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.weightx = 1.0;
- statusPanel.add(status, gridBagConstraints);
- getContentPane().add(statusPanel, java.awt.BorderLayout.SOUTH);
-
- installPanel = new InstallPanel(this);
-
- pack();
- }//GEN-END:initComponents
-
-
- private void installButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_installButtonActionPerformed
- dir = jTextField1.getText();
- showInstallPanel();
- installPanel.destDir = dir;
-
- dir += "/baseq2";
- jTextField1.setText(dir);
-
- new Thread(installPanel).start();
- }//GEN-LAST:event_installButtonActionPerformed
-
- private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitButtonActionPerformed
- System.exit(1);
- dispose();
- }//GEN-LAST:event_exitButtonActionPerformed
-
- private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
-
- dir = jTextField1.getText();
- Cvar.Set("cddir", dir);
- FS.setCDDir();
-
- synchronized(this) {
- notifyAll();
- }
- }//GEN-LAST:event_okButtonActionPerformed
-
- private void changeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_changeButtonActionPerformed
- JFileChooser chooser = new JFileChooser();
- chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- chooser.setDialogType(JFileChooser.CUSTOM_DIALOG);
- chooser.setMultiSelectionEnabled(false);
- chooser.setDialogTitle("choose a valid baseq2 directory");
- chooser.showDialog(this, "OK");
-
- dir = null;
- try {
- dir = chooser.getSelectedFile().getCanonicalPath();
- } catch (IOException e) {}
- jTextField1.setText(dir);
-
- }//GEN-LAST:event_changeButtonActionPerformed
-
- private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
- System.exit(1);
- dispose();
- }//GEN-LAST:event_formWindowClosing
-
- // Variables declaration - do not modify//GEN-BEGIN:variables
- private javax.swing.JButton changeButton;
- private javax.swing.JButton exitButton;
- private javax.swing.JButton installButton;
- private Jake2Canvas canvas;
- private javax.swing.JPanel choosePanel;
- private JPanel statusPanel;
- private InstallPanel installPanel;
- private JLabel status;
- private javax.swing.JTextField jTextField1;
- private javax.swing.JButton okButton;
- // End of variables declaration//GEN-END:variables
-
- private String dir;
-
- void showChooseDialog() {
- getContentPane().remove(statusPanel);
- getContentPane().remove(installPanel);
- getContentPane().add(choosePanel, BorderLayout.SOUTH);
- validate();
- repaint();
- }
-
- void showStatus() {
- getContentPane().remove(choosePanel);
- getContentPane().add(statusPanel, BorderLayout.SOUTH);
- validate();
- repaint();
- }
-
- void showInstallPanel() {
- getContentPane().remove(choosePanel);
- getContentPane().add(installPanel, BorderLayout.SOUTH);
- validate();
- repaint();
- }
-
- void setStatus(String text) {
- status.setText(text);
- }
-
- void testQ2Data() {
- while (FS.LoadFile("pics/colormap.pcx") == null) {
- showChooseDialog();
-
- try {
- synchronized(this) {
- wait();
- }
- } catch (InterruptedException e) {}
- }
- showStatus();
- repaint();
- }
-
- static class Jake2Canvas extends Canvas {
- private Image image;
- Jake2Canvas() {
- setSize(400, 200);
- image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/splash.png"));
- while (!Toolkit.getDefaultToolkit().prepareImage(image, -1, -1, null)) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {}
- }
- }
-
-
- /* (non-Javadoc)
- * @see java.awt.Component#paint(java.awt.Graphics)
- */
- public void paint(Graphics g) {
- g.drawImage(image, 0, 0, null);
- }
-
- }
-
- static class InstallPanel extends JPanel implements Runnable {
-
- static final String[] locs = {
- "ftp://ftp.fu-berlin.de/pc/msdos/games/idgames/idstuff/quake2/q2-314-demo-x86.exe",
- "ftp://ftp.demon.co.uk/pub/mirrors/idsoftware/quake2/q2-314-demo-x86.exe",
- "ftp://ftp.fragzone.se/pub/spel/quake2/q2-314-demo-x86.exe",
- "ftp://ftp.idsoftware.com/idstuff/quake2/q2-314-demo-x86.exe" };
- static byte[] buf = new byte[8192];
- String destDir;
-
- JProgressBar progress = new JProgressBar();
- JLabel label = new JLabel("test");
- Q2DataDialog parent;
-
- public InstallPanel(Q2DataDialog d) {
- initComponents();
- parent = d;
- }
-
- void initComponents() {
- progress.setMinimum(0);
- progress.setMaximum(100);
- setLayout(new GridBagLayout());
- GridBagConstraints gridBagConstraints = new GridBagConstraints();
-
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 0;
- gridBagConstraints.gridwidth = 1;
- gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.weightx = 1.0;
- gridBagConstraints.anchor = GridBagConstraints.SOUTH;
- add(label, gridBagConstraints);
- gridBagConstraints.gridy = 1;
- gridBagConstraints.anchor = GridBagConstraints.NORTH;
- add(progress, gridBagConstraints);
- Dimension d = new Dimension(400, 100);
- setMinimumSize(d);
- setMaximumSize(d);
- setPreferredSize(d);
- }
-
- public void run() {
-
- InputStream in = null;
- OutputStream out = null;
- File outFile = null;
-
- label.setText("downloading...");
-
- File dir = null;
- try {
- dir = new File(destDir);
- dir.mkdirs();
- }
- catch (Exception e) {}
- try {
- if (!dir.isDirectory() || !dir.canWrite()) return;
- }
- catch (Exception e) {
- return;
- }
-
- for (int i = 0; i < locs.length; i++) {
- try {
- URL url = new URL(locs[i]);
- URLConnection conn = url.openConnection();
- int length = conn.getContentLength();
- progress.setMaximum(length / 1024);
-
- in = conn.getInputStream();
-
- outFile = File.createTempFile("Jake2Data", ".zip");
- outFile.deleteOnExit();
- out = new FileOutputStream(outFile);
-
- copyStream(in, out);
- break;
- } catch (Exception e) {}
- }
- try {
- installData(outFile.getCanonicalPath());
- } catch (Exception e) {}
-
-
- try {
- if (outFile != null) outFile.delete();
- } catch (Exception e) {}
-
- parent.showChooseDialog();
- parent.okButtonActionPerformed(null);
- }
-
-
- void installData(String filename) {
- try {
- ZipFile f = new ZipFile(filename);
- Enumeration e = f.entries();
- while (e.hasMoreElements()) {
- ZipEntry entry = (ZipEntry)e.nextElement();
- String name = entry.getName();
- int i;
- if ((i = name.indexOf("/baseq2")) > -1 && name.indexOf(".dll") == -1) {
- name = destDir + name.substring(i);
- File outFile = new File(name);
- if (entry.isDirectory()) {
- outFile.mkdirs();
- } else {
- label.setText("installing " + outFile.getName());
- progress.setMaximum((int)entry.getSize()/1024);
- progress.setValue(0);
- outFile.getParentFile().mkdirs();
- OutputStream out = new FileOutputStream(outFile);
- InputStream in = f.getInputStream(entry);
- copyStream(in, out);
- }
- }
- }
- } catch (Exception e) {}
- }
-
- void copyStream(InputStream in, OutputStream out) {
- try {
- int c = 0;
- int l;
- while ((l = in.read(buf)) > 0) {
- out.write(buf, 0, l);
- c += l;
- progress.setValue(c / 1024);
- }
- } catch (Exception e) {}
-
- try {
- in.close();
- } catch (Exception e) {}
- try {
- out.close();
- } catch (Exception e) {}
- }
- }
-
-}
+/* + * Q2DataDialog.java + * + * Created on 17. September 2004, 20:13 + */ + +package jake2.qcommon; + +import java.awt.*; +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import javax.swing.*; + +/** + * + * @author hoz + */ +public class Q2DataDialog extends javax.swing.JDialog { + + /** Creates new form Q2DataDialog */ + public Q2DataDialog() { + super(); + initComponents(); + + DisplayMode mode = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode(); + int x = (mode.getWidth() - getWidth()) / 2; + int y = (mode.getHeight() - getHeight()) / 2; + setLocation(x, y); + dir = System.getProperty("user.home") + "/jake2"; + jTextField1.setText(dir); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + private void initComponents() {//GEN-BEGIN:initComponents + java.awt.GridBagConstraints gridBagConstraints; + + choosePanel = new javax.swing.JPanel(); + statusPanel = new JPanel(); + status = new JLabel("initializing Jake2..."); + jTextField1 = new javax.swing.JTextField(); + changeButton = new javax.swing.JButton(); + installButton = new javax.swing.JButton(); + exitButton = new javax.swing.JButton(); + okButton = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); + setTitle("Jake2 - Bytonic Software"); + + setResizable(false); + addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent evt) { + formWindowClosing(evt); + } + }); + + choosePanel.setLayout(new java.awt.GridBagLayout()); + + choosePanel.setMaximumSize(new java.awt.Dimension(400, 100)); + choosePanel.setMinimumSize(new java.awt.Dimension(400, 100)); + choosePanel.setPreferredSize(new java.awt.Dimension(400, 100)); + jTextField1.setPreferredSize(null); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.weightx = 1.0; + choosePanel.add(jTextField1, gridBagConstraints); + + changeButton.setText("change"); + changeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + changeButtonActionPerformed(evt); + } + }); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 0; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; + choosePanel.add(changeButton, gridBagConstraints); + + installButton.setText("Install"); + installButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + installButtonActionPerformed(evt); + } + }); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + choosePanel.add(installButton, gridBagConstraints); + + exitButton.setText("Exit"); + exitButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + exitButtonActionPerformed(evt); + } + }); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 1; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + choosePanel.add(exitButton, gridBagConstraints); + + okButton.setText("OK"); + okButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okButtonActionPerformed(evt); + } + }); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 1; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; + choosePanel.add(okButton, gridBagConstraints); + + //getContentPane().add(choosePanel, java.awt.BorderLayout.SOUTH); + + Jake2Canvas c = new Jake2Canvas(); + getContentPane().add(c, BorderLayout.CENTER); + + statusPanel.setLayout(new java.awt.GridBagLayout()); + statusPanel.setMaximumSize(new java.awt.Dimension(400, 100)); + statusPanel.setMinimumSize(new java.awt.Dimension(400, 100)); + statusPanel.setPreferredSize(new java.awt.Dimension(400, 100)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridwidth = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.weightx = 1.0; + statusPanel.add(status, gridBagConstraints); + getContentPane().add(statusPanel, java.awt.BorderLayout.SOUTH); + + installPanel = new InstallPanel(this); + + pack(); + }//GEN-END:initComponents + + + private void installButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_installButtonActionPerformed + dir = jTextField1.getText(); + showInstallPanel(); + installPanel.destDir = dir; + + dir += "/baseq2"; + jTextField1.setText(dir); + + new Thread(installPanel).start(); + }//GEN-LAST:event_installButtonActionPerformed + + private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitButtonActionPerformed + System.exit(1); + dispose(); + }//GEN-LAST:event_exitButtonActionPerformed + + private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed + + dir = jTextField1.getText(); + Cvar.Set("cddir", dir); + FS.setCDDir(); + + synchronized(this) { + notifyAll(); + } + }//GEN-LAST:event_okButtonActionPerformed + + private void changeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_changeButtonActionPerformed + JFileChooser chooser = new JFileChooser(); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setDialogType(JFileChooser.CUSTOM_DIALOG); + chooser.setMultiSelectionEnabled(false); + chooser.setDialogTitle("choose a valid baseq2 directory"); + chooser.showDialog(this, "OK"); + + dir = null; + try { + dir = chooser.getSelectedFile().getCanonicalPath(); + } catch (IOException e) {} + jTextField1.setText(dir); + + }//GEN-LAST:event_changeButtonActionPerformed + + private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing + System.exit(1); + dispose(); + }//GEN-LAST:event_formWindowClosing + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton changeButton; + private javax.swing.JButton exitButton; + private javax.swing.JButton installButton; + private Jake2Canvas canvas; + private javax.swing.JPanel choosePanel; + private JPanel statusPanel; + private InstallPanel installPanel; + private JLabel status; + private javax.swing.JTextField jTextField1; + private javax.swing.JButton okButton; + // End of variables declaration//GEN-END:variables + + private String dir; + + void showChooseDialog() { + getContentPane().remove(statusPanel); + getContentPane().remove(installPanel); + getContentPane().add(choosePanel, BorderLayout.SOUTH); + validate(); + repaint(); + } + + void showStatus() { + getContentPane().remove(choosePanel); + getContentPane().add(statusPanel, BorderLayout.SOUTH); + validate(); + repaint(); + } + + void showInstallPanel() { + getContentPane().remove(choosePanel); + getContentPane().add(installPanel, BorderLayout.SOUTH); + validate(); + repaint(); + } + + void setStatus(String text) { + status.setText(text); + } + + void testQ2Data() { + while (FS.LoadFile("pics/colormap.pcx") == null) { + showChooseDialog(); + + try { + synchronized(this) { + wait(); + } + } catch (InterruptedException e) {} + } + showStatus(); + repaint(); + } + + static class Jake2Canvas extends Canvas { + private Image image; + Jake2Canvas() { + setSize(400, 200); + image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/splash.png")); + while (!Toolkit.getDefaultToolkit().prepareImage(image, -1, -1, null)) { + try { + Thread.sleep(50); + } catch (InterruptedException e) {} + } + } + + + /* (non-Javadoc) + * @see java.awt.Component#paint(java.awt.Graphics) + */ + public void paint(Graphics g) { + g.drawImage(image, 0, 0, null); + } + + } + + static class InstallPanel extends JPanel implements Runnable { + + static final String[] locs = { + "ftp://ftp.fu-berlin.de/pc/msdos/games/idgames/idstuff/quake2/q2-314-demo-x86.exe", + "ftp://ftp.demon.co.uk/pub/mirrors/idsoftware/quake2/q2-314-demo-x86.exe", + "ftp://ftp.fragzone.se/pub/spel/quake2/q2-314-demo-x86.exe", + "ftp://ftp.idsoftware.com/idstuff/quake2/q2-314-demo-x86.exe" }; + static byte[] buf = new byte[8192]; + String destDir; + + JProgressBar progress = new JProgressBar(); + JLabel label = new JLabel("test"); + Q2DataDialog parent; + + public InstallPanel(Q2DataDialog d) { + initComponents(); + parent = d; + } + + void initComponents() { + progress.setMinimum(0); + progress.setMaximum(100); + setLayout(new GridBagLayout()); + GridBagConstraints gridBagConstraints = new GridBagConstraints(); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridwidth = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.weightx = 1.0; + gridBagConstraints.anchor = GridBagConstraints.SOUTH; + add(label, gridBagConstraints); + gridBagConstraints.gridy = 1; + gridBagConstraints.anchor = GridBagConstraints.NORTH; + add(progress, gridBagConstraints); + Dimension d = new Dimension(400, 100); + setMinimumSize(d); + setMaximumSize(d); + setPreferredSize(d); + } + + public void run() { + + InputStream in = null; + OutputStream out = null; + File outFile = null; + + label.setText("downloading..."); + + File dir = null; + try { + dir = new File(destDir); + dir.mkdirs(); + } + catch (Exception e) {} + try { + if (!dir.isDirectory() || !dir.canWrite()) return; + } + catch (Exception e) { + return; + } + + for (int i = 0; i < locs.length; i++) { + try { + URL url = new URL(locs[i]); + URLConnection conn = url.openConnection(); + int length = conn.getContentLength(); + progress.setMaximum(length / 1024); + + in = conn.getInputStream(); + + outFile = File.createTempFile("Jake2Data", ".zip"); + outFile.deleteOnExit(); + out = new FileOutputStream(outFile); + + copyStream(in, out); + break; + } catch (Exception e) {} + } + try { + installData(outFile.getCanonicalPath()); + } catch (Exception e) {} + + + try { + if (outFile != null) outFile.delete(); + } catch (Exception e) {} + + parent.showChooseDialog(); + parent.okButtonActionPerformed(null); + } + + + void installData(String filename) { + try { + ZipFile f = new ZipFile(filename); + Enumeration e = f.entries(); + while (e.hasMoreElements()) { + ZipEntry entry = (ZipEntry)e.nextElement(); + String name = entry.getName(); + int i; + if ((i = name.indexOf("/baseq2")) > -1 && name.indexOf(".dll") == -1) { + name = destDir + name.substring(i); + File outFile = new File(name); + if (entry.isDirectory()) { + outFile.mkdirs(); + } else { + label.setText("installing " + outFile.getName()); + progress.setMaximum((int)entry.getSize()/1024); + progress.setValue(0); + outFile.getParentFile().mkdirs(); + OutputStream out = new FileOutputStream(outFile); + InputStream in = f.getInputStream(entry); + copyStream(in, out); + } + } + } + } catch (Exception e) {} + } + + void copyStream(InputStream in, OutputStream out) { + try { + int c = 0; + int l; + while ((l = in.read(buf)) > 0) { + out.write(buf, 0, l); + c += l; + progress.setValue(c / 1024); + } + } catch (Exception e) {} + + try { + in.close(); + } catch (Exception e) {} + try { + out.close(); + } catch (Exception e) {} + } + } + +} diff --git a/src/jake2/qcommon/netchan_t.java b/src/jake2/qcommon/netchan_t.java index 06a283a..77022d6 100644 --- a/src/jake2/qcommon/netchan_t.java +++ b/src/jake2/qcommon/netchan_t.java @@ -1,79 +1,87 @@ /* -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 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. + * + * 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. + * + */ -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. +// Created on 27.11.2003 by RST. +// $Id: netchan_t.java,v 1.2 2004-09-22 19:22:09 salomo Exp $ +package jake2.qcommon; -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. +import jake2.*; -See the GNU General Public License for more details. +public class netchan_t { -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. + public boolean fatal_error; -*/ + // was enum {NS_CLIENT, NS_SERVER} + public int sock; -// Created on 27.11.2003 by RST. -// $Id: netchan_t.java,v 1.1 2004-07-07 19:59:34 hzi Exp $ + public int dropped; // between last packet and previous -package jake2.qcommon; + public int last_received; // for timeouts -import jake2.*; + public int last_sent; // for retransmits -public class netchan_t { + public netadr_t remote_address = new netadr_t(); + + public int qport; // qport value to write when transmitting + + // sequencing variables + public int incoming_sequence; + + public int incoming_acknowledged; + + public int incoming_reliable_acknowledged; // single bit + public int incoming_reliable_sequence; // single bit, maintained local - public boolean fatal_error; + public int outgoing_sequence; - // was enum {NS_CLIENT, NS_SERVER} - public int sock; + public int reliable_sequence; // single bit - public int dropped; // between last packet and previous + public int last_reliable_sequence; // sequence number of last send - public int last_received; // for timeouts - public int last_sent; // for retransmits + // reliable staging and holding areas + public sizebuf_t message = new sizebuf_t(); // writing buffer to send to + // server - public netadr_t remote_address = new netadr_t(); - public int qport; // qport value to write when transmitting + public byte message_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // leave + // space for + // header - // sequencing variables - public int incoming_sequence; - public int incoming_acknowledged; - public int incoming_reliable_acknowledged; // single bit + // message is copied to this buffer when it is first transfered + public int reliable_length; - public int incoming_reliable_sequence; // single bit, maintained local + public byte reliable_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // unpcked + // reliable + // message - public int outgoing_sequence; - public int reliable_sequence; // single bit - public int last_reliable_sequence; // sequence number of last send + //ok. + public void clear() { + sock = dropped = last_received = last_sent = 0; + remote_address = new netadr_t(); + qport = incoming_sequence = incoming_acknowledged = incoming_reliable_acknowledged = incoming_reliable_sequence = outgoing_sequence = reliable_sequence = last_reliable_sequence = 0; + message = new sizebuf_t(); - // reliable staging and holding areas - public sizebuf_t message = new sizebuf_t(); // writing buffer to send to server - public byte message_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // leave space for header + message_buf = new byte[Defines.MAX_MSGLEN - 16]; - // message is copied to this buffer when it is first transfered - int reliable_length; - - byte reliable_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // unpcked reliable message + reliable_length = 0; + reliable_buf = new byte[Defines.MAX_MSGLEN - 16]; + } - //ok. - public void clear() - { - sock=dropped=last_received=last_sent=0; - remote_address = new netadr_t(); - qport = incoming_sequence = incoming_acknowledged = incoming_reliable_acknowledged = incoming_reliable_sequence - = outgoing_sequence = reliable_sequence = last_reliable_sequence =0; - message = new sizebuf_t(); - - message_buf = new byte[Defines.MAX_MSGLEN - 16]; - - reliable_length =0; - reliable_buf = new byte[Defines.MAX_MSGLEN - 16]; - } - -} +}
\ No newline at end of file |