package electrosphere.engine.loadingthreads; import java.util.Arrays; import java.util.concurrent.TimeUnit; import org.joml.Vector3d; import org.joml.Vector3f; import electrosphere.client.block.cells.ClientBlockCellManager; import electrosphere.client.entity.camera.CameraEntityUtils; import electrosphere.client.entity.crosshair.Crosshair; import electrosphere.client.fluid.cells.FluidCellManager; import electrosphere.client.sim.ClientSimulation; import electrosphere.client.terrain.cells.ClientDrawCellManager; import electrosphere.client.terrain.foliage.FoliageCellManager; import electrosphere.client.ui.menu.MenuGenerators; import electrosphere.client.ui.menu.WindowStrings; import electrosphere.client.ui.menu.WindowUtils; import electrosphere.client.ui.menu.mainmenu.MenuCharacterCreation; import electrosphere.controls.ControlHandler; import electrosphere.engine.Globals; import electrosphere.engine.assetmanager.AssetDataStrings; import electrosphere.engine.signal.Signal.SignalType; import electrosphere.engine.threads.LabeledThread.ThreadLabel; import electrosphere.entity.DrawableUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityUtils; import electrosphere.logger.LoggerInterface; import electrosphere.net.NetUtils; import electrosphere.net.client.ClientNetworking; import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.ActorTextureMask; public class ClientLoading { /** * Number of frames to wait before updating status of draw cell manager loading */ static final int DRAW_CELL_UPDATE_RATE = 60; /** * The number of frames the draw cell is expected to take (minimum) to init */ static final int DRAW_CELL_EXPECTED_MINIMUM_FRAMES_TO_INIT = 10; /** * Loads the race data from the server * @param params no params */ protected static void loadCharacterServer(Object[] params){ if(params.length < 1){ throw new Error("Expected 1 params!"); } boolean useLocalConnection = (boolean)params[0]; WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.WINDOW_MENU_MAIN), false); WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu()); WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.WINDOW_LOADING), true); WindowUtils.updateLoadingWindow("Waiting on server"); //disable menu input Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.NO_INPUT); //initialize the client thread (client) if(useLocalConnection){ LoadingUtils.initLocalConnection(true); } else { ClientLoading.initClientThread(); } //while we don't know what races are playable, wait WindowUtils.updateLoadingWindow("Waiting on lore"); while(Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces().size() == 0){ try { TimeUnit.MILLISECONDS.sleep(5); } catch (InterruptedException ex) {} } //once we have them, bring up the character creation interface //init character creation window //eventually should replace with at ui to select an already created character or create a new one WindowUtils.replaceMainMenuContents(MenuCharacterCreation.createCharacterSelectionWindow()); //make loading dialog disappear WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.WINDOW_LOADING), false); //make character creation window visible WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.WINDOW_MENU_MAIN), true); //recapture window Globals.controlHandler.setRecapture(true); //log LoggerInterface.loggerEngine.INFO("[Client]Finished loading character creation menu"); //set menu controls again Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.TITLE_MENU); } protected static void loadClientWorld(Object[] params){ Globals.signalSystem.post(SignalType.UI_MODIFICATION, () -> { WindowUtils.closeWindow(WindowStrings.WINDOW_MENU_MAIN); WindowUtils.recursiveSetVisible(WindowStrings.WINDOW_LOADING, true); WindowUtils.updateLoadingWindow("LOADING"); }); //disable menu input Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.NO_INPUT); //initialize the "real" objects simulation initClientSimulation(); LoadingUtils.setSimulationsToReady(); //initialize the gridded managers (client) initDrawCellManager(true); initFoliageManager(); initFluidCellManager(true); initBlockCellManager(true); //initialize the basic graphical entities of the world (skybox, camera) initWorldBaseGraphicalEntities(); //init arena specific stuff (ie different skybox colors) initArenaGraphicalEntities(); //sets micro and macro sims to ready if they exist setSimulationsToReady(); //set simulations to ready if they exist LoadingUtils.setSimulationsToReady(); //make loading window disappear Globals.signalSystem.post(SignalType.UI_MODIFICATION, () -> { WindowUtils.recursiveSetVisible(WindowStrings.WINDOW_LOADING, false); Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true; Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = true; Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = true; Globals.RENDER_FLAG_RENDER_UI = true; Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND = false; Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false; }); //recapture screen Globals.controlHandler.setRecapture(true); LoggerInterface.loggerEngine.INFO("[Client]Finished loading main game"); //set controls state Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.MAIN_GAME); } /** * Loads the viewport */ protected static void loadViewport(Object[] params){ Globals.signalSystem.post(SignalType.UI_MODIFICATION, () -> { WindowUtils.closeWindow(WindowStrings.WINDOW_MENU_MAIN); WindowUtils.recursiveSetVisible(WindowStrings.WINDOW_LOADING, true); }); //disable menu input Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.NO_INPUT); //init camera Globals.playerCamera = CameraEntityUtils.spawnBasicCameraEntity(new Vector3d(0,0,0), new Vector3d(-1,0,0)); Globals.cameraHandler.setTrackPlayerEntity(false); Globals.cameraHandler.setUpdate(false); //initialize the "real" objects simulation initClientSimulation(); //initialize the cell managers (client) initDrawCellManager(false); initFluidCellManager(false); initBlockCellManager(false); initFoliageManager(); //sets micro and macro sims to ready if they exist setSimulationsToReady(); //make loading window disappear Globals.signalSystem.post(SignalType.UI_MODIFICATION, () -> { WindowUtils.recursiveSetVisible(WindowStrings.WINDOW_LOADING, false); Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true; Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = true; Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = true; Globals.RENDER_FLAG_RENDER_UI = true; Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND = false; Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false; }); //recapture screen Globals.controlHandler.setRecapture(true); LoggerInterface.loggerEngine.INFO("[Client]Finished loading main game"); //set controls state Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.MAIN_GAME); } /** * Inits the client networking thread and socket */ private static void initClientThread(){ //start client networking if(Globals.RUN_CLIENT){ Globals.clientConnection = new ClientNetworking(NetUtils.getAddress(),NetUtils.getPort()); Globals.threadManager.start(ThreadLabel.NETWORKING_CLIENT, new Thread(Globals.clientConnection)); } } /** * Creates client simulation object */ private static void initClientSimulation(){ if(Globals.clientSimulation == null){ Globals.clientSimulation = new ClientSimulation(); } } /** * Sets client simulation object state to ready */ private static void setSimulationsToReady(){ Globals.clientSimulation.setReady(true); } private static void initWorldBaseGraphicalEntities(){ /* Skybox */ // Model skyboxModel = Globals.assetManager.fetchModel(AssetDataStrings.ASSET_STRING_SKYBOX_BASIC); // Globals.skybox = EntityUtils.spawnDrawableEntity(AssetDataStrings.ASSET_STRING_SKYBOX_BASIC); /* Player Camera */ CameraEntityUtils.initCamera(); /* Targeting crosshair */ Crosshair.initCrossHairEntity(); } static void initArenaGraphicalEntities(){ float skyR = 150; float skyG = 200; float skyB = 250; float groundR = 20; float groundG = 20; float groundB = 20; Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); //starry sky true skybox Entity skybox = EntityCreationUtils.createClientSpatialEntity(); EntityCreationUtils.makeEntityDrawable(skybox, "Models/environment/skyboxSphere.fbx"); DrawableUtils.disableCulling(skybox); EntityUtils.getRotation(skybox).rotateX((float)(-Math.PI/2.0f)); EntityUtils.getScale(skybox).mul(600000.0f); Globals.clientScene.registerBehaviorTree(() -> { EntityUtils.getPosition(skybox).set(EntityUtils.getPosition(Globals.playerEntity)); }); Globals.assetManager.queueOverrideMeshShader("Models/environment/skyboxSphere.fbx", "Sphere", "Shaders/entities/skysphere/skysphere.vs", "Shaders/entities/skysphere/skysphere.fs"); //cloud ring pseudo skybox // Entity cloudRing = EntityCreationUtils.createClientSpatialEntity(); // EntityCreationUtils.makeEntityDrawable(cloudRing, "Models/environment/cloudRing.fbx"); // DrawableUtils.makeEntityTransparent(cloudRing); // DrawableUtils.disableCulling(cloudRing); // EntityUtils.getRotation(cloudRing).rotateX((float)(-Math.PI/2.0f)); // EntityUtils.getScale(cloudRing).mul(100000.0f); // Globals.clientScene.registerBehaviorTree(new ApplyRotationTree(cloudRing,new Quaterniond().rotationZ(0.0001))); // Globals.assetManager.queueOverrideMeshShader("Models/environment/cloudRing.fbx", "Sphere", "Shaders/skysphere/skysphere.vs", "Shaders/skysphere/skysphere.fs"); //player's cursor Globals.playerCursor = EntityCreationUtils.createClientSpatialEntity(); EntityCreationUtils.makeEntityDrawable(Globals.playerCursor, AssetDataStrings.UNITSPHERE); Actor cursorActor = EntityUtils.getActor(Globals.playerCursor); cursorActor.addTextureMask(new ActorTextureMask("sphere", Arrays.asList(new String[]{"Textures/transparent_red.png"}))); DrawableUtils.makeEntityTransparent(Globals.playerCursor); EntityUtils.getScale(Globals.playerCursor).set(0.2f); //cloud object // Entity cloudEnt = EntityCreationUtils.createClientSpatialEntity(); // EntityCreationUtils.makeEntityDrawablePreexistingModel(cloudEnt, Globals.assetManager.queuedAsset(new QueuedModel(() -> { // Model rVal = new Model(); // Mesh m = GeometryMeshGen.genBox(1, 1, 1); // //shader logic // m.setShader(VisualShader.loadSpecificShader("Shaders/entities/clouds/clouds.vs", "Shaders/entities/clouds/clouds.fs")); // m.setParent(rVal); // rVal.getMeshes().add(m); // rVal.setBoundingSphere(0,0,0,2); // return rVal; // }))); } static final int MAX_DRAW_CELL_WAIT = 1000; /** * Inits the drawcell manager * @param blockForInit Blocks the thread until the draw cell manager is ready */ static void initDrawCellManager(boolean blockForInit){ int iterations = 0; WindowUtils.updateLoadingWindow("WAITING ON WORLD DATA"); while(blockForInit && (Globals.clientWorldData == null || InitialAssetLoading.atlasQueuedTexture == null || !InitialAssetLoading.atlasQueuedTexture.hasLoaded()) && Globals.threadManager.shouldKeepRunning()){ try { TimeUnit.MILLISECONDS.sleep(10); iterations++; } catch (InterruptedException ex) { LoggerInterface.loggerEngine.ERROR(ex); } if(iterations > MAX_DRAW_CELL_WAIT){ String message = "Draw cell took too long to init!\n" + Globals.clientWorldData + "\n" + InitialAssetLoading.atlasQueuedTexture.hasLoaded(); throw new IllegalStateException(message); } } //initialize draw cell manager // Globals.drawCellManager = new DrawCellManager(Globals.clientTerrainManager, 0, 0, 0); Globals.clientDrawCellManager = new ClientDrawCellManager(Globals.voxelTextureAtlas, Globals.clientWorldData.getWorldDiscreteSize()); //Alerts the client simulation that it should start loading terrain Globals.clientSimulation.setLoadingTerrain(true); //wait for all the terrain data to arrive int i = 0; while( blockForInit && !Globals.clientDrawCellManager.isInitialized() && Globals.threadManager.shouldKeepRunning() ){ i++; if(i % DRAW_CELL_UPDATE_RATE == 0){ WindowUtils.updateLoadingWindow("WAITING ON SERVER TO SEND TERRAIN (" + Globals.clientTerrainManager.getAllChunks().size() + ")"); } try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException ex) { ex.printStackTrace(); } } if(i < DRAW_CELL_EXPECTED_MINIMUM_FRAMES_TO_INIT){ LoggerInterface.loggerEngine.WARNING("Draw cell manager loaded exceptionally fast!"); } } /** * Inits the fluid cell manager * @param blockForInit Blocks the thread until the fluid cell manager is ready */ static void initFluidCellManager(boolean blockForInit){ //wait for world data WindowUtils.updateLoadingWindow("WAITING ON WORLD DATA"); while(blockForInit && Globals.clientWorldData == null && Globals.threadManager.shouldKeepRunning()){ try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException ex) { } } //initialize draw cell manager Globals.fluidCellManager = new FluidCellManager(Globals.clientTerrainManager, 0, 0, 0); Globals.fluidCellManager.setGenerateDrawables(true); Globals.clientSimulation.setLoadingTerrain(true); //wait for all the terrain data to arrive WindowUtils.updateLoadingWindow("REQUESTING FLUID CHUNKS FROM SERVER (" + Globals.fluidCellManager.getUnrequestedSize() + ")"); while(blockForInit && Globals.fluidCellManager.containsUnrequestedCell() && Globals.threadManager.shouldKeepRunning() && Globals.RUN_FLUIDS){ try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException ex) { ex.printStackTrace(); } } //wait for undrawable cells // WindowUtils.updateLoadingWindow("WAITING ON SERVER TO SEND FLUID CHUNKS (" + Globals.fluidCellManager.getUndrawableSize() + ")"); // while(blockForInit && Globals.fluidCellManager.containsUndrawableCell() && Globals.threadManager.shouldKeepRunning()){ // try { // TimeUnit.MILLISECONDS.sleep(10); // } catch (InterruptedException ex) { // ex.printStackTrace(); // } // } } /** * Inits the block cell manager * @param blockForInit Blocks the thread until the block cell manager is ready */ static void initBlockCellManager(boolean blockForInit){ int iterations = 0; WindowUtils.updateLoadingWindow("WAITING ON WORLD DATA"); while(blockForInit && (Globals.clientWorldData == null || InitialAssetLoading.atlasQueuedTexture == null || !InitialAssetLoading.atlasQueuedTexture.hasLoaded()) && Globals.threadManager.shouldKeepRunning()){ try { TimeUnit.MILLISECONDS.sleep(10); iterations++; } catch (InterruptedException ex) { LoggerInterface.loggerEngine.ERROR(ex); } if(iterations > MAX_DRAW_CELL_WAIT){ String message = "Draw cell took too long to init!\n" + Globals.clientWorldData + "\n" + InitialAssetLoading.atlasQueuedTexture.hasLoaded(); throw new IllegalStateException(message); } } Globals.clientBlockCellManager = new ClientBlockCellManager(Globals.blockTextureAtlas, Globals.clientWorldData.getWorldDiscreteSize()); //Alerts the client simulation that it should start loading blocks Globals.clientSimulation.setLoadingTerrain(true); //wait for all the block data to arrive int i = 0; while( blockForInit && !Globals.clientBlockCellManager.isInitialized() && Globals.threadManager.shouldKeepRunning() ){ i++; if(i % DRAW_CELL_UPDATE_RATE == 0){ WindowUtils.updateLoadingWindow("WAITING ON SERVER TO SEND BLOCKS (" + Globals.clientTerrainManager.getAllChunks().size() + ")"); } try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException ex) { ex.printStackTrace(); } } if(i < DRAW_CELL_EXPECTED_MINIMUM_FRAMES_TO_INIT){ LoggerInterface.loggerEngine.WARNING("Block cell manager loaded exceptionally fast!"); } } /** * Starts up the foliage manager */ private static void initFoliageManager(){ Globals.foliageCellManager = new FoliageCellManager(Globals.clientWorldData.getWorldDiscreteSize()); Globals.foliageCellManager.init(); // Globals.foliageCellManager.start(); } }