engine.logic.Multiplayer.java Source code

Java tutorial

Introduction

Here is the source code for engine.logic.Multiplayer.java

Source

/*
 * Copyright LWJGL. All rights reserved.
 * License terms: http://lwjgl.org/license.php
 */
package engine.logic;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryonet.Client;
import engine.networking.data.NetworkingDataSingleton;
import engine.networking.entity.Player;
import engine.scene.Scene;
import math.Vec3;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.Callback;
import org.lwjgl.system.Platform;
import org.lwjgl.system.macosx.ObjCRuntime;
import singleton.HolderSingleton;

import java.io.File;
import java.io.IOException;

import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.glfw.GLFWNativeCocoa.glfwGetCocoaWindow;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.JNI.invokePPP;
import static org.lwjgl.system.JNI.invokePPV;
import static org.lwjgl.system.JNI.invokePPZ;
import static org.lwjgl.system.MemoryUtil.*;
import static org.lwjgl.system.macosx.ObjCRuntime.sel_getUid;

public class Multiplayer {
    private Client client;
    private NetworkingDataSingleton networkingDataSingleton;

    private Scene scene;
    private InputHandler inputHandler;
    private GLFWErrorCallback errorCallback;
    private GLFWKeyCallback keyCallback;
    private GLFWFramebufferSizeCallback fsCallback;
    private Callback debugProc;

    public static long window;
    public static int WIDTH = 1280;
    public static int HEIGHT = 720;
    private Object lock = new Object();
    private boolean destroyed;

    public Multiplayer(Client client) {
        this.client = client;
        networkingDataSingleton = NetworkingDataSingleton.getInstance();
    }

    public void run() {
        System.setProperty("org.lwjgl.librarypath", new File("frameworks/lwjgl3/native").getAbsolutePath());
        try {
            init();
            winProcLoop();

            synchronized (lock) {
                destroyed = true;
                glfwDestroyWindow(window);
            }
            if (debugProc != null)
                debugProc.free();
            keyCallback.free();
            fsCallback.free();
        } finally {
            glfwTerminate();
            errorCallback.free();
        }
    }

    private void init() {
        glfwSetErrorCallback(errorCallback = GLFWErrorCallback.createPrint(System.err));

        if (!glfwInit())
            throw new IllegalStateException("Unable to initialize GLFW");

        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

        window = glfwCreateWindow(WIDTH, HEIGHT, "Hello World!", NULL, NULL);
        if (window == NULL)
            throw new RuntimeException("Failed to create the GLFW window");

        if (Platform.get() == Platform.MACOSX) {
            System.out.println("OSX detected! Changing to hdpi mode");
            long cocoaWindow = glfwGetCocoaWindow(window);

            long objc_msgSend = ObjCRuntime.getLibrary().getFunctionAddress("objc_msgSend");
            long contentView = invokePPP(objc_msgSend, cocoaWindow, sel_getUid("contentView"));

            invokePPV(objc_msgSend, contentView, sel_getUid("setWantsBestResolutionOpenGLSurface:"), false);

            boolean bool = invokePPZ(objc_msgSend, contentView, sel_getUid("wantsBestResolutionOpenGLSurface"));
            System.out.println("wantsBestResolutionOpenGLSurface = " + bool);
        }

        glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
            public void invoke(long window, int key, int scancode, int action, int mods) {
                if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
                    glfwSetWindowShouldClose(window, true);
            }
        });
        glfwSetFramebufferSizeCallback(window, fsCallback = new GLFWFramebufferSizeCallback() {
            public void invoke(long window, int w, int h) {
                if (w > 0 && h > 0) {
                    WIDTH = w;
                    HEIGHT = h;
                }

                System.out.println("glfwSetFramebufferSizeCallback: newWidth:" + WIDTH + " newHeight:" + HEIGHT);
            }
        });

        GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        glfwSetWindowPos(window, (vidmode.width() - WIDTH) / 2, (vidmode.height() - HEIGHT) / 2);
        glfwShowWindow(window);
    }

    private void renderLoop() {
        glfwMakeContextCurrent(window);

        GL.createCapabilities();

        glfwSwapInterval(0); //disable vsync
        debugProc = GLUtil.setupDebugMessageCallback();

        scene = new Scene();
        inputHandler = new InputHandler(window, scene);

        float deltaTime;
        long lastNanoTime = 0;

        long lastFpsNanoTime = 0;
        int fps = 0;
        long tempTime;

        while (!destroyed) {
            long time = System.nanoTime();
            deltaTime = (float) (time - lastNanoTime) * 1e-9f;
            lastNanoTime = time;

            inputHandler.updateInput(deltaTime);
            scene.update(deltaTime);
            scene.render(deltaTime);
            limitFps(30);

            fps++;
            tempTime = time - lastFpsNanoTime;
            if (tempTime > 1000000000) {
                glfwSetWindowTitle(window,
                        "FPS: " + fps + " Frametime: " + (float) ((tempTime / fps / 10000)) / 100 + "ms");
                lastFpsNanoTime = time;
                fps = 0;
            }

            synchronized (lock) {
                if (!destroyed) {
                    glfwSwapBuffers(window);
                }
            }
        }
    }

    private void winProcLoop() {
        new Thread(() -> {
            renderLoop();
        }).start();

        while (!glfwWindowShouldClose(window)) {
            glfwWaitEvents();
        }

        System.out.println("Shutting down...");
        System.exit(-1);
    }

    private long variableYieldTimeFPS, lastTimeFPS;

    /**
     * An accurate limitFps method that adapts automatically
     * to the system it runs on to provide reliable results.
     *
     * @param fps The desired frame rate, in frames per second
     * @author kappa (On the LWJGL Forums)
     */
    private void limitFps(int fps) {
        if (fps <= 0)
            return;

        long sleepTime = 1000000000 / fps; // nanoseconds to sleep this frame
        // yieldTime + remainder micro & nano seconds if smaller than sleepTime
        long yieldTime = Math.min(sleepTime, variableYieldTimeFPS + sleepTime % (1000 * 1000));
        long overSleep = 0; // time the limitFps goes over by

        try {
            while (true) {
                long t = System.nanoTime() - lastTimeFPS;

                if (t < sleepTime - yieldTime) {
                    Thread.sleep(1);
                } else if (t < sleepTime) {
                    // burn the last few CPU cycles to ensure accuracy
                    Thread.yield();
                } else {
                    overSleep = t - sleepTime;
                    break; // exit while loop
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lastTimeFPS = System.nanoTime() - Math.min(overSleep, sleepTime);

            // auto tune the time limitFps should yield
            if (overSleep > variableYieldTimeFPS) {
                // increase by 200 microseconds (1/5 a ms)
                variableYieldTimeFPS = Math.min(variableYieldTimeFPS + 200 * 1000, sleepTime);
            } else if (overSleep < variableYieldTimeFPS - 200 * 1000) {
                // decrease by 2 microseconds
                variableYieldTimeFPS = Math.max(variableYieldTimeFPS - 2 * 1000, 0);
            }
        }
    }
}