示例#1
0
        public static bool PF_inPHS(float[] p1, float[] p2)
        {
            int leafnum;
            int cluster;
            int area1, area2;

            byte[] mask;
            leafnum = CM.CM_PointLeafnum(p1);
            cluster = CM.CM_LeafCluster(leafnum);
            area1   = CM.CM_LeafArea(leafnum);
            mask    = CM.CM_ClusterPHS(cluster);
            leafnum = CM.CM_PointLeafnum(p2);
            cluster = CM.CM_LeafCluster(leafnum);
            area2   = CM.CM_LeafArea(leafnum);
            if (cluster == -1)
            {
                return(false);
            }
            if (mask != null && (0 == (mask[cluster >> 3] & (1 << (cluster & 7)))))
            {
                return(false);
            }
            if (!CM.CM_AreasConnected(area1, area2))
            {
                return(false);
            }
            return(true);
        }
示例#2
0
        /**
         * PF_inPHS.
         *
         * Also checks portalareas so that doors block sound.
         */
        public static bool PF_inPHS(float[] p1, float[] p2)
        {
            int leafnum;
            int cluster;
            int area1, area2;

            byte[] mask;

            leafnum = CM.CM_PointLeafnum(p1);
            cluster = CM.CM_LeafCluster(leafnum);
            area1   = CM.CM_LeafArea(leafnum);
            mask    = CM.CM_ClusterPHS(cluster);

            leafnum = CM.CM_PointLeafnum(p2);
            cluster = CM.CM_LeafCluster(leafnum);
            area2   = CM.CM_LeafArea(leafnum);

            // quake2 bugfix
            if (cluster == -1)
            {
                return(false);
            }

            if (mask != null && 0 == (mask[cluster >> 3] & (1 << (cluster & 7))))
            {
                return(false);                // more than one bounce away
            }
            if (!CM.CM_AreasConnected(area1, area2))
            {
                return(false);                // a door blocks hearing
            }
            return(true);
        }
示例#3
0
        public static void SV_Multicast(Single[] origin, Int32 to)
        {
            client_t client;

            Byte[]  mask = null;
            Int32   leafnum, cluster;
            Int32   j;
            Boolean reliable;
            Int32   area1, area2;

            reliable = false;
            if (to != Defines.MULTICAST_ALL_R && to != Defines.MULTICAST_ALL)
            {
                leafnum = CM.CM_PointLeafnum(origin);
                area1   = CM.CM_LeafArea(leafnum);
            }
            else
            {
                leafnum = 0;
                area1   = 0;
            }

            if (SV_INIT.svs.demofile != null)
            {
                SZ.Write(SV_INIT.svs.demo_multicast, SV_INIT.sv.multicast.data, SV_INIT.sv.multicast.cursize);
            }
            switch (to)

            {
            case Defines.MULTICAST_ALL_R:
                reliable = true;
                break;

            case Defines.MULTICAST_ALL:
                leafnum = 0;
                mask    = null;
                break;

            case Defines.MULTICAST_PHS_R:
                reliable = true;
                break;

            case Defines.MULTICAST_PHS:
                leafnum = CM.CM_PointLeafnum(origin);
                cluster = CM.CM_LeafCluster(leafnum);
                mask    = CM.CM_ClusterPHS(cluster);
                break;

            case Defines.MULTICAST_PVS_R:
                reliable = true;
                break;

            case Defines.MULTICAST_PVS:
                leafnum = CM.CM_PointLeafnum(origin);
                cluster = CM.CM_LeafCluster(leafnum);
                mask    = CM.CM_ClusterPVS(cluster);
                break;

            default:
                mask = null;
                Com.Error(Defines.ERR_FATAL, "SV_Multicast: bad to:" + to + "\\n");
                break;
            }

            for (j = 0; j < SV_MAIN.maxclients.value; j++)
            {
                client = SV_INIT.svs.clients[j];
                if (client.state == Defines.cs_free || client.state == Defines.cs_zombie)
                {
                    continue;
                }
                if (client.state != Defines.cs_spawned && !reliable)
                {
                    continue;
                }
                if (mask != null)
                {
                    leafnum = CM.CM_PointLeafnum(client.edict.s.origin);
                    cluster = CM.CM_LeafCluster(leafnum);
                    area2   = CM.CM_LeafArea(leafnum);
                    if (!CM.CM_AreasConnected(area1, area2))
                    {
                        continue;
                    }
                    if (cluster == -1)
                    {
                        continue;
                    }
                    if (mask != null && (0 == (mask[cluster >> 3] & (1 << (cluster & 7)))))
                    {
                        continue;
                    }
                }

                if (reliable)
                {
                    SZ.Write(client.netchan.message, SV_INIT.sv.multicast.data, SV_INIT.sv.multicast.cursize);
                }
                else
                {
                    SZ.Write(client.datagram, SV_INIT.sv.multicast.data, SV_INIT.sv.multicast.cursize);
                }
            }

            SZ.Clear(SV_INIT.sv.multicast);
        }
