{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreiflz7fwypri2map7nfoqlkhwufjcjk2eculby65ntsroxu3oi3fuq",
    "uri": "at://did:plc:dxjzgxe7cvirxkwfjr2tjspt/app.bsky.feed.post/3mnq4zirmpdf2"
  },
  "path": "/t/zay-es-and-hidden-states/49615#post_4",
  "publishedAt": "2026-06-07T20:45:56.000Z",
  "site": "https://hub.jmonkeyengine.org",
  "tags": [
    "@author",
    "@Override"
  ],
  "textContent": "The reason I asked is because there is already a facility for filtering out entities by a particular component. That’s how Mythruna works. If the entity has a BodyPosition outside of the client’s visible zones, that client can’t see anything about it.\n\nThis uses the ComponentVisibility feature. I guess my bpos stuff is still in the unreleased MOSS libraries so I’ll paste the example here.\n\n\n    /*\n     * $Id$\n     *\n     * Copyright (c) 2021, Simsilica, LLC\n     * All rights reserved.\n     *\n     * Redistribution and use in source and binary forms, with or without\n     * modification, are permitted provided that the following conditions\n     * are met:\n     *\n     * 1. Redistributions of source code must retain the above copyright\n     *    notice, this list of conditions and the following disclaimer.\n     *\n     * 2. Redistributions in binary form must reproduce the above copyright\n     *    notice, this list of conditions and the following disclaimer in\n     *    the documentation and/or other materials provided with the\n     *    distribution.\n     *\n     * 3. Neither the name of the copyright holder nor the names of its\n     *    contributors may be used to endorse or promote products derived\n     *    from this software without specific prior written permission.\n     *\n     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n     * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n     * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n     * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n     * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n     * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n     * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n     * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n     * OF THE POSSIBILITY OF SUCH DAMAGE.\n     */\n\n    package com.simsilica.bpos.net;\n\n    import java.util.*;\n\n    import org.slf4j.*;\n\n    import com.simsilica.es.*;\n    import com.simsilica.es.server.ComponentVisibility;\n    import com.simsilica.ethereal.NetworkStateListener;\n\n    import com.simsilica.bpos.BodyPosition;\n\n    /**\n     *  Used on the server for a specific client connection to limit that client's\n     *  visibility of any entity containing a BodyPosition to just what the\n     *  SimEthereal visibility says they can see.  This is usually added by a\n     *  server-side service during client initialization.\n     *\n     *  @author    Paul Speed\n     */\n    public class BodyVisibility implements ComponentVisibility {\n\n        static Logger log = LoggerFactory.getLogger(BodyVisibility.class);\n\n        private NetworkStateListener netState;\n        private EntityData ed;\n\n        private Set<Long> lastActiveIds;\n\n        private Map<EntityId, BodyPosition> lastValues = new HashMap<>();\n\n        protected BodyVisibility( NetworkStateListener netState, Set<Long> lastActiveIds ) {\n            this.netState = netState;\n            this.lastActiveIds = lastActiveIds;\n        }\n\n        public BodyVisibility( NetworkStateListener netState ) {\n            this(netState, null);\n        }\n\n        @Override\n        public Class<? extends EntityComponent> getComponentType() {\n            return BodyPosition.class;\n        }\n\n        @Override\n        public void initialize( EntityData ed ) {\n            this.ed = ed;\n        }\n\n        @Override\n        public <T extends EntityComponent> T getComponent( EntityId entityId, Class<T> type ) {\n            if( log.isTraceEnabled() ) {\n                log.trace(\"getComponent(\" + entityId + \", \" + type + \")\");\n            }\n            //if( !netState.getActiveIds().contains(entityId) ) {\n            //    return null;\n            //}\n            if( !lastValues.containsKey(entityId) ) {\n                return null;\n            }\n            return ed.getComponent(entityId, type);\n        }\n\n        @Override\n        public Set<EntityId> getEntityIds( ComponentFilter filter ) {\n            if( log.isTraceEnabled() ) {\n                log.trace(\"getEntityIds(\" + filter + \")\");\n            }\n            if( filter != null ) {\n                throw new UnsupportedOperationException(\"Filtering + body visibility not yet supported\");\n            }\n\n            /*Set<Long> active = netState.getActiveIds();\n            log.info(\"active:\" + active);\n\n            Set<EntityId> results = new HashSet<>();\n            for( Long l : active ) {\n                results.add(new EntityId(l));\n            }\n\n            return results;*/\n            return lastValues.keySet();\n        }\n\n        public boolean collectChanges( Queue<EntityChange> updates ) {\n            Set<Long> active = netState.getActiveIds();\n            boolean changed = false;\n            if( log.isTraceEnabled() ) {\n                log.trace(\"active:\" + active);\n                log.trace(\"updates before:\" + updates);\n            }\n\n            // Remove any BodyPosition updates that don't belong to the active\n            // set\n            for( Iterator<EntityChange> it = updates.iterator(); it.hasNext(); ) {\n                EntityChange change = it.next();\n                if( change.getComponentType() == BodyPosition.class\n                    && !active.contains(change.getEntityId().getId()) ) {\n                    if( log.isTraceEnabled() ) {\n                        log.trace(\"removing irrelevant change:\" + change);\n                    }\n                    it.remove();\n                }\n            }\n\n            // First process the removals\n            for( Iterator<EntityId> it = lastValues.keySet().iterator(); it.hasNext(); ) {\n                EntityId id = it.next();\n                if( active.contains(id.getId()) ) {\n                    continue;\n                }\n                if( log.isTraceEnabled() ) {\n                    log.trace(\"removing:\" + id);\n                }\n                updates.add(new EntityChange(id, BodyPosition.class));\n                it.remove();\n                changed = true;\n            }\n\n            // Now the adds\n            for( Long l : active ) {\n                EntityId id = new EntityId(l);\n                if( lastValues.containsKey(id) ) {\n                    continue;\n                }\n                if( log.isTraceEnabled() ) {\n                    log.trace(\"adding:\" + id);\n                }\n                BodyPosition pos = ed.getComponent(id, BodyPosition.class);\n                lastValues.put(id, pos);\n                updates.add(new EntityChange(id, pos));\n                changed = true;\n            }\n\n            if( changed ) {\n                if( log.isTraceEnabled() ) {\n                    log.trace(\"done collectChanges() \" + active);\n                }\n            }\n\n            return changed;\n        }\n    }\n\n\nOn the server you just register a ComponentVisibility object with the client-specific hosted entity data.\n\nEdit: rereading the classes, I guess it doesn’t prevent all queries against the entity but will filter the entity out of entity sets that have that component. I’d have to experiment to be 100% sure because my memory says one thing and the javadoc says another.",
  "title": "Zay-ES and hidden states"
}