package electrosphere.engine;

import java.lang.management.ManagementFactory;

import java.util.ArrayList;

import org.joml.Matrix4d;
import org.joml.Vector3f;

import electrosphere.audio.AudioEngine;
import electrosphere.audio.VirtualAudioSourceManager;
import electrosphere.audio.collision.HitboxAudioService;
import electrosphere.audio.movement.MovementAudioService;
import electrosphere.auth.AuthenticationManager;
import electrosphere.client.block.ClientBlockManager;
import electrosphere.client.block.cells.BlockTextureAtlas;
import electrosphere.client.block.cells.ClientBlockCellManager;
import electrosphere.client.chemistry.ClientChemistryCollisionCallback;
import electrosphere.client.entity.character.ClientCharacterManager;
import electrosphere.client.entity.particle.ParticleService;
import electrosphere.client.fluid.cells.FluidCellManager;
import electrosphere.client.fluid.manager.ClientFluidManager;
import electrosphere.client.player.ClientPlayerData;
import electrosphere.client.scene.ClientSceneWrapper;
import electrosphere.client.scene.ClientWorldData;
import electrosphere.client.sim.ClientSimulation;
import electrosphere.client.terrain.cells.ClientDrawCellManager;
import electrosphere.client.terrain.cells.VoxelTextureAtlas;
import electrosphere.client.terrain.foliage.FoliageCellManager;
import electrosphere.client.terrain.manager.ClientTerrainManager;
import electrosphere.client.ui.menu.WindowUtils;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.CollisionWorldData;
import electrosphere.controls.CameraHandler;
import electrosphere.controls.ControlCallback;
import electrosphere.controls.ControlHandler;
import electrosphere.controls.MouseCallback;
import electrosphere.controls.ScrollCallback;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.engine.assetmanager.AssetManager;
import electrosphere.engine.loadingthreads.InitialAssetLoading;
import electrosphere.engine.os.fs.FileWatcherService;
import electrosphere.engine.profiler.Profiler;
import electrosphere.engine.service.ServiceManager;
import electrosphere.engine.signal.SignalSystem;
import electrosphere.engine.signal.sync.MainThreadSignalService;
import electrosphere.engine.threads.ThreadManager;
import electrosphere.engine.time.Timekeeper;
import electrosphere.entity.Entity;
import electrosphere.entity.scene.Scene;
import electrosphere.game.config.UserSettings;
import electrosphere.game.data.common.CommonEntityType;
import electrosphere.game.data.particle.ParticleDefinition;
import electrosphere.game.data.voxel.VoxelType;
import electrosphere.game.server.structure.virtual.StructureManager;
import electrosphere.game.server.world.MacroData;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.client.ClientNetworking;
import electrosphere.net.config.NetConfig;
import electrosphere.net.monitor.NetMonitor;
import electrosphere.net.server.Server;
import electrosphere.net.server.player.Player;
import electrosphere.net.server.player.PlayerManager;
import electrosphere.net.synchronization.client.ClientSynchronizationManager;
import electrosphere.net.synchronization.server.EntityValueTrackingService;
import electrosphere.net.synchronization.server.ServerSynchronizationManager;
import electrosphere.renderer.RenderUtils;
import electrosphere.renderer.RenderingEngine;
import electrosphere.renderer.actor.instance.InstanceManager;
import electrosphere.renderer.light.PointLight;
import electrosphere.renderer.light.SpotLight;
import electrosphere.renderer.loading.ModelPretransforms;
import electrosphere.renderer.meshgen.FluidChunkModelGeneration;
import electrosphere.renderer.model.Material;
import electrosphere.renderer.shader.ShaderOptionMap;
import electrosphere.renderer.shader.VisualShader;
import electrosphere.renderer.texture.TextureMap;
import electrosphere.renderer.ui.ElementService;
import electrosphere.renderer.ui.elements.ImagePanel;
import electrosphere.renderer.ui.font.FontManager;
import electrosphere.script.ScriptEngine;
import electrosphere.server.ai.AIManager;
import electrosphere.server.datacell.EntityDataCellMapper;
import electrosphere.server.datacell.RealmManager;
import electrosphere.server.db.DatabaseController;
import electrosphere.server.pathfinding.NavMeshManager;
import electrosphere.server.poseactor.PoseModel;
import electrosphere.server.saves.Save;
import electrosphere.server.simulation.MacroSimulation;
import electrosphere.server.simulation.MicroSimulation;
import electrosphere.util.FileUtils;

/**
 * Global values
 */
public class Globals {

    //
    //Process data
    //
    public static String javaPID;

    //
    //Thread manager
    //
    public static ThreadManager threadManager;

    //
    //Service manager
    //
    static ServiceManager serviceManager;

    //
    //Signal system
    //
    public static SignalSystem signalSystem;

    //
    //Top level user settings object
    //
    public static UserSettings userSettings;

    //
    //Timekeeper
    //
    public static Timekeeper timekeeper;
    
    //
    //Rendering Engine
    //
    public static RenderingEngine renderingEngine;
    
    //
    //Audio Engine
    //
    public static AudioEngine audioEngine;
    public static VirtualAudioSourceManager virtualAudioSourceManager;
    public static MovementAudioService movementAudioService;
    public static HitboxAudioService hitboxAudioService;
    
    
    //
    //Core Engine signals
    //
    public static boolean ENGINE_SHUTDOWN_FLAG = false;
    //main debug flag
    //current enables imgui debug menu or not
    public static boolean ENGINE_DEBUG = true;


    //
    //Profiler
    //
    public static Profiler profiler;

    //
    //Garbage Collection
    //
    //set to true to trigger full GC every frame
    //a full GC includes collecting old generations as well -- likely very laggy!!
    public static boolean EXPLICIT_GC = false;
    /**
     * Number of frames to wait before triggering gc again
     */
    public static final int GC_FRAME_FREQUENCY = 15;

    //
    //Engine timing
    //
    public static boolean EXPLICIT_SLEEP = true;
    
    //
    //Client connection to server
    //
    public static ClientNetworking clientConnection;
    public static boolean RUN_DEMO = false;
    public static boolean RUN_CLIENT = true;
    public static boolean RUN_HIDDEN = false; //glfw session will be created with hidden window
    public static boolean RUN_AUDIO = true;
    public static boolean RUN_SCRIPTS = true;
    public static boolean RUN_PHYSICS = true; //toggles whether physics is run or not
    public static boolean RUN_FLUIDS = false; //toggles whether fluid physics is run or not
    public static int clientCharacterID;
    public static NetConfig netConfig = null;
    
    //
    //Server manager thing
    //
    public static Server server;
    public static ServerSynchronizationManager serverSynchronizationManager;
    public static boolean RUN_SERVER = true;

    //
    //Authentication manager
    //
    public static AuthenticationManager authenticationManager;
    
    
    //
    //Controls Handler
    //
    public static ControlHandler controlHandler;
    public static boolean updateCamera = true;
    public static ControlCallback controlCallback = new ControlCallback();
    public static MouseCallback mouseCallback = new MouseCallback();
    public static ScrollCallback scrollCallback = new ScrollCallback();
    
    
    //
    // Game Save stuff
    //
    public static Save currentSave = null;
    
    
    //
    // Game config
    //
    public static electrosphere.game.data.Config gameConfigDefault;
    public static electrosphere.game.data.Config gameConfigCurrent;
    
    //
    // Database stuff
    //
    public static DatabaseController dbController = new DatabaseController();

    //
    //Camera handler stuff
    //
    public static CameraHandler cameraHandler = new CameraHandler();
    
    //
    //Server scene management
    //
    public static RealmManager realmManager;
    public static EntityDataCellMapper entityDataCellMapper;

    //
    //behavior tree tracking service
    //
    public static EntityValueTrackingService entityValueTrackingService;
    
    //
    //Player manager
    //
    public static PlayerManager playerManager;
    public static Player clientPlayer;
    public static String clientUsername;
    public static String clientPassword;
    
    //
    //Generic OpenGL Statements
    //
    public static long window = -1;
    
    
    
    //
    //OpenGL - Other
    //
    
    public static int WINDOW_WIDTH;
    public static int WINDOW_HEIGHT;
    public static boolean WINDOW_DECORATED = true; //used to control whether the window is created with decorations or not (ie for testing)
    public static boolean WINDOW_FULLSCREEN = false; //used to control whether the window is created fullscreen or not (ie for testing)
    
    //title bar dimensions
    public static int WINDOW_TITLE_BAR_HEIGHT = 0;
    
    public static float verticalFOV = 90;
    public static float aspectRatio = 2.0f;
    public static float nearClip = 0.01f;
    
    //matrices for drawing models
    public static Matrix4d viewMatrix = new Matrix4d();
    public static Matrix4d projectionMatrix;
    public static Matrix4d lightDepthMatrix = new Matrix4d();
    
    //locations for shadow map specific variables
    public static int depthMapShaderProgramLoc = 0;
    
    
    
    
    
    
    //
    //OpenGL - Abstracted engine objects
    //
    public static String textureDiffuseDefault;
    public static String textureSpecularDefault;
    public static Material materialDefault;
    
    public static String blackTexture = "Textures/b1.png";
    public static String testingTexture = "Textures/Testing1.png";
    public static String whiteTexture = "Textures/w1.png";
    public static String offWhiteTexture = "Textures/ow1.png";
    
    public static String imagePlaneModelID;
    public static String solidPlaneModelID;
    
    public static ArrayList<PointLight> lightPointListDefault;
    public static SpotLight lightSpotDefault;
    
    public static TextureMap textureMapDefault;
    public static ModelPretransforms modelPretransforms;
    
    public static VisualShader defaultMeshShader;
    public static VisualShader terrainShaderProgram;
    public static VisualShader blockShader;
    
    //
    // Particle stuff
    //
    public static ParticleDefinition particleDefinition;
    public static ParticleService particleService;

    public static ShaderOptionMap shaderOptionMap;

    //manages all loaded fonts
    public static FontManager fontManager;
    
    
    
    //
    //Engine - Main managers/variables
    //

    //manages all models loaded into memory
    public static AssetManager assetManager;
    
    //macro simulation
    public static MacroSimulation macroSimulation;
    public static MacroData macroData;

    //flag to only run a simulation without full client
    public static boolean RUN_SIMULATION_ONLY = false;
    
    //micro simulation
    public static MicroSimulation microSimulation;
    
    //script engine
    public static ScriptEngine scriptEngine;

    //services
    public static MainThreadSignalService mainThreadSignalService;
    
    //client scene management
    public static Scene clientScene;
    public static ClientSceneWrapper clientSceneWrapper;
    public static ClientSimulation clientSimulation;
    public static ClientSynchronizationManager clientSynchronizationManager;

    //instanced actor manager
    public static InstanceManager clientInstanceManager = new InstanceManager();

    //client side foliage manager
    // public static ClientFoliageManager clientFoliageManager;
    public static FoliageCellManager foliageCellManager;

    //client world data
    public static ClientWorldData clientWorldData;
    public static ClientCharacterManager clientCharacterManager = new ClientCharacterManager();
    
    //client gridded manager
    public static ClientTerrainManager clientTerrainManager;
    public static ClientFluidManager clientFluidManager;
    public static ClientBlockManager clientBlockManager;
    
    //client player data
    public static ClientPlayerData clientPlayerData = new ClientPlayerData();
    
    //chunk stuff
    //draw cell manager
    public static ClientDrawCellManager clientDrawCellManager;
    public static VoxelTextureAtlas voxelTextureAtlas = new VoxelTextureAtlas();
    public static ClientBlockCellManager clientBlockCellManager;
    public static BlockTextureAtlas blockTextureAtlas = new BlockTextureAtlas();

    //fluid cell manager
    public static FluidCellManager fluidCellManager;
    
    //navmesh manager
    public static NavMeshManager navMeshManager;
    
    //famous fuckin last words, but temporary solution
    //global arraylist of values for the skybox colors
    //edit(6/1/21):    :upside_down_smile:
    public static ArrayList<Vector3f> skyboxColors;
    
    //thread for loading different game states
    public static InitialAssetLoading initialAssetLoadingThread = new InitialAssetLoading();

    //manager for all widgets currently being drawn to screen
    public static ElementService elementService;
    public static int openInventoriesCount = 0;

    //file service
    public static FileWatcherService fileWatcherService;
    
    //collision world data
    public static CollisionWorldData commonWorldData;
    
    //structure manager
    public static StructureManager structureManager;
    
    
    //the player camera entity
    public static Entity playerCamera;

    //the player in world cursor
    public static Entity playerCursor;
    public static Entity playerBlockCursor;
    
    //the creature the player camera will orbit and will receive controlHandler movementTree updates
    public static Entity playerEntity;
    //the entity for the first person modal (view model)
    public static Entity firstPersonEntity;

    /**
     * The target of the interaction
     */
    public static Entity interactionTarget = null;

    //client current selected voxel type
    public static VoxelType clientSelectedVoxelType = null;
    //the selected type of entity to spawn
    public static CommonEntityType selectedSpawntype = null;
    
    //skybox entity
    public static Entity skybox;
    
    
    //ai manager
    public static AIManager aiManager;

    //drag item state
    public static Entity draggedItem = null;
    public static Object dragSourceInventory = null;
    
    
    
    
    
    //
    //Base engine creation flags
    //
    public static boolean HEADLESS = false;
    
    
    //
    //
    // Renderer flags
    //
    //
    public static boolean RENDER_FLAG_RENDER_SHADOW_MAP = false;
    public static boolean RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = false;
    public static boolean RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = false;
    public static boolean RENDER_FLAG_RENDER_BLACK_BACKGROUND = true;
    public static boolean RENDER_FLAG_RENDER_WHITE_BACKGROUND = false;
    public static boolean RENDER_FLAG_RENDER_UI = true;
    public static boolean RENDER_FLAG_RENDER_UI_BOUNDS = false;



    //
    // Debugging tools
    //
    public static NetMonitor netMonitor;
    
    
    /**
     * Inits globals
     */
    public static void initGlobals(){
        //initialize logging interfaces
        LoggerInterface.initLoggers();
        LoggerInterface.loggerStartup.INFO("Initialize global variables");
        //gets java pid of engine
        if(Globals.javaPID == null){
            Globals.javaPID = ManagementFactory.getRuntimeMXBean().getName();
        }
        //load user settings
        Globals.WINDOW_WIDTH = 1920;
        Globals.WINDOW_HEIGHT = 1080;
        UserSettings.loadUserSettings();
        //timekeeper
        timekeeper = new Timekeeper();
        Globals.threadManager = new ThreadManager();
        Globals.threadManager.init();

        //render flags
        RENDER_FLAG_RENDER_SHADOW_MAP = false;
        RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = false;
        RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = false;
        RENDER_FLAG_RENDER_BLACK_BACKGROUND = true;
        RENDER_FLAG_RENDER_WHITE_BACKGROUND = false;
        RENDER_FLAG_RENDER_UI = true;
        RENDER_FLAG_RENDER_UI_BOUNDS = false;
        //load in default texture map
        textureMapDefault = TextureMap.construct("Textures/default_texture_map.json");
        //load model pretransforms
        modelPretransforms = FileUtils.loadObjectFromAssetPath("Models/modelPretransforms.json", ModelPretransforms.class);
        modelPretransforms.init();
        //load in shader options map
        shaderOptionMap = FileUtils.loadObjectFromAssetPath("Shaders/shaderoptions.json", ShaderOptionMap.class);
        shaderOptionMap.debug();
        //client scene wrapper
        clientScene = new Scene();
        clientSceneWrapper = new ClientSceneWrapper(clientScene, new CollisionEngine(), CollisionEngine.create(new ClientChemistryCollisionCallback()), new CollisionEngine());
        //temporary hold for skybox colors
        skyboxColors = new ArrayList<Vector3f>();
        //load asset manager
        assetManager = new AssetManager();
        //ai manager
        aiManager = new AIManager(0);
        //realm & data cell manager
        realmManager = new RealmManager();
        entityDataCellMapper = new EntityDataCellMapper();
        //nav mesh manager
        navMeshManager = new NavMeshManager();
        //gridded managers
        Globals.clientTerrainManager = new ClientTerrainManager();
        Globals.clientFluidManager = new ClientFluidManager();
        Globals.clientBlockManager = new ClientBlockManager();
        //game config
        gameConfigDefault = electrosphere.game.data.Config.loadDefaultConfig();
        gameConfigCurrent = gameConfigDefault;
        NetConfig.readNetConfig();

        //
        //Values that depend on the loaded config
        Globals.clientSelectedVoxelType = (VoxelType)gameConfigCurrent.getVoxelData().getTypes().toArray()[1];
        //player manager
        playerManager = new PlayerManager();
        //behavior tree tracking service
        entityValueTrackingService = new EntityValueTrackingService();
        //net monitor
        if(Globals.userSettings.getNetRunNetMonitor()){
            netMonitor = new NetMonitor();
        }
        //client synchronization manager
        clientSynchronizationManager = new ClientSynchronizationManager();
        //profiler
        profiler = new Profiler();
        Globals.serverSynchronizationManager = new ServerSynchronizationManager();
        Globals.movementAudioService = new MovementAudioService();
        Globals.hitboxAudioService = new HitboxAudioService();

        //
        //Service manager
        serviceManager = new ServiceManager();
        serviceManager.init();
        //add services here
        Globals.signalSystem = (SignalSystem)serviceManager.registerService(new SignalSystem());
        Globals.elementService = (ElementService)serviceManager.registerService(new ElementService());
        Globals.particleService = (ParticleService)serviceManager.registerService(new ParticleService());
        Globals.scriptEngine = (ScriptEngine)serviceManager.registerService(new ScriptEngine());
        Globals.mainThreadSignalService = (MainThreadSignalService)serviceManager.registerService(new MainThreadSignalService());
        Globals.fileWatcherService = (FileWatcherService)serviceManager.registerService(new FileWatcherService());
        serviceManager.instantiate();
        //
        //End service manager


        //
        //Register all signals
        Globals.signalSystem.registerService(Globals.elementService);
        Globals.signalSystem.registerService(Globals.particleService);
        Globals.signalSystem.registerService(Globals.scriptEngine);
        Globals.signalSystem.registerService(Globals.mainThreadSignalService);
        Globals.signalSystem.registerService(Globals.fileWatcherService);


    }
    
    /**
     * Inits default audio resources
     */
    public static void initDefaultAudioResources(){
        String[] audioToInit = new String[]{
            "/Audio/ambienceWind1SeamlessMono.ogg",
            "/Audio/weapons/swordUnsheath1.ogg",
            "/Audio/weapons/swoosh-03.ogg",
            "/Audio/movement/Equip A.wav",
            "/Audio/weapons/collisions/FleshWeaponHit1.wav",
            "/Audio/weapons/collisions/Massive Punch A.wav",
            "/Audio/weapons/collisions/Massive Punch B.wav",
            "/Audio/weapons/collisions/Massive Punch C.wav",
            "Audio/weapons/collisions/Sword Hit A.wav",
            "Audio/weapons/collisions/Sword Hit B.wav",
            "Audio/weapons/collisions/Sword Hit C.wav",
            "Audio/weapons/collisions/Sword Hit D.wav",
            "Audio/weapons/collisions/Sword Hit E.wav",
            AssetDataStrings.UI_TONE_CONFIRM_PRIMARY,
            AssetDataStrings.UI_TONE_CONFIRM_SECONDARY,
            AssetDataStrings.UI_TONE_CURSOR_PRIMARY,
            AssetDataStrings.UI_TONE_CURSOR_SECONDARY,
            AssetDataStrings.UI_TONE_BACK_PRIMARY,
            AssetDataStrings.UI_TONE_BACK_SECONDARY,
            AssetDataStrings.UI_TONE_ERROR_PRIMARY,
            AssetDataStrings.UI_TONE_ERROR_SECONDARY,
            AssetDataStrings.UI_TONE_BUTTON_TITLE,
            AssetDataStrings.UI_SFX_ITEM_GRAB,
            AssetDataStrings.UI_SFX_ITEM_RELEASE,
            AssetDataStrings.UI_SFX_INVENTORY_OPEN,
            AssetDataStrings.UI_SFX_INVENTORY_CLOSE,
        };
        LoggerInterface.loggerStartup.INFO("Loading default audio resources");
        for(String path : audioToInit){
            Globals.assetManager.addAudioPathToQueue(path);
        }
        Globals.movementAudioService.init();
    }

