Refactored movement controls

- Movement control code is now in its own class
- Movement direction controls are now more bug-resistant
  - No longer event-driven; uses InputTracker instead
  - Temporarily? function with menus open
- Other movement controls are now registered local Controls
- Removed flying and sprinting indicators from F3 layer
- TestPlayerControls is now a singleton
  - resetInstance() now resets the instance's fields
This commit is contained in:
OLEGSHA 2021-12-13 11:06:28 +03:00
parent b4ff5114bd
commit c93f0df30d
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
7 changed files with 362 additions and 263 deletions

View File

@ -143,20 +143,6 @@ public class ControlTriggers {
); );
} }
//
//
///
///
//
//
//
//
//
//
//
//
//
public static ControlTriggerInputBased localOf( public static ControlTriggerInputBased localOf(
String id, String id,
Consumer<InputEvent> action, Consumer<InputEvent> action,

View File

@ -58,22 +58,6 @@ public class LayerTestGUI extends GUILayer {
TestPlayerControls tpc = TestPlayerControls.getInstance(); TestPlayerControls tpc = TestPlayerControls.getInstance();
group.addChild(
new Label(
"IsFlyingDisplay",
font,
tmp_dynFormat("LayerTestGUI.IsFlyingDisplay", tpc::isFlying)
)
);
group.addChild(
new Label(
"IsSprintingDisplay",
font,
tmp_dynFormat("LayerTestGUI.IsSprintingDisplay", tpc::isSprinting)
)
);
group.addChild( group.addChild(
new Label( new Label(
"CameraModeDisplay", "CameraModeDisplay",

View File

@ -29,12 +29,16 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.lwjgl.glfw.GLFW;
import glm.vec._3.i.Vec3i; import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.client.ClientState; import ru.windcorp.progressia.client.ClientState;
import ru.windcorp.progressia.client.audio.Sound; import ru.windcorp.progressia.client.audio.Sound;
import ru.windcorp.progressia.client.comms.controls.*; import ru.windcorp.progressia.client.comms.controls.*;
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
import ru.windcorp.progressia.client.graphics.input.KeyEvent; import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.KeyMatcher; import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
import ru.windcorp.progressia.client.graphics.input.WheelScrollEvent;
import ru.windcorp.progressia.client.graphics.world.Selection; import ru.windcorp.progressia.client.graphics.world.Selection;
import ru.windcorp.progressia.client.world.block.*; import ru.windcorp.progressia.client.world.block.*;
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerRegistry; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerRegistry;
@ -287,6 +291,8 @@ public class TestContent {
} }
private static void regsiterControls() { private static void regsiterControls() {
TestPlayerControls.getInstance().registerControls();
ControlDataRegistry data = ControlDataRegistry.getInstance(); ControlDataRegistry data = ControlDataRegistry.getInstance();
ControlTriggerRegistry triggers = ControlTriggerRegistry.getInstance(); ControlTriggerRegistry triggers = ControlTriggerRegistry.getInstance();
ControlLogicRegistry logic = ControlLogicRegistry.getInstance(); ControlLogicRegistry logic = ControlLogicRegistry.getInstance();
@ -328,6 +334,33 @@ public class TestContent {
); );
logic.register(ControlLogic.of("Test:PlaceTile", TestContent::onTilePlaceReceived)); logic.register(ControlLogic.of("Test:PlaceTile", TestContent::onTilePlaceReceived));
triggers.register(
ControlTriggers.localOf(
"Test:SwitchPlacingModeMMB",
KeyEvent.class,
() -> TestPlayerControls.getInstance().switchPlacingMode(),
KeyMatcher.MMB::matches
)
);
triggers.register(
ControlTriggers.localOf(
"Test:SwitchPlacingModeWheel",
WheelScrollEvent.class,
() -> TestPlayerControls.getInstance().switchPlacingMode(),
e -> e.hasHorizontalMovement() || InputTracker.isKeyPressed(GLFW.GLFW_KEY_LEFT_CONTROL)
)
);
triggers.register(
ControlTriggers.localOf(
"Test:SelectNextBlockOrTile",
WheelScrollEvent.class,
e -> TestPlayerControls.getInstance().selectNextBlockOrTile(e),
e -> !e.hasHorizontalMovement() && !InputTracker.isKeyPressed(GLFW.GLFW_KEY_LEFT_CONTROL)
)
);
triggers.register( triggers.register(
ControlTriggers.localOf( ControlTriggers.localOf(
"Test:StartNextMusic", "Test:StartNextMusic",

View File

@ -19,7 +19,6 @@
package ru.windcorp.progressia.test; package ru.windcorp.progressia.test;
import glm.Glm; import glm.Glm;
import glm.mat._3.Mat3;
import glm.mat._4.Mat4; import glm.mat._4.Mat4;
import glm.vec._3.Vec3; import glm.vec._3.Vec3;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
@ -27,61 +26,29 @@ import ru.windcorp.progressia.client.ClientState;
import ru.windcorp.progressia.client.graphics.GUI; import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend; 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.backend.InputTracker;
import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent; import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent;
import ru.windcorp.progressia.client.graphics.input.InputEvent; import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.client.graphics.input.KeyEvent; import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.WheelScrollEvent; import ru.windcorp.progressia.client.graphics.input.WheelScrollEvent;
import ru.windcorp.progressia.client.graphics.world.LocalPlayer; import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
import ru.windcorp.progressia.client.localization.Localizer; import ru.windcorp.progressia.client.localization.Localizer;
import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.util.Matrices; import ru.windcorp.progressia.common.util.Matrices;
import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.server.ServerState; import ru.windcorp.progressia.test.controls.MovementControls;
public class TestPlayerControls { public class TestPlayerControls {
private static TestPlayerControls instance = new TestPlayerControls(); private static final TestPlayerControls INSTANCE = new TestPlayerControls();
public static TestPlayerControls getInstance() { public static TestPlayerControls getInstance() {
return instance; return INSTANCE;
} }
private static final double MODE_SWITCH_MAX_DELAY = 300 * Units.MILLISECONDS; private final MovementControls movementControls = new MovementControls();
private static final double MODE_SPRINT_SWITCH_MAX_DELAY = 100 * Units.MILLISECONDS;
private static final double MIN_JUMP_DELAY = 300 * Units.MILLISECONDS;
// Horizontal and vertical max control speed when flying
private static final float FLYING_SPEED = Units.get("6 m/s");
// (0; 1], 1 is instant change, 0 is no control authority
private static final float FLYING_CONTROL_AUTHORITY = Units.get("2 1/s");
// Horizontal max control speed when walking
private static final float WALKING_SPEED = Units.get("4 m/s");
// Horizontal max control speed when sprinting
private static final float SPRINTING_SPEED = Units.get("6 m/s");
// (0; 1], 1 is instant change, 0 is no control authority
private static final float WALKING_CONTROL_AUTHORITY = Units.get("15 1/s");
// Vertical velocity instantly added to player when they jump
private static final float JUMP_VELOCITY = 5f * Units.METERS_PER_SECOND;
private boolean isFlying = true;
private boolean isSprinting = false;
private int movementForward = 0;
private int movementRight = 0;
private int movementUp = 0;
private double lastSpacePress = Double.NEGATIVE_INFINITY;
private double lastSprintPress = Double.NEGATIVE_INFINITY;
private int selectedBlock = 0; private int selectedBlock = 0;
private int selectedTile = 0; private int selectedTile = 0;
@ -90,75 +57,30 @@ public class TestPlayerControls {
private LayerTestGUI debugLayer = null; private LayerTestGUI debugLayer = null;
private Runnable updateCallback = null; private Runnable updateCallback = null;
{
reset();
}
public static void resetInstance() { public static void resetInstance() {
instance = new TestPlayerControls(); INSTANCE.reset();
}
private void reset() {
movementControls.reset();
debugLayer = null;
updateCallback = null;
selectedBlock = 0;
selectedTile = 0;
isBlockSelected = true;
} }
public void applyPlayerControls() { public void applyPlayerControls() {
if (ClientState.getInstance() == null || !ClientState.getInstance().isReady()) { movementControls.applyPlayerControls();
return;
} }
EntityData player = getEntity(); public void registerControls() {
movementControls.registerControls();
final float speed, authority;
if (isFlying) {
speed = FLYING_SPEED;
authority = FLYING_CONTROL_AUTHORITY;
} else {
speed = isSprinting ? SPRINTING_SPEED : WALKING_SPEED;
authority = WALKING_CONTROL_AUTHORITY;
}
Mat3 movementTransform = getMovementTransform(player, null);
Vec3 desiredVelocity = new Vec3(movementForward, movementRight, 0);
if (movementForward != 0 && movementRight != 0) {
desiredVelocity.normalize();
}
desiredVelocity.z = movementUp;
movementTransform.mul_(desiredVelocity); // bug in jglm, .mul() and .mul_() are
// swapped
desiredVelocity.mul(speed);
Vec3 newVelocity = new Vec3()
.set(desiredVelocity)
.sub(player.getVelocity())
.mul((float) Math.exp(-authority * GraphicsInterface.getFrameLength()))
.negate()
.add(desiredVelocity);
if (!isFlying) {
Vec3 up = player.getUpVector();
Vec3 wantedVertical = VectorUtil.projectOnVector(player.getVelocity(), up, null);
VectorUtil.projectOnSurface(newVelocity, up).add(wantedVertical);
}
player.getVelocity().set(newVelocity);
// THIS IS TERRIBLE TEST
EntityData serverEntity = ServerState.getInstance().getWorld().getData()
.getEntity(TestContent.PLAYER_ENTITY_ID);
if (serverEntity != null) {
serverEntity.setPosition(player.getPosition());
}
}
private Mat3 getMovementTransform(EntityData player, Mat3 mat) {
if (mat == null) {
mat = new Mat3();
}
Vec3 f = player.getForwardVector(null);
Vec3 u = player.getUpVector();
Vec3 s = u.cross_(f);
return mat.set(
+f.x, +f.y, +f.z,
-s.x, -s.y, -s.z,
+u.x, +u.y, +u.z
);
} }
public void handleInput(InputEvent event) { public void handleInput(InputEvent event) {
@ -169,81 +91,39 @@ public class TestPlayerControls {
} else if (event instanceof CursorMoveEvent) { } else if (event instanceof CursorMoveEvent) {
onMouseMoved((CursorMoveEvent) event); onMouseMoved((CursorMoveEvent) event);
event.consume(); event.consume();
} else if (event instanceof WheelScrollEvent) {
onWheelScroll((WheelScrollEvent) event);
event.consume();
} }
} }
private boolean onKeyEvent(KeyEvent event) { 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;
handleSprint(event);
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()) if (!event.isPress())
return false; return false;
switch (event.getKey()) {
case GLFW.GLFW_KEY_ESCAPE:
handleEscape(); handleEscape();
break; break;
case GLFW.GLFW_KEY_F11: case GLFW.GLFW_KEY_F11:
if (!event.isPress())
return false;
GraphicsInterface.makeFullscreen(!GraphicsBackend.isFullscreen()); GraphicsInterface.makeFullscreen(!GraphicsBackend.isFullscreen());
updateGUI(); updateGUI();
break; break;
case GLFW.GLFW_KEY_F12: case GLFW.GLFW_KEY_F12:
if (!event.isPress())
return false;
GraphicsBackend.setVSyncEnabled(!GraphicsBackend.isVSyncEnabled()); GraphicsBackend.setVSyncEnabled(!GraphicsBackend.isVSyncEnabled());
updateGUI(); updateGUI();
break; break;
case GLFW.GLFW_KEY_F3: case GLFW.GLFW_KEY_F3:
if (!event.isPress())
return false;
handleDebugLayerSwitch(); handleDebugLayerSwitch();
break; break;
case GLFW.GLFW_KEY_F5: case GLFW.GLFW_KEY_F5:
if (!event.isPress())
return false;
handleCameraMode(); handleCameraMode();
break; break;
case GLFW.GLFW_KEY_L: case GLFW.GLFW_KEY_L:
if (!event.isPress())
return false;
handleLanguageSwitch(); handleLanguageSwitch();
break; break;
case GLFW.GLFW_MOUSE_BUTTON_3:
if (!event.isPress())
return false;
switchPlacingMode();
break;
default: default:
return false; return false;
} }
@ -251,70 +131,7 @@ public class TestPlayerControls {
return true; return true;
} }
private void handleSpace(int multiplier) {
boolean isPressed = multiplier > 0;
double timeSinceLastSpacePress = GraphicsInterface.getTime() - lastSpacePress;
if (isPressed && timeSinceLastSpacePress < MODE_SWITCH_MAX_DELAY) {
isSprinting = false;
isFlying = !isFlying;
updateGUI();
movementUp = +1;
} else {
if (isFlying) {
movementUp += +1 * multiplier;
} else {
if (isPressed && timeSinceLastSpacePress > MIN_JUMP_DELAY) {
jump();
}
}
}
lastSpacePress = GraphicsInterface.getTime();
}
private void handleSprint(KeyEvent event) {
double timeSinceLastSpacePress = GraphicsInterface.getTime() - lastSprintPress;
if (event.isPress() && timeSinceLastSpacePress < MODE_SPRINT_SWITCH_MAX_DELAY && !isFlying) {
isSprinting = !isSprinting;
updateGUI();
}
lastSprintPress = GraphicsInterface.getTime();
if (isSprinting && event.isRelease()) {
isSprinting = false;
updateGUI();
}
}
private void jump() {
if (ClientState.getInstance() == null || !ClientState.getInstance().isReady()) {
return;
}
Vec3 up = getEntity().getUpVector();
getEntity().getVelocity().add(
up.x * JUMP_VELOCITY,
up.y * JUMP_VELOCITY,
up.z * JUMP_VELOCITY
);
}
private void handleShift(int multiplier) {
if (isFlying) {
movementUp += -1 * multiplier;
}
}
private void handleEscape() { private void handleEscape() {
movementForward = 0;
movementRight = 0;
movementUp = 0;
GUI.addTopLayer(new LayerButtonTest()); GUI.addTopLayer(new LayerButtonTest());
} }
@ -390,15 +207,12 @@ public class TestPlayerControls {
Matrices.release(mat); Matrices.release(mat);
} }
private void onWheelScroll(WheelScrollEvent event) { public void switchPlacingMode() {
if (event.hasHorizontalMovement()) { isBlockSelected = !isBlockSelected;
switchPlacingMode(); updateGUI();
}
if (InputTracker.isKeyPressed(GLFW.GLFW_KEY_LEFT_CONTROL)) {
switchPlacingMode();
return;
} }
public void selectNextBlockOrTile(WheelScrollEvent event) {
if (isBlockSelected) { if (isBlockSelected) {
selectedBlock += event.isUp() ? +1 : -1; selectedBlock += event.isUp() ? +1 : -1;
@ -424,11 +238,6 @@ public class TestPlayerControls {
updateGUI(); updateGUI();
} }
private void switchPlacingMode() {
isBlockSelected = !isBlockSelected;
updateGUI();
}
public EntityData getEntity() { public EntityData getEntity() {
return getPlayer().getEntity(); return getPlayer().getEntity();
} }
@ -443,12 +252,8 @@ public class TestPlayerControls {
} }
} }
public boolean isFlying() { public MovementControls getMovementControls() {
return isFlying; return movementControls;
}
public boolean isSprinting() {
return isSprinting;
} }
public BlockData getSelectedBlock() { public BlockData getSelectedBlock() {
@ -463,4 +268,12 @@ public class TestPlayerControls {
return isBlockSelected; return isBlockSelected;
} }
public boolean isFlying() {
return movementControls.isFlying();
}
public boolean isSprinting() {
return movementControls.isSprinting();
}
} }

View File

@ -0,0 +1,287 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* 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.controls;
import org.lwjgl.glfw.GLFW;
import glm.mat._3.Mat3;
import glm.vec._3.Vec3;
import ru.windcorp.progressia.client.ClientState;
import ru.windcorp.progressia.client.comms.controls.ControlTriggerRegistry;
import ru.windcorp.progressia.client.comms.controls.ControlTriggers;
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.TestContent;
public class MovementControls {
/**
* Max delay between space presses that can toggle flying
*/
private static final double FLYING_SWITCH_MAX_DELAY = Units.get("300 ms");
/**
* Max delay between W presses that can toggle sprinting
*/
private static final double SPRINTING_SWITCH_MAX_DELAY = Units.get("300 ms");
/**
* Min delay between jumps
*/
private static final double JUMP_MIN_DELAY = Units.get("300 ms");
/**
* Horizontal and vertical max control speed when flying
*/
private static final float FLYING_SPEED = Units.get("6 m/s");
/**
* (0; 1], 1 is instant change, 0 is no control authority
*/
private static final float FLYING_CONTROL_AUTHORITY = Units.get("2 1/s");
/**
* Horizontal max control speed when walking
*/
private static final float WALKING_SPEED = Units.get("4 m/s");
/**
* Horizontal max control speed when sprinting
*/
private static final float SPRINTING_SPEED = Units.get("6 m/s");
/**
* (0; 1], 1 is instant change, 0 is no control authority
*/
private static final float WALKING_CONTROL_AUTHORITY = Units.get("15 1/s");
/**
* Vertical velocity instantly added to player when they jump
*/
private static final float JUMP_VELOCITY = Units.get("5 m/s");
private boolean isFlying;
private boolean isSprinting;
private double lastSpacePress;
private double lastSprintPress;
{
reset();
}
public void applyPlayerControls() {
if (ClientState.getInstance() == null || !ClientState.getInstance().isReady()) {
return;
}
EntityData player = ClientState.getInstance().getLocalPlayer().getEntity();
assert player != null;
final float speed, authority;
if (isFlying) {
speed = FLYING_SPEED;
authority = FLYING_CONTROL_AUTHORITY;
} else {
speed = isSprinting ? SPRINTING_SPEED : WALKING_SPEED;
authority = WALKING_CONTROL_AUTHORITY;
}
Mat3 movementTransform = getMovementTransform(player, null);
Vec3 desiredVelocity = getDesiredVelocity(movementTransform, speed);
Vec3 newVelocity = getNewVelocity(desiredVelocity, player.getVelocity(), authority, player.getUpVector());
player.getVelocity().set(newVelocity);
tmp_syncServerEntity();
}
private void tmp_syncServerEntity() {
// THIS IS TERRIBLE TEST
EntityData serverEntity = ServerState.getInstance().getWorld().getData()
.getEntity(TestContent.PLAYER_ENTITY_ID);
if (serverEntity != null) {
ClientState.getInstance().getLocalPlayer().getEntity().copy(serverEntity);
}
}
private Mat3 getMovementTransform(EntityData player, Mat3 mat) {
if (mat == null) {
mat = new Mat3();
}
Vec3 f = player.getForwardVector(null);
Vec3 u = player.getUpVector();
Vec3 s = f.cross_(u);
//@formatter:off
return mat.set(
f.x, f.y, f.z,
s.x, s.y, s.z,
u.x, u.y, u.z
);
//@formatter:on
}
private Vec3 getDesiredVelocity(Mat3 movementTransform, float speed) {
int forward = 0;
int right = 0;
int up = 0;
forward += InputTracker.isKeyPressed(GLFW.GLFW_KEY_W) ? 1 : 0;
forward -= InputTracker.isKeyPressed(GLFW.GLFW_KEY_S) ? 1 : 0;
right += InputTracker.isKeyPressed(GLFW.GLFW_KEY_D) ? 1 : 0;
right -= InputTracker.isKeyPressed(GLFW.GLFW_KEY_A) ? 1 : 0;
if (isFlying) {
up += InputTracker.isKeyPressed(GLFW.GLFW_KEY_SPACE) ? 1 : 0;
up -= InputTracker.isKeyPressed(GLFW.GLFW_KEY_LEFT_SHIFT) ? 1 : 0;
}
Vec3 desiredVelocity = new Vec3(forward, right, 0);
if (forward != 0 && right != 0) {
desiredVelocity.normalize();
}
desiredVelocity.z = up;
// bug in jglm, .mul() and .mul_() are swapped
movementTransform.mul_(desiredVelocity);
desiredVelocity.mul(speed);
return desiredVelocity;
}
private Vec3 getNewVelocity(Vec3 desiredVelocity, Vec3 oldVelocity, float authority, Vec3 up) {
// newVelocity = oldVelocity + small change toward desiredVelocity
Vec3 newVelocity = new Vec3()
.set(desiredVelocity)
.sub(oldVelocity)
.mul((float) Math.exp(-authority * GraphicsInterface.getFrameLength()))
.negate()
.add(desiredVelocity);
// If we aren't flying, don't change vertical component
if (!isFlying) {
Vec3 wantedVertical = VectorUtil.projectOnVector(oldVelocity, up, null);
VectorUtil.projectOnSurface(newVelocity, up);
newVelocity.add(wantedVertical);
}
return newVelocity;
}
public void reset() {
isFlying = true;
isSprinting = false;
lastSpacePress = Double.NEGATIVE_INFINITY;
lastSprintPress = Double.NEGATIVE_INFINITY;
}
public void registerControls() {
ControlTriggerRegistry triggers = ControlTriggerRegistry.getInstance();
triggers.register(
ControlTriggers.localOf(
"Test:JumpOrToggleFlight",
KeyEvent.class,
this::handleSpacePress,
new KeyMatcher("Space")::matches
)
);
triggers.register(
ControlTriggers.localOf(
"Test:ToggleSprint",
KeyEvent.class,
this::toggleSprint,
new KeyMatcher("W")::matches,
e -> !isFlying
)
);
triggers.register(
ControlTriggers.localOf(
"Test:DisableSprint",
KeyEvent.class,
this::disableSprint,
new KeyMatcher("W")::matchesIgnoringAction,
KeyEvent::isRelease
)
);
}
private void handleSpacePress(KeyEvent e) {
double timeSinceLastSpacePress = e.getTime() - lastSpacePress;
if (timeSinceLastSpacePress < FLYING_SWITCH_MAX_DELAY) {
isSprinting = false;
isFlying = !isFlying;
} else if (!isFlying && timeSinceLastSpacePress >= JUMP_MIN_DELAY) {
jump();
}
lastSpacePress = e.getTime();
}
private void jump() {
if (ClientState.getInstance() == null || !ClientState.getInstance().isReady()) {
return;
}
EntityData player = ClientState.getInstance().getLocalPlayer().getEntity();
assert player != null;
Vec3 up = player.getUpVector();
player.getVelocity().add(
up.x * JUMP_VELOCITY,
up.y * JUMP_VELOCITY,
up.z * JUMP_VELOCITY
);
}
private void toggleSprint(KeyEvent e) {
if (e.getTime() - lastSprintPress < SPRINTING_SWITCH_MAX_DELAY) {
isSprinting = !isSprinting;
}
lastSprintPress = e.getTime();
}
private void disableSprint(KeyEvent e) {
isSprinting = false;
}
public boolean isFlying() {
return isFlying;
}
public boolean isSprinting() {
return isSprinting;
}
}

View File

@ -4,8 +4,6 @@ LayerAbout.Title = Progressia
LayerAbout.Version = Version: %s LayerAbout.Version = Version: %s
LayerAbout.DebugHint = Debug GUI: F3 LayerAbout.DebugHint = Debug GUI: F3
LayerTestGUI.IsFlyingDisplay = Flying: %5s (Space bar x2)
LayerTestGUI.IsSprintingDisplay = Sprinting: %5s (W x2)
LayerTestGUI.CameraModeDisplay = Camera mode: %5d (F5) LayerTestGUI.CameraModeDisplay = Camera mode: %5d (F5)
LayerTestGUI.LanguageDisplay = Language: %5s (L) LayerTestGUI.LanguageDisplay = Language: %5s (L)
LayerTestGUI.FPSDisplay = FPS: LayerTestGUI.FPSDisplay = FPS:

View File

@ -4,8 +4,6 @@ LayerAbout.Title = Прогрессия
LayerAbout.Version = Версия: %s LayerAbout.Version = Версия: %s
LayerAbout.DebugHint = Отладочный GUI: F3 LayerAbout.DebugHint = Отладочный GUI: F3
LayerTestGUI.IsFlyingDisplay = Полёт: %5s (Пробел x2)
LayerTestGUI.IsSprintingDisplay = Бег: %5s (W x2)
LayerTestGUI.CameraModeDisplay = Камера: %5d (F5) LayerTestGUI.CameraModeDisplay = Камера: %5d (F5)
LayerTestGUI.LanguageDisplay = Язык: %5s (L) LayerTestGUI.LanguageDisplay = Язык: %5s (L)
LayerTestGUI.FPSDisplay = FPS: LayerTestGUI.FPSDisplay = FPS: