<commit_before>/*
 * Copyright (c) 2009-2011 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.jme3.network.physicssync;

import com.jme3.app.Application;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.network.connection.Server;
import com.jme3.network.connection.Client;
import com.jme3.network.events.MessageListener;
import com.jme3.network.message.Message;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author normenhansen
 */
public class PhysicsSyncManager implements MessageListener {

    private Server server;
    private Client client;
    float syncFrequency = 0.25f;
    HashMap<Long, Object> syncObjects = new HashMap<Long, Object>();
    double time = 0;
    double offset = Double.MIN_VALUE;
    private double maxDelay = .050;
    float syncTimer = 0;
    List<PhysicsSyncMessage> messageQueue = new LinkedList<PhysicsSyncMessage>();
    Application app;

    public PhysicsSyncManager(Application app, Server server) {
        this.app = app;
        this.server = server;
    }

    public PhysicsSyncManager(Application app, Client client) {
        this.app = app;
        this.client = client;
        client.addMessageListener(this, SyncCharacterMessage.class, SyncRigidBodyMessage.class, RigidBodyControlMessage.class, CharacterControlMessage.class);
    }

    //TODO: run on physics tick..?
    public void update(float tpf) {
        time += tpf;
        if (time < 0) {
            //TODO: overflow
            time = 0;
        }
        if (client != null) {
            for (Iterator<PhysicsSyncMessage> it = messageQueue.iterator(); it.hasNext();) {
                PhysicsSyncMessage message = it.next();
                if (message.delayTime <= 0) {
                    doMessage(message);
                    it.remove();
                } else {
                    message.delayTime -= tpf;
                }
            }
        } else if (server != null) {
            syncTimer += tpf;
            if (syncTimer >= syncFrequency) {
                sendSyncData();
                syncTimer = 0;
            }
        }
    }

    public long addObject(PhysicsCollisionObject object) {
        long id = 0;
        while (syncObjects.containsKey(id)) {
            id++;
        }
        syncObjects.put(id, object);
        return id;
    }

    public void addObject(long id, Object object) {
        syncObjects.put(id, object);
    }

    public void removeObject(Object object) {
        for (Iterator<Entry<Long, Object>> it = syncObjects.entrySet().iterator(); it.hasNext();) {
            Entry<Long, Object> entry = it.next();
            if (entry.getValue() == object) {
                it.remove();
                return;
            }
        }
    }

    public void removeObject(long id) {
        syncObjects.remove(id);
    }

    protected void doMessage(PhysicsSyncMessage message) {
        Object object = syncObjects.get(message.syncId);
        if (object != null) {
            message.applyData(object);
        } else {
            Logger.getLogger(PhysicsSyncManager.class.getName()).log(Level.WARNING, "Cannot find physics object for: ({0}){1}", new Object[]{message.syncId, message});
        }
    }