    /**
     * Texture paths to be loaded when renderer inits
     */
    private static String[] defaultTexturePaths = new String[]{
        "Textures/default_diffuse.png",
        "Textures/default_specular.png",
        "Textures/b1.png",
        "Textures/w1.png",
        "Textures/ow1.png",
        "Textures/ui/WindowBorder.png",
        "Textures/ui/uiOutline1.png",
        AssetDataStrings.UI_ENGINE_LOGO_1,
        AssetDataStrings.UI_FRAME_TEXTURE_DEFAULT_1,
        AssetDataStrings.UI_FRAME_TEXTURE_DEFAULT_2,
        AssetDataStrings.UI_FRAME_TEXTURE_DEFAULT_3,
        "Textures/ui/circle.png",
        "Textures/ui/square.png",
        "Textures/color/transparent_green.png",
        "Textures/color/transparent_magenta.png",
        "Textures/color/transparent_orange.png",
        "Textures/color/transparent_teal.png",
        "Textures/color/transparent_yellow.png",
        "Textures/bloodsplat1.png",
    };

    /**
     * The set of models who should correspond to no pose model
     */
    private static String[] defaultModelsWithNoPose = new String[]{
        AssetDataStrings.POSE_EMPTY,
        AssetDataStrings.UNITSPHERE,
        AssetDataStrings.UNITCYLINDER,
        AssetDataStrings.UNITCUBE,
        AssetDataStrings.MODEL_BLOCK_SINGLE,
    };
    
    /**
     * Inits default graphical resources
     */
    public static void initDefaultGraphicalResources(){
        LoggerInterface.loggerStartup.INFO("Loading default graphical resources");

        //load default textures
        for(String defaultTexturePath: defaultTexturePaths){
            Globals.assetManager.addTexturePathtoQueue(defaultTexturePath);
        }

        //create default material
        materialDefault = new Material();
        materialDefault.set_diffuse("Textures/default_diffuse.png");
        materialDefault.set_specular("Textures/default_specular.png");

        //create font manager
        fontManager = new FontManager();
        fontManager.loadFonts();
        assetManager.registerModelWithPath(RenderUtils.createBitmapCharacter(), AssetDataStrings.BITMAP_CHARACTER_MODEL);
        //particle billboard model
        assetManager.registerModelWithPath(RenderUtils.createParticleModel(), AssetDataStrings.MODEL_PARTICLE);
        //initialize required windows
        WindowUtils.initBaseWindows();
        //init default shaderProgram
        defaultMeshShader = VisualShader.smartAssembleShader(false,true);
        //init terrain shader program
        terrainShaderProgram = VisualShader.loadSpecificShader("/Shaders/entities/terrain2/terrain2.vs", "/Shaders/entities/terrain2/terrain2.fs");
        blockShader = VisualShader.loadSpecificShader("/Shaders/entities/block/block.vs", "/Shaders/entities/block/block.fs");
        //init fluid shader program
        FluidChunkModelGeneration.fluidChunkShaderProgram = VisualShader.loadSpecificShader("/Shaders/entities/fluid2/fluid2.vs", "/Shaders/entities/fluid2/fluid2.fs");
        //init models
        assetManager.registerModelWithPath(RenderUtils.createUnitsphere(), AssetDataStrings.UNITSPHERE);
        assetManager.registerModelWithPath(RenderUtils.createUnitCylinder(), AssetDataStrings.UNITCYLINDER);
        assetManager.registerModelWithPath(RenderUtils.createUnitCube(), AssetDataStrings.UNITCUBE);
        assetManager.registerModelWithPath(RenderUtils.createBlockSingleModel(), AssetDataStrings.MODEL_BLOCK_SINGLE);
        assetManager.addModelPathToQueue("Models/basic/geometry/SmallCube.fbx");
        assetManager.addModelPathToQueue("Models/basic/geometry/unitcapsule.glb");
        assetManager.addModelPathToQueue("Models/basic/geometry/unitplane.fbx");
        assetManager.addModelPathToQueue("Models/basic/geometry/unitcube.fbx");
        imagePlaneModelID = assetManager.registerModel(RenderUtils.createPlaneModel("Shaders/core/plane/plane.vs", "Shaders/core/plane/plane.fs"));
        assetManager.addShaderToQueue("Shaders/core/plane/plane.vs", "Shaders/core/plane/plane.fs");
        solidPlaneModelID = assetManager.registerModel(RenderUtils.createInWindowPanel("Shaders/ui/plainBox/plainBox.vs", "Shaders/ui/plainBox/plainBox.fs"));

        //init pose models for basic shapes
        PoseModel emptyPoseModel = PoseModel.createEmpty();
        for(String modelPath : defaultModelsWithNoPose){
            assetManager.registerPoseModelWithPath(emptyPoseModel, modelPath);
        }

        //image panel
        ImagePanel.imagePanelModelPath = assetManager.registerModel(RenderUtils.createPlaneModel("Shaders/core/imagepanel/imagepanel.vs", "Shaders/core/imagepanel/imagepanel.fs"));

        Globals.assetManager.addShaderToQueue("Shaders/ui/plainBox/plainBox.vs", "Shaders/ui/plainBox/plainBox.fs");
        
        //window content shader
        assetManager.addShaderToQueue("Shaders/ui/windowContent/windowContent.vs", "Shaders/ui/windowContent/windowContent.fs");
        
        //debug shaders
        assetManager.addShaderToQueue("Shaders/ui/debug/windowBorder/windowBound.vs", "Shaders/ui/debug/windowBorder/windowBound.fs");
        assetManager.addShaderToQueue("Shaders/ui/debug/windowContentBorder/windowContentBound.vs", "Shaders/ui/debug/windowContentBorder/windowContentBound.fs");

        //compute shaders
        assetManager.addComputeShaderToQueue(AssetDataStrings.COMPUTE_LIGHT_CLUSTER);
        assetManager.addComputeShaderToQueue(AssetDataStrings.COMPUTE_LIGHT_CULL);

        //as these assets are required for the renderer to work, we go ahead and
        //load them into memory now. The loading time penalty is worth it I think.
        Globals.assetManager.loadAssetsInQueue();
    }

