Added gravity and refactored player controls
- Added gravity (still testing)
  - Two modes: realistic (9.8 m/s^2) and Minecraft (32 m/s^2)
  - Switch with G
    - Changing (0; 0; 0) rebound to H
- Added walking controls
  - Minecraft-style
  - WIP
- LayerTestGUI now displays dev options
- Added Units
			
			
This commit is contained in:
		| @@ -3,10 +3,10 @@ package ru.windcorp.progressia.client; | |||||||
| import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel; | import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel; | ||||||
| import ru.windcorp.progressia.client.graphics.GUI; | import ru.windcorp.progressia.client.graphics.GUI; | ||||||
| import ru.windcorp.progressia.client.graphics.flat.LayerTestUI; | import ru.windcorp.progressia.client.graphics.flat.LayerTestUI; | ||||||
| import ru.windcorp.progressia.client.graphics.gui.LayerTestGUI; |  | ||||||
| import ru.windcorp.progressia.client.graphics.world.LayerWorld; | import ru.windcorp.progressia.client.graphics.world.LayerWorld; | ||||||
| import ru.windcorp.progressia.common.world.WorldData; | import ru.windcorp.progressia.common.world.WorldData; | ||||||
| import ru.windcorp.progressia.server.ServerState; | import ru.windcorp.progressia.server.ServerState; | ||||||
|  | import ru.windcorp.progressia.test.LayerTestGUI; | ||||||
|  |  | ||||||
| public class ClientState { | public class ClientState { | ||||||
| 	 | 	 | ||||||
|   | |||||||
| @@ -1,125 +0,0 @@ | |||||||
| /******************************************************************************* |  | ||||||
|  * Progressia |  | ||||||
|  * Copyright (C) 2020  Wind Corporation |  | ||||||
|  * |  | ||||||
|  * This program is free software: you can redistribute it and/or modify |  | ||||||
|  * it under the terms of the GNU General Public License as published by |  | ||||||
|  * the Free Software Foundation, either version 3 of the License, or |  | ||||||
|  * (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  * This program is distributed in the hope that it will be useful, |  | ||||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  * GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  * You should have received a copy of the GNU General Public License |  | ||||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. |  | ||||||
|  *******************************************************************************/ |  | ||||||
| package ru.windcorp.progressia.client.graphics.gui; |  | ||||||
|  |  | ||||||
| import com.google.common.eventbus.Subscribe; |  | ||||||
| import glm.vec._2.i.Vec2i; |  | ||||||
| import org.lwjgl.glfw.GLFW; |  | ||||||
| import ru.windcorp.progressia.client.graphics.Colors; |  | ||||||
| import ru.windcorp.progressia.client.graphics.flat.RenderTarget; |  | ||||||
| import ru.windcorp.progressia.client.graphics.font.Font; |  | ||||||
| import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent; |  | ||||||
| import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; |  | ||||||
| import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; |  | ||||||
| import ru.windcorp.progressia.client.graphics.input.KeyEvent; |  | ||||||
| import ru.windcorp.progressia.client.localization.Localizer; |  | ||||||
| import ru.windcorp.progressia.client.localization.MutableString; |  | ||||||
| import ru.windcorp.progressia.client.localization.MutableStringLocalized; |  | ||||||
|  |  | ||||||
| public class LayerTestGUI extends GUILayer { |  | ||||||
| 	 |  | ||||||
| 	private static class DebugComponent extends Component { |  | ||||||
| 		private final int color; |  | ||||||
| 		 |  | ||||||
| 		public DebugComponent(String name, Vec2i size, int color) { |  | ||||||
| 			super(name); |  | ||||||
| 			this.color = color; |  | ||||||
| 			 |  | ||||||
| 			setPreferredSize(size); |  | ||||||
| 			 |  | ||||||
| 			addListener(new Object() { |  | ||||||
| 				@Subscribe |  | ||||||
| 				public void onHoverChanged(HoverEvent e) { |  | ||||||
| 					requestReassembly(); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 			 |  | ||||||
| 			addListener(KeyEvent.class, this::onClicked); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		private boolean onClicked(KeyEvent event) { |  | ||||||
| 			if (!event.isMouse()) { |  | ||||||
| 				return false; |  | ||||||
| 			} else if (event.isPress() && event.isLeftMouseButton()) { |  | ||||||
| 				System.out.println("You pressed a Component!"); |  | ||||||
| 			} |  | ||||||
| 			return true; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		@Override |  | ||||||
| 		protected void assembleSelf(RenderTarget target) { |  | ||||||
| 			target.fill(getX(), getY(), getWidth(), getHeight(), Colors.BLACK); |  | ||||||
| 			 |  | ||||||
| 			target.fill( |  | ||||||
| 					getX() + 2, getY() + 2, |  | ||||||
| 					getWidth() - 4, getHeight() - 4, |  | ||||||
| 					isHovered() ? Colors.DEBUG_YELLOW : color |  | ||||||
| 			); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public LayerTestGUI() { |  | ||||||
| 		super("LayerTestGui", new LayoutAlign(1, 0.75, 5)); |  | ||||||
| 		 |  | ||||||
| 		Panel panel = new Panel("Alex", new LayoutVertical(5)); |  | ||||||
| 		 |  | ||||||
| 		panel.addChild(new DebugComponent("Bravo", new Vec2i(200, 100), 0x44FF44)); |  | ||||||
| 		 |  | ||||||
| 		Component charlie = new DebugComponent("Charlie", null, 0x222222); |  | ||||||
| 		charlie.setLayout(new LayoutVertical(5)); |  | ||||||
|  |  | ||||||
| 		//Debug |  | ||||||
| 		Localizer.getInstance().setLanguage("ru-RU"); |  | ||||||
| 		MutableString epsilon = new MutableStringLocalized("Epsilon") |  | ||||||
| 				.addListener(() -> ((Label)charlie.getChild(0)).update()).format(34, "thirty-four"); |  | ||||||
| 		// These two are swapped in code due to a bug in layouts, fixing ATM |  | ||||||
| 		charlie.addChild( |  | ||||||
| 				new Label( |  | ||||||
| 						"Delta", |  | ||||||
| 						new Font().withColor(0xCCBB44).deriveShadow().deriveBold(), |  | ||||||
| 						"Пре-альфа!" |  | ||||||
| 				) |  | ||||||
| 		); |  | ||||||
| 		charlie.addChild( |  | ||||||
| 				new Label( |  | ||||||
| 						"Epsilon", |  | ||||||
| 						new Font().withColor(0x4444BB).deriveItalic(), |  | ||||||
| 						() -> epsilon.get().concat("\u269b") |  | ||||||
| 				) |  | ||||||
| 		); |  | ||||||
| 		panel.addChild(charlie); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 		charlie.addListener(KeyEvent.class, e -> { |  | ||||||
| 			if(e.isPress() && e.getKey() == GLFW.GLFW_KEY_L) { |  | ||||||
| 				Localizer localizer = Localizer.getInstance(); |  | ||||||
| 				if (localizer.getLanguage().equals("ru-RU")) { |  | ||||||
| 					localizer.setLanguage("en-US"); |  | ||||||
| 				} else { |  | ||||||
| 					localizer.setLanguage("ru-RU"); |  | ||||||
| 				} |  | ||||||
| 				return true; |  | ||||||
| 			} return false; |  | ||||||
| 		}); |  | ||||||
| 		charlie.setFocusable(true); |  | ||||||
| 		charlie.takeFocus(); |  | ||||||
|  |  | ||||||
| 		getRoot().addChild(panel); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -272,6 +272,10 @@ public class Camera { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	public int getCurrentModeIndex() { | ||||||
|  | 		return currentModeIndex; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	public float getLastAnchorYaw() { | 	public float getLastAnchorYaw() { | ||||||
| 		return lastAnchorYaw; | 		return lastAnchorYaw; | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -20,41 +20,27 @@ package ru.windcorp.progressia.client.graphics.world; | |||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| import org.lwjgl.glfw.GLFW; |  | ||||||
|  |  | ||||||
| import glm.Glm; |  | ||||||
| import glm.mat._3.Mat3; |  | ||||||
| import glm.vec._2.Vec2; |  | ||||||
| import glm.vec._3.Vec3; |  | ||||||
| import ru.windcorp.progressia.client.Client; | import ru.windcorp.progressia.client.Client; | ||||||
|  | import ru.windcorp.progressia.client.ClientState; | ||||||
| import ru.windcorp.progressia.client.comms.controls.InputBasedControls; | import ru.windcorp.progressia.client.comms.controls.InputBasedControls; | ||||||
| import ru.windcorp.progressia.client.graphics.Layer; | import ru.windcorp.progressia.client.graphics.Layer; | ||||||
| import ru.windcorp.progressia.client.graphics.backend.FaceCulling; | import ru.windcorp.progressia.client.graphics.backend.FaceCulling; | ||||||
| import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend; |  | ||||||
| import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; | import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; | ||||||
| import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent; |  | ||||||
| import ru.windcorp.progressia.client.graphics.input.InputEvent; |  | ||||||
| import ru.windcorp.progressia.client.graphics.input.KeyEvent; |  | ||||||
| import ru.windcorp.progressia.client.graphics.input.bus.Input; | import ru.windcorp.progressia.client.graphics.input.bus.Input; | ||||||
|  | import ru.windcorp.progressia.common.Units; | ||||||
| import ru.windcorp.progressia.common.collision.Collideable; | import ru.windcorp.progressia.common.collision.Collideable; | ||||||
| import ru.windcorp.progressia.common.collision.colliders.Collider; | import ru.windcorp.progressia.common.collision.colliders.Collider; | ||||||
| import ru.windcorp.progressia.common.util.FloatMathUtils; |  | ||||||
| import ru.windcorp.progressia.common.util.Vectors; |  | ||||||
| import ru.windcorp.progressia.common.world.entity.EntityData; | import ru.windcorp.progressia.common.world.entity.EntityData; | ||||||
| import ru.windcorp.progressia.test.CollisionModelRenderer; | import ru.windcorp.progressia.test.CollisionModelRenderer; | ||||||
|  | import ru.windcorp.progressia.test.TestPlayerControls; | ||||||
|  |  | ||||||
| public class LayerWorld extends Layer { | public class LayerWorld extends Layer { | ||||||
| 	 | 	 | ||||||
| 	private final Mat3 angMat = new Mat3(); |  | ||||||
|  |  | ||||||
| 	private int movementForward = 0; |  | ||||||
| 	private int movementRight = 0; |  | ||||||
| 	private int movementUp = 0; |  | ||||||
| 	 |  | ||||||
| 	private final WorldRenderHelper helper = new WorldRenderHelper(); | 	private final WorldRenderHelper helper = new WorldRenderHelper(); | ||||||
| 	 | 	 | ||||||
| 	private final Client client; | 	private final Client client; | ||||||
| 	private final InputBasedControls inputBasedControls; | 	private final InputBasedControls inputBasedControls; | ||||||
|  | 	private final TestPlayerControls tmp_testControls = TestPlayerControls.getInstance(); | ||||||
|  |  | ||||||
| 	public LayerWorld(Client client) { | 	public LayerWorld(Client client) { | ||||||
| 		super("World"); | 		super("World"); | ||||||
| @@ -75,40 +61,12 @@ public class LayerWorld extends Layer { | |||||||
| 	 | 	 | ||||||
| 	@Override | 	@Override | ||||||
| 	protected void doRender() { | 	protected void doRender() { | ||||||
| 		if (client.getLocalPlayer() != null) { |  | ||||||
| 			tmp_handleControls(); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		Camera camera = client.getCamera(); | 		Camera camera = client.getCamera(); | ||||||
| 		if (camera.hasAnchor()) { | 		if (camera.hasAnchor()) { | ||||||
| 			renderWorld(); | 			renderWorld(); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private void tmp_handleControls() { |  | ||||||
| 		EntityData player = client.getLocalPlayer(); |  | ||||||
| 		 |  | ||||||
| 		angMat.identity().rotateZ(player.getYaw()); |  | ||||||
| 		 |  | ||||||
| 		Vec3 movement = Vectors.grab3(); |  | ||||||
| 		 |  | ||||||
| 		// Horizontal and vertical max control speed |  | ||||||
| 		final float movementSpeed = 0.1f * 60.0f; |  | ||||||
| 		// (0; 1], 1 is instant change, 0 is no control authority |  | ||||||
| 		final float controlAuthority = 0.1f; |  | ||||||
| 		 |  | ||||||
| 		movement.set(movementForward, -movementRight, 0); |  | ||||||
| 		if (movementForward != 0 && movementRight != 0) movement.normalize(); |  | ||||||
| 		angMat.mul_(movement); // bug in jglm, .mul() and mul_() are swapped |  | ||||||
| 		movement.z = movementUp; |  | ||||||
| 		movement.mul(movementSpeed); |  | ||||||
| 		movement.sub(player.getVelocity()); |  | ||||||
| 		movement.mul(controlAuthority); |  | ||||||
| 		player.getVelocity().add(movement); |  | ||||||
| 		 |  | ||||||
| 		Vectors.release(movement); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	private void renderWorld() { | 	private void renderWorld() { | ||||||
| 		client.getCamera().apply(helper); | 		client.getCamera().apply(helper); | ||||||
| 		FaceCulling.push(true); | 		FaceCulling.push(true); | ||||||
| @@ -127,11 +85,16 @@ public class LayerWorld extends Layer { | |||||||
| 	private static final boolean RENDER_COLLISION_MODELS = false; | 	private static final boolean RENDER_COLLISION_MODELS = false; | ||||||
| 	 | 	 | ||||||
| 	private void tmp_doEveryFrame() { | 	private void tmp_doEveryFrame() { | ||||||
|  | 		float tickLength = (float) GraphicsInterface.getFrameLength(); | ||||||
|  | 		 | ||||||
| 		try { | 		try { | ||||||
| 			tmp_performCollisions(); | 			tmp_performCollisions(tickLength); | ||||||
|  | 			 | ||||||
|  | 			tmp_testControls.applyPlayerControls(); | ||||||
| 			 | 			 | ||||||
| 			for (EntityData data : this.client.getWorld().getData().getEntities()) { | 			for (EntityData data : this.client.getWorld().getData().getEntities()) { | ||||||
| 				tmp_applyFriction(data); | 				tmp_applyFriction(data); | ||||||
|  | 				tmp_applyGravity(data, tickLength); | ||||||
| 				tmp_renderCollisionModel(data); | 				tmp_renderCollisionModel(data); | ||||||
| 			} | 			} | ||||||
| 		} catch (Throwable e) { | 		} catch (Throwable e) { | ||||||
| @@ -147,121 +110,47 @@ public class LayerWorld extends Layer { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private void tmp_performCollisions() { | 	private void tmp_performCollisions(float tickLength) { | ||||||
| 		tmp_collideableList.clear(); | 		tmp_collideableList.clear(); | ||||||
| 		tmp_collideableList.addAll(this.client.getWorld().getData().getEntities()); | 		tmp_collideableList.addAll(this.client.getWorld().getData().getEntities()); | ||||||
| 		 | 		 | ||||||
| 		Collider.performCollisions( | 		Collider.performCollisions( | ||||||
| 				tmp_collideableList, | 				tmp_collideableList, | ||||||
| 				this.client.getWorld().getData(), | 				this.client.getWorld().getData(), | ||||||
| 				(float) GraphicsInterface.getFrameLength(), | 				tickLength, | ||||||
| 				tmp_colliderWorkspace | 				tmp_colliderWorkspace | ||||||
| 		); | 		); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private void tmp_applyFriction(EntityData entity) { | 	private void tmp_applyFriction(EntityData entity) { | ||||||
| 		final float frictionCoeff = 1 - 1e-2f; | 		final float frictionCoeff = 1 - 1e-5f; | ||||||
| 		entity.getVelocity().mul(frictionCoeff); | 		entity.getVelocity().mul(frictionCoeff); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	private void tmp_applyGravity(EntityData entity, float tickLength) { | ||||||
|  | 		if (ClientState.getInstance().getLocalPlayer() == entity && tmp_testControls.isFlying()) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		final float gravitationalAcceleration; | ||||||
|  | 		 | ||||||
|  | 		if (tmp_testControls.useMinecraftGravity()) { | ||||||
|  | 			gravitationalAcceleration = 32f * Units.METERS_PER_SECOND_SQUARED; // plz dont sue me M$ | ||||||
|  | 		} else { | ||||||
|  | 			gravitationalAcceleration = 9.81f * Units.METERS_PER_SECOND_SQUARED; | ||||||
|  | 		} | ||||||
|  | 		entity.getVelocity().add(0, 0, -gravitationalAcceleration * tickLength); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	protected void handleInput(Input input) { | 	protected void handleInput(Input input) { | ||||||
| 		if (input.isConsumed()) return; | 		if (input.isConsumed()) return; | ||||||
| 		 | 		 | ||||||
| 		InputEvent event = input.getEvent(); | 		tmp_testControls.handleInput(input); | ||||||
| 		 |  | ||||||
| 		if (event instanceof KeyEvent) { |  | ||||||
| 			if (onKeyEvent((KeyEvent) event)) { |  | ||||||
| 				input.consume(); |  | ||||||
| 			} |  | ||||||
| 		} else if (event instanceof CursorMoveEvent) { |  | ||||||
| 			onMouseMoved((CursorMoveEvent) event); |  | ||||||
| 			input.consume(); |  | ||||||
| 		} |  | ||||||
| 		 | 		 | ||||||
| 		if (!input.isConsumed()) { | 		if (!input.isConsumed()) { | ||||||
| 			inputBasedControls.handleInput(input); | 			inputBasedControls.handleInput(input); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private boolean flag = true; |  | ||||||
| 	 |  | ||||||
| 	private boolean onKeyEvent(KeyEvent event) { |  | ||||||
| 		if (event.isRepeat()) return false; |  | ||||||
| 		 |  | ||||||
| 		int multiplier = event.isPress() ? 1 : -1; |  | ||||||
| 		 |  | ||||||
| 		switch (event.getKey()) { |  | ||||||
| 		case GLFW.GLFW_KEY_W: |  | ||||||
| 			movementForward += +1 * multiplier; |  | ||||||
| 			break; |  | ||||||
| 		case GLFW.GLFW_KEY_S: |  | ||||||
| 			movementForward += -1 * multiplier; |  | ||||||
| 			break; |  | ||||||
| 		case GLFW.GLFW_KEY_A: |  | ||||||
| 			movementRight += -1 * multiplier; |  | ||||||
| 			break; |  | ||||||
| 		case GLFW.GLFW_KEY_D: |  | ||||||
| 			movementRight += +1 * multiplier; |  | ||||||
| 			break; |  | ||||||
| 		case GLFW.GLFW_KEY_SPACE: |  | ||||||
| 			movementUp += +1 * multiplier; |  | ||||||
| 			break; |  | ||||||
| 		case GLFW.GLFW_KEY_LEFT_SHIFT: |  | ||||||
| 			movementUp += -1 * multiplier; |  | ||||||
| 			break; |  | ||||||
| 			 |  | ||||||
| 		case GLFW.GLFW_KEY_ESCAPE: |  | ||||||
| 			if (!event.isPress()) return false; |  | ||||||
| 			 |  | ||||||
| 			if (flag) { |  | ||||||
| 				GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL); |  | ||||||
| 			} else { |  | ||||||
| 				GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			flag = !flag; |  | ||||||
| 			break; |  | ||||||
| 			 |  | ||||||
| 		case GLFW.GLFW_KEY_F5: |  | ||||||
| 			if (!event.isPress()) return false; |  | ||||||
| 			 |  | ||||||
| 			if (client.getCamera().hasAnchor()) { |  | ||||||
| 				client.getCamera().selectNextMode(); |  | ||||||
| 			} |  | ||||||
| 			break; |  | ||||||
| 			 |  | ||||||
| 		default: |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	private void onMouseMoved(CursorMoveEvent event) { |  | ||||||
| 		if (!flag) return; |  | ||||||
| 		 |  | ||||||
| 		final float yawScale = -0.002f; |  | ||||||
| 		final float pitchScale = yawScale; |  | ||||||
|  |  | ||||||
| 		EntityData player = client.getLocalPlayer(); |  | ||||||
| 		 |  | ||||||
| 		if (player != null) { |  | ||||||
| 			normalizeAngles(player.getDirection().add( |  | ||||||
| 					(float) (event.getChangeX() * yawScale), |  | ||||||
| 					(float) (event.getChangeY() * pitchScale) |  | ||||||
| 			)); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	private void normalizeAngles(Vec2 dir) { |  | ||||||
| 		// Normalize yaw |  | ||||||
| 		dir.x = FloatMathUtils.normalizeAngle(dir.x); |  | ||||||
| 		 |  | ||||||
| 		// Clamp pitch |  | ||||||
| 		dir.y = Glm.clamp( |  | ||||||
| 				dir.y, -FloatMathUtils.PI_F/2, +FloatMathUtils.PI_F/2 |  | ||||||
| 		); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										56
									
								
								src/main/java/ru/windcorp/progressia/common/Units.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/main/java/ru/windcorp/progressia/common/Units.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | package ru.windcorp.progressia.common; | ||||||
|  |  | ||||||
|  | public class Units { | ||||||
|  | 	 | ||||||
|  | 	// Base units | ||||||
|  | 	// We're SI. | ||||||
|  | 	public static final float METERS                     = 1; | ||||||
|  | 	public static final float KILOGRAMS                  = 1; | ||||||
|  | 	public static final float SECONDS                    = 1; | ||||||
|  |  | ||||||
|  | 	// Length                                             | ||||||
|  | 	public static final float CENTIMETERS                = METERS / 100;  | ||||||
|  | 	public static final float MILLIMETERS                = METERS / 1000; | ||||||
|  | 	public static final float KILOMETERS                 = METERS * 1000; | ||||||
|  | 	 | ||||||
|  | 	// Surface | ||||||
|  | 	public static final float SQUARE_CENTIMETERS         = CENTIMETERS * CENTIMETERS; | ||||||
|  | 	public static final float SQUARE_METERS              = METERS * METERS; | ||||||
|  | 	public static final float SQUARE_MILLIMETERS         = MILLIMETERS * MILLIMETERS; | ||||||
|  | 	public static final float SQUARE_KILOMETERS          = KILOMETERS * KILOMETERS; | ||||||
|  | 	 | ||||||
|  | 	// Volume | ||||||
|  | 	public static final float CUBIC_CENTIMETERS          = CENTIMETERS * CENTIMETERS * CENTIMETERS; | ||||||
|  | 	public static final float CUBIC_METERS               = METERS * METERS * METERS; | ||||||
|  | 	public static final float CUBIC_MILLIMETERS          = MILLIMETERS * MILLIMETERS * MILLIMETERS; | ||||||
|  | 	public static final float CUBIC_KILOMETERS           = KILOMETERS * KILOMETERS * KILOMETERS; | ||||||
|  |  | ||||||
|  | 	// Mass                                               | ||||||
|  | 	public static final float GRAMS                      = KILOGRAMS / 1000; | ||||||
|  | 	public static final float TONNES                     = KILOGRAMS * 1000; | ||||||
|  | 	 | ||||||
|  | 	// Density | ||||||
|  | 	public static final float KILOGRAMS_PER_CUBIC_METER  = KILOGRAMS / CUBIC_METERS; | ||||||
|  | 	public static final float GRAMS_PER_CUBIC_CENTIMETER = GRAMS / CUBIC_CENTIMETERS; | ||||||
|  |  | ||||||
|  | 	// Time                                               | ||||||
|  | 	public static final float MILLISECONDS               = SECONDS / 1000; | ||||||
|  | 	public static final float MINUTES                    = SECONDS * 60; | ||||||
|  | 	public static final float HOURS                      = MINUTES * 60; | ||||||
|  | 	public static final float DAYS                       = HOURS * 24; | ||||||
|  | 	 | ||||||
|  | 	// Frequency | ||||||
|  | 	public static final float HERTZ                      = 1 / SECONDS; | ||||||
|  | 	public static final float KILOHERTZ                  = HERTZ * 1000; | ||||||
|  |  | ||||||
|  | 	// Velocity                                           | ||||||
|  | 	public static final float METERS_PER_SECOND          = METERS / SECONDS; | ||||||
|  | 	public static final float KILOMETERS_PER_HOUR        = KILOMETERS / HOURS; | ||||||
|  |  | ||||||
|  | 	// Acceleration                                       | ||||||
|  | 	public static final float METERS_PER_SECOND_SQUARED  = METERS_PER_SECOND / SECONDS; | ||||||
|  |  | ||||||
|  | 	// Force                                              | ||||||
|  | 	public static final float NEWTONS                    = METERS_PER_SECOND_SQUARED * KILOGRAMS; | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										155
									
								
								src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										155
									
								
								src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,155 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  |  * Progressia | ||||||
|  |  * Copyright (C) 2020  Wind Corporation | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||||
|  |  *******************************************************************************/ | ||||||
|  | package ru.windcorp.progressia.test; | ||||||
|  |  | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Collection; | ||||||
|  |  | ||||||
|  | import ru.windcorp.progressia.client.ClientState; | ||||||
|  | import ru.windcorp.progressia.client.graphics.font.Font; | ||||||
|  | import ru.windcorp.progressia.client.graphics.gui.GUILayer; | ||||||
|  | import ru.windcorp.progressia.client.graphics.gui.Label; | ||||||
|  | import ru.windcorp.progressia.client.graphics.gui.Panel; | ||||||
|  | import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; | ||||||
|  | import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; | ||||||
|  |  | ||||||
|  | public class LayerTestGUI extends GUILayer { | ||||||
|  | 	 | ||||||
|  | 	public LayerTestGUI() { | ||||||
|  | 		super("LayerTestGui", new LayoutAlign(0, 1, 5)); | ||||||
|  | 		 | ||||||
|  | 		Panel panel = new Panel("ControlDisplays", new LayoutVertical(5)); | ||||||
|  | 		 | ||||||
|  | 		Collection<Label> labels = new ArrayList<>(); | ||||||
|  | 		 | ||||||
|  | 		panel.addChild(new Label( | ||||||
|  | 				"IsFlyingDisplay", new Font().withColor(0x37A3E6).deriveShadow(), | ||||||
|  | 				() -> String.format("Flying:         %5s (Space bar x2)", TestPlayerControls.getInstance().isFlying()) | ||||||
|  | 		)); | ||||||
|  | 		 | ||||||
|  | 		panel.addChild(new Label( | ||||||
|  | 				"IsMouseCapturedDisplay", new Font().withColor(0x37A3E6).deriveShadow(), | ||||||
|  | 				() -> String.format("Mouse captured: %5s (esc)", TestPlayerControls.getInstance().isMouseCaptured()) | ||||||
|  | 		)); | ||||||
|  | 		 | ||||||
|  | 		panel.addChild(new Label( | ||||||
|  | 				"CameraModeDisplay", new Font().withColor(0x37A3E6).deriveShadow(), | ||||||
|  | 				() -> String.format("Camera mode:    %5d (F5)", ClientState.getInstance().getCamera().getCurrentModeIndex()) | ||||||
|  | 		)); | ||||||
|  | 		 | ||||||
|  | 		panel.addChild(new Label( | ||||||
|  | 				"GravityModeDisplay", new Font().withColor(0x37A3E6).deriveShadow(), | ||||||
|  | 				() -> String.format("Gravity:    %9s (G)", TestPlayerControls.getInstance().useMinecraftGravity() ? "Minecraft" : "Realistic") | ||||||
|  | 		)); | ||||||
|  | 		 | ||||||
|  | 		panel.getChildren().forEach(c -> labels.add((Label) c)); | ||||||
|  | 		TestPlayerControls.getInstance().setUpdateCallback(() -> labels.forEach(Label::update)); | ||||||
|  |  | ||||||
|  | 		getRoot().addChild(panel); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | //	private static class DebugComponent extends Component { | ||||||
|  | //		private final int color; | ||||||
|  | //		 | ||||||
|  | //		public DebugComponent(String name, Vec2i size, int color) { | ||||||
|  | //			super(name); | ||||||
|  | //			this.color = color; | ||||||
|  | //			 | ||||||
|  | //			setPreferredSize(size); | ||||||
|  | //			 | ||||||
|  | //			addListener(new Object() { | ||||||
|  | //				@Subscribe | ||||||
|  | //				public void onHoverChanged(HoverEvent e) { | ||||||
|  | //					requestReassembly(); | ||||||
|  | //				} | ||||||
|  | //			}); | ||||||
|  | //			 | ||||||
|  | //			addListener(KeyEvent.class, this::onClicked); | ||||||
|  | //		} | ||||||
|  | //		 | ||||||
|  | //		private boolean onClicked(KeyEvent event) { | ||||||
|  | //			if (!event.isMouse()) { | ||||||
|  | //				return false; | ||||||
|  | //			} else if (event.isPress() && event.isLeftMouseButton()) { | ||||||
|  | //				System.out.println("You pressed a Component!"); | ||||||
|  | //			} | ||||||
|  | //			return true; | ||||||
|  | //		} | ||||||
|  | //		 | ||||||
|  | //		@Override | ||||||
|  | //		protected void assembleSelf(RenderTarget target) { | ||||||
|  | //			target.fill(getX(), getY(), getWidth(), getHeight(), Colors.BLACK); | ||||||
|  | //			 | ||||||
|  | //			target.fill( | ||||||
|  | //					getX() + 2, getY() + 2, | ||||||
|  | //					getWidth() - 4, getHeight() - 4, | ||||||
|  | //					isHovered() ? Colors.DEBUG_YELLOW : color | ||||||
|  | //			); | ||||||
|  | //		} | ||||||
|  | //	} | ||||||
|  | // | ||||||
|  | //	public LayerTestGUI() { | ||||||
|  | //		super("LayerTestGui", new LayoutAlign(1, 0.75, 5)); | ||||||
|  | //		 | ||||||
|  | //		Panel panel = new Panel("Alex", new LayoutVertical(5)); | ||||||
|  | //		 | ||||||
|  | //		panel.addChild(new DebugComponent("Bravo", new Vec2i(200, 100), 0x44FF44)); | ||||||
|  | //		 | ||||||
|  | //		Component charlie = new DebugComponent("Charlie", null, 0x222222); | ||||||
|  | //		charlie.setLayout(new LayoutVertical(5)); | ||||||
|  | // | ||||||
|  | //		//Debug | ||||||
|  | //		Localizer.getInstance().setLanguage("ru-RU"); | ||||||
|  | //		MutableString epsilon = new MutableStringLocalized("Epsilon") | ||||||
|  | //				.addListener(() -> ((Label)charlie.getChild(0)).update()).format(34, "thirty-four"); | ||||||
|  | //		// These two are swapped in code due to a bug in layouts, fixing ATM | ||||||
|  | //		charlie.addChild( | ||||||
|  | //				new Label( | ||||||
|  | //						"Delta", | ||||||
|  | //						new Font().withColor(0xCCBB44).deriveShadow().deriveBold(), | ||||||
|  | //						"Пре-альфа!" | ||||||
|  | //				) | ||||||
|  | //		); | ||||||
|  | //		charlie.addChild( | ||||||
|  | //				new Label( | ||||||
|  | //						"Epsilon", | ||||||
|  | //						new Font().withColor(0x4444BB).deriveItalic(), | ||||||
|  | //						() -> epsilon.get().concat("\u269b") | ||||||
|  | //				) | ||||||
|  | //		); | ||||||
|  | //		panel.addChild(charlie); | ||||||
|  | // | ||||||
|  | // | ||||||
|  | //		charlie.addListener(KeyEvent.class, e -> { | ||||||
|  | //			if(e.isPress() && e.getKey() == GLFW.GLFW_KEY_L) { | ||||||
|  | //				Localizer localizer = Localizer.getInstance(); | ||||||
|  | //				if (localizer.getLanguage().equals("ru-RU")) { | ||||||
|  | //					localizer.setLanguage("en-US"); | ||||||
|  | //				} else { | ||||||
|  | //					localizer.setLanguage("ru-RU"); | ||||||
|  | //				} | ||||||
|  | //				return true; | ||||||
|  | //			} return false; | ||||||
|  | //		}); | ||||||
|  | //		charlie.setFocusable(true); | ||||||
|  | //		charlie.takeFocus(); | ||||||
|  | // | ||||||
|  | //		getRoot().addChild(panel); | ||||||
|  | //	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -98,7 +98,7 @@ public class TestContent { | |||||||
|  |  | ||||||
| 	private static void regsiterControls() { | 	private static void regsiterControls() { | ||||||
| 		ControlDataRegistry.getInstance().register(new ControlData("Test", "Switch000")); | 		ControlDataRegistry.getInstance().register(new ControlData("Test", "Switch000")); | ||||||
| 		ControlTriggerRegistry.getInstance().register(new ControlTriggerOnKeyPress("Test", "Switch000", new KeyMatcher(GLFW.GLFW_KEY_G, new int[0], 0)::matches)); | 		ControlTriggerRegistry.getInstance().register(new ControlTriggerOnKeyPress("Test", "Switch000", new KeyMatcher(GLFW.GLFW_KEY_H, new int[0], 0)::matches)); | ||||||
| 		ControlLogicRegistry.getInstance().register(new ControlLogic("Test", "Switch000") { | 		ControlLogicRegistry.getInstance().register(new ControlLogic("Test", "Switch000") { | ||||||
| 			@Override | 			@Override | ||||||
| 			public void apply(Server server, PacketControl packet, Client client) { | 			public void apply(Server server, PacketControl packet, Client client) { | ||||||
|   | |||||||
| @@ -0,0 +1,270 @@ | |||||||
|  | package ru.windcorp.progressia.test; | ||||||
|  |  | ||||||
|  | import org.lwjgl.glfw.GLFW; | ||||||
|  |  | ||||||
|  | import glm.Glm; | ||||||
|  | import glm.mat._3.Mat3; | ||||||
|  | import glm.vec._2.Vec2; | ||||||
|  | import glm.vec._3.Vec3; | ||||||
|  | import ru.windcorp.progressia.client.ClientState; | ||||||
|  | import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend; | ||||||
|  | import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; | ||||||
|  | import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent; | ||||||
|  | import ru.windcorp.progressia.client.graphics.input.InputEvent; | ||||||
|  | import ru.windcorp.progressia.client.graphics.input.KeyEvent; | ||||||
|  | import ru.windcorp.progressia.client.graphics.input.bus.Input; | ||||||
|  | import ru.windcorp.progressia.common.Units; | ||||||
|  | import ru.windcorp.progressia.common.util.FloatMathUtils; | ||||||
|  | import ru.windcorp.progressia.common.util.Matrices; | ||||||
|  | import ru.windcorp.progressia.common.util.Vectors; | ||||||
|  | import ru.windcorp.progressia.common.world.entity.EntityData; | ||||||
|  |  | ||||||
|  | public class TestPlayerControls { | ||||||
|  | 	 | ||||||
|  | 	private static final TestPlayerControls INSTANCE = new TestPlayerControls(); | ||||||
|  | 	 | ||||||
|  | 	public static TestPlayerControls getInstance() { | ||||||
|  | 		return INSTANCE; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	private TestPlayerControls() {} | ||||||
|  | 	 | ||||||
|  | 	private static final double MODE_SWITCH_MAX_DELAY = 100 * Units.MILLISECONDS; | ||||||
|  | 	private static final double MIN_JUMP_DELAY = 200 * Units.MILLISECONDS; | ||||||
|  |  | ||||||
|  | 	// Horizontal and vertical max control speed when flying | ||||||
|  | 	private static final float FLYING_SPEED = 6.0f * Units.METERS_PER_SECOND; | ||||||
|  | 	 | ||||||
|  | 	// (0; 1], 1 is instant change, 0 is no control authority | ||||||
|  | 	private static final float FLYING_CONTROL_AUTHORITY = 0.05f; | ||||||
|  | 	 | ||||||
|  | 	// Horizontal and vertical max control speed when walking | ||||||
|  | 	private static final float WALKING_SPEED = 5.0f * Units.METERS_PER_SECOND; | ||||||
|  | 	 | ||||||
|  | 	// (0; 1], 1 is instant change, 0 is no control authority | ||||||
|  | 	private static final float WALKING_CONTROL_AUTHORITY = 0.1f; | ||||||
|  | 	 | ||||||
|  | 	// Vertical velocity instantly add to player when they jump | ||||||
|  | 	private static final float JUMP_VELOCITY = 5f * Units.METERS_PER_SECOND; | ||||||
|  | 	 | ||||||
|  | 	private boolean isFlying = true; | ||||||
|  | 	 | ||||||
|  | 	private int movementForward = 0; | ||||||
|  | 	private int movementRight = 0; | ||||||
|  | 	private int movementUp = 0; | ||||||
|  | 	 | ||||||
|  | 	private double lastSpacePress = Double.NEGATIVE_INFINITY; | ||||||
|  | 	 | ||||||
|  | 	private boolean captureMouse = true; | ||||||
|  | 	private boolean useMinecraftGravity = false; | ||||||
|  | 	 | ||||||
|  | 	private Runnable updateCallback = null; | ||||||
|  | 	 | ||||||
|  | 	public void applyPlayerControls() { | ||||||
|  | 		if (ClientState.getInstance() == null || ClientState.getInstance().getLocalPlayer() == null) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		EntityData player = getPlayer(); | ||||||
|  | 		Mat3 angMat = Matrices.grab3(); | ||||||
|  | 		 | ||||||
|  | 		angMat.identity().rotateZ(player.getYaw()); | ||||||
|  | 		 | ||||||
|  | 		Vec3 movement = Vectors.grab3(); | ||||||
|  | 		 | ||||||
|  | 		movement.set(movementForward, -movementRight, 0); | ||||||
|  | 		 | ||||||
|  | 		if (movementForward != 0 && movementRight != 0) { | ||||||
|  | 			movement.normalize(); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		angMat.mul_(movement); // bug in jglm, .mul() and mul_() are swapped | ||||||
|  | 		 | ||||||
|  | 		if (isFlying) { | ||||||
|  | 			movement.z = movementUp; | ||||||
|  | 			movement.mul(FLYING_SPEED); | ||||||
|  | 			movement.sub(player.getVelocity()); | ||||||
|  | 			movement.mul(FLYING_CONTROL_AUTHORITY); | ||||||
|  | 		} else { | ||||||
|  | 			movement.mul(WALKING_SPEED); | ||||||
|  | 			movement.sub(player.getVelocity()); | ||||||
|  | 			movement.mul(WALKING_CONTROL_AUTHORITY); | ||||||
|  | 			movement.z = 0; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		player.getVelocity().add(movement); | ||||||
|  | 		 | ||||||
|  | 		Matrices.release(angMat); | ||||||
|  | 		Vectors.release(movement); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	public void handleInput(Input input) { | ||||||
|  | 		if (ClientState.getInstance() == null || ClientState.getInstance().getLocalPlayer() == null) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		InputEvent event = input.getEvent(); | ||||||
|  | 		 | ||||||
|  | 		if (event instanceof KeyEvent) { | ||||||
|  | 			if (onKeyEvent((KeyEvent) event)) { | ||||||
|  | 				input.consume(); | ||||||
|  | 			} | ||||||
|  | 		} else if (event instanceof CursorMoveEvent) { | ||||||
|  | 			onMouseMoved((CursorMoveEvent) event); | ||||||
|  | 			input.consume(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private boolean onKeyEvent(KeyEvent event) { | ||||||
|  | 		if (event.isRepeat()) return false; | ||||||
|  | 		 | ||||||
|  | 		int multiplier = event.isPress() ? 1 : -1; | ||||||
|  | 		 | ||||||
|  | 		switch (event.getKey()) { | ||||||
|  | 		case GLFW.GLFW_KEY_W: | ||||||
|  | 			movementForward += +1 * multiplier; | ||||||
|  | 			break; | ||||||
|  | 		case GLFW.GLFW_KEY_S: | ||||||
|  | 			movementForward += -1 * multiplier; | ||||||
|  | 			break; | ||||||
|  | 		case GLFW.GLFW_KEY_A: | ||||||
|  | 			movementRight += -1 * multiplier; | ||||||
|  | 			break; | ||||||
|  | 		case GLFW.GLFW_KEY_D: | ||||||
|  | 			movementRight += +1 * multiplier; | ||||||
|  | 			break; | ||||||
|  | 		case GLFW.GLFW_KEY_SPACE: | ||||||
|  | 			handleSpace(multiplier); | ||||||
|  | 			break; | ||||||
|  | 		case GLFW.GLFW_KEY_LEFT_SHIFT: | ||||||
|  | 			handleShift(multiplier); | ||||||
|  | 			break; | ||||||
|  | 			 | ||||||
|  | 		case GLFW.GLFW_KEY_ESCAPE: | ||||||
|  | 			if (!event.isPress()) return false; | ||||||
|  | 			handleEscape(); | ||||||
|  | 			break; | ||||||
|  | 			 | ||||||
|  | 		case GLFW.GLFW_KEY_F5: | ||||||
|  | 			if (!event.isPress()) return false; | ||||||
|  | 			handleCameraMode(); | ||||||
|  | 			break; | ||||||
|  | 			 | ||||||
|  | 		case GLFW.GLFW_KEY_G: | ||||||
|  | 			if (!event.isPress()) return false; | ||||||
|  | 			handleGravitySwitch(); | ||||||
|  | 			break; | ||||||
|  | 			 | ||||||
|  | 		default: | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private void handleSpace(int multiplier) { | ||||||
|  | 		boolean isPressed = multiplier > 0; | ||||||
|  | 		 | ||||||
|  | 		double timeSinceLastSpacePress = GraphicsInterface.getTime() - lastSpacePress; | ||||||
|  | 		 | ||||||
|  | 		if (isPressed && timeSinceLastSpacePress < MODE_SWITCH_MAX_DELAY) { | ||||||
|  | 			isFlying = !isFlying; | ||||||
|  | 			updateGUI(); | ||||||
|  | 			movementUp = +1; | ||||||
|  | 		} else { | ||||||
|  | 			if (isFlying) { | ||||||
|  | 				movementUp += +1 * multiplier; | ||||||
|  | 			} else { | ||||||
|  | 				if (isPressed && timeSinceLastSpacePress > MIN_JUMP_DELAY) { | ||||||
|  | 					jump(); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		lastSpacePress = GraphicsInterface.getTime(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private void jump() { | ||||||
|  | 		getPlayer().getVelocity().add(0, 0, JUMP_VELOCITY * (useMinecraftGravity ? 2 : 1)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private void handleShift(int multiplier) { | ||||||
|  | 		if (isFlying) { | ||||||
|  | 			movementUp += -1 * multiplier; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private void handleEscape() { | ||||||
|  | 		if (captureMouse) { | ||||||
|  | 			GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL); | ||||||
|  | 		} else { | ||||||
|  | 			GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		captureMouse = !captureMouse; | ||||||
|  | 		updateGUI(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	private void handleCameraMode() { | ||||||
|  | 		if (ClientState.getInstance().getCamera().hasAnchor()) { | ||||||
|  | 			ClientState.getInstance().getCamera().selectNextMode(); | ||||||
|  | 			updateGUI(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private void handleGravitySwitch() { | ||||||
|  | 		useMinecraftGravity = !useMinecraftGravity; | ||||||
|  | 		updateGUI(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private void onMouseMoved(CursorMoveEvent event) { | ||||||
|  | 		if (!captureMouse) return; | ||||||
|  | 		 | ||||||
|  | 		final float yawScale = -0.002f; | ||||||
|  | 		final float pitchScale = yawScale; | ||||||
|  |  | ||||||
|  | 		EntityData player = getPlayer(); | ||||||
|  | 		 | ||||||
|  | 		normalizeAngles(player.getDirection().add( | ||||||
|  | 				(float) (event.getChangeX() * yawScale), | ||||||
|  | 				(float) (event.getChangeY() * pitchScale) | ||||||
|  | 		)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private void normalizeAngles(Vec2 dir) { | ||||||
|  | 		// Normalize yaw | ||||||
|  | 		dir.x = FloatMathUtils.normalizeAngle(dir.x); | ||||||
|  | 		 | ||||||
|  | 		// Clamp pitch | ||||||
|  | 		dir.y = Glm.clamp( | ||||||
|  | 				dir.y, -FloatMathUtils.PI_F/2, +FloatMathUtils.PI_F/2 | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	private EntityData getPlayer() { | ||||||
|  | 		return ClientState.getInstance().getLocalPlayer(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	public void setUpdateCallback(Runnable updateCallback) { | ||||||
|  | 		this.updateCallback = updateCallback; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	private void updateGUI() { | ||||||
|  | 		if (this.updateCallback != null) { | ||||||
|  | 			this.updateCallback.run(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	public boolean isFlying() { | ||||||
|  | 		return isFlying; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	public boolean isMouseCaptured() { | ||||||
|  | 		return captureMouse; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	public boolean useMinecraftGravity() { | ||||||
|  | 		return useMinecraftGravity; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user