示例#4
0
        public static void SV_LinkEdict(edict_t ent)
        {
            areanode_t node;
            int        num_leafs;
            int        j, k;
            int        area;
            int        topnode = 0;

            if (ent.area.prev != null)
            {
                SV_UnlinkEdict(ent);
            }
            if (ent == GameBase.g_edicts[0])
            {
                return;
            }
            if (!ent.inuse)
            {
                return;
            }
            Math3D.VectorSubtract(ent.maxs, ent.mins, ent.size);
            if (ent.solid == Defines.SOLID_BBOX && 0 == (ent.svflags & Defines.SVF_DEADMONSTER))
            {
                int i = (int)(ent.maxs[0] / 8);
                if (i < 1)
                {
                    i = 1;
                }
                if (i > 31)
                {
                    i = 31;
                }
                j = (int)((-ent.mins[2]) / 8);
                if (j < 1)
                {
                    j = 1;
                }
                if (j > 31)
                {
                    j = 31;
                }
                k = (int)((ent.maxs[2] + 32) / 8);
                if (k < 1)
                {
                    k = 1;
                }
                if (k > 63)
                {
                    k = 63;
                }
                ent.s.solid = (k << 10) | (j << 5) | i;
            }
            else if (ent.solid == Defines.SOLID_BSP)
            {
                ent.s.solid = 31;
            }
            else
            {
                ent.s.solid = 0;
            }
            if (ent.solid == Defines.SOLID_BSP && (ent.s.angles[0] != 0 || ent.s.angles[1] != 0 || ent.s.angles[2] != 0))
            {
                float max, v;
                max = 0;
                for (int i = 0; i < 3; i++)
                {
                    v = Math.Abs(ent.mins[i]);
                    if (v > max)
                    {
                        max = v;
                    }
                    v = Math.Abs(ent.maxs[i]);
                    if (v > max)
                    {
                        max = v;
                    }
                }

                for (int i = 0; i < 3; i++)
                {
                    ent.absmin[i] = ent.s.origin[i] - max;
                    ent.absmax[i] = ent.s.origin[i] + max;
                }
            }
            else
            {
                Math3D.VectorAdd(ent.s.origin, ent.mins, ent.absmin);
                Math3D.VectorAdd(ent.s.origin, ent.maxs, ent.absmax);
            }

            ent.absmin[0]--;
            ent.absmin[1]--;
            ent.absmin[2]--;
            ent.absmax[0]++;
            ent.absmax[1]++;
            ent.absmax[2]++;
            ent.num_clusters = 0;
            ent.areanum      = 0;
            ent.areanum2     = 0;
            int[] iw = new[] { topnode };
            num_leafs = CM.CM_BoxLeafnums(ent.absmin, ent.absmax, SV_WORLD.leafs, SV_WORLD.MAX_TOTAL_ENT_LEAFS, iw);
            topnode   = iw[0];
            for (int i = 0; i < num_leafs; i++)
            {
                SV_WORLD.clusters[i] = CM.CM_LeafCluster(SV_WORLD.leafs[i]);
                area = CM.CM_LeafArea(SV_WORLD.leafs[i]);
                if (area != 0)
                {
                    if (ent.areanum != 0 && ent.areanum != area)
                    {
                        if (ent.areanum2 != 0 && ent.areanum2 != area && SV_INIT.sv.state == Defines.ss_loading)
                        {
                            Com.DPrintf("Object touching 3 areas at " + ent.absmin[0] + " " + ent.absmin[1] + " " + ent.absmin[2] + "\\n");
                        }
                        ent.areanum2 = area;
                    }
                    else
                    {
                        ent.areanum = area;
                    }
                }
            }

            if (num_leafs >= SV_WORLD.MAX_TOTAL_ENT_LEAFS)
            {
                ent.num_clusters = -1;
                ent.headnode     = topnode;
            }
            else
            {
                ent.num_clusters = 0;
                for (int i = 0; i < num_leafs; i++)
                {
                    if (SV_WORLD.clusters[i] == -1)
                    {
                        continue;
                    }
                    for (j = 0; j < i; j++)
                    {
                        if (SV_WORLD.clusters[j] == SV_WORLD.clusters[i])
                        {
                            break;
                        }
                    }
                    if (j == i)
                    {
                        if (ent.num_clusters == Defines.MAX_ENT_CLUSTERS)
                        {
                            ent.num_clusters = -1;
                            ent.headnode     = topnode;
                            break;
                        }

                        ent.clusternums[ent.num_clusters++] = SV_WORLD.clusters[i];
                    }
                }
            }

            if (0 == ent.linkcount)
            {
                Math3D.VectorCopy(ent.s.origin, ent.s.old_origin);
            }

            ent.linkcount++;
            if (ent.solid == Defines.SOLID_NOT)
            {
                return;
            }
            node = SV_WORLD.sv_areanodes[0];
            while (true)
            {
                if (node.axis == -1)
                {
                    break;
                }
                if (ent.absmin[node.axis] > node.dist)
                {
                    node = node.children[0];
                }
                else if (ent.absmax[node.axis] < node.dist)
                {
                    node = node.children[1];
                }
                else
                {
                    break;
                }
            }

            if (ent.solid == Defines.SOLID_TRIGGER)
            {
                InsertLinkBefore(ent.area, node.trigger_edicts);
            }
            else
            {
                InsertLinkBefore(ent.area, node.solid_edicts);
            }
        }