    /**
     * Unloads scene
     */
    public static void unloadScene(){
        Globals.playerEntity = null;
        Globals.playerCamera = null;
        Globals.firstPersonEntity = null;
        Globals.clientPlayer = null;
        Globals.playerManager = new PlayerManager();
        Globals.clientScene = new Scene();
        Globals.clientSceneWrapper = new ClientSceneWrapper(Globals.clientScene, new CollisionEngine(), CollisionEngine.create(new ClientChemistryCollisionCallback()), new CollisionEngine());
        Globals.clientSynchronizationManager = new ClientSynchronizationManager();
        Globals.server = null;
        Globals.serverSynchronizationManager = new ServerSynchronizationManager();
        if(Globals.realmManager != null){
            Globals.realmManager.reset();
        }
        Globals.dbController.disconnect();
    }

    /**
     * Resets global values
     */
    public static void resetGlobals(){
        Globals.unloadScene();
        //
        //Actual globals to destroy
        Globals.assetManager = null;
        Globals.elementService = null;
        Globals.realmManager = null;
        Globals.clientSceneWrapper = null;
        Globals.clientScene = null;
        Globals.clientWorldData = null;
        Globals.audioEngine = null;
        Globals.renderingEngine = null;
        Globals.threadManager = null;
        Globals.signalSystem = null;
        Globals.serviceManager = null;
        Globals.fileWatcherService = null;
        Globals.clientConnection = null;
        Globals.clientSynchronizationManager = null;
        Globals.server = null;
        Globals.serverSynchronizationManager = null;
        Globals.playerManager = null;
        Globals.javaPID = null;
        Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true;
        Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = false;
        Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = false;
        Globals.RENDER_FLAG_RENDER_UI = false;
        Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND = false;
        Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false;
        Globals.window = -1;
        LoggerInterface.destroyLoggers();
    }

    

}