    protected void delayMessage(PhysicsSyncMessage message) {
        if (offset == Double.MIN_VALUE) {
            offset = this.time - message.time;
            Logger.getLogger(PhysicsSyncManager.class.getName()).log(Level.INFO, "Initial offset {0}", offset);
        }
        double delayTime = (message.time + offset) - time;
        double off = 0;
        if (delayTime > maxDelay) {
            off = -(delayTime - maxDelay);
            Logger.getLogger(PhysicsSyncManager.class.getName()).log(Level.INFO, "Increase offset by {0} due to high delaytime {1}", new Object[]{off, delayTime});
            changeOffset(off);
        } else if (delayTime < -maxDelay) {
            off = -(delayTime - maxDelay);
            changeOffset(off);
            Logger.getLogger(PhysicsSyncManager.class.getName()).log(Level.INFO, "Decrease offset by {0} due to low delaytime {1}", new Object[]{off, delayTime});
        }
        message.delayTime = delayTime + maxDelay + off;
        messageQueue.add(message);<commit_msg>- make maxDelay absolute again<commit_after>/*
 * Copyright (c) 2009-2011 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.jme3.network.physicssync;

import com.jme3.app.Application;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.network.connection.Server;
import com.jme3.network.connection.Client;
import com.jme3.network.events.MessageListener;
import com.jme3.network.message.Message;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author normenhansen
 */
public class PhysicsSyncManager implements MessageListener {

    private Server server;
    private Client client;
    float syncFrequency = 0.25f;
    HashMap<Long, Object> syncObjects = new HashMap<Long, Object>();
    double time = 0;
    double offset = Double.MIN_VALUE;
    private double maxDelay = 0.250;
    float syncTimer = 0;
    List<PhysicsSyncMessage> messageQueue = new LinkedList<PhysicsSyncMessage>();
    Application app;

    public PhysicsSyncManager(Application app, Server server) {
        this.app = app;
        this.server = server;
    }

    public PhysicsSyncManager(Application app, Client client) {
        this.app = app;
        this.client = client;
        client.addMessageListener(this, SyncCharacterMessage.class, SyncRigidBodyMessage.class, RigidBodyControlMessage.class, CharacterControlMessage.class);
    }

    //TODO: run on physics tick..?
    public void update(float tpf) {
        time += tpf;
        if (time < 0) {
            //TODO: overflow
            time = 0;
        }
        if (client != null) {
            for (Iterator<PhysicsSyncMessage> it = messageQueue.iterator(); it.hasNext();) {
                PhysicsSyncMessage message = it.next();
                if (message.delayTime <= 0) {
                    doMessage(message);
                    it.remove();
                } else {
                    message.delayTime -= tpf;
                }
            }
        } else if (server != null) {
            syncTimer += tpf;
            if (syncTimer >= syncFrequency) {
                sendSyncData();
                syncTimer = 0;
            }
        }
    }

    public long addObject(PhysicsCollisionObject object) {
        long id = 0;
        while (syncObjects.containsKey(id)) {
            id++;
        }
        syncObjects.put(id, object);
        return id;
    }

    public void addObject(long id, Object object) {
        syncObjects.put(id, object);
    }

    public void removeObject(Object object) {
        for (Iterator<Entry<Long, Object>> it = syncObjects.entrySet().iterator(); it.hasNext();) {
            Entry<Long, Object> entry = it.next();
            if (entry.getValue() == object) {
                it.remove();
                return;
            }
        }
    }

    public void removeObject(long id) {
        syncObjects.remove(id);
    }

    protected void doMessage(PhysicsSyncMessage message) {
        Object object = syncObjects.get(message.syncId);
        if (object != null) {
            message.applyData(object);
        } else {
            Logger.getLogger(PhysicsSyncManager.class.getName()).log(Level.WARNING, "Cannot find physics object for: ({0}){1}", new Object[]{message.syncId, message});
        }
    }

    protected void delayMessage(PhysicsSyncMessage message) {
        if (offset == Double.MIN_VALUE) {
            offset = this.time - message.time;
            Logger.getLogger(PhysicsSyncManager.class.getName()).log(Level.INFO, "Initial offset {0}", offset);
        }
        double delayTime = (message.time + offset) - time;
        double off = 0;
        if (delayTime > maxDelay) {
            off -= delayTime - maxDelay;
            Logger.getLogger(PhysicsSyncManager.class.getName()).log(Level.INFO, "Decrease offset by {0} due to high delaytime {1}", new Object[]{off, delayTime});
            changeOffset(off);
        } else if (delayTime < 0) {
            off = -delayTime;
            changeOffset(off);
            Logger.getLogger(PhysicsSyncManager.class.getName()).log(Level.INFO, "Increase offset by {0} due to low delaytime {1}", new Object[]{off, delayTime});
        }
        message.delayTime = delayTime + off;
        messageQueue.add(message);
{'fraction_non_alphanumeric': 0.09666226040978189, 'fraction_numerical': 0.006444150693985459, 'mean_word_length': 2.6793313069908815, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2888499', 'n_tokens_mistral': 3370, 'n_tokens_neox': 3174, 'n_words': 1013}