示例#5
0
        public static void SV_BuildClientFrame(client_t client)
        {
            Int32 e, i;

            Single[]       org = new Single[] { 0, 0, 0 };
            edict_t        ent;
            edict_t        clent;
            client_frame_t frame;
            entity_state_t state;
            Int32          l;
            Int32          clientarea, clientcluster;
            Int32          leafnum;
            Int32          c_fullsend;

            Byte[] clientphs;
            Byte[] bitvector;
            clent = client.edict;
            if (clent.client == null)
            {
                return;
            }
            frame          = client.frames[SV_INIT.sv.framenum & Defines.UPDATE_MASK];
            frame.senttime = SV_INIT.svs.realtime;
            for (i = 0; i < 3; i++)
            {
                org[i] = clent.client.ps.pmove.origin[i] * 0.125F + clent.client.ps.viewoffset[i];
            }
            leafnum         = CM.CM_PointLeafnum(org);
            clientarea      = CM.CM_LeafArea(leafnum);
            clientcluster   = CM.CM_LeafCluster(leafnum);
            frame.areabytes = CM.CM_WriteAreaBits(frame.areabits, clientarea);
            frame.ps.Set(clent.client.ps);
            SV_FatPVS(org);
            clientphs          = CM.CM_ClusterPHS(clientcluster);
            frame.num_entities = 0;
            frame.first_entity = SV_INIT.svs.next_client_entities;
            c_fullsend         = 0;
            for (e = 1; e < GameBase.num_edicts; e++)
            {
                ent = GameBase.g_edicts[e];
                if ((ent.svflags & Defines.SVF_NOCLIENT) != 0)
                {
                    continue;
                }
                if (0 == ent.s.modelindex && 0 == ent.s.effects && 0 == ent.s.sound && 0 == ent.s.event_renamed)
                {
                    continue;
                }
                if (ent != clent)
                {
                    if (!CM.CM_AreasConnected(clientarea, ent.areanum))
                    {
                        if (0 == ent.areanum2 || !CM.CM_AreasConnected(clientarea, ent.areanum2))
                        {
                            continue;
                        }
                    }

                    if ((ent.s.renderfx & Defines.RF_BEAM) != 0)
                    {
                        l = ent.clusternums[0];
                        if (0 == (clientphs[l >> 3] & (1 << (l & 7))))
                        {
                            continue;
                        }
                    }
                    else
                    {
                        if (ent.s.sound == 0)
                        {
                            bitvector = SV_ENTS.fatpvs;
                        }
                        else
                        {
                            bitvector = SV_ENTS.fatpvs;
                        }
                        if (ent.num_clusters == -1)
                        {
                            if (!CM.CM_HeadnodeVisible(ent.headnode, bitvector))
                            {
                                continue;
                            }
                            c_fullsend++;
                        }
                        else
                        {
                            for (i = 0; i < ent.num_clusters; i++)
                            {
                                l = ent.clusternums[i];
                                if ((bitvector[l >> 3] & (1 << (l & 7))) != 0)
                                {
                                    break;
                                }
                            }

                            if (i == ent.num_clusters)
                            {
                                continue;
                            }
                        }

                        if (ent.s.modelindex == 0)
                        {
                            Single[] delta = new Single[] { 0, 0, 0 };
                            Single   len;
                            Math3D.VectorSubtract(org, ent.s.origin, delta);
                            len = Math3D.VectorLength(delta);
                            if (len > 400)
                            {
                                continue;
                            }
                        }
                    }
                }

                var ix = SV_INIT.svs.next_client_entities % SV_INIT.svs.num_client_entities;
                state = SV_INIT.svs.client_entities[ix];
                if (ent.s.number != e)
                {
                    Com.DPrintf("FIXING ENT.S.NUMBER!!!\\n");
                    ent.s.number = e;
                }

                SV_INIT.svs.client_entities[ix].Set(ent.s);
                if (ent.owner == client.edict)
                {
                    state.solid = 0;
                }
                SV_INIT.svs.next_client_entities++;
                frame.num_entities++;
            }
        }
示例#6
0
        public static void SV_LinkEdict(edict_t ent)
        {
            areanode_t node;
            int        num_leafs;
            int        j, k;
            int        area;
            var        topnode = 0;

            if (ent.area.prev != null)
            {
                SV_WORLD.SV_UnlinkEdict(ent);                 // unlink from old position
            }
            if (ent == GameBase.g_edicts[0])
            {
                return;                 // don't add the world
            }
            if (!ent.inuse)
            {
                return;
            }

            // set the size
            Math3D.VectorSubtract(ent.maxs, ent.mins, ent.size);

            // encode the size into the entity_state for client prediction
            if (ent.solid == Defines.SOLID_BBOX && 0 == (ent.svflags & Defines.SVF_DEADMONSTER))
            {
                // assume that x/y are equal and symetric
                var i = (int)(ent.maxs[0] / 8);

                if (i < 1)
                {
                    i = 1;
                }

                if (i > 31)
                {
                    i = 31;
                }

                // z is not symetric
                j = (int)(-ent.mins[2] / 8);

                if (j < 1)
                {
                    j = 1;
                }

                if (j > 31)
                {
                    j = 31;
                }

                // and z maxs can be negative...
                k = (int)((ent.maxs[2] + 32) / 8);

                if (k < 1)
                {
                    k = 1;
                }

                if (k > 63)
                {
                    k = 63;
                }

                ent.s.solid = (k << 10) | (j << 5) | i;
            }
            else if (ent.solid == Defines.SOLID_BSP)
            {
                ent.s.solid = 31;                 // a solid_bbox will never create this value
            }
            else
            {
                ent.s.solid = 0;
            }

            // set the abs box
            if (ent.solid == Defines.SOLID_BSP && (ent.s.angles[0] != 0 || ent.s.angles[1] != 0 || ent.s.angles[2] != 0))
            {
                // expand for rotation
                float max, v;
                max = 0;

                for (var i = 0; i < 3; i++)
                {
                    v = Math.Abs(ent.mins[i]);

                    if (v > max)
                    {
                        max = v;
                    }

                    v = Math.Abs(ent.maxs[i]);

                    if (v > max)
                    {
                        max = v;
                    }
                }

                for (var i = 0; i < 3; i++)
                {
                    ent.absmin[i] = ent.s.origin[i] - max;
                    ent.absmax[i] = ent.s.origin[i] + max;
                }
            }
            else
            {
                // normal
                Math3D.VectorAdd(ent.s.origin, ent.mins, ent.absmin);
                Math3D.VectorAdd(ent.s.origin, ent.maxs, ent.absmax);
            }

            // because movement is clipped an epsilon away from an actual edge,
            // we must fully check even when bounding boxes don't quite touch
            ent.absmin[0]--;
            ent.absmin[1]--;
            ent.absmin[2]--;
            ent.absmax[0]++;
            ent.absmax[1]++;
            ent.absmax[2]++;

            // link to PVS leafs
            ent.num_clusters = 0;
            ent.areanum      = 0;
            ent.areanum2     = 0;

            // get all leafs, including solids
            int[] iw = { topnode };
            num_leafs = CM.CM_BoxLeafnums(ent.absmin, ent.absmax, SV_WORLD.leafs, SV_WORLD.MAX_TOTAL_ENT_LEAFS, iw);
            topnode   = iw[0];

            // set areas
            for (var i = 0; i < num_leafs; i++)
            {
                SV_WORLD.clusters[i] = CM.CM_LeafCluster(SV_WORLD.leafs[i]);
                area = CM.CM_LeafArea(SV_WORLD.leafs[i]);

                if (area != 0)
                {
                    // doors may legally straggle two areas,
                    // but nothing should evern need more than that
                    if (ent.areanum != 0 && ent.areanum != area)
                    {
                        if (ent.areanum2 != 0 && ent.areanum2 != area && SV_INIT.sv.state == Defines.ss_loading)
                        {
                            Com.DPrintf("Object touching 3 areas at " + ent.absmin[0] + " " + ent.absmin[1] + " " + ent.absmin[2] + "\n");
                        }

                        ent.areanum2 = area;
                    }
                    else
                    {
                        ent.areanum = area;
                    }
                }
            }

            if (num_leafs >= SV_WORLD.MAX_TOTAL_ENT_LEAFS)
            {
                // assume we missed some leafs, and mark by headnode
                ent.num_clusters = -1;
                ent.headnode     = topnode;
            }
            else
            {
                ent.num_clusters = 0;

                for (var i = 0; i < num_leafs; i++)
                {
                    if (SV_WORLD.clusters[i] == -1)
                    {
                        continue;                         // not a visible leaf
                    }
                    for (j = 0; j < i; j++)
                    {
                        if (SV_WORLD.clusters[j] == SV_WORLD.clusters[i])
                        {
                            break;
                        }
                    }

                    if (j == i)
                    {
                        if (ent.num_clusters == Defines.MAX_ENT_CLUSTERS)
                        {
                            // assume we missed some leafs, and mark by headnode
                            ent.num_clusters = -1;
                            ent.headnode     = topnode;

                            break;
                        }

                        ent.clusternums[ent.num_clusters++] = SV_WORLD.clusters[i];
                    }
                }
            }

            // if first time, make sure old_origin is valid
            if (0 == ent.linkcount)
            {
                Math3D.VectorCopy(ent.s.origin, ent.s.old_origin);
            }

            ent.linkcount++;

            if (ent.solid == Defines.SOLID_NOT)
            {
                return;
            }

            // find the first node that the ent's box crosses
            node = SV_WORLD.sv_areanodes[0];

            while (true)
            {
                if (node.axis == -1)
                {
                    break;
                }

                if (ent.absmin[node.axis] > node.dist)
                {
                    node = node.children[0];
                }
                else if (ent.absmax[node.axis] < node.dist)
                {
                    node = node.children[1];
                }
                else
                {
                    break;                     // crosses the node
                }
            }

            // link it in
            if (ent.solid == Defines.SOLID_TRIGGER)
            {
                SV_WORLD.InsertLinkBefore(ent.area, node.trigger_edicts);
            }
            else
            {
                SV_WORLD.InsertLinkBefore(ent.area, node.solid_edicts);
            }
        }
