Skip to content

Commit

Permalink
Some refactoring for hybrid mode (#67)
Browse files Browse the repository at this point in the history
* refactor hybrid moe

* handle mouse in hybrid mode

* hybrid mode splitted to regular and with mouse

* name cnahges

* crash fixed

* remove cursor locking

---------

Co-authored-by: Innokenty <[email protected]>
Co-authored-by: Anatoly Belikov <[email protected]>
  • Loading branch information
3 people authored Aug 14, 2023
1 parent 74aceab commit 3014c97
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 58 deletions.
125 changes: 75 additions & 50 deletions src/main/java/io/singularitynet/Client/VereyaModClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
import io.singularitynet.mixin.MinecraftClientMixin;
import io.singularitynet.mixin.MouseAccessorMixin;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.minecraft.client.Keyboard;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.Mouse;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.client.gui.screen.*;
import net.minecraft.text.Text;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
Expand All @@ -25,7 +27,7 @@
public class VereyaModClient implements ClientModInitializer, IMalmoModClient, ScreenEvents
{
public static final String CONTROLLABLE = "ControlledMobs";
private InputType prevInputType = null;
private long timeSwitchHybrid = 0;

public static final String AGENT_DEAD_QUIT_CODE = "MALMO_AGENT_DIED";
public static final String AGENT_UNRESPONSIVE_CODE = "MALMO_AGENT_NOT_RESPONDING";
Expand Down Expand Up @@ -87,15 +89,26 @@ public void lockCursor(){

@Override
public boolean isCursorLocked() {
MissionBehaviour behaviour = VereyaModClient.this.stateMachine.currentMissionBehaviour();

// This stops Minecraft from doing the annoying thing of stealing your mouse.
if(VereyaModClient.this.inputType == InputType.AI) {
// do not let to lock if we are overriding inputs
if (behaviour != null && behaviour.commandHandler.isOverriding()) {
return true;
}
return super.isCursorLocked();
}

public void onMouseUsed(){
if (VereyaModClient.this.inputType == InputType.HYBRID_MOUSE_KEYBOARD){
setOverrideHybrid(false);
}
}

public boolean shouldUpdate(){
return VereyaModClient.this.inputType == InputType.HUMAN;
MissionBehaviour behaviour = VereyaModClient.this.stateMachine.currentMissionBehaviour();
// If AI is not overriding we should update the mouse
return behaviour == null || !behaviour.commandHandler.isOverriding();
}

@Override
Expand Down Expand Up @@ -130,7 +143,6 @@ public void onKey(long window, int key, int scancode, int action, int modifiers)

@Override
public void onInitializeClient() {
this.prevInputType = InputType.AI;
this.stateMachine = new ClientStateMachine(ClientState.WAITING_FOR_MOD_READY, (IMalmoModClient) this);
// subscribe to setScreen event
ScreenEvents.SET_SCREEN.register(this);
Expand All @@ -146,6 +158,19 @@ public void setup(){
Mouse mouse = new MyMouse(MinecraftClient.getInstance());
mouse.setup(MinecraftClient.getInstance().getWindow().getHandle());
((MinecraftClientMixin)MinecraftClient.getInstance()).setMouse(mouse);
// register callback to run each frame
ClientTickEvents.END_CLIENT_TICK.register(client -> this.checkHybrideOverrides());
}

private void checkHybrideOverrides() {
if (this.getInputType() == InputType.HYBRID_MOUSE_KEYBOARD) {
MissionBehaviour behaviour = this.stateMachine.currentMissionBehaviour();
if (behaviour != null && !behaviour.commandHandler.isOverriding()) {
long currentTime = System.currentTimeMillis();
if (currentTime - timeSwitchHybrid > 1000)
setOverrideHybrid(true);
}
}
}

@Override
Expand All @@ -156,11 +181,20 @@ public InputType getInputType() {
// Control overriding:
enum InputType
{
HUMAN, AI, HYBRID
HUMAN, AI, HYBRID_KEYBOARD, HYBRID_MOUSE_KEYBOARD;
private static final InputType[] rVals = {HUMAN, AI};
private static final InputType[] hVals = {HYBRID_KEYBOARD, HYBRID_MOUSE_KEYBOARD};

public InputType next() {
return rVals[(this.ordinal() + 1) % rVals.length];
}

public InputType hNext() {
return hVals[(this.ordinal() + 1) % hVals.length];
}
}

protected InputType inputType = InputType.HUMAN;
protected InputType inputTypeAbs = InputType.HUMAN;

private static ClientStateMachine stateMachine;

Expand Down Expand Up @@ -188,10 +222,14 @@ public void setInputType(InputType input)
LOGGER.debug("commandHandler is null, returning");
return;
}
this.stateMachine.currentMissionBehaviour().commandHandler.setOverriding(input == InputType.AI);

this.stateMachine.currentMissionBehaviour().commandHandler.setOverriding(input == InputType.AI || input == InputType.HYBRID_MOUSE_KEYBOARD);

this.inputType = input;
if (input == InputType.HUMAN)
// send chat message
if (MinecraftClient.getInstance().player != null)
MinecraftClient.getInstance().player.sendMessage(Text.of("input type set to: " + input.name()), true);
if (input == InputType.HUMAN || input == InputType.HYBRID_MOUSE_KEYBOARD)
{
MinecraftClient.getInstance().mouse.lockCursor();
}
Expand All @@ -202,55 +240,42 @@ public void setInputType(InputType input)
}

private void onKey(long window, int key, int scancode, int action, int modifiers) {
// do default thing if any screen is open
Screen screen = MinecraftClient.getInstance().currentScreen;
if (screen != null) {
if (screen instanceof ChatScreen) {
return;
}
}

if ((key == GLFW.GLFW_KEY_F6) && (action == GLFW.GLFW_PRESS))
{
if (inputTypeAbs == InputType.HYBRID)
{
inputTypeAbs = this.prevInputType;
setInputType(this.prevInputType);
}
else
{
this.prevInputType = inputTypeAbs;
inputTypeAbs = InputType.HYBRID;
setInputType(InputType.AI);
}
setInputType(inputType.hNext());
}
if (inputTypeAbs==InputType.HYBRID) {
boolean bKey = (key == GLFW.GLFW_KEY_W) || (key == GLFW.GLFW_KEY_S) || (key == GLFW.GLFW_KEY_A) ||
(key == GLFW.GLFW_KEY_D) || (key == GLFW.GLFW_KEY_SPACE);
if (bKey && (action == GLFW.GLFW_PRESS)) {
if ((inputType == InputType.AI) & !(MinecraftClient.getInstance().currentScreen instanceof ChatScreen)) {
setInputType(InputType.HUMAN);
} else {
return;
}
} else if (bKey && (action == GLFW.GLFW_RELEASE)) {
if (inputType == InputType.HUMAN) {
setInputType(InputType.AI);
} else {
return;
}

if (((inputType == InputType.HYBRID_KEYBOARD))) {
if ((action == GLFW.GLFW_PRESS)) {
this.stateMachine.currentMissionBehaviour().commandHandler.setOverriding(false);
} else if ((action == GLFW.GLFW_RELEASE)) {
this.stateMachine.currentMissionBehaviour().commandHandler.setOverriding(true);
}
}

if (key != GLFW.GLFW_KEY_ENTER)
return;
if (action != GLFW.GLFW_PRESS) return;

Screen screen = MinecraftClient.getInstance().currentScreen;
if (screen != null) {
if (screen instanceof ChatScreen) {
// if chat is open, do nothing
return;
}
if (inputType == InputType.HYBRID_MOUSE_KEYBOARD && action == GLFW.GLFW_PRESS) {
// human controls the inputs
setOverrideHybrid(false);
}
if (inputType == InputType.AI) {
setInputType(InputType.HUMAN);
inputTypeAbs = InputType.HUMAN;
} else {
setInputType(InputType.AI);
inputTypeAbs = InputType.AI;

if ((key == GLFW.GLFW_KEY_ENTER) && (action != GLFW.GLFW_RELEASE))
setInputType(inputType.next());
}

private void setOverrideHybrid(boolean override) {
MissionBehaviour behaviour = this.stateMachine.currentMissionBehaviour();
if (behaviour == null) {
return;
}
timeSwitchHybrid = System.currentTimeMillis();
behaviour.commandHandler.setOverriding(override);
}
}
19 changes: 11 additions & 8 deletions src/main/java/io/singularitynet/mixin/MouseMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,31 @@

import io.singularitynet.Client.VereyaModClient;
import net.minecraft.client.Mouse;
import org.apache.logging.log4j.LogManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@Mixin(Mouse.class)
public class MouseMixin {
@Inject(method="onMouseButton", at = @At("HEAD"))
private void onOnMouseButton(long window, int button, int action, int mods, CallbackInfo ci) {
if(VereyaModClient.MyMouse.class.isInstance(this)){
VereyaModClient.MyMouse myMouse = ((VereyaModClient.MyMouse)((Object)this));
myMouse.onMouseUsed();
}
}

/**
* Cancellable injection, note that we set the "cancellable"
* flag to "true" in the injector annotation
*/
@Inject(method = "onCursorPos", at = @At("HEAD"), cancellable = true)
private void onOnCursorPos(long window, double x, double y, CallbackInfo ci) {
if(VereyaModClient.MyMouse.class.isInstance(this)){
// it's not possible to cast 'this' to MyMouse
// one way is to cast this to Object and then object to MyMouse
// or use class.getDeclaredMethod etc
boolean result = ((VereyaModClient.MyMouse)((Object)this)).shouldUpdate();
VereyaModClient.MyMouse myMouse = ((VereyaModClient.MyMouse)((Object)this));
myMouse.onMouseUsed();
boolean result = myMouse.shouldUpdate();
if (result)
return;
ci.cancel();
Expand Down

0 comments on commit 3014c97

Please sign in to comment.