示例#7
0
        /**
         * Decides which entities are going to be visible to the client, and copies
         * off the playerstat and areabits.
         */
        public static void SV_BuildClientFrame(client_t client)
        {
            int e, i;

            float[]        org = { 0, 0, 0 };
            edict_t        ent;
            edict_t        clent;
            client_frame_t frame;
            entity_state_t state;
            int            l;
            int            clientarea, clientcluster;
            int            leafnum;
            int            c_fullsend;

            byte[] clientphs;
            byte[] bitvector;

            clent = client.edict;

            if (clent.client == null)
            {
                return;                 // not in game yet
            }
            // this is the frame we are creating
            frame = client.frames[SV_INIT.sv.framenum & Defines.UPDATE_MASK];

            frame.senttime = SV_INIT.svs.realtime;             // save it for ping calc later

            // find the client's PVS
            for (i = 0; i < 3; i++)
            {
                org[i] = clent.client.ps.pmove.origin[i] * 0.125f + clent.client.ps.viewoffset[i];
            }

            leafnum       = CM.CM_PointLeafnum(org);
            clientarea    = CM.CM_LeafArea(leafnum);
            clientcluster = CM.CM_LeafCluster(leafnum);

            // calculate the visible areas
            frame.areabytes = CM.CM_WriteAreaBits(frame.areabits, clientarea);

            // grab the current player_state_t
            frame.ps.set(clent.client.ps);

            SV_ENTS.SV_FatPVS(org);
            clientphs = CM.CM_ClusterPHS(clientcluster);

            // build up the list of visible entities
            frame.num_entities = 0;
            frame.first_entity = SV_INIT.svs.next_client_entities;

            c_fullsend = 0;

            for (e = 1; e < GameBase.num_edicts; e++)
            {
                ent = GameBase.g_edicts[e];

                // ignore ents without visible models
                if ((ent.svflags & Defines.SVF_NOCLIENT) != 0)
                {
                    continue;
                }

                // ignore ents without visible models unless they have an effect
                if (0 == ent.s.modelindex && 0 == ent.s.effects && 0 == ent.s.sound && 0 == ent.s.@event)
                {
                    continue;
                }

                // ignore if not touching a PV leaf
                // check area
                if (ent != clent)
                {
                    if (!CM.CM_AreasConnected(clientarea, ent.areanum))
                    {
                        // doors can legally straddle two areas, so we may need to check another one
                        if (0 == ent.areanum2 || !CM.CM_AreasConnected(clientarea, ent.areanum2))
                        {
                            continue;                             // blocked by a door
                        }
                    }

                    // beams just check one point for PHS
                    if ((ent.s.renderfx & Defines.RF_BEAM) != 0)
                    {
                        l = ent.clusternums[0];

                        if (0 == (clientphs[l >> 3] & (1 << (l & 7))))
                        {
                            continue;
                        }
                    }
                    else
                    {
                        // FIXME: if an ent has a model and a sound, but isn't
                        // in the PVS, only the PHS, clear the model
                        if (ent.s.sound == 0)
                        {
                            bitvector = SV_ENTS.fatpvs;                             //clientphs;
                        }
                        else
                        {
                            bitvector = SV_ENTS.fatpvs;
                        }

                        if (ent.num_clusters == -1)
                        {
                            // too many leafs for
                            // individual check, go by
                            // headnode
                            if (!CM.CM_HeadnodeVisible(ent.headnode, bitvector))
                            {
                                continue;
                            }

                            c_fullsend++;
                        }
                        else
                        {
                            // check individual leafs
                            for (i = 0; i < ent.num_clusters; i++)
                            {
                                l = ent.clusternums[i];

                                if ((bitvector[l >> 3] & (1 << (l & 7))) != 0)
                                {
                                    break;
                                }
                            }

                            if (i == ent.num_clusters)
                            {
                                continue;                                 // not visible
                            }
                        }

                        if (ent.s.modelindex == 0)
                        {
                            // don't send sounds if they
                            // will be attenuated away
                            float[] delta = { 0, 0, 0 };
                            float   len;

                            Math3D.VectorSubtract(org, ent.s.origin, delta);
                            len = Math3D.VectorLength(delta);

                            if (len > 400)
                            {
                                continue;
                            }
                        }
                    }
                }

                // add it to the circular client_entities array
                var ix = SV_INIT.svs.next_client_entities % SV_INIT.svs.num_client_entities;
                state = SV_INIT.svs.client_entities[ix];

                if (ent.s.number != e)
                {
                    Com.DPrintf("FIXING ENT.S.NUMBER!!!\n");
                    ent.s.number = e;
                }

                //*state = ent.s;
                SV_INIT.svs.client_entities[ix].set(ent.s);

                // don't mark players missiles as solid
                if (ent.owner == client.edict)
                {
                    state.solid = 0;
                }

                SV_INIT.svs.next_client_entities++;
                frame.num_entities++;
            }
        }