Merge branch 'master' into movement-duplicate-switch

This commit is contained in:
Brady
2018-09-07 19:36:06 -05:00
committed by GitHub
95 changed files with 2647 additions and 1339 deletions

View File

@@ -1,71 +1,71 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch;
import net.minecraft.launchwrapper.ITweaker;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.spongepowered.asm.launch.MixinBootstrap;
import org.spongepowered.asm.mixin.MixinEnvironment;
import org.spongepowered.asm.mixin.Mixins;
import org.spongepowered.tools.obfuscation.mcp.ObfuscationServiceMCP;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Brady
* @since 7/31/2018 9:59 PM
*/
public class BaritoneTweaker implements ITweaker {
List<String> args;
@Override
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
this.args = new ArrayList<>(args);
if (gameDir != null) addArg("gameDir", gameDir.getAbsolutePath());
if (assetsDir != null) addArg("assetsDir", assetsDir.getAbsolutePath());
if (profile != null) addArg("version", profile);
}
@Override
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
MixinBootstrap.init();
MixinEnvironment.getDefaultEnvironment().setSide(MixinEnvironment.Side.CLIENT);
MixinEnvironment.getDefaultEnvironment().setObfuscationContext(ObfuscationServiceMCP.NOTCH);
Mixins.addConfiguration("mixins.baritone.json");
}
@Override
public final String getLaunchTarget() {
return "net.minecraft.client.main.Main";
}
@Override
public final String[] getLaunchArguments() {
return this.args.toArray(new String[0]);
}
private void addArg(String label, String value) {
if (!args.contains("--" + label) && value != null) {
this.args.add("--" + label);
this.args.add(value);
}
}
}
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch;
import net.minecraft.launchwrapper.ITweaker;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.spongepowered.asm.launch.MixinBootstrap;
import org.spongepowered.asm.mixin.MixinEnvironment;
import org.spongepowered.asm.mixin.Mixins;
import org.spongepowered.tools.obfuscation.mcp.ObfuscationServiceMCP;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Brady
* @since 7/31/2018 9:59 PM
*/
public class BaritoneTweaker implements ITweaker {
List<String> args;
@Override
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
this.args = new ArrayList<>(args);
if (gameDir != null) addArg("gameDir", gameDir.getAbsolutePath());
if (assetsDir != null) addArg("assetsDir", assetsDir.getAbsolutePath());
if (profile != null) addArg("version", profile);
}
@Override
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
MixinBootstrap.init();
MixinEnvironment.getDefaultEnvironment().setSide(MixinEnvironment.Side.CLIENT);
MixinEnvironment.getDefaultEnvironment().setObfuscationContext(ObfuscationServiceMCP.NOTCH);
Mixins.addConfiguration("mixins.baritone.json");
}
@Override
public final String getLaunchTarget() {
return "net.minecraft.client.main.Main";
}
@Override
public final String[] getLaunchArguments() {
return this.args.toArray(new String[0]);
}
private void addArg(String label, String value) {
if (!args.contains("--" + label) && value != null) {
this.args.add("--" + label);
this.args.add(value);
}
}
}

View File

@@ -1,44 +1,44 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.spongepowered.asm.mixin.MixinEnvironment;
import org.spongepowered.tools.obfuscation.mcp.ObfuscationServiceMCP;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Brady
* @since 7/31/2018 10:09 PM
*/
public class BaritoneTweakerForge extends BaritoneTweaker {
@Override
public final void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
this.args = new ArrayList<>();
}
@Override
public final void injectIntoClassLoader(LaunchClassLoader classLoader) {
super.injectIntoClassLoader(classLoader);
MixinEnvironment.getDefaultEnvironment().setObfuscationContext(ObfuscationServiceMCP.SEARGE);
}
}
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.spongepowered.asm.mixin.MixinEnvironment;
import org.spongepowered.tools.obfuscation.mcp.ObfuscationServiceMCP;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Brady
* @since 7/31/2018 10:09 PM
*/
public class BaritoneTweakerForge extends BaritoneTweaker {
@Override
public final void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
this.args = new ArrayList<>();
}
@Override
public final void injectIntoClassLoader(LaunchClassLoader classLoader) {
super.injectIntoClassLoader(classLoader);
MixinEnvironment.getDefaultEnvironment().setObfuscationContext(ObfuscationServiceMCP.SEARGE);
}
}

View File

@@ -1,34 +1,34 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Brady
* @since 7/31/2018 10:10 PM
*/
public class BaritoneTweakerOptifine extends BaritoneTweaker {
@Override
public final void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
this.args = new ArrayList<>();
}
}
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Brady
* @since 7/31/2018 10:10 PM
*/
public class BaritoneTweakerOptifine extends BaritoneTweaker {
@Override
public final void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
this.args = new ArrayList<>();
}
}

View File

@@ -0,0 +1,58 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.utils.accessor.IAnvilChunkLoader;
import net.minecraft.world.chunk.storage.AnvilChunkLoader;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.io.File;
/**
* @author Brady
* @since 9/4/2018
*/
@Mixin(AnvilChunkLoader.class)
public class MixinAnvilChunkLoader implements IAnvilChunkLoader {
@Shadow @Final private File chunkSaveLocation;
@Override
public File getChunkSaveLocation() {
return this.chunkSaveLocation;
}
}

View File

@@ -29,7 +29,7 @@ import javax.annotation.Nonnull;
* @since 8/25/2018
*/
@Mixin(BlockPos.class)
public abstract class MixinBlockPos extends Vec3i {
public class MixinBlockPos extends Vec3i {
public MixinBlockPos(int xIn, int yIn, int zIn) {
super(xIn, yIn, zIn);

View File

@@ -0,0 +1,57 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.utils.accessor.IChunkProviderServer;
import net.minecraft.world.chunk.storage.IChunkLoader;
import net.minecraft.world.gen.ChunkProviderServer;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
/**
* @author Brady
* @since 9/4/2018
*/
@Mixin(ChunkProviderServer.class)
public class MixinChunkProviderServer implements IChunkProviderServer {
@Shadow @Final private IChunkLoader chunkLoader;
@Override
public IChunkLoader getChunkLoader() {
return this.chunkLoader;
}
}

View File

@@ -18,8 +18,8 @@
package baritone.launch.mixins;
import baritone.Baritone;
import baritone.event.events.RelativeMoveEvent;
import baritone.event.events.type.EventState;
import baritone.api.event.events.RelativeMoveEvent;
import baritone.api.event.events.type.EventState;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;

View File

@@ -18,9 +18,9 @@
package baritone.launch.mixins;
import baritone.Baritone;
import baritone.event.events.ChatEvent;
import baritone.event.events.PlayerUpdateEvent;
import baritone.event.events.type.EventState;
import baritone.api.event.events.ChatEvent;
import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.type.EventState;
import net.minecraft.client.entity.EntityPlayerSP;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

View File

@@ -18,7 +18,7 @@
package baritone.launch.mixins;
import baritone.Baritone;
import baritone.event.events.RenderEvent;
import baritone.api.event.events.RenderEvent;
import net.minecraft.client.renderer.EntityRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

View File

@@ -1,44 +1,44 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.Baritone;
import net.minecraft.client.settings.GameSettings;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* @author Brady
* @since 8/1/2018 12:28 AM
*/
@Mixin(GameSettings.class)
public class MixinGameSettings {
@Redirect(
method = "isKeyDown",
at = @At(
value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
)
)
private static boolean isKeyDown(int keyCode) {
return Baritone.INSTANCE.getInputOverrideHandler().isKeyDown(keyCode);
}
}
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.Baritone;
import net.minecraft.client.settings.GameSettings;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* @author Brady
* @since 8/1/2018 12:28 AM
*/
@Mixin(GameSettings.class)
public class MixinGameSettings {
@Redirect(
method = "isKeyDown",
at = @At(
value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
)
)
private static boolean isKeyDown(int keyCode) {
return Baritone.INSTANCE.getInputOverrideHandler().isKeyDown(keyCode);
}
}

View File

@@ -1,47 +1,47 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.Baritone;
import net.minecraft.client.gui.inventory.GuiContainer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* @author Brady
* @since 7/31/2018 10:47 PM
*/
@Mixin(GuiContainer.class)
public class MixinGuiContainer {
@Redirect(
method = {
"mouseClicked",
"mouseReleased"
},
at = @At(
value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
)
)
private boolean isKeyDown(int keyCode) {
return Baritone.INSTANCE.getInputOverrideHandler().isKeyDown(keyCode);
}
}
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.Baritone;
import net.minecraft.client.gui.inventory.GuiContainer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* @author Brady
* @since 7/31/2018 10:47 PM
*/
@Mixin(GuiContainer.class)
public class MixinGuiContainer {
@Redirect(
method = {
"mouseClicked",
"mouseReleased"
},
at = @At(
value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
)
)
private boolean isKeyDown(int keyCode) {
return Baritone.INSTANCE.getInputOverrideHandler().isKeyDown(keyCode);
}
}

View File

@@ -1,48 +1,48 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.Baritone;
import net.minecraft.client.gui.GuiScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* @author Brady
* @since 7/31/2018 10:38 PM
*/
@Mixin(GuiScreen.class)
public class MixinGuiScreen {
@Redirect(
method = {
"isCtrlKeyDown",
"isShiftKeyDown",
"isAltKeyDown"
},
at = @At(
value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
)
)
private static boolean isKeyDown(int keyCode) {
return Baritone.INSTANCE.getInputOverrideHandler().isKeyDown(keyCode);
}
}
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.Baritone;
import net.minecraft.client.gui.GuiScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* @author Brady
* @since 7/31/2018 10:38 PM
*/
@Mixin(GuiScreen.class)
public class MixinGuiScreen {
@Redirect(
method = {
"isCtrlKeyDown",
"isShiftKeyDown",
"isAltKeyDown"
},
at = @At(
value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
)
)
private static boolean isKeyDown(int keyCode) {
return Baritone.INSTANCE.getInputOverrideHandler().isKeyDown(keyCode);
}
}

View File

@@ -1,43 +1,43 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.Baritone;
import net.minecraft.client.settings.KeyBinding;
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.CallbackInfoReturnable;
/**
* @author Brady
* @since 7/31/2018 11:44 PM
*/
@Mixin(KeyBinding.class)
public abstract class MixinKeyBinding {
@Inject(
method = "isKeyDown",
at = @At("HEAD"),
cancellable = true
)
private void isKeyDown(CallbackInfoReturnable<Boolean> cir) {
if (Baritone.INSTANCE.getInputOverrideHandler().isInputForcedDown((KeyBinding) (Object) this))
cir.setReturnValue(true);
}
}
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.Baritone;
import net.minecraft.client.settings.KeyBinding;
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.CallbackInfoReturnable;
/**
* @author Brady
* @since 7/31/2018 11:44 PM
*/
@Mixin(KeyBinding.class)
public class MixinKeyBinding {
@Inject(
method = "isKeyDown",
at = @At("HEAD"),
cancellable = true
)
private void isKeyDown(CallbackInfoReturnable<Boolean> cir) {
if (Baritone.INSTANCE.getInputOverrideHandler().isInputForcedDown((KeyBinding) (Object) this))
cir.setReturnValue(true);
}
}

View File

@@ -1,174 +1,176 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.Baritone;
import baritone.behavior.impl.PathingBehavior;
import baritone.event.events.BlockInteractEvent;
import baritone.event.events.TickEvent;
import baritone.event.events.WorldEvent;
import baritone.event.events.type.EventState;
import baritone.utils.ExampleBaritoneControl;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
/**
* @author Brady
* @since 7/31/2018 10:51 PM
*/
@Mixin(Minecraft.class)
public class MixinMinecraft {
@Shadow private int leftClickCounter;
@Shadow public EntityPlayerSP player;
@Shadow public WorldClient world;
@Inject(
method = "init",
at = @At("RETURN")
)
private void init(CallbackInfo ci) {
Baritone.INSTANCE.init();
ExampleBaritoneControl.INSTANCE.initAndRegister();
}
@Inject(
method = "runTick",
at = @At(
value = "FIELD",
opcode = Opcodes.GETFIELD,
target = "net/minecraft/client/Minecraft.currentScreen:Lnet/minecraft/client/gui/GuiScreen;",
ordinal = 5,
shift = At.Shift.BY,
by = -3
)
)
private void runTick(CallbackInfo ci) {
Minecraft mc = (Minecraft) (Object) this;
Baritone.INSTANCE.getGameEventHandler().onTick(new TickEvent(
EventState.PRE,
(mc.player != null && mc.world != null)
? TickEvent.Type.IN
: TickEvent.Type.OUT
));
}
@Redirect(
method = "runTickKeyboard",
at = @At(
value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
)
)
private boolean Keyboard$isKeyDown(int keyCode) {
return Baritone.INSTANCE.getInputOverrideHandler().isKeyDown(keyCode);
}
@Inject(
method = "processKeyBinds",
at = @At("HEAD")
)
private void runTickKeyboard(CallbackInfo ci) {
Baritone.INSTANCE.getGameEventHandler().onProcessKeyBinds();
}
@Inject(
method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V",
at = @At("HEAD")
)
private void preLoadWorld(WorldClient world, String loadingMessage, CallbackInfo ci) {
// If we're unloading the world but one doesn't exist, ignore it
if (this.world == null && world == null)
return;
Baritone.INSTANCE.getGameEventHandler().onWorldEvent(
new WorldEvent(
world,
EventState.PRE
)
);
}
@Inject(
method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V",
at = @At("RETURN")
)
private void postLoadWorld(WorldClient world, String loadingMessage, CallbackInfo ci) {
// If we're unloading the world but one doesn't exist, ignore it
if (this.world == null && world == null)
return;
Baritone.INSTANCE.getGameEventHandler().onWorldEvent(
new WorldEvent(
world,
EventState.POST
)
);
}
@Redirect(
method = "runTick",
at = @At(
value = "FIELD",
opcode = Opcodes.GETFIELD,
target = "net/minecraft/client/gui/GuiScreen.allowUserInput:Z"
)
)
private boolean isAllowUserInput(GuiScreen screen) {
return (PathingBehavior.INSTANCE.getCurrent() != null && player != null) || screen.allowUserInput;
}
@Inject(
method = "clickMouse",
at = @At(
value = "INVOKE",
target = "net/minecraft/client/multiplayer/PlayerControllerMP.clickBlock(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;)Z"
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void onBlockBreak(CallbackInfo ci, BlockPos pos) {
Baritone.INSTANCE.getGameEventHandler().onBlockInteract(new BlockInteractEvent(pos, BlockInteractEvent.Type.BREAK));
}
@Inject(
method = "rightClickMouse",
at = @At(
value = "INVOKE",
target = "net/minecraft/client/entity/EntityPlayerSP.swingArm(Lnet/minecraft/util/EnumHand;)V"
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void onBlockUse(CallbackInfo ci, EnumHand var1[], int var2, int var3, EnumHand enumhand, ItemStack itemstack, BlockPos blockpos, int i, EnumActionResult enumactionresult) {
Baritone.INSTANCE.getGameEventHandler().onBlockInteract(new BlockInteractEvent(blockpos, BlockInteractEvent.Type.USE));
}
}
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.Baritone;
import baritone.api.event.events.BlockInteractEvent;
import baritone.api.event.events.TickEvent;
import baritone.api.event.events.WorldEvent;
import baritone.api.event.events.type.EventState;
import baritone.behavior.impl.PathingBehavior;
import baritone.utils.ExampleBaritoneControl;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
/**
* @author Brady
* @since 7/31/2018 10:51 PM
*/
@Mixin(Minecraft.class)
public class MixinMinecraft {
@Shadow
private int leftClickCounter;
@Shadow
public EntityPlayerSP player;
@Shadow
public WorldClient world;
@Inject(
method = "init",
at = @At("RETURN")
)
private void init(CallbackInfo ci) {
Baritone.INSTANCE.init();
ExampleBaritoneControl.INSTANCE.initAndRegister();
}
@Inject(
method = "runTick",
at = @At(
value = "FIELD",
opcode = Opcodes.GETFIELD,
target = "net/minecraft/client/Minecraft.currentScreen:Lnet/minecraft/client/gui/GuiScreen;",
ordinal = 5,
shift = At.Shift.BY,
by = -3
)
)
private void runTick(CallbackInfo ci) {
Minecraft mc = (Minecraft) (Object) this;
Baritone.INSTANCE.getGameEventHandler().onTick(new TickEvent(
EventState.PRE,
(mc.player != null && mc.world != null)
? TickEvent.Type.IN
: TickEvent.Type.OUT
));
}
@Redirect(
method = "runTickKeyboard",
at = @At(
value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
)
)
private boolean Keyboard$isKeyDown(int keyCode) {
return Baritone.INSTANCE.getInputOverrideHandler().isKeyDown(keyCode);
}
@Inject(
method = "processKeyBinds",
at = @At("HEAD")
)
private void runTickKeyboard(CallbackInfo ci) {
Baritone.INSTANCE.getGameEventHandler().onProcessKeyBinds();
}
@Inject(
method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V",
at = @At("HEAD")
)
private void preLoadWorld(WorldClient world, String loadingMessage, CallbackInfo ci) {
// If we're unloading the world but one doesn't exist, ignore it
if (this.world == null && world == null) {
return;
}
Baritone.INSTANCE.getGameEventHandler().onWorldEvent(
new WorldEvent(
world,
EventState.PRE
)
);
}
@Inject(
method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V",
at = @At("RETURN")
)
private void postLoadWorld(WorldClient world, String loadingMessage, CallbackInfo ci) {
// still fire event for both null, as that means we've just finished exiting a world
Baritone.INSTANCE.getGameEventHandler().onWorldEvent(
new WorldEvent(
world,
EventState.POST
)
);
}
@Redirect(
method = "runTick",
at = @At(
value = "FIELD",
opcode = Opcodes.GETFIELD,
target = "net/minecraft/client/gui/GuiScreen.allowUserInput:Z"
)
)
private boolean isAllowUserInput(GuiScreen screen) {
return (PathingBehavior.INSTANCE.getCurrent() != null && player != null) || screen.allowUserInput;
}
@Inject(
method = "clickMouse",
at = @At(
value = "INVOKE",
target = "net/minecraft/client/multiplayer/PlayerControllerMP.clickBlock(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;)Z"
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void onBlockBreak(CallbackInfo ci, BlockPos pos) {
Baritone.INSTANCE.getGameEventHandler().onBlockInteract(new BlockInteractEvent(pos, BlockInteractEvent.Type.BREAK));
}
@Inject(
method = "rightClickMouse",
at = @At(
value = "INVOKE",
target = "net/minecraft/client/entity/EntityPlayerSP.swingArm(Lnet/minecraft/util/EnumHand;)V"
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void onBlockUse(CallbackInfo ci, EnumHand var1[], int var2, int var3, EnumHand enumhand, ItemStack itemstack, BlockPos blockpos, int i, EnumActionResult enumactionresult) {
Baritone.INSTANCE.getGameEventHandler().onBlockInteract(new BlockInteractEvent(blockpos, BlockInteractEvent.Type.USE));
}
}

View File

@@ -18,8 +18,8 @@
package baritone.launch.mixins;
import baritone.Baritone;
import baritone.event.events.ChunkEvent;
import baritone.event.events.type.EventState;
import baritone.api.event.events.ChunkEvent;
import baritone.api.event.events.type.EventState;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.network.play.server.SPacketChunkData;
import net.minecraft.network.play.server.SPacketCombatEvent;

View File

@@ -18,8 +18,8 @@
package baritone.launch.mixins;
import baritone.Baritone;
import baritone.event.events.PacketEvent;
import baritone.event.events.type.EventState;
import baritone.api.event.events.PacketEvent;
import baritone.api.event.events.type.EventState;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.concurrent.Future;
@@ -37,12 +37,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
* @since 8/6/2018 9:30 PM
*/
@Mixin(NetworkManager.class)
public abstract class MixinNetworkManager {
public class MixinNetworkManager {
@Shadow private Channel channel;
@Shadow protected abstract void channelRead0(ChannelHandlerContext p_channelRead0_1_, Packet<?> p_channelRead0_2_) throws Exception;
@Inject(
method = "dispatchPacket",
at = @At("HEAD")

View File

@@ -18,8 +18,8 @@
package baritone.launch.mixins;
import baritone.Baritone;
import baritone.event.events.ChunkEvent;
import baritone.event.events.type.EventState;
import baritone.api.event.events.ChunkEvent;
import baritone.api.event.events.type.EventState;
import net.minecraft.client.multiplayer.WorldClient;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

View File

@@ -1,28 +1,26 @@
{
"required": true,
"package": "baritone.launch.mixins",
"refmap": "mixins.baritone.refmap.json",
"compatibilityLevel": "JAVA_8",
"verbose": false,
"injectors": {
"maxShiftBy": 2
},
"client": [
"MixinBlockPos",
"MixinEntity",
"MixinEntityPlayerSP",
"MixinEntityRenderer",
"MixinGameSettings",
"MixinGuiContainer",
"MixinGuiScreen",
"MixinInventoryPlayer",
"MixinKeyBinding",
"MixinMinecraft",
"MixinNetHandlerPlayClient",
"MixinNetworkManager",
"MixinWorldClient",
"accessor.IAnvilChunkLoader",
"accessor.IChunkProviderServer"
]
{
"required": true,
"package": "baritone.launch.mixins",
"refmap": "mixins.baritone.refmap.json",
"compatibilityLevel": "JAVA_8",
"verbose": false,
"injectors": {
"maxShiftBy": 2
},
"client": [
"MixinAnvilChunkLoader",
"MixinBlockPos",
"MixinChunkProviderServer",
"MixinEntity",
"MixinEntityPlayerSP",
"MixinEntityRenderer",
"MixinGameSettings",
"MixinGuiContainer",
"MixinGuiScreen",
"MixinKeyBinding",
"MixinMinecraft",
"MixinNetHandlerPlayClient",
"MixinNetworkManager",
"MixinWorldClient"
]
}

View File

@@ -17,12 +17,9 @@
package baritone;
import baritone.api.event.GameEventHandler;
import baritone.behavior.Behavior;
import baritone.behavior.impl.LookBehavior;
import baritone.behavior.impl.MemoryBehavior;
import baritone.behavior.impl.PathingBehavior;
import baritone.behavior.impl.LocationTrackingBehavior;
import baritone.event.GameEventHandler;
import baritone.behavior.impl.*;
import baritone.utils.InputOverrideHandler;
import net.minecraft.client.Minecraft;
@@ -31,6 +28,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
/**
* @author Brady
@@ -54,11 +52,20 @@ public enum Baritone {
private List<Behavior> behaviors;
private File dir;
/**
* List of consumers to be called after Baritone has initialized
*/
private List<Consumer<Baritone>> onInitConsumers;
/**
* Whether or not Baritone is active
*/
private boolean active;
Baritone() {
this.onInitConsumers = new ArrayList<>();
}
public synchronized void init() {
if (initialized) {
return;
@@ -72,6 +79,8 @@ public enum Baritone {
registerBehavior(LookBehavior.INSTANCE);
registerBehavior(MemoryBehavior.INSTANCE);
registerBehavior(LocationTrackingBehavior.INSTANCE);
registerBehavior(FollowBehavior.INSTANCE);
registerBehavior(MineBehavior.INSTANCE);
}
this.dir = new File(Minecraft.getMinecraft().gameDir, "baritone");
if (!Files.exists(dir.toPath())) {
@@ -82,6 +91,8 @@ public enum Baritone {
this.active = true;
this.initialized = true;
this.onInitConsumers.forEach(consumer -> consumer.accept(this));
}
public final boolean isInitialized() {
@@ -120,4 +131,8 @@ public enum Baritone {
public final File getDir() {
return this.dir;
}
public final void registerInitListener(Consumer<Baritone> runnable) {
this.onInitConsumers.add(runnable);
}
}

View File

@@ -56,14 +56,20 @@ public class Settings {
*/
public Setting<Boolean> allowWaterBucketFall = new Setting<>(true);
/**
* Allow Baritone to assume it can walk on still water just like any other block.
* This functionality is assumed to be provided by a separate library that might have imported Baritone.
*/
public Setting<Boolean> assumeWalkOnWater = new Setting<>(false);
/**
* Blocks that Baritone is allowed to place (as throwaway, for sneak bridging, pillaring, etc.)
*/
public Setting<List<Item>> acceptableThrowawayItems = new Setting<>(Arrays.asList(
public Setting<List<Item>> acceptableThrowawayItems = new Setting<>(new ArrayList<>(Arrays.asList(
Item.getItemFromBlock(Blocks.DIRT),
Item.getItemFromBlock(Blocks.COBBLESTONE),
Item.getItemFromBlock(Blocks.NETHERRACK)
));
)));
/**
* Enables some more advanced vine features. They're honestly just gimmicks and won't ever be needed in real
@@ -71,6 +77,17 @@ public class Settings {
*/
public Setting<Boolean> allowVines = new Setting<>(false);
/**
* Slab behavior is complicated, disable this for higher path reliability. Leave enabled if you have bottom slabs
* everywhere in your base.
*/
public Setting<Boolean> allowWalkOnBottomSlab = new Setting<>(true);
/**
* For example, if you have Mining Fatigue or Haste, adjust the costs of breaking blocks accordingly.
*/
public Setting<Boolean> considerPotionEffects = new Setting<>(true);
/**
* This is the big A* setting.
* As long as your cost heuristic is an *underestimate*, it's guaranteed to find you the best path.
@@ -116,8 +133,16 @@ public class Settings {
/**
* After calculating a path (potentially through cached chunks), artificially cut it off to just the part that is
* entirely within currently loaded chunks. Improves path safety because cached chunks are heavily simplified.
* See issue #114 for why this is disabled.
*/
public Setting<Boolean> cutoffAtLoadBoundary = new Setting<>(true);
public Setting<Boolean> cutoffAtLoadBoundary = new Setting<>(false);
/**
* Stop 5 movements before anything that made the path COST_INF.
* For example, if lava has spread across the path, don't walk right up to it then recalculate, it might
* still be spreading lol
*/
public Setting<Integer> costVerificationLookahead = new Setting<>(5);
/**
* Static cutoff factor. 0.9 means cut off the last 10% of all paths, regardless of chunk load state
@@ -147,6 +172,13 @@ public class Settings {
*/
public Setting<Integer> maxFallHeightBucket = new Setting<>(20);
/**
* Is it okay to sprint through a descend followed by a diagonal?
* The player overshoots the landing, but not enough to fall off. And the diagonal ensures that there isn't
* lava or anything that's !canWalkInto in that space, so it's technically safe, just a little sketchy.
*/
public Setting<Boolean> allowOvershootDiagonalDescend = new Setting<>(true);
/**
* If your goal is a GoalBlock in an unloaded chunk, assume it's far enough away that the Y coord
* doesn't matter yet, and replace it with a GoalXZ to the same place before calculating a path.
@@ -164,7 +196,12 @@ public class Settings {
/**
* Pathing can never take longer than this
*/
public Setting<Number> pathTimeoutMS = new Setting<>(4000L);
public Setting<Number> pathTimeoutMS = new Setting<>(2000L);
/**
* Planning ahead while executing a segment can never take longer than this
*/
public Setting<Number> planAheadTimeoutMS = new Setting<>(4000L);
/**
* For debugging, consider nodes much much slower
@@ -197,6 +234,11 @@ public class Settings {
*/
public Setting<Boolean> chatControl = new Setting<>(true);
/**
* A second override over chatControl to force it on
*/
public Setting<Boolean> removePrefix = new Setting<>(false);
/**
* Render the path
*/
@@ -309,10 +351,10 @@ public class Settings {
}
@SuppressWarnings("unchecked")
public <T> List<Setting<T>> getByValueType(Class<T> klass) {
public <T> List<Setting<T>> getAllValuesByType(Class<T> klass) {
List<Setting<T>> result = new ArrayList<>();
for (Setting<?> setting : allSettings) {
if (setting.klass.equals(klass)) {
if (setting.getValueClass().equals(klass)) {
result.add((Setting<T>) setting);
}
}

View File

@@ -32,13 +32,14 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event;
package baritone.api.event;
import baritone.Baritone;
import baritone.api.event.events.*;
import baritone.api.event.events.type.EventState;
import baritone.api.event.listener.IGameEventListener;
import baritone.chunk.WorldProvider;
import baritone.event.events.*;
import baritone.event.events.type.EventState;
import baritone.event.listener.IGameEventListener;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.InputOverrideHandler;
import baritone.utils.interfaces.Toggleable;
@@ -133,9 +134,10 @@ public final class GameEventHandler implements IGameEventListener, Helper {
public final void onWorldEvent(WorldEvent event) {
WorldProvider cache = WorldProvider.INSTANCE;
BlockStateInterface.clearCachedChunk();
switch (event.getState()) {
case PRE:
cache.closeWorld();
break;
case POST:
cache.closeWorld();
@@ -157,11 +159,6 @@ public final class GameEventHandler implements IGameEventListener, Helper {
dispatch(listener -> listener.onReceivePacket(event));
}
@Override
public final void onQueryItemSlotForBlocks(ItemSlotEvent event) {
dispatch(listener -> listener.onQueryItemSlotForBlocks(event));
}
@Override
public void onPlayerRelativeMove(RelativeMoveEvent event) {
dispatch(listener -> listener.onPlayerRelativeMove(event));

View File

@@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
package baritone.api.event.events;
import net.minecraft.util.math.BlockPos;

View File

@@ -15,9 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
package baritone.api.event.events;
import baritone.event.events.type.Cancellable;
import baritone.api.event.events.type.Cancellable;
/**
* @author Brady

View File

@@ -15,9 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
package baritone.api.event.events;
import baritone.event.events.type.EventState;
import baritone.api.event.events.type.EventState;
/**
* @author Brady

View File

@@ -15,9 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
package baritone.api.event.events;
import baritone.event.listener.IGameEventListener;
import baritone.api.event.listener.IGameEventListener;
/**
* Called in some cases where a player's inventory has it's current slot queried.

View File

@@ -15,9 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
package baritone.api.event.events;
import baritone.event.events.type.EventState;
import baritone.api.event.events.type.EventState;
import net.minecraft.network.Packet;
/**

View File

@@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
package baritone.api.event.events;
public enum PathEvent {
CALC_STARTED,

View File

@@ -15,9 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
package baritone.api.event.events;
import baritone.event.events.type.EventState;
import baritone.api.event.events.type.EventState;
/**
* @author Brady

View File

@@ -15,9 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
package baritone.api.event.events;
import baritone.event.events.type.EventState;
import baritone.api.event.events.type.EventState;
/**
* @author Brady

View File

@@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
package baritone.api.event.events;
/**
* @author Brady

View File

@@ -15,9 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
package baritone.api.event.events;
import baritone.event.events.type.EventState;
import baritone.api.event.events.type.EventState;
public final class TickEvent {

View File

@@ -15,9 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
package baritone.api.event.events;
import baritone.event.events.type.EventState;
import baritone.api.event.events.type.EventState;
import net.minecraft.client.multiplayer.WorldClient;
/**

View File

@@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events.type;
package baritone.api.event.events.type;
/**
* @author Brady

View File

@@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events.type;
package baritone.api.event.events.type;
/**
* @author Brady

View File

@@ -32,9 +32,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.listener;
package baritone.api.event.listener;
import baritone.event.events.*;
import baritone.api.event.events.*;
/**
* An implementation of {@link IGameEventListener} that has all methods
@@ -74,9 +74,6 @@ public interface AbstractGameEventListener extends IGameEventListener {
@Override
default void onReceivePacket(PacketEvent event) {}
@Override
default void onQueryItemSlotForBlocks(ItemSlotEvent event) {}
@Override
default void onPlayerRelativeMove(RelativeMoveEvent event) {}

View File

@@ -32,11 +32,10 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.listener;
package baritone.api.event.listener;
import baritone.event.events.*;
import baritone.api.event.events.*;
import io.netty.util.concurrent.GenericFutureListener;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiGameOver;
@@ -44,7 +43,6 @@ import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.util.text.ITextComponent;
@@ -120,14 +118,6 @@ public interface IGameEventListener {
*/
void onReceivePacket(PacketEvent event);
/**
* Run when a query is made for a player's inventory current slot in the context of blocks
*
* @see InventoryPlayer#getDestroySpeed(IBlockState)
* @see InventoryPlayer#canHarvestBlock(IBlockState)
*/
void onQueryItemSlotForBlocks(ItemSlotEvent event);
/**
* Run once per game tick from before and after the player's moveRelative method is called
*

View File

@@ -17,7 +17,7 @@
package baritone.behavior;
import baritone.event.listener.AbstractGameEventListener;
import baritone.api.event.listener.AbstractGameEventListener;
import baritone.utils.Helper;
import baritone.utils.interfaces.Toggleable;

View File

@@ -0,0 +1,60 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.behavior.impl;
import baritone.api.event.events.TickEvent;
import baritone.behavior.Behavior;
import baritone.pathing.goals.GoalNear;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos;
/**
* Follow an entity
*
* @author leijurv
*/
public class FollowBehavior extends Behavior {
public static final FollowBehavior INSTANCE = new FollowBehavior();
private FollowBehavior() {
}
Entity following;
@Override
public void onTick(TickEvent event) {
if (event.getType() == TickEvent.Type.OUT) {
return;
}
if (following == null) {
return;
}
// lol this is trashy but it works
PathingBehavior.INSTANCE.setGoal(new GoalNear(new BlockPos(following), 3));
PathingBehavior.INSTANCE.path();
}
public void follow(Entity follow) {
this.following = follow;
}
public void cancel() {
PathingBehavior.INSTANCE.cancel();
follow(null);
}
}

View File

@@ -20,7 +20,7 @@ package baritone.behavior.impl;
import baritone.behavior.Behavior;
import baritone.chunk.Waypoint;
import baritone.chunk.WorldProvider;
import baritone.event.events.BlockInteractEvent;
import baritone.api.event.events.BlockInteractEvent;
import baritone.utils.BlockStateInterface;
import net.minecraft.block.BlockBed;

View File

@@ -20,9 +20,8 @@ package baritone.behavior.impl;
import baritone.Baritone;
import baritone.Settings;
import baritone.behavior.Behavior;
import baritone.event.events.PlayerUpdateEvent;
import baritone.event.events.RelativeMoveEvent;
import baritone.event.events.type.EventState;
import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.RelativeMoveEvent;
import baritone.utils.Rotation;
public class LookBehavior extends Behavior {

View File

@@ -17,10 +17,7 @@
package baritone.behavior.impl;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.Rotation;
import baritone.utils.Utils;
import baritone.utils.*;
import net.minecraft.block.BlockFire;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.*;
@@ -87,18 +84,6 @@ public final class LookBehaviorUtils implements Helper {
return Optional.empty();
}
private static RayTraceResult rayTraceTowards(Rotation rotation) {
double blockReachDistance = mc.playerController.getBlockReachDistance();
Vec3d start = mc.player.getPositionEyes(1.0F);
Vec3d direction = calcVec3dFromRotation(rotation);
Vec3d end = start.add(
direction.x * blockReachDistance,
direction.y * blockReachDistance,
direction.z * blockReachDistance
);
return mc.world.rayTraceBlocks(start, end, false, false, true);
}
/**
* Checks if coordinate is reachable with the given block-face rotation offset
*
@@ -108,7 +93,7 @@ public final class LookBehaviorUtils implements Helper {
*/
protected static Optional<Rotation> reachableOffset(BlockPos pos, Vec3d offsetPos) {
Rotation rotation = Utils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F), offsetPos);
RayTraceResult result = rayTraceTowards(rotation);
RayTraceResult result = RayTraceUtils.rayTraceTowards(rotation);
System.out.println(result);
if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK) {
if (result.getBlockPos().equals(pos)) {

View File

@@ -1,9 +1,9 @@
package baritone.behavior.impl;
import baritone.behavior.Behavior;
import baritone.event.events.PacketEvent;
import baritone.event.events.PlayerUpdateEvent;
import baritone.event.events.type.EventState;
import baritone.api.event.events.PacketEvent;
import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.type.EventState;
import net.minecraft.item.ItemStack;
import net.minecraft.network.Packet;
import net.minecraft.network.play.client.CPacketCloseWindow;
@@ -59,7 +59,7 @@ public class MemoryBehavior extends Behavior {
TileEntityLockable lockable = (TileEntityLockable) tileEntity;
int size = lockable.getSizeInventory();
this.futureInventories.add(new FutureInventory(System.currentTimeMillis(), size, lockable.getGuiID(), tileEntity.getPos()));
this.futureInventories.add(new FutureInventory(System.nanoTime() / 1000000L, size, lockable.getGuiID(), tileEntity.getPos()));
}
}
@@ -81,7 +81,7 @@ public class MemoryBehavior extends Behavior {
SPacketOpenWindow packet = event.cast();
// Remove any entries that were created over a second ago, this should make up for INSANE latency
this.futureInventories.removeIf(i -> System.currentTimeMillis() - i.time > 1000);
this.futureInventories.removeIf(i -> System.nanoTime() / 1000000L - i.time > 1000);
this.futureInventories.stream()
.filter(i -> i.type.equals(packet.getGuiId()) && i.slots == packet.getSlotCount())

View File

@@ -0,0 +1,111 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.behavior.impl;
import baritone.api.event.events.PathEvent;
import baritone.behavior.Behavior;
import baritone.chunk.CachedChunk;
import baritone.chunk.ChunkPacker;
import baritone.chunk.WorldProvider;
import baritone.chunk.WorldScanner;
import baritone.pathing.goals.Goal;
import baritone.pathing.goals.GoalComposite;
import baritone.pathing.goals.GoalTwoBlocks;
import baritone.utils.BlockStateInterface;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* Mine blocks of a certain type
*
* @author leijurv
*/
public class MineBehavior extends Behavior {
public static final MineBehavior INSTANCE = new MineBehavior();
private MineBehavior() {
}
List<String> mining;
@Override
public void onPathEvent(PathEvent event) {
updateGoal();
}
public void updateGoal() {
if (mining == null) {
return;
}
List<BlockPos> locs = scanFor(mining, 64);
if (locs.isEmpty()) {
displayChatMessageRaw("No locations for " + mining + " known, cancelling");
cancel();
return;
}
PathingBehavior.INSTANCE.setGoal(new GoalComposite(locs.stream().map(GoalTwoBlocks::new).toArray(Goal[]::new)));
PathingBehavior.INSTANCE.path();
}
public static List<BlockPos> scanFor(List<String> mining, int max) {
List<BlockPos> locs = new ArrayList<>();
List<String> uninteresting = new ArrayList<>();
//long b = System.currentTimeMillis();
for (String m : mining) {
if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(ChunkPacker.stringToBlock(m))) {
locs.addAll(WorldProvider.INSTANCE.getCurrentWorld().cache.getLocationsOf(m, 1, 1));
} else {
uninteresting.add(m);
}
}
//System.out.println("Scan of cached chunks took " + (System.currentTimeMillis() - b) + "ms");
if (!uninteresting.isEmpty()) {
//long before = System.currentTimeMillis();
locs.addAll(WorldScanner.INSTANCE.scanLoadedChunks(uninteresting, max));
//System.out.println("Scan of loaded chunks took " + (System.currentTimeMillis() - before) + "ms");
}
BlockPos playerFeet = MineBehavior.INSTANCE.playerFeet();
locs.sort(Comparator.comparingDouble(playerFeet::distanceSq));
// remove any that are within loaded chunks that aren't actually what we want
locs.removeAll(locs.stream()
.filter(pos -> !(MineBehavior.INSTANCE.world().getChunk(pos) instanceof EmptyChunk))
.filter(pos -> !mining.contains(ChunkPacker.blockToString(BlockStateInterface.get(pos).getBlock()).toLowerCase()))
.collect(Collectors.toList()));
if (locs.size() > max) {
locs = locs.subList(0, max);
}
return locs;
}
public void mine(String... mining) {
this.mining = mining == null || mining.length == 0 ? null : new ArrayList<>(Arrays.asList(mining));
updateGoal();
}
public void cancel() {
PathingBehavior.INSTANCE.cancel();
mine();
}
}

View File

@@ -18,17 +18,16 @@
package baritone.behavior.impl;
import baritone.Baritone;
import baritone.api.event.events.PathEvent;
import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.RenderEvent;
import baritone.api.event.events.TickEvent;
import baritone.behavior.Behavior;
import baritone.event.events.PathEvent;
import baritone.event.events.PlayerUpdateEvent;
import baritone.event.events.RenderEvent;
import baritone.event.events.TickEvent;
import baritone.pathing.calc.AStarPathFinder;
import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.calc.IPathFinder;
import baritone.pathing.goals.Goal;
import baritone.pathing.goals.GoalBlock;
import baritone.pathing.goals.GoalXZ;
import baritone.pathing.goals.*;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.path.IPath;
import baritone.pathing.path.PathExecutor;
import baritone.utils.BlockStateInterface;
@@ -196,27 +195,39 @@ public class PathingBehavior extends Behavior {
current = null;
next = null;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(AbstractNodeCostSearch::cancel);
}
public void path() {
/**
* Start calculating a path if we aren't already
*
* @return true if this call started path calculation, false if it was already calculating or executing a path
*/
public boolean path() {
if (goal == null) {
return false;
}
if (goal.isInGoal(playerFeet())) {
return false;
}
synchronized (pathPlanLock) {
if (current != null) {
displayChatMessageRaw("Currently executing a path. Please cancel it first.");
return;
return false;
}
synchronized (pathCalcLock) {
if (isPathCalcInProgress) {
return;
return false;
}
dispatchPathEvent(PathEvent.CALC_STARTED);
findPathInNewThread(pathStart(), true, Optional.empty());
return true;
}
}
}
public BlockPos pathStart() {
BlockPos feet = playerFeet();
if (BlockStateInterface.get(feet.down()).getBlock().equals(Blocks.AIR)) {
if (BlockStateInterface.get(feet.down()).getBlock().equals(Blocks.AIR) && MovementHelper.canWalkOn(feet.down().down())) {
return feet.down();
}
return feet;
@@ -293,18 +304,37 @@ public class PathingBehavior extends Behavior {
displayChatMessageRaw("no goal");
return Optional.empty();
}
if (Baritone.settings().simplifyUnloadedYCoord.get() && goal instanceof GoalBlock) {
BlockPos pos = ((GoalBlock) goal).getGoalPos();
if (world().getChunk(pos) instanceof EmptyChunk) {
displayChatMessageRaw("Simplifying GoalBlock to GoalXZ due to distance");
if (Baritone.settings().simplifyUnloadedYCoord.get()) {
BlockPos pos = null;
if (goal instanceof GoalBlock) {
pos = ((GoalBlock) goal).getGoalPos();
}
if (goal instanceof GoalTwoBlocks) {
pos = ((GoalTwoBlocks) goal).getGoalPos();
}
if (goal instanceof GoalNear) {
pos = ((GoalNear) goal).getGoalPos();
}
if (goal instanceof GoalGetToBlock) {
pos = ((GoalGetToBlock) goal).getGoalPos();
}
// TODO simplify each individual goal in a GoalComposite
if (pos != null && world().getChunk(pos) instanceof EmptyChunk) {
displayChatMessageRaw("Simplifying " + goal.getClass() + " to GoalXZ due to distance");
goal = new GoalXZ(pos.getX(), pos.getZ());
}
}
long timeout;
if (current == null) {
timeout = Baritone.settings().pathTimeoutMS.<Long>get();
} else {
timeout = Baritone.settings().planAheadTimeoutMS.<Long>get();
}
try {
IPathFinder pf = new AStarPathFinder(start, goal, previous.map(IPath::positions));
return pf.calculate();
return pf.calculate(timeout);
} catch (Exception e) {
displayChatMessageRaw("Exception: " + e);
displayChatMessageRaw("Pathing exception: " + e);
e.printStackTrace();
return Optional.empty();
}

View File

@@ -121,7 +121,10 @@ public final class CachedChunk implements IBlockTypeAccess {
if (heightMap[internalPos] == y) {
// we have this exact block, it's a surface block
IBlockState state = ChunkPacker.stringToBlock(overview[internalPos]).getDefaultState();
//System.out.println("Saying that " + x + "," + y + "," + z + " is " + state);
/*System.out.println("Saying that " + x + "," + y + "," + z + " is " + state);
if (!Minecraft.getMinecraft().world.getBlockState(new BlockPos(x + this.x * 16, y, z + this.z * 16)).getBlock().equals(state.getBlock())) {
throw new IllegalStateException("failed " + Minecraft.getMinecraft().world.getBlockState(new BlockPos(x + this.x * 16, y, z + this.z * 16)).getBlock() + " " + state.getBlock() + " " + (x + this.x * 16) + " " + y + " " + (z + this.z * 16));
}*/
return state;
}
PathingBlockType type = getType(x, y, z);
@@ -139,7 +142,8 @@ public final class CachedChunk implements IBlockTypeAccess {
int index = z << 4 | x;
heightMap[index] = 0;
for (int y = 256; y >= 0; y--) {
if (getType(x, y, z) != PathingBlockType.AIR) {
int i = getPositionIndex(x, y, z);
if (data.get(i) || data.get(i + 1)) {
heightMap[index] = y;
break;
}
@@ -183,7 +187,7 @@ public final class CachedChunk implements IBlockTypeAccess {
* @return The bit index
*/
public static int getPositionIndex(int x, int y, int z) {
return (x + (z << 4) + (y << 8)) * 2;
return (x << 1) | (z << 5) | (y << 9);
}
/**

View File

@@ -77,6 +77,10 @@ public final class CachedRegion implements IBlockTypeAccess {
return null;
}
public final boolean isCached(int x, int z) {
return chunks[x >> 4][z >> 4] != null;
}
public final LinkedList<BlockPos> getLocationsOf(String block) {
LinkedList<BlockPos> res = new LinkedList<>();
for (int chunkX = 0; chunkX < 32; chunkX++) {
@@ -117,8 +121,8 @@ public final class CachedRegion implements IBlockTypeAccess {
Files.createFile(regionFile);
try (
FileOutputStream fileOut = new FileOutputStream(regionFile.toFile());
GZIPOutputStream gzipOut = new GZIPOutputStream(fileOut);
DataOutputStream out = new DataOutputStream(gzipOut);
GZIPOutputStream gzipOut = new GZIPOutputStream(fileOut, 16384);
DataOutputStream out = new DataOutputStream(gzipOut)
) {
out.writeInt(CACHED_REGION_MAGIC);
for (int z = 0; z < 32; z++) {
@@ -179,12 +183,12 @@ public final class CachedRegion implements IBlockTypeAccess {
return;
System.out.println("Loading region " + x + "," + z + " from disk " + path);
long start = System.currentTimeMillis();
long start = System.nanoTime() / 1000000L;
try (
FileInputStream fileIn = new FileInputStream(regionFile.toFile());
GZIPInputStream gzipIn = new GZIPInputStream(fileIn);
DataInputStream in = new DataInputStream(gzipIn);
GZIPInputStream gzipIn = new GZIPInputStream(fileIn, 32768);
DataInputStream in = new DataInputStream(gzipIn)
) {
int magic = in.readInt();
if (magic != CACHED_REGION_MAGIC) {
@@ -231,21 +235,23 @@ public final class CachedRegion implements IBlockTypeAccess {
if (tmpCached[x][z] != null) {
// 16 * 16 * 256 = 65536 so a short is enough
// ^ haha jokes on leijurv, java doesn't have unsigned types so that isn't correct
// also ur gay if u have more than 32767 special blocks in a chunk
short numSpecialBlockTypes = in.readShort();
// also why would you have more than 32767 special blocks in a chunk
// haha double jokes on you now it works for 65535 not just 32767
int numSpecialBlockTypes = in.readShort() & 0xffff;
for (int i = 0; i < numSpecialBlockTypes; i++) {
String blockName = in.readUTF();
List<BlockPos> locs = new ArrayList<>();
location[x][z].put(blockName, locs);
short numLocations = in.readShort();
int numLocations = in.readShort() & 0xffff;
if (numLocations == 0) {
// an entire chunk full of air can happen in the end
numLocations = 65536;
}
for (int j = 0; j < numLocations; j++) {
byte xz = in.readByte();
int X = xz & 0x0f;
int Z = (xz >>> 4) & 0x0f;
int Y = (int) in.readByte();
if (Y < 0) {
Y += 256;
}
int Y = in.readByte() & 0xff;
locs.add(new BlockPos(X, Y, Z));
}
}
@@ -260,7 +266,7 @@ public final class CachedRegion implements IBlockTypeAccess {
}
}
hasUnsavedChanges = false;
long end = System.currentTimeMillis();
long end = System.nanoTime() / 1000000L;
System.out.println("Loaded region successfully in " + (end - start) + "ms");
} catch (IOException ex) {
ex.printStackTrace();

View File

@@ -59,28 +59,28 @@ public final class CachedWorld implements IBlockTypeAccess {
if (!Files.exists(directory)) {
try {
Files.createDirectories(directory);
} catch (IOException ignored) {}
} catch (IOException ignored) {
}
}
this.directory = directory.toString();
System.out.println("Cached world directory: " + directory);
// Insert an invalid region element
cachedRegions.put(0, null);
new PackerThread().start();
new Thread() {
public void run() {
try {
while (true) {
// since a region only saves if it's been modified since its last save
// saving every 10 minutes means that once it's time to exit
// we'll only have a couple regions to save
save();
Thread.sleep(600000);
}
} catch (InterruptedException e) {
e.printStackTrace();
new Thread(() -> {
try {
Thread.sleep(30000);
while (true) {
// since a region only saves if it's been modified since its last save
// saving every 10 minutes means that once it's time to exit
// we'll only have a couple regions to save
save();
Thread.sleep(600000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}.start();
}).start();
}
public final void queueForPacking(Chunk chunk) {
@@ -101,6 +101,17 @@ public final class CachedWorld implements IBlockTypeAccess {
return region.getBlock(x & 511, y, z & 511);
}
public final boolean isCached(BlockPos pos) {
int x = pos.getX();
int z = pos.getZ();
CachedRegion region = getRegion(x >> 9, z >> 9);
if (region == null) {
return false;
}
return region.isCached(x & 511, z & 511);
}
public final LinkedList<BlockPos> getLocationsOf(String block, int minimum, int maxRegionDistanceSq) {
LinkedList<BlockPos> res = new LinkedList<>();
int playerRegionX = playerFeet().getX() >> 9;
@@ -140,22 +151,22 @@ public final class CachedWorld implements IBlockTypeAccess {
System.out.println("Not saving to disk; chunk caching is disabled.");
return;
}
long start = System.currentTimeMillis();
this.cachedRegions.values().forEach(region -> {
long start = System.nanoTime() / 1000000L;
this.cachedRegions.values().parallelStream().forEach(region -> {
if (region != null)
region.save(this.directory);
});
long now = System.currentTimeMillis();
long now = System.nanoTime() / 1000000L;
System.out.println("World save took " + (now - start) + "ms");
}
public final void reloadAllFromDisk() {
long start = System.currentTimeMillis();
long start = System.nanoTime() / 1000000L;
this.cachedRegions.values().forEach(region -> {
if (region != null)
region.load(this.directory);
});
long now = System.currentTimeMillis();
long now = System.nanoTime() / 1000000L;
System.out.println("World load took " + (now - start) + "ms");
}

View File

@@ -18,18 +18,19 @@
package baritone.chunk;
import baritone.pathing.movement.MovementHelper;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.pathing.PathingBlockType;
import net.minecraft.block.Block;
import net.minecraft.block.BlockAir;
import net.minecraft.block.BlockDoublePlant;
import net.minecraft.block.BlockFlower;
import net.minecraft.block.BlockTallGrass;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.BlockStateContainer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import java.util.*;
@@ -41,46 +42,86 @@ public final class ChunkPacker implements Helper {
private ChunkPacker() {}
private static BitSet originalPacker(Chunk chunk) {
BitSet bitSet = new BitSet(CachedChunk.SIZE);
for (int y = 0; y < 256; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int index = CachedChunk.getPositionIndex(x, y, z);
IBlockState state = chunk.getBlockState(x, y, z);
boolean[] bits = getPathingBlockType(state).getBits();
bitSet.set(index, bits[0]);
bitSet.set(index + 1, bits[1]);
}
}
}
return bitSet;
}
public static CachedChunk pack(Chunk chunk) {
long start = System.currentTimeMillis();
long start = System.nanoTime() / 1000000L;
Map<String, List<BlockPos>> specialBlocks = new HashMap<>();
BitSet bitSet = new BitSet(CachedChunk.SIZE);
try {
for (int y = 0; y < 256; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int index = CachedChunk.getPositionIndex(x, y, z);
Block block = chunk.getBlockState(x, y, z).getBlock();
boolean[] bits = getPathingBlockType(block).getBits();
bitSet.set(index, bits[0]);
bitSet.set(index + 1, bits[1]);
if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(block)) {
String name = blockToString(block);
specialBlocks.computeIfAbsent(name, b -> new ArrayList<>()).add(new BlockPos(x, y, z));
ExtendedBlockStorage[] chunkInternalStorageArray = chunk.getBlockStorageArray();
for (int y0 = 0; y0 < 16; y0++) {
ExtendedBlockStorage extendedblockstorage = chunkInternalStorageArray[y0];
if (extendedblockstorage == null) {
// any 16x16x16 area that's all air will have null storage
// for example, in an ocean biome, with air from y=64 to y=256
// the first 4 extended blocks storages will be full
// and the remaining 12 will be null
// since the index into the bitset is calculated from the x y and z
// and doesn't function as an append, we can entirely skip the scanning
// since a bitset is initialized to all zero, and air is saved as zeros
continue;
}
BlockStateContainer bsc = extendedblockstorage.getData();
int yReal = y0 << 4;
// the mapping of BlockStateContainer.getIndex from xyz to index is y << 8 | z << 4 | x;
// for better cache locality, iterate in that order
for (int y1 = 0; y1 < 16; y1++) {
int y = y1 | yReal;
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int index = CachedChunk.getPositionIndex(x, y, z);
IBlockState state = bsc.get(x, y1, z);
boolean[] bits = getPathingBlockType(state).getBits();
bitSet.set(index, bits[0]);
bitSet.set(index + 1, bits[1]);
Block block = state.getBlock();
if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(block)) {
String name = blockToString(block);
specialBlocks.computeIfAbsent(name, b -> new ArrayList<>()).add(new BlockPos(x, y, z));
}
}
}
}
}
/*if (!bitSet.equals(originalPacker(chunk))) {
throw new IllegalStateException();
}*/
} catch (Exception e) {
e.printStackTrace();
}
//System.out.println("Packed special blocks: " + specialBlocks);
long end = System.currentTimeMillis();
long end = System.nanoTime() / 1000000L;
//System.out.println("Chunk packing took " + (end - start) + "ms for " + chunk.x + "," + chunk.z);
String[] blockNames = new String[256];
for (int z = 0; z < 16; z++) {
outerLoop:
for (int x = 0; x < 16; x++) {
int height = chunk.getHeightValue(x, z);
IBlockState blockState = chunk.getBlockState(x, height, z);
for (int y = height; y > 0; y--) {
blockState = chunk.getBlockState(x, y, z);
if (getPathingBlockType(blockState.getBlock()) != PathingBlockType.AIR) {
break;
for (int y = 255; y >= 0; y--) {
int index = CachedChunk.getPositionIndex(x, y, z);
if (bitSet.get(index) || bitSet.get(index + 1)) {
String name = blockToString(chunk.getBlockState(x, y, z).getBlock());
blockNames[z << 4 | x] = name;
continue outerLoop;
}
}
String name = blockToString(blockState.getBlock());
blockNames[z << 4 | x] = name;
blockNames[z << 4 | x] = "air";
}
}
CachedChunk cached = new CachedChunk(chunk.x, chunk.z, bitSet, blockNames, specialBlocks);
@@ -104,19 +145,21 @@ public final class ChunkPacker implements Helper {
return Block.getBlockFromName(name);
}
private static PathingBlockType getPathingBlockType(Block block) {
if (BlockStateInterface.isWater(block)) {
private static PathingBlockType getPathingBlockType(IBlockState state) {
Block block = state.getBlock();
if (block.equals(Blocks.WATER)) {
// only water source blocks are plausibly usable, flowing water should be avoid
return PathingBlockType.WATER;
}
if (MovementHelper.avoidWalkingInto(block)) {
if (MovementHelper.avoidWalkingInto(block) || block.equals(Blocks.FLOWING_WATER) || MovementHelper.isBottomSlab(state)) {
return PathingBlockType.AVOID;
}
// We used to do an AABB check here
// however, this failed in the nether when you were near a nether fortress
// because fences check their adjacent blocks in the world for their fence connection status to determine AABB shape
// this caused a nullpointerexception when we saved chunks on unload, because they were unable to check their neighbors
if (block instanceof BlockAir || block instanceof BlockTallGrass || block instanceof BlockDoublePlant) {
if (block == Blocks.AIR || block instanceof BlockTallGrass || block instanceof BlockDoublePlant || block instanceof BlockFlower) {
return PathingBlockType.AIR;
}

View File

@@ -17,12 +17,11 @@
package baritone.chunk;
import com.google.common.collect.ImmutableList;
import net.minecraft.util.math.BlockPos;
import org.apache.commons.lang3.ArrayUtils;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
/**
* A single waypoint
@@ -30,6 +29,7 @@ import java.util.Map;
* @author leijurv
*/
public class Waypoint {
public final String name;
public final Tag tag;
private final long creationTimestamp;
@@ -72,19 +72,21 @@ public class Waypoint {
}
public enum Tag {
HOME, DEATH, BED, USER;
HOME("home", "base"),
DEATH("death"),
BED("bed", "spawn"),
USER();
}
private static final List<Tag> TAG_LIST = ImmutableList.<Tag>builder().add(Tag.values()).build();
public static final Map<String, Tag> TAG_MAP;
private final String[] names;
static {
HashMap<String, Tag> map = new HashMap<>();
map.put("home", Tag.HOME);
map.put("base", Tag.HOME);
map.put("bed", Tag.BED);
map.put("spawn", Tag.BED);
map.put("death", Tag.DEATH);
TAG_MAP = Collections.unmodifiableMap(map);
Tag(String... names) {
this.names = names;
}
public static Tag fromString(String name) {
return TAG_LIST.stream().filter(tag -> ArrayUtils.contains(tag.names, name.toLowerCase())).findFirst().orElse(null);
}
}
}

View File

@@ -18,8 +18,8 @@
package baritone.chunk;
import baritone.Baritone;
import baritone.launch.mixins.accessor.IAnvilChunkLoader;
import baritone.launch.mixins.accessor.IChunkProviderServer;
import baritone.utils.accessor.IAnvilChunkLoader;
import baritone.utils.accessor.IChunkProviderServer;
import baritone.utils.Helper;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.server.integrated.IntegratedServer;

View File

@@ -0,0 +1,100 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.chunk;
import baritone.utils.Helper;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.multiplayer.ChunkProviderClient;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.BlockStateContainer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
public enum WorldScanner implements Helper {
INSTANCE;
public List<BlockPos> scanLoadedChunks(List<String> blockTypes, int max) {
List<Block> asBlocks = blockTypes.stream().map(ChunkPacker::stringToBlock).collect(Collectors.toList());
if (asBlocks.contains(null)) {
throw new IllegalStateException("Invalid block name should have been caught earlier: " + blockTypes.toString());
}
LinkedList<BlockPos> res = new LinkedList<>();
if (asBlocks.isEmpty()) {
return res;
}
ChunkProviderClient chunkProvider = world().getChunkProvider();
int playerChunkX = playerFeet().getX() >> 4;
int playerChunkZ = playerFeet().getZ() >> 4;
int searchRadius = 2;
while (true) {
boolean allUnloaded = true;
for (int xoff = -searchRadius; xoff <= searchRadius; xoff++) {
for (int zoff = -searchRadius; zoff <= searchRadius; zoff++) {
int distance = xoff * xoff + zoff * zoff;
if (distance != searchRadius) {
continue;
}
int chunkX = xoff + playerChunkX;
int chunkZ = zoff + playerChunkZ;
Chunk chunk = chunkProvider.getLoadedChunk(chunkX, chunkZ);
if (chunk == null) {
continue;
}
allUnloaded = false;
ExtendedBlockStorage[] chunkInternalStorageArray = chunk.getBlockStorageArray();
chunkX = chunkX << 4;
chunkZ = chunkZ << 4;
for (int y0 = 0; y0 < 16; y0++) {
ExtendedBlockStorage extendedblockstorage = chunkInternalStorageArray[y0];
if (extendedblockstorage == null) {
continue;
}
int yReal = y0 << 4;
BlockStateContainer bsc = extendedblockstorage.getData();
// the mapping of BlockStateContainer.getIndex from xyz to index is y << 8 | z << 4 | x;
// for better cache locality, iterate in that order
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
IBlockState state = bsc.get(x, y, z);
if (asBlocks.contains(state.getBlock())) {
res.add(new BlockPos(chunkX | x, yReal | y, chunkZ | z));
}
}
}
}
}
}
}
if (allUnloaded) {
return res;
}
if (res.size() >= max) {
return res;
}
searchRadius++;
}
}
}

View File

@@ -1,62 +0,0 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.Baritone;
import baritone.event.events.ItemSlotEvent;
import net.minecraft.entity.player.InventoryPlayer;
import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* @author Brady
* @since 8/20/2018
*/
@Mixin(InventoryPlayer.class)
public class MixinInventoryPlayer {
@Redirect(
method = "getDestroySpeed",
at = @At(
value = "FIELD",
opcode = Opcodes.GETFIELD,
target = "net/minecraft/entity/player/InventoryPlayer.currentItem:I"
)
)
private int getDestroySpeed$getCurrentItem(InventoryPlayer inventory) {
ItemSlotEvent event = new ItemSlotEvent(inventory.currentItem);
Baritone.INSTANCE.getGameEventHandler().onQueryItemSlotForBlocks(event);
return event.getSlot();
}
@Redirect(
method = "canHarvestBlock",
at = @At(
value = "FIELD",
opcode = Opcodes.GETFIELD,
target = "net/minecraft/entity/player/InventoryPlayer.currentItem:I"
)
)
private int canHarvestBlock$getCurrentItem(InventoryPlayer inventory) {
ItemSlotEvent event = new ItemSlotEvent(inventory.currentItem);
Baritone.INSTANCE.getGameEventHandler().onQueryItemSlotForBlocks(event);
return event.getSlot();
}
}

View File

@@ -18,9 +18,9 @@
package baritone.pathing.calc;
import baritone.Baritone;
import baritone.chunk.CachedWorld;
import baritone.chunk.WorldProvider;
import baritone.pathing.calc.openset.BinaryHeapOpenSet;
import baritone.pathing.calc.openset.IOpenSet;
import baritone.pathing.goals.Goal;
import baritone.pathing.movement.ActionCosts;
import baritone.pathing.movement.CalculationContext;
@@ -31,9 +31,9 @@ import baritone.pathing.path.IPath;
import baritone.utils.Helper;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ChunkProviderClient;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.Collection;
import java.util.HashSet;
@@ -55,11 +55,11 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
}
@Override
protected Optional<IPath> calculate0() {
protected Optional<IPath> calculate0(long timeout) {
startNode = getNodeAtPosition(start);
startNode.cost = 0;
startNode.combinedCost = startNode.estimatedCostToGoal;
IOpenSet openSet = new BinaryHeapOpenSet();
BinaryHeapOpenSet openSet = new BinaryHeapOpenSet();
openSet.insert(startNode);
startNode.isOpen = true;
bestSoFar = new PathNode[COEFFICIENTS.length];//keep track of the best node by the metric of (estimatedCostToGoal + cost / COEFFICIENTS[i])
@@ -70,17 +70,23 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
CalculationContext calcContext = new CalculationContext();
HashSet<BetterBlockPos> favored = favoredPositions.orElse(null);
currentlyRunning = this;
long startTime = System.currentTimeMillis();
CachedWorld cachedWorld = Optional.ofNullable(WorldProvider.INSTANCE.getCurrentWorld()).map(w -> w.cache).orElse(null);
ChunkProviderClient chunkProvider = Minecraft.getMinecraft().world.getChunkProvider();
long startTime = System.nanoTime() / 1000000L;
boolean slowPath = Baritone.settings().slowPath.get();
long timeoutTime = startTime + (slowPath ? Baritone.settings().slowPathTimeoutMS : Baritone.settings().pathTimeoutMS).<Long>get();
long lastPrintout = 0;
if (slowPath) {
displayChatMessageRaw("slowPath is on, path timeout will be " + Baritone.settings().slowPathTimeoutMS.<Long>get() + "ms instead of " + timeout + "ms");
}
long timeoutTime = startTime + (slowPath ? Baritone.settings().slowPathTimeoutMS.<Long>get() : timeout);
//long lastPrintout = 0;
int numNodes = 0;
int numMovementsConsidered = 0;
int numEmptyChunk = 0;
boolean favoring = favoredPositions.isPresent();
int pathingMaxChunkBorderFetch = Baritone.settings().pathingMaxChunkBorderFetch.get(); // grab all settings beforehand so that changing settings during pathing doesn't cause a crash or unpredictable behavior
double favorCoeff = Baritone.settings().backtrackCostFavoringCoefficient.get();
boolean minimumImprovementRepropagation = Baritone.settings().minimumImprovementRepropagation.get();
while (!openSet.isEmpty() && numEmptyChunk < pathingMaxChunkBorderFetch && System.currentTimeMillis() < timeoutTime) {
while (!openSet.isEmpty() && numEmptyChunk < pathingMaxChunkBorderFetch && System.nanoTime() / 1000000L - timeoutTime < 0 && !cancelRequested) {
if (slowPath) {
try {
Thread.sleep(Baritone.settings().slowPathTimeDelayMS.<Long>get());
@@ -92,39 +98,33 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
mostRecentConsidered = currentNode;
BetterBlockPos currentNodePos = currentNode.pos;
numNodes++;
if (System.currentTimeMillis() > lastPrintout + 1000) {//print once a second
System.out.println("searching... at " + currentNodePos + ", considered " + numNodes + " nodes so far");
lastPrintout = System.currentTimeMillis();
}
if (goal.isInGoal(currentNodePos)) {
currentlyRunning = null;
displayChatMessageRaw("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, " + numMovementsConsidered + " movements considered");
return Optional.of(new Path(startNode, currentNode, numNodes));
}
//long constructStart = System.nanoTime();
Movement[] possibleMovements = getConnectedPositions(currentNodePos, calcContext);//movement that we could take that start at currentNodePos, in random order
shuffle(possibleMovements);
//long constructEnd = System.nanoTime();
//System.out.println(constructEnd - constructStart);
for (Movement movementToGetToNeighbor : possibleMovements) {
if (movementToGetToNeighbor == null) {
continue;
}
BetterBlockPos dest = (BetterBlockPos) movementToGetToNeighbor.getDest();
boolean isPositionCached = false;
if (WorldProvider.INSTANCE.getCurrentWorld() != null) {
if (WorldProvider.INSTANCE.getCurrentWorld().cache.getBlock(dest) != null) {
isPositionCached = true;
int chunkX = currentNodePos.x >> 4;
int chunkZ = currentNodePos.z >> 4;
if (dest.x >> 4 != chunkX || dest.z >> 4 != chunkZ) {
// only need to check if the destination is a loaded chunk if it's in a different chunk than the start of the movement
if (chunkProvider.getLoadedChunk(chunkX, chunkZ) == null) {
// see issue #106
if (cachedWorld == null || !cachedWorld.isCached(dest)) {
numEmptyChunk++;
continue;
}
}
}
if (!isPositionCached && Minecraft.getMinecraft().world.getChunk(dest) instanceof EmptyChunk) {
numEmptyChunk++;
continue;
}
//long costStart = System.nanoTime();
// TODO cache cost
double actionCost = movementToGetToNeighbor.getCost(calcContext);
//long costEnd = System.nanoTime();
//System.out.println(movementToGetToNeighbor.getClass() + "" + (costEnd - costStart));
numMovementsConsidered++;
if (actionCost >= ActionCosts.COST_INF) {
continue;
}
@@ -162,6 +162,9 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
for (int i = 0; i < bestSoFar.length; i++) {
double heuristic = neighbor.estimatedCostToGoal + neighbor.cost / COEFFICIENTS[i];
if (heuristic < bestHeuristicSoFar[i]) {
if (bestHeuristicSoFar[i] - heuristic < 0.01 && minimumImprovementRepropagation) {
continue;
}
bestHeuristicSoFar[i] = heuristic;
bestSoFar[i] = neighbor;
}
@@ -169,6 +172,13 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
}
}
}
if (cancelRequested) {
currentlyRunning = null;
return Optional.empty();
}
System.out.println(numMovementsConsidered + " movements considered");
System.out.println("Open set size: " + openSet.size());
System.out.println((int) (numNodes * 1.0 / ((System.nanoTime() / 1000000L - startTime) / 1000F)) + " nodes per second");
double bestDist = 0;
for (int i = 0; i < bestSoFar.length; i++) {
if (bestSoFar[i] == null) {
@@ -179,18 +189,18 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
bestDist = dist;
}
if (dist > MIN_DIST_PATH * MIN_DIST_PATH) { // square the comparison since distFromStartSq is squared
displayChatMessageRaw("Took " + (System.currentTimeMillis() - startTime) + "ms, A* cost coefficient " + COEFFICIENTS[i]);
displayChatMessageRaw("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, A* cost coefficient " + COEFFICIENTS[i] + ", " + numMovementsConsidered + " movements considered");
if (COEFFICIENTS[i] >= 3) {
System.out.println("Warning: cost coefficient is greater than three! Probably means that");
System.out.println("the path I found is pretty terrible (like sneak-bridging for dozens of blocks)");
System.out.println("But I'm going to do it anyway, because yolo");
}
System.out.println("Path goes for " + dist + " blocks");
System.out.println("Path goes for " + Math.sqrt(dist) + " blocks");
currentlyRunning = null;
return Optional.of(new Path(startNode, bestSoFar[i], numNodes));
}
}
displayChatMessageRaw("Even with a cost coefficient of " + COEFFICIENTS[COEFFICIENTS.length - 1] + ", I couldn't get more than " + bestDist + " blocks =(");
displayChatMessageRaw("Even with a cost coefficient of " + COEFFICIENTS[COEFFICIENTS.length - 1] + ", I couldn't get more than " + Math.sqrt(bestDist) + " blocks");
displayChatMessageRaw("No path found =(");
currentlyRunning = null;
return Optional.empty();

View File

@@ -17,13 +17,13 @@
package baritone.pathing.calc;
import baritone.behavior.impl.PathingBehavior;
import baritone.pathing.goals.Goal;
import baritone.pathing.path.IPath;
import baritone.utils.pathing.BetterBlockPos;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.util.math.BlockPos;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
@@ -42,7 +42,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
protected final Goal goal;
protected final Map<BetterBlockPos, PathNode> map;
private final Long2ObjectOpenHashMap<PathNode> map; // see issue #107
protected PathNode startNode;
@@ -52,6 +52,8 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
private volatile boolean isFinished;
protected boolean cancelRequested;
/**
* This is really complicated and hard to explain. I wrote a comment in the old version of MineBot but it was so
* long it was easier as a Google Doc (because I could insert charts).
@@ -67,19 +69,34 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
AbstractNodeCostSearch(BlockPos start, Goal goal) {
this.start = new BetterBlockPos(start.getX(), start.getY(), start.getZ());
this.goal = goal;
this.map = new HashMap<>();
this.map = new Long2ObjectOpenHashMap<>();
}
public synchronized Optional<IPath> calculate() {
public void cancel() {
cancelRequested = true;
}
public synchronized Optional<IPath> calculate(long timeout) {
if (isFinished) {
throw new IllegalStateException("Path Finder is currently in use, and cannot be reused!");
}
Optional<IPath> path = calculate0();
isFinished = true;
return path;
this.cancelRequested = false;
try {
Optional<IPath> path = calculate0(timeout);
isFinished = true;
return path;
} catch (Exception e) {
currentlyRunning = null;
isFinished = true;
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
} else {
throw new RuntimeException(e);
}
}
}
protected abstract Optional<IPath> calculate0();
protected abstract Optional<IPath> calculate0(long timeout);
/**
* Determines the distance squared from the specified node to the start
@@ -105,7 +122,19 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
* @return The associated node
*/
protected PathNode getNodeAtPosition(BetterBlockPos pos) {
return map.computeIfAbsent(pos, p -> new PathNode(p, goal));
// see issue #107
long hashCode = pos.hashCode;
PathNode node = map.get(hashCode);
if (node == null) {
node = new PathNode(pos, goal);
map.put(hashCode, node);
}
return node;
}
public static void forceCancel() {
PathingBehavior.INSTANCE.cancel();
currentlyRunning = null;
}
@Override

View File

@@ -39,7 +39,7 @@ public interface IPathFinder {
*
* @return The final path
*/
Optional<IPath> calculate();
Optional<IPath> calculate(long timeout);
/**
* Intended to be called concurrently with calculatePath from a different thread to tell if it's finished yet

View File

@@ -26,7 +26,7 @@ import java.util.Arrays;
*
* @author leijurv
*/
public class BinaryHeapOpenSet implements IOpenSet {
public final class BinaryHeapOpenSet implements IOpenSet {
/**
* The initial capacity of the heap (2^10)
@@ -52,6 +52,10 @@ public class BinaryHeapOpenSet implements IOpenSet {
this.array = new PathNode[size];
}
public int size() {
return size;
}
@Override
public final void insert(PathNode value) {
if (size >= array.length - 1) {
@@ -104,14 +108,13 @@ public class BinaryHeapOpenSet implements IOpenSet {
int smallerChild = 2;
double cost = val.combinedCost;
do {
int right = smallerChild + 1;
PathNode smallerChildNode = array[smallerChild];
double smallerChildCost = smallerChildNode.combinedCost;
if (right <= size) {
PathNode rightChildNode = array[right];
if (smallerChild < size) {
PathNode rightChildNode = array[smallerChild + 1];
double rightChildCost = rightChildNode.combinedCost;
if (smallerChildCost > rightChildCost) {
smallerChild = right;
smallerChild++;
smallerChildCost = rightChildCost;
smallerChildNode = rightChildNode;
}
@@ -124,8 +127,7 @@ public class BinaryHeapOpenSet implements IOpenSet {
val.heapPosition = smallerChild;
smallerChildNode.heapPosition = index;
index = smallerChild;
smallerChild = index << 1;
} while (smallerChild <= size);
} while ((smallerChild <<= 1) <= size);
return result;
}
}

View File

@@ -22,10 +22,11 @@ import baritone.pathing.calc.PathNode;
/**
* A linked list implementation of an open set. This is the original implementation from MineBot.
* It has incredibly fast insert performance, at the cost of O(n) removeLowest.
* It sucks. BinaryHeapOpenSet results in more than 10x more nodes considered in 4 seconds.
*
* @author leijurv
*/
public class LinkedListOpenSet implements IOpenSet {
class LinkedListOpenSet implements IOpenSet {
private Node first = null;
@Override

View File

@@ -17,25 +17,47 @@
package baritone.pathing.goals;
import net.minecraft.util.EnumFacing;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.util.math.BlockPos;
/**
* Don't get into the block, but get directly adjacent to it. Useful for chests.
*
* @author avecowa
*/
public class GoalGetToBlock extends GoalComposite {
public class GoalGetToBlock implements Goal {
private final int x;
private final int y;
private final int z;
public GoalGetToBlock(BlockPos pos) {
super(adjacentBlocks(pos));
this.x = pos.getX();
this.y = pos.getY();
this.z = pos.getZ();
}
private static BlockPos[] adjacentBlocks(BlockPos pos) {
BlockPos[] sides = new BlockPos[6];
for (int i = 0; i < 6; i++) {
sides[i] = pos.offset(EnumFacing.values()[i]);
public BlockPos getGoalPos() {
return new BetterBlockPos(x, y, z);
}
@Override
public boolean isInGoal(BlockPos pos) {
int xDiff = pos.getX() - this.x;
int yDiff = pos.getY() - this.y;
int zDiff = pos.getZ() - this.z;
if (yDiff < 0) {
yDiff++;
}
return sides;
return Math.abs(xDiff) + Math.abs(yDiff) + Math.abs(zDiff) <= 1;
}
@Override
public double heuristic(BlockPos pos) {
int xDiff = pos.getX() - this.x;
int yDiff = pos.getY() - this.y;
int zDiff = pos.getZ() - this.z;
return GoalBlock.calculate(xDiff, yDiff, zDiff);
}
}

View File

@@ -0,0 +1,64 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.pathing.goals;
import net.minecraft.util.math.BlockPos;
public class GoalNear implements Goal {
final int x;
final int y;
final int z;
final int rangeSq;
public GoalNear(BlockPos pos, int range) {
this.x = pos.getX();
this.y = pos.getY();
this.z = pos.getZ();
this.rangeSq = range * range;
}
@Override
public boolean isInGoal(BlockPos pos) {
int diffX = x - pos.getX();
int diffY = y - pos.getY();
int diffZ = z - pos.getZ();
return diffX * diffX + diffY * diffY + diffZ * diffZ <= rangeSq;
}
@Override
public double heuristic(BlockPos pos) {
int diffX = x - pos.getX();
int diffY = y - pos.getY();
int diffZ = z - pos.getZ();
return GoalBlock.calculate(diffX, diffY, diffZ);
}
public BlockPos getGoalPos() {
return new BlockPos(x, y, z);
}
@Override
public String toString() {
return "GoalNear{" +
"x=" + x +
", y=" + y +
", z=" + z +
", rangeSq=" + rangeSq +
'}';
}
}

View File

@@ -68,6 +68,10 @@ public class GoalTwoBlocks implements Goal {
return GoalBlock.calculate(xDiff, yDiff, zDiff);
}
public BlockPos getGoalPos() {
return new BlockPos(x, y, z);
}
@Override
public String toString() {
return "GoalTwoBlocks{x=" + x + ",y=" + y + ",z=" + z + "}";

View File

@@ -20,6 +20,7 @@ package baritone.pathing.goals;
import baritone.Baritone;
import baritone.utils.Utils;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
/**
@@ -88,9 +89,9 @@ public class GoalXZ implements Goal {
}
public static GoalXZ fromDirection(Vec3d origin, float yaw, double distance) {
double theta = Utils.degToRad(yaw);
double x = origin.x - Math.sin(theta) * distance;
double z = origin.z + Math.cos(theta) * distance;
float theta = (float) Utils.degToRad(yaw);
double x = origin.x - MathHelper.sin(theta) * distance;
double z = origin.z + MathHelper.cos(theta) * distance;
return new GoalXZ((int) x, (int) z);
}

View File

@@ -24,7 +24,8 @@ public interface ActionCosts extends ActionCostsButOnlyTheOnesThatMakeMickeyDieI
*/
double WALK_ONE_BLOCK_COST = 20 / 4.317; // 4.633
double WALK_ONE_IN_WATER_COST = 20 / 2.2;
double WALK_ONE_OVER_SOUL_SAND_COST = WALK_ONE_IN_WATER_COST; // TODO issue #7
double WALK_ONE_OVER_SOUL_SAND_COST = WALK_ONE_BLOCK_COST * 0.5; // 0.4 in BlockSoulSand but effectively about half
double SPRINT_ONE_OVER_SOUL_SAND_COST = WALK_ONE_OVER_SOUL_SAND_COST / 0.75;
double LADDER_UP_ONE_COST = 20 / 2.35;
double LADDER_DOWN_ONE_COST = 20 / 3.0;
double SNEAK_ONE_BLOCK_COST = 20 / 1.3;

View File

@@ -46,7 +46,6 @@ public class CalculationContext implements Helper {
}
public CalculationContext(ToolSet toolSet) {
player().setSprinting(true);
this.toolSet = toolSet;
this.hasThrowaway = Baritone.settings().allowPlace.get() && MovementHelper.throwaway(false);
this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.get() && InventoryPlayer.isHotbar(player().inventory.getSlotFor(STACK_BUCKET_WATER)) && !world().provider.isNether();

View File

@@ -21,18 +21,13 @@ import baritone.Baritone;
import baritone.behavior.impl.LookBehavior;
import baritone.behavior.impl.LookBehaviorUtils;
import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.pathing.movement.movements.MovementDownward;
import baritone.pathing.movement.movements.MovementPillar;
import baritone.pathing.movement.movements.MovementTraverse;
import baritone.utils.*;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLadder;
import net.minecraft.block.BlockVine;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@@ -40,6 +35,8 @@ import static baritone.utils.InputOverrideHandler.Input;
public abstract class Movement implements Helper, MovementHelper {
protected static final EnumFacing[] HORIZONTALS = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST};
private MovementState currentState = new MovementState().setStatus(MovementStatus.PREPPING);
protected final BlockPos src;
@@ -52,44 +49,34 @@ public abstract class Movement implements Helper, MovementHelper {
protected final BlockPos[] positionsToBreak;
/**
* The positions where we need to place a block before this movement can ensue
* The position where we need to place a block before this movement can ensue
*/
protected final BlockPos[] positionsToPlace;
protected final BlockPos positionToPlace;
private boolean didBreakLastTick;
private Double cost;
protected Movement(BlockPos src, BlockPos dest, BlockPos[] toBreak, BlockPos[] toPlace) {
protected Movement(BlockPos src, BlockPos dest, BlockPos[] toBreak, BlockPos toPlace) {
this.src = src;
this.dest = dest;
this.positionsToBreak = toBreak;
this.positionsToPlace = toPlace;
this.positionToPlace = toPlace;
}
protected Movement(BlockPos src, BlockPos dest, BlockPos[] toBreak, BlockPos[] toPlace, Vec3d rotationTarget) {
this(src, dest, toBreak, toPlace);
protected Movement(BlockPos src, BlockPos dest, BlockPos[] toBreak) {
this(src, dest, toBreak, null);
}
public double getCost(CalculationContext context) {
if (cost == null) {
if (context == null)
context = new CalculationContext();
cost = calculateCost0(context);
cost = calculateCost(context);
}
return cost;
}
private double calculateCost0(CalculationContext context) {
if (!(this instanceof MovementPillar) && !(this instanceof MovementTraverse) && !(this instanceof MovementDownward)) {
Block fromDown = BlockStateInterface.get(src.down()).getBlock();
if (fromDown instanceof BlockLadder || fromDown instanceof BlockVine) {
return COST_INF;
}
}
return calculateCost(context);
}
protected abstract double calculateCost(CalculationContext context);
public double recalculateCost() {
@@ -97,6 +84,10 @@ public abstract class Movement implements Helper, MovementHelper {
return getCost(null);
}
public double calculateCostWithoutCaching() {
return calculateCost(new CalculationContext());
}
/**
* Handles the execution of the latest Movement
* State, and offers a Status to the calling class.
@@ -104,7 +95,6 @@ public abstract class Movement implements Helper, MovementHelper {
* @return Status
*/
public MovementStatus update() {
player().setSprinting(false);
MovementState latestState = updateState(currentState);
if (BlockStateInterface.isLiquid(playerFeet())) {
latestState.setInput(Input.JUMP, true);
@@ -159,7 +149,7 @@ public abstract class Movement implements Helper, MovementHelper {
somethingInTheWay = true;
Optional<Rotation> reachable = LookBehaviorUtils.reachable(blockPos);
if (reachable.isPresent()) {
player().inventory.currentItem = new ToolSet().getBestSlot(BlockStateInterface.get(blockPos));
MovementHelper.switchToBestToolFor(BlockStateInterface.get(blockPos));
state.setTarget(new MovementState.MovementTarget(reachable.get(), true)).setInput(Input.CLICK_LEFT, true);
return false;
}
@@ -215,39 +205,53 @@ public abstract class Movement implements Helper, MovementHelper {
}
public double getTotalHardnessOfBlocksToBreak(CalculationContext ctx) {
/*
double sum = 0;
HashSet<BlockPos> toBreak = new HashSet();
for (BlockPos positionsToBreak1 : positionsToBreak) {
toBreak.add(positionsToBreak1);
if (this instanceof ActionFall) {//if we are digging straight down, assume we have already broken the sand above us
continue;
}
BlockPos tmp = positionsToBreak1.up();
while (canFall(tmp)) {
toBreak.add(tmp);
tmp = tmp.up();
}
if (positionsToBreak.length == 0) {
return 0;
}
for (BlockPos pos : toBreak) {
sum += getHardness(ts, Baritone.get(pos), pos);
if (sum >= COST_INF) {
return COST_INF;
}
if (positionsToBreak.length == 1) {
return MovementHelper.getMiningDurationTicks(ctx, positionsToBreak[0], true);
}
if (!Baritone.allowBreakOrPlace || !Baritone.hasThrowaway) {
for (int i = 0; i < blocksToPlace.length; i++) {
if (!canWalkOn(positionsToPlace[i])) {
return COST_INF;
int firstColumnX = positionsToBreak[0].getX();
int firstColumnZ = positionsToBreak[0].getZ();
int firstColumnMaxY = positionsToBreak[0].getY();
int firstColumnMaximalIndex = 0;
boolean hasSecondColumn = false;
int secondColumnX = -1;
int secondColumnZ = -1;
int secondColumnMaxY = -1;
int secondColumnMaximalIndex = -1;
for (int i = 0; i < positionsToBreak.length; i++) {
BlockPos pos = positionsToBreak[i];
if (pos.getX() == firstColumnX && pos.getZ() == firstColumnZ) {
if (pos.getY() > firstColumnMaxY) {
firstColumnMaxY = pos.getY();
firstColumnMaximalIndex = i;
}
} else {
if (!hasSecondColumn || (pos.getX() == secondColumnX && pos.getZ() == secondColumnZ)) {
if (hasSecondColumn) {
if (pos.getY() > secondColumnMaxY) {
secondColumnMaxY = pos.getY();
secondColumnMaximalIndex = i;
}
} else {
hasSecondColumn = true;
secondColumnX = pos.getX();
secondColumnZ = pos.getZ();
secondColumnMaxY = pos.getY();
secondColumnMaximalIndex = i;
}
} else {
throw new IllegalStateException("I literally have no idea " + Arrays.asList(positionsToBreak));
}
}
}*/
//^ the above implementation properly deals with falling blocks, TODO integrate
}
double sum = 0;
for (BlockPos pos : positionsToBreak) {
sum += MovementHelper.getMiningDurationTicks(ctx, pos);
for (int i = 0; i < positionsToBreak.length; i++) {
sum += MovementHelper.getMiningDurationTicks(ctx, positionsToBreak[i], firstColumnMaximalIndex == i || secondColumnMaximalIndex == i);
if (sum >= COST_INF) {
return COST_INF;
break;
}
}
return sum;
@@ -274,6 +278,10 @@ public abstract class Movement implements Helper, MovementHelper {
return state;
}
public BlockPos getDirection() {
return getDest().subtract(getSrc());
}
public List<BlockPos> toBreakCached = null;
public List<BlockPos> toPlaceCached = null;
public List<BlockPos> toWalkIntoCached = null;
@@ -297,10 +305,8 @@ public abstract class Movement implements Helper, MovementHelper {
return toPlaceCached;
}
List<BlockPos> result = new ArrayList<>();
for (BlockPos positionToBreak : positionsToPlace) {
if (!MovementHelper.canWalkOn(positionToBreak)) {
result.add(positionToBreak);
}
if (positionToPlace != null && !MovementHelper.canWalkOn(positionToPlace)) {
result.add(positionToPlace);
}
toPlaceCached = result;
return result;

View File

@@ -48,16 +48,14 @@ public interface MovementHelper extends ActionCosts, Helper {
static boolean avoidBreaking(BlockPos pos, IBlockState state) {
Block b = state.getBlock();
BlockPos below = new BlockPos(pos.getX(), pos.getY() - 1, pos.getZ());
Block below = BlockStateInterface.get(new BlockPos(pos.getX(), pos.getY() - 1, pos.getZ())).getBlock();
return Blocks.ICE.equals(b) // ice becomes water, and water can mess up the path
|| b instanceof BlockSilverfish // obvious reasons
|| BlockStateInterface.isLiquid(new BlockPos(pos.getX(), pos.getY() + 1, pos.getZ()))//don't break anything touching liquid on any side
|| BlockStateInterface.isLiquid(new BlockPos(pos.getX() + 1, pos.getY(), pos.getZ()))
|| BlockStateInterface.isLiquid(new BlockPos(pos.getX() - 1, pos.getY(), pos.getZ()))
|| BlockStateInterface.isLiquid(new BlockPos(pos.getX(), pos.getY(), pos.getZ() + 1))
|| BlockStateInterface.isLiquid(new BlockPos(pos.getX(), pos.getY(), pos.getZ() - 1))
|| (!(b instanceof BlockLilyPad && BlockStateInterface.isWater(below)) && BlockStateInterface.isLiquid(below));//if it's a lilypad above water, it's ok to break, otherwise don't break if its liquid
// TODO revisit this. why is it not okay to break non-lilypads that are right above water?
|| BlockStateInterface.isLiquid(new BlockPos(pos.getX(), pos.getY(), pos.getZ() - 1));
}
/**
@@ -93,10 +91,18 @@ public interface MovementHelper extends ActionCosts, Helper {
return true;
}
}
IBlockState up = BlockStateInterface.get(pos.up());
if (BlockStateInterface.isFlowing(state) || up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) {
if (BlockStateInterface.isFlowing(state)) {
return false; // Don't walk through flowing liquids
}
if (block instanceof BlockLiquid) {
if (Baritone.settings().assumeWalkOnWater.get()) {
return false;
}
IBlockState up = BlockStateInterface.get(pos.up());
if (up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) {
return false;
}
}
return block.isPassable(mc.world, pos);
}
@@ -158,7 +164,7 @@ public interface MovementHelper extends ActionCosts, Helper {
return true;
}
return (facing == playerFacing) == open;
return facing == playerFacing == open;
}
static boolean avoidWalkingInto(Block block) {
@@ -178,6 +184,9 @@ public interface MovementHelper extends ActionCosts, Helper {
*/
static boolean canWalkOn(BlockPos pos, IBlockState state) {
Block block = state.getBlock();
if (block == Blocks.AIR) {
return false;
}
if (block instanceof BlockLadder || (Baritone.settings().allowVines.get() && block instanceof BlockVine)) { // TODO reconsider this
return true;
}
@@ -187,12 +196,33 @@ public interface MovementHelper extends ActionCosts, Helper {
if (Blocks.FARMLAND.equals(block) || Blocks.GRASS_PATH.equals(block)) {
return true;
}
if (block instanceof BlockAir) {
return false;
if (Blocks.ENDER_CHEST.equals(block) || Blocks.CHEST.equals(block)) {
return true;
}
if (block instanceof BlockSlab) {
if (!Baritone.settings().allowWalkOnBottomSlab.get()) {
if (((BlockSlab) block).isDouble()) {
return true;
}
return state.getValue(BlockSlab.HALF) != BlockSlab.EnumBlockHalf.BOTTOM;
}
return true;
}
if (block instanceof BlockStairs) {
return true;
}
if (BlockStateInterface.isWater(block)) {
Block up = BlockStateInterface.get(pos.up()).getBlock();
return BlockStateInterface.isWater(up) || up instanceof BlockLilyPad; // You can only walk on water if there is water above it
if (up instanceof BlockLilyPad) {
return true;
}
if (BlockStateInterface.isFlowing(state)) {
// the only scenario in which we can walk on flowing water is if it's under still water with jesus off
return BlockStateInterface.isWater(up) && !Baritone.settings().assumeWalkOnWater.get();
}
// if assumeWalkOnWater is on, we can only walk on water if there isn't water above it
// if assumeWalkOnWater is off, we can only walk on water if there is water above it
return BlockStateInterface.isWater(up) ^ Baritone.settings().assumeWalkOnWater.get();
}
if (Blocks.MAGMA.equals(block)) {
return false;
@@ -208,12 +238,18 @@ public interface MovementHelper extends ActionCosts, Helper {
return BlockStateInterface.get(pos).getBlock() instanceof BlockFalling;
}
static double getMiningDurationTicks(CalculationContext context, BlockPos position) {
IBlockState state = BlockStateInterface.get(position);
return getMiningDurationTicks(context, position, state);
static boolean canPlaceAgainst(BlockPos pos) {
IBlockState state = BlockStateInterface.get(pos);
// TODO isBlockNormalCube isn't the best check for whether or not we can place a block against it. e.g. glass isn't normalCube but we can place against it
return state.isBlockNormalCube();
}
static double getMiningDurationTicks(CalculationContext context, BlockPos position, IBlockState state) {
static double getMiningDurationTicks(CalculationContext context, BlockPos position, boolean includeFalling) {
IBlockState state = BlockStateInterface.get(position);
return getMiningDurationTicks(context, position, state, includeFalling);
}
static double getMiningDurationTicks(CalculationContext context, BlockPos position, IBlockState state, boolean includeFalling) {
Block block = state.getBlock();
if (!block.equals(Blocks.AIR) && !canWalkThrough(position, state)) { // TODO is the air check really necessary? Isn't air canWalkThrough?
if (!context.allowBreak()) {
@@ -223,9 +259,31 @@ public interface MovementHelper extends ActionCosts, Helper {
return COST_INF;
}
double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; // TODO see if this is still necessary. it's from MineBot when we wanted to penalize breaking its crafting table
return m / context.getToolSet().getStrVsBlock(state, position);
double strVsBlock = context.getToolSet().getStrVsBlock(state);
if (strVsBlock < 0)
return COST_INF;
double result = m / strVsBlock;
if (includeFalling) {
BlockPos up = position.up();
IBlockState above = BlockStateInterface.get(up);
if (above.getBlock() instanceof BlockFalling) {
result += getMiningDurationTicks(context, up, above, true);
}
}
return result;
}
return 0;
return 0; // we won't actually mine it, so don't check fallings above
}
static boolean isBottomSlab(IBlockState state) {
return state.getBlock() instanceof BlockSlab
&& !((BlockSlab) state.getBlock()).isDouble()
&& state.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM;
}
static boolean isBottomSlab(BlockPos pos) {
return isBottomSlab(BlockStateInterface.get(pos));
}
/**
@@ -304,22 +362,22 @@ public interface MovementHelper extends ActionCosts, Helper {
static Movement generateMovementFallOrDescend(BlockPos pos, BlockPos dest, CalculationContext calcContext) {
// A
//SA
// B
// A
// B
// C
// D
//if S is where you start, both of B need to be air for a movementfall
//if S is where you start, B needs to be air for a movementfall
//A is plausibly breakable by either descend or fall
//C, D, etc determine the length of the fall
for (int i = 1; i < 3; i++) {
if (!canWalkThrough(dest.down(i))) {
//if any of these two (B in the diagram) aren't air
//have to do a descend, because fall is impossible
//this doesn't guarantee descend is possible, it just guarantees fall is impossible
return new MovementDescend(pos, dest.down()); // standard move out by 1 and descend by 1
}
if (!canWalkThrough(dest.down(2))) {
//if B in the diagram aren't air
//have to do a descend, because fall is impossible
//this doesn't guarantee descend is possible, it just guarantees fall is impossible
return new MovementDescend(pos, dest.down()); // standard move out by 1 and descend by 1
}
// we're clear for a fall 2
// let's see how far we can fall
for (int fallHeight = 3; true; fallHeight++) {

View File

@@ -39,29 +39,10 @@ import java.util.Objects;
public class MovementAscend extends Movement {
private BlockPos[] against = new BlockPos[3];
private int ticksWithoutPlacement = 0;
public MovementAscend(BlockPos src, BlockPos dest) {
super(src, dest, new BlockPos[]{dest, src.up(2), dest.up()}, new BlockPos[]{dest.down()});
BlockPos placementLocation = positionsToPlace[0]; // dest.down()
int i = 0;
if (!placementLocation.north().equals(src))
against[i++] = placementLocation.north();
if (!placementLocation.south().equals(src))
against[i++] = placementLocation.south();
if (!placementLocation.east().equals(src))
against[i++] = placementLocation.east();
if (!placementLocation.west().equals(src))
against[i] = placementLocation.west();
// TODO: add ability to place against .down() as well as the cardinal directions
// useful for when you are starting a staircase without anything to place against
// Counterpoint to the above TODO ^ you should move then pillar instead of ascend
super(src, dest, new BlockPos[]{dest, src.up(2), dest.up()}, dest.down());
}
@Override
@@ -72,16 +53,34 @@ public class MovementAscend extends Movement {
@Override
protected double calculateCost(CalculationContext context) {
IBlockState toPlace = BlockStateInterface.get(positionsToPlace[0]);
if (!MovementHelper.canWalkOn(positionsToPlace[0], toPlace)) {
IBlockState srcDown = BlockStateInterface.get(src.down());
if (srcDown.getBlock() == Blocks.LADDER || srcDown.getBlock() == Blocks.VINE) {
return COST_INF;
}
// we can jump from soul sand, but not from a bottom slab
boolean jumpingFromBottomSlab = MovementHelper.isBottomSlab(srcDown);
IBlockState toPlace = BlockStateInterface.get(positionToPlace);
boolean jumpingToBottomSlab = MovementHelper.isBottomSlab(toPlace);
if (jumpingFromBottomSlab && !jumpingToBottomSlab) {
return COST_INF;// the only thing we can ascend onto from a bottom slab is another bottom slab
}
if (!MovementHelper.canWalkOn(positionToPlace, toPlace)) {
if (!context.hasThrowaway()) {
return COST_INF;
}
if (!BlockStateInterface.isAir(toPlace) && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(positionsToPlace[0], toPlace)) {
if (!BlockStateInterface.isAir(toPlace) && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(positionToPlace, toPlace)) {
return COST_INF;
}
for (BlockPos against1 : against) {
if (BlockStateInterface.get(against1).isBlockNormalCube()) {
// TODO: add ability to place against .down() as well as the cardinal directions
// useful for when you are starting a staircase without anything to place against
// Counterpoint to the above TODO ^ you should move then pillar instead of ascend
for (int i = 0; i < 4; i++) {
BlockPos against1 = positionToPlace.offset(HORIZONTALS[i]);
if (against1.equals(src)) {
continue;
}
if (MovementHelper.canPlaceAgainst(against1)) {
return JUMP_ONE_BLOCK_COST + WALK_ONE_BLOCK_COST + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context);
}
}
@@ -108,9 +107,11 @@ public class MovementAscend extends Movement {
// it's possible srcUp is AIR from the start, and srcUp2 is falling
// and in that scenario, when we arrive and break srcUp2, that lets srcUp3 fall on us and suffocate us
}
// TODO maybe change behavior if src.down() is soul sand?
double walk = WALK_ONE_BLOCK_COST;
if (toPlace.getBlock().equals(Blocks.SOUL_SAND)) {
if (jumpingToBottomSlab && !jumpingFromBottomSlab) {
return walk + getTotalHardnessOfBlocksToBreak(context); // we don't hit space we just walk into the slab
}
if (!jumpingToBottomSlab && toPlace.getBlock().equals(Blocks.SOUL_SAND)) {
walk *= WALK_ONE_OVER_SOUL_SAND_COST / WALK_ONE_BLOCK_COST;
}
// we hit space immediately on entering this action
@@ -129,9 +130,14 @@ public class MovementAscend extends Movement {
return state.setStatus(MovementStatus.SUCCESS);
}
if (!MovementHelper.canWalkOn(positionsToPlace[0])) {
for (BlockPos anAgainst : against) {
if (BlockStateInterface.get(anAgainst).isBlockNormalCube()) {
IBlockState jumpingOnto = BlockStateInterface.get(positionToPlace);
if (!MovementHelper.canWalkOn(positionToPlace, jumpingOnto)) {
for (int i = 0; i < 4; i++) {
BlockPos anAgainst = positionToPlace.offset(HORIZONTALS[i]);
if (anAgainst.equals(src)) {
continue;
}
if (MovementHelper.canPlaceAgainst(anAgainst)) {
if (!MovementHelper.throwaway(true)) {//get ready to place a throwaway block
return state.setStatus(MovementStatus.UNREACHABLE);
}
@@ -142,7 +148,7 @@ public class MovementAscend extends Movement {
EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit;
LookBehaviorUtils.getSelectedBlock().ifPresent(selectedBlock -> {
if (Objects.equals(selectedBlock, anAgainst) && selectedBlock.offset(side).equals(positionsToPlace[0])) {
if (Objects.equals(selectedBlock, anAgainst) && selectedBlock.offset(side).equals(positionToPlace)) {
ticksWithoutPlacement++;
state.setInput(InputOverrideHandler.Input.SNEAK, true);
if (player().isSneaking()) {
@@ -152,6 +158,8 @@ public class MovementAscend extends Movement {
// After 20 ticks without placement, we might be standing in the way, move back
state.setInput(InputOverrideHandler.Input.MOVE_BACK, true);
}
} else {
state.setInput(InputOverrideHandler.Input.CLICK_LEFT, true); // break whatever replaceable block is in the way
}
System.out.println("Trying to look at " + anAgainst + ", actually looking at" + selectedBlock);
});
@@ -161,6 +169,11 @@ public class MovementAscend extends Movement {
return state.setStatus(MovementStatus.UNREACHABLE);
}
MovementHelper.moveTowards(state, dest);
if (MovementHelper.isBottomSlab(jumpingOnto)) {
if (!MovementHelper.isBottomSlab(src.down())) {
return state; // don't jump while walking from a non double slab into a bottom slab
}
}
if (headBonkClear()) {
return state.setInput(InputOverrideHandler.Input.JUMP, true);

View File

@@ -25,15 +25,13 @@ import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLadder;
import net.minecraft.block.BlockVine;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
public class MovementDescend extends Movement {
public MovementDescend(BlockPos start, BlockPos end) {
super(start, end, new BlockPos[]{end.up(2), end.up(), end}, new BlockPos[]{end.down()});
super(start, end, new BlockPos[]{end.up(2), end.up(), end}, end.down());
}
@Override
@@ -44,18 +42,22 @@ public class MovementDescend extends Movement {
@Override
protected double calculateCost(CalculationContext context) {
if (!MovementHelper.canWalkOn(positionsToPlace[0])) {
Block fromDown = BlockStateInterface.get(src.down()).getBlock();
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return COST_INF;
}
if (!MovementHelper.canWalkOn(positionToPlace)) {
return COST_INF;
}
Block tmp1 = BlockStateInterface.get(dest).getBlock();
if (tmp1 instanceof BlockLadder || tmp1 instanceof BlockVine) {
if (tmp1 == Blocks.LADDER || tmp1 == Blocks.VINE) {
return COST_INF;
}
// we walk half the block plus 0.3 to get to the edge, then we walk the other 0.2 while simultaneously falling (math.max because of how it's in parallel)
double walk = WALK_OFF_BLOCK_COST;
if (BlockStateInterface.get(src.down()).getBlock().equals(Blocks.SOUL_SAND)) {
if (fromDown == Blocks.SOUL_SAND) {
// use this ratio to apply the soul sand speed penalty to our 0.8 block distance
walk *= WALK_ONE_OVER_SOUL_SAND_COST / WALK_ONE_BLOCK_COST;
walk = WALK_ONE_OVER_SOUL_SAND_COST;
}
return walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST) + getTotalHardnessOfBlocksToBreak(context);
}

View File

@@ -17,12 +17,13 @@
package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import net.minecraft.block.Block;
import net.minecraft.block.BlockMagma;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
@@ -49,66 +50,52 @@ public class MovementDiagonal extends Movement {
super(start, end, new BlockPos[]{dir1, dir1.up(), dir2, dir2.up(), end, end.up()}, new BlockPos[]{end.down()});
}
@Override
public MovementState updateState(MovementState state) {
super.updateState(state);
if (state.getStatus() != MovementState.MovementStatus.RUNNING)
return state;
if (playerFeet().equals(dest)) {
state.setStatus(MovementState.MovementStatus.SUCCESS);
return state;
}
if (!BlockStateInterface.isLiquid(playerFeet()) && Baritone.settings().allowSprint.get()) {
player().setSprinting(true);
}
MovementHelper.moveTowards(state, dest);
return state;
}
@Override
protected double calculateCost(CalculationContext context) {
Block fromDown = BlockStateInterface.get(src.down()).getBlock();
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return COST_INF;
}
if (!MovementHelper.canWalkThrough(positionsToBreak[4]) || !MovementHelper.canWalkThrough(positionsToBreak[5])) {
return COST_INF;
}
IBlockState destWalkOn = BlockStateInterface.get(positionsToPlace[0]);
if (!MovementHelper.canWalkOn(positionsToPlace[0], destWalkOn)) {
BlockPos destDown = dest.down();
IBlockState destWalkOn = BlockStateInterface.get(destDown);
if (!MovementHelper.canWalkOn(destDown, destWalkOn)) {
return COST_INF;
}
double multiplier = WALK_ONE_BLOCK_COST;
// For either possible soul sand, that affects half of our walking
if (destWalkOn.getBlock().equals(Blocks.SOUL_SAND)) {
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
}
if (BlockStateInterface.get(src.down()).getBlock().equals(Blocks.SOUL_SAND)) {
if (fromDown == Blocks.SOUL_SAND) {
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
}
if (BlockStateInterface.get(positionsToBreak[2].down()).getBlock() instanceof BlockMagma) {
Block cuttingOver1 = BlockStateInterface.get(positionsToBreak[2].down()).getBlock();
if (cuttingOver1 instanceof BlockMagma || BlockStateInterface.isLava(cuttingOver1)) {
return COST_INF;
}
if (BlockStateInterface.get(positionsToBreak[4].down()).getBlock() instanceof BlockMagma) {
Block cuttingOver2 = BlockStateInterface.get(positionsToBreak[4].down()).getBlock();
if (cuttingOver2 instanceof BlockMagma || BlockStateInterface.isLava(cuttingOver2)) {
return COST_INF;
}
double optionA = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0]) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1]);
double optionB = MovementHelper.getMiningDurationTicks(context, positionsToBreak[2]) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[3]);
IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]);
IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]);
IBlockState pb2 = BlockStateInterface.get(positionsToBreak[2]);
IBlockState pb3 = BlockStateInterface.get(positionsToBreak[3]);
double optionA = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0], pb0, false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1], pb1, true);
double optionB = MovementHelper.getMiningDurationTicks(context, positionsToBreak[2], pb2, false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[3], pb3, true);
if (optionA != 0 && optionB != 0) {
return COST_INF;
}
if (optionA == 0) {
if (MovementHelper.avoidWalkingInto(BlockStateInterface.getBlock(positionsToBreak[2]))) {
return COST_INF;
}
if (MovementHelper.avoidWalkingInto(BlockStateInterface.getBlock(positionsToBreak[3]))) {
if (MovementHelper.avoidWalkingInto(pb2.getBlock()) || MovementHelper.avoidWalkingInto(pb3.getBlock())) {
return COST_INF;
}
}
if (optionB == 0) {
if (MovementHelper.avoidWalkingInto(BlockStateInterface.getBlock(positionsToBreak[0]))) {
return COST_INF;
}
if (MovementHelper.avoidWalkingInto(BlockStateInterface.getBlock(positionsToBreak[1]))) {
if (MovementHelper.avoidWalkingInto(pb0.getBlock()) || MovementHelper.avoidWalkingInto(pb1.getBlock())) {
return COST_INF;
}
}
@@ -129,6 +116,23 @@ public class MovementDiagonal extends Movement {
return multiplier * SQRT_2;
}
@Override
public MovementState updateState(MovementState state) {
super.updateState(state);
if (state.getStatus() != MovementState.MovementStatus.RUNNING)
return state;
if (playerFeet().equals(dest)) {
state.setStatus(MovementState.MovementStatus.SUCCESS);
return state;
}
if (!BlockStateInterface.isLiquid(playerFeet())) {
state.setInput(InputOverrideHandler.Input.SPRINT, true);
}
MovementHelper.moveTowards(state, dest);
return state;
}
@Override
protected boolean prepared(MovementState state) {
return true;

View File

@@ -23,9 +23,8 @@ import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLadder;
import net.minecraft.block.BlockVine;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
public class MovementDownward extends Movement {
@@ -33,7 +32,7 @@ public class MovementDownward extends Movement {
private int numTicks = 0;
public MovementDownward(BlockPos start, BlockPos end) {
super(start, end, new BlockPos[]{end}, new BlockPos[0]);
super(start, end, new BlockPos[]{end});
}
@Override
@@ -49,11 +48,12 @@ public class MovementDownward extends Movement {
}
IBlockState d = BlockStateInterface.get(dest);
Block td = d.getBlock();
boolean ladder = td instanceof BlockLadder || td instanceof BlockVine;
boolean ladder = td == Blocks.LADDER || td == Blocks.VINE;
if (ladder) {
return LADDER_DOWN_ONE_COST;
} else {
return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context, dest, d);
// we're standing on it, while it might be block falling, it'll be air by the time we get here in the movement
return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context, dest, d, false);
}
}

View File

@@ -25,7 +25,11 @@ import baritone.pathing.movement.MovementState;
import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.utils.*;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFalling;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
@@ -38,14 +42,22 @@ public class MovementFall extends Movement {
private static final ItemStack STACK_BUCKET_EMPTY = new ItemStack(Items.BUCKET);
public MovementFall(BlockPos src, BlockPos dest) {
super(src, dest, MovementFall.buildPositionsToBreak(src, dest), new BlockPos[]{dest.down()});
super(src, dest, MovementFall.buildPositionsToBreak(src, dest));
}
@Override
protected double calculateCost(CalculationContext context) {
if (!MovementHelper.canWalkOn(positionsToPlace[0])) {
Block fromDown = BlockStateInterface.get(src.down()).getBlock();
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return COST_INF;
}
IBlockState fallOnto = BlockStateInterface.get(dest.down());
if (!MovementHelper.canWalkOn(dest.down(), fallOnto)) {
return COST_INF;
}
if (MovementHelper.isBottomSlab(fallOnto)) {
return COST_INF; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect
}
double placeBucketCost = 0.0;
if (!BlockStateInterface.isWater(dest) && src.getY() - dest.getY() > context.maxFallHeightNoWater()) {
if (!context.hasWaterBucket()) {
@@ -56,25 +68,29 @@ public class MovementFall extends Movement {
}
placeBucketCost = context.placeBlockCost();
}
double frontTwo = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0]) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1]);
if (frontTwo >= COST_INF) {
return COST_INF;
double frontThree = 0;
for (int i = 0; i < 3; i++) {
frontThree += MovementHelper.getMiningDurationTicks(context, positionsToBreak[i], false);
// don't include falling because we will check falling right after this, and if it's there it's COST_INF
if (frontThree >= COST_INF) {
return COST_INF;
}
}
if (BlockStateInterface.get(positionsToBreak[0].up()).getBlock() instanceof BlockFalling) {
return COST_INF;
}
for (int i = 2; i < positionsToBreak.length; i++) {
for (int i = 3; i < positionsToBreak.length; i++) {
// TODO is this the right check here?
// MiningDurationTicks is all right, but shouldn't it be canWalkThrough instead?
// Lilypads (i think?) are 0 ticks to mine, but they definitely cause fall damage
// Same thing for falling through water... we can't actually do that
// And falling through signs is possible, but they do have a mining duration, right?
if (MovementHelper.getMiningDurationTicks(context, positionsToBreak[i]) > 0) {
if (MovementHelper.getMiningDurationTicks(context, positionsToBreak[i], false) > 0) {
//can't break while falling
return COST_INF;
}
}
return WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[positionsToBreak.length - 1] + placeBucketCost + frontTwo;
return WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[positionsToBreak.length - 1] + placeBucketCost + frontThree;
}
@Override
@@ -86,7 +102,7 @@ public class MovementFall extends Movement {
BlockPos playerFeet = playerFeet();
Rotation targetRotation = null;
if (!BlockStateInterface.isWater(dest) && src.getY() - dest.getY() > Baritone.settings().maxFallHeightNoWater.get() && !playerFeet.equals(dest)) {
if (!player().inventory.hasItemStack(STACK_BUCKET_WATER) || world().provider.isNether()) {
if (!InventoryPlayer.isHotbar(player().inventory.getSlotFor(STACK_BUCKET_WATER)) || world().provider.isNether()) {
state.setStatus(MovementStatus.UNREACHABLE);
return state;
}
@@ -109,7 +125,7 @@ public class MovementFall extends Movement {
}
if (playerFeet.equals(dest) && (player().posY - playerFeet.getY() < 0.094 // lilypads
|| BlockStateInterface.isWater(dest))) {
if (BlockStateInterface.isWater(dest) && player().inventory.hasItemStack(STACK_BUCKET_EMPTY)) {
if (BlockStateInterface.isWater(dest) && InventoryPlayer.isHotbar(player().inventory.getSlotFor(STACK_BUCKET_EMPTY))) {
player().inventory.currentItem = player().inventory.getSlotFor(STACK_BUCKET_EMPTY);
if (player().motionY >= 0) {
return state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);

View File

@@ -28,14 +28,13 @@ import baritone.utils.Utils;
import net.minecraft.block.*;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.util.math.BlockPos;
public class MovementPillar extends Movement {
private int numTicks = 0;
public MovementPillar(BlockPos start, BlockPos end) {
super(start, end, new BlockPos[]{start.up(2)}, new BlockPos[]{start});
super(start, end, new BlockPos[]{start.up(2)}, start);
}
@Override
@@ -48,11 +47,16 @@ public class MovementPillar extends Movement {
protected double calculateCost(CalculationContext context) {
Block fromDown = BlockStateInterface.get(src).getBlock();
boolean ladder = fromDown instanceof BlockLadder || fromDown instanceof BlockVine;
Block fromDownDown = BlockStateInterface.get(src.down()).getBlock();
IBlockState fromDownDown = BlockStateInterface.get(src.down());
if (!ladder) {
if (fromDownDown instanceof BlockLadder || fromDownDown instanceof BlockVine) {
if (fromDownDown.getBlock() instanceof BlockLadder || fromDownDown.getBlock() instanceof BlockVine) {
return COST_INF;
}
if (fromDownDown.getBlock() instanceof BlockSlab) {
if (!((BlockSlab) fromDownDown.getBlock()).isDouble() && fromDownDown.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM) {
return COST_INF; // can't pillar up from a bottom slab onto a non ladder
}
}
}
if (!context.hasThrowaway() && !ladder) {
return COST_INF;
@@ -63,6 +67,9 @@ public class MovementPillar extends Movement {
}
}
double hardness = getTotalHardnessOfBlocksToBreak(context);
if (hardness >= COST_INF) {
return COST_INF;
}
if (hardness != 0) {
Block tmp = BlockStateInterface.get(src.up(2)).getBlock();
if (tmp instanceof BlockLadder || tmp instanceof BlockVine) {
@@ -70,15 +77,22 @@ public class MovementPillar extends Movement {
} else {
BlockPos chkPos = src.up(3);
IBlockState check = BlockStateInterface.get(chkPos);
if (!MovementHelper.canWalkOn(chkPos, check) || MovementHelper.canWalkThrough(chkPos, check) || check.getBlock() instanceof BlockFalling) {//if the block above where we want to break is not a full block, don't do it
// TODO why does canWalkThrough mean this action is COST_INF?
// BlockFalling makes sense, and !canWalkOn deals with weird cases like if it were lava
// but I don't understand why canWalkThrough makes it impossible
return COST_INF;
if (check.getBlock() instanceof BlockFalling) {
// see MovementAscend's identical check for breaking a falling block above our head
if (!(tmp instanceof BlockFalling) || !(BlockStateInterface.get(src.up(1)).getBlock() instanceof BlockFalling)) {
return COST_INF;
}
}
// this is commented because it may have had a purpose, but it's very unclear what it was. it's from the minebot era.
//if (!MovementHelper.canWalkOn(chkPos, check) || MovementHelper.canWalkThrough(chkPos, check)) {//if the block above where we want to break is not a full block, don't do it
// TODO why does canWalkThrough mean this action is COST_INF?
// BlockFalling makes sense, and !canWalkOn deals with weird cases like if it were lava
// but I don't understand why canWalkThrough makes it impossible
// return COST_INF;
//}
}
}
if (fromDown instanceof BlockLiquid || fromDownDown instanceof BlockLiquid) {//can't pillar on water or in water
if (fromDown instanceof BlockLiquid || fromDownDown.getBlock() instanceof BlockLiquid) {//can't pillar on water or in water
return COST_INF;
}
if (ladder) {
@@ -115,7 +129,7 @@ public class MovementPillar extends Movement {
boolean vine = fromDown.getBlock() instanceof BlockVine;
if (!ladder) {
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F),
Utils.getBlockPosCenter(positionsToPlace[0]),
Utils.getBlockPosCenter(positionToPlace),
new Rotation(mc.player.rotationYaw, mc.player.rotationPitch)), true));
}
@@ -127,9 +141,12 @@ public class MovementPillar extends Movement {
return state.setStatus(MovementState.MovementStatus.UNREACHABLE);
}
if (playerFeet().equals(against.up()) || playerFeet().equals(dest))
if (playerFeet().equals(against.up()) || playerFeet().equals(dest)) {
return state.setStatus(MovementState.MovementStatus.SUCCESS);
}
if (MovementHelper.isBottomSlab(src.down())) {
state.setInput(InputOverrideHandler.Input.JUMP, true);
}
/*
if (thePlayer.getPosition0().getX() != from.getX() || thePlayer.getPosition0().getZ() != from.getZ()) {
Baritone.moveTowardsBlock(from);

View File

@@ -17,7 +17,6 @@
package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.behavior.impl.LookBehaviorUtils;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
@@ -38,30 +37,13 @@ import java.util.Objects;
public class MovementTraverse extends Movement {
private BlockPos[] against = new BlockPos[3];
/**
* Did we have to place a bridge block or was it always there
*/
private boolean wasTheBridgeBlockAlwaysThere = true;
public MovementTraverse(BlockPos from, BlockPos to) {
super(from, to, new BlockPos[]{to.up(), to}, new BlockPos[]{to.down()});
int i = 0;
if (!to.north().equals(from))
against[i++] = to.north().down();
if (!to.south().equals(from))
against[i++] = to.south().down();
if (!to.east().equals(from))
against[i++] = to.east().down();
if (!to.west().equals(from))
against[i] = to.west().down();
//note: do NOT add ability to place against .down().down()
super(from, to, new BlockPos[]{to.up(), to}, to.down());
}
@Override
@@ -74,20 +56,26 @@ public class MovementTraverse extends Movement {
protected double calculateCost(CalculationContext context) {
IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]);
IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]);
IBlockState destOn = BlockStateInterface.get(positionsToPlace[0]);
if (MovementHelper.canWalkOn(positionsToPlace[0], destOn)) {//this is a walk, not a bridge
IBlockState destOn = BlockStateInterface.get(positionToPlace);
Block srcDown = BlockStateInterface.getBlock(src.down());
if (MovementHelper.canWalkOn(positionToPlace, destOn)) {//this is a walk, not a bridge
double WC = WALK_ONE_BLOCK_COST;
if (BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock())) {
WC = WALK_ONE_IN_WATER_COST;
} else {
if (Blocks.SOUL_SAND.equals(destOn.getBlock())) {
if (destOn.getBlock() == Blocks.SOUL_SAND) {
WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
}
if (Blocks.SOUL_SAND.equals(BlockStateInterface.get(src.down()).getBlock())) {
if (srcDown == Blocks.SOUL_SAND) {
WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
}
}
if (MovementHelper.canWalkThrough(positionsToBreak[0], pb0) && MovementHelper.canWalkThrough(positionsToBreak[1], pb1)) {
double hardness1 = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0], pb0, true);
if (hardness1 >= COST_INF) {
return COST_INF;
}
double hardness2 = MovementHelper.getMiningDurationTicks(context, positionsToBreak[1], pb1, false);
if (hardness1 == 0 && hardness2 == 0) {
if (WC == WALK_ONE_BLOCK_COST && context.canSprint()) {
// If there's nothing in the way, and this isn't water or soul sand, and we aren't sneak placing
// We can sprint =D
@@ -95,28 +83,36 @@ public class MovementTraverse extends Movement {
}
return WC;
}
// double hardness1 = blocksToBreak[0].getBlockHardness(Minecraft.getMinecraft().world, positionsToBreak[0]);
// double hardness2 = blocksToBreak[1].getBlockHardness(Minecraft.getMinecraft().world, positionsToBreak[1]);
// Out.log("Can't walk through " + blocksToBreak[0] + " (hardness" + hardness1 + ") or " + blocksToBreak[1] + " (hardness " + hardness2 + ")");
return WC + getTotalHardnessOfBlocksToBreak(context);
if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) {
hardness1 *= 5;
hardness2 *= 5;
}
return WC + hardness1 + hardness2;
} else {//this is a bridge, so we need to place a block
Block srcDown = BlockStateInterface.get(src.down()).getBlock();
if (srcDown instanceof BlockLadder || srcDown instanceof BlockVine) {
if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) {
return COST_INF;
}
IBlockState pp0 = BlockStateInterface.get(positionsToPlace[0]);
if (pp0.getBlock().equals(Blocks.AIR) || (!BlockStateInterface.isWater(pp0.getBlock()) && MovementHelper.isReplacable(positionsToPlace[0], pp0))) {
if (destOn.getBlock().equals(Blocks.AIR) || MovementHelper.isReplacable(positionToPlace, destOn)) {
boolean throughWater = BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock());
if (BlockStateInterface.isWater(destOn.getBlock()) && throughWater) {
return COST_INF;
}
if (!context.hasThrowaway()) {
return COST_INF;
}
double WC = BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock()) ? WALK_ONE_IN_WATER_COST : WALK_ONE_BLOCK_COST;
for (BlockPos against1 : against) {
if (BlockStateInterface.get(against1).isBlockNormalCube()) {
double WC = throughWater ? WALK_ONE_IN_WATER_COST : WALK_ONE_BLOCK_COST;
for (int i = 0; i < 4; i++) {
BlockPos against1 = dest.offset(HORIZONTALS[i]);
if (against1.equals(src)) {
continue;
}
against1 = against1.down();
if (MovementHelper.canPlaceAgainst(against1)) {
return WC + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context);
}
}
if (Blocks.SOUL_SAND.equals(srcDown)) {
return COST_INF; // can't sneak and backplace against soul sand =/
if (srcDown == Blocks.SOUL_SAND || (srcDown instanceof BlockSlab && !((BlockSlab) srcDown).isDouble())) {
return COST_INF; // can't sneak and backplace against soul sand or half slabs =/
}
WC = WC * SNEAK_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST;//since we are placing, we are sneaking
return WC + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context);
@@ -132,6 +128,8 @@ public class MovementTraverse extends Movement {
if (state.getStatus() != MovementState.MovementStatus.RUNNING)
return state;
state.setInput(InputOverrideHandler.Input.SNEAK, false);
Block fd = BlockStateInterface.get(src.down()).getBlock();
boolean ladder = fd instanceof BlockLadder || fd instanceof BlockVine;
IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]);
@@ -169,7 +167,7 @@ public class MovementTraverse extends Movement {
}
}
boolean isTheBridgeBlockThere = MovementHelper.canWalkOn(positionsToPlace[0]) || ladder;
boolean isTheBridgeBlockThere = MovementHelper.canWalkOn(positionToPlace) || ladder;
BlockPos whereAmI = playerFeet();
if (whereAmI.getY() != dest.getY() && !ladder) {
displayChatMessageRaw("Wrong Y coordinate");
@@ -184,11 +182,11 @@ public class MovementTraverse extends Movement {
state.setStatus(MovementState.MovementStatus.SUCCESS);
return state;
}
if (wasTheBridgeBlockAlwaysThere && !BlockStateInterface.isLiquid(playerFeet()) && Baritone.settings().allowSprint.get()) {
player().setSprinting(true);
if (wasTheBridgeBlockAlwaysThere && !BlockStateInterface.isLiquid(playerFeet())) {
state.setInput(InputOverrideHandler.Input.SPRINT, true);
}
Block destDown = BlockStateInterface.get(dest.down()).getBlock();
if (ladder && (destDown instanceof BlockVine || destDown instanceof BlockLadder)) {
if (whereAmI.getY() != dest.getY() && ladder && (destDown instanceof BlockVine || destDown instanceof BlockLadder)) {
new MovementPillar(dest.down(), dest).updateState(state); // i'm sorry
return state;
}
@@ -196,13 +194,29 @@ public class MovementTraverse extends Movement {
return state;
} else {
wasTheBridgeBlockAlwaysThere = false;
for (BlockPos against1 : against) {
if (BlockStateInterface.get(against1).isBlockNormalCube()) {
for (int i = 0; i < 4; i++) {
BlockPos against1 = dest.offset(HORIZONTALS[i]);
if (against1.equals(src)) {
continue;
}
against1 = against1.down();
if (MovementHelper.canPlaceAgainst(against1)) {
if (!MovementHelper.throwaway(true)) { // get ready to place a throwaway block
displayChatMessageRaw("bb pls get me some blocks. dirt or cobble");
return state.setStatus(MovementState.MovementStatus.UNREACHABLE);
}
state.setInput(InputOverrideHandler.Input.SNEAK, true);
Block standingOn = BlockStateInterface.get(playerFeet().down()).getBlock();
if (standingOn.equals(Blocks.SOUL_SAND) || standingOn instanceof BlockSlab) { // see issue #118
double dist = Math.max(Math.abs(dest.getX() + 0.5 - player().posX), Math.abs(dest.getZ() + 0.5 - player().posZ));
if (dist < 0.85) { // 0.5 + 0.3 + epsilon
MovementHelper.moveTowards(state, dest);
state.setInput(InputOverrideHandler.Input.MOVE_FORWARD, false);
state.setInput(InputOverrideHandler.Input.MOVE_BACK, true);
return state;
}
}
state.setInput(InputOverrideHandler.Input.MOVE_BACK, false);
double faceX = (dest.getX() + against1.getX() + 1.0D) * 0.5D;
double faceY = (dest.getY() + against1.getY()) * 0.5D;
double faceZ = (dest.getZ() + against1.getZ() + 1.0D) * 0.5D;
@@ -210,7 +224,7 @@ public class MovementTraverse extends Movement {
EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit;
if (Objects.equals(LookBehaviorUtils.getSelectedBlock().orElse(null), against1) && Minecraft.getMinecraft().player.isSneaking()) {
if (LookBehaviorUtils.getSelectedBlock().get().offset(side).equals(positionsToPlace[0])) {
if (LookBehaviorUtils.getSelectedBlock().get().offset(side).equals(positionToPlace)) {
return state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
} else {
// Out.gui("Wrong. " + side + " " + LookBehaviorUtils.getSelectedBlock().get().offset(side) + " " + positionsToPlace[0], Out.Mode.Debug);
@@ -242,7 +256,7 @@ public class MovementTraverse extends Movement {
return state;
}
// Out.log("Trying to look at " + goalLook + ", actually looking at" + Baritone.whatAreYouLookingAt());
return state;
return state.setInput(InputOverrideHandler.Input.CLICK_LEFT, true);
} else {
MovementHelper.moveTowards(state, positionsToBreak[0]);
return state;
@@ -250,4 +264,15 @@ public class MovementTraverse extends Movement {
}
}
}
@Override
protected boolean prepared(MovementState state) {
if (playerFeet().equals(src) || playerFeet().equals(src.down())) {
Block block = BlockStateInterface.getBlock(src.down());
if (block == Blocks.LADDER || block == Blocks.VINE) {
state.setInput(InputOverrideHandler.Input.SNEAK, true);
}
}
return super.prepared(state);
}
}

View File

@@ -18,10 +18,12 @@
package baritone.pathing.path;
import baritone.Baritone;
import baritone.event.events.TickEvent;
import baritone.pathing.movement.ActionCosts;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementState;
import baritone.api.event.events.TickEvent;
import baritone.pathing.movement.*;
import baritone.pathing.movement.movements.MovementDescend;
import baritone.pathing.movement.movements.MovementDiagonal;
import baritone.pathing.movement.movements.MovementFall;
import baritone.pathing.movement.movements.MovementTraverse;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import net.minecraft.client.entity.EntityPlayerSP;
@@ -42,8 +44,9 @@ import static baritone.pathing.movement.MovementState.MovementStatus.*;
* @author leijurv
*/
public class PathExecutor implements Helper {
private static final double MAX_MAX_DIST_FROM_PATH = 3;
private static final double MAX_DIST_FROM_PATH = 2;
private static final double MAX_TICKS_AWAY = 200; // ten seconds
private static final double MAX_TICKS_AWAY = 200; // ten seconds. ok to decrease this, but it must be at least 110, see issue #102
private final IPath path;
private int pathPosition;
private int ticksAway;
@@ -128,6 +131,17 @@ public class PathExecutor implements Helper {
} else {
ticksAway = 0;
}
if (distanceFromPath > MAX_MAX_DIST_FROM_PATH) {
if (!(path.movements().get(pathPosition) instanceof MovementFall)) { // might be midair
if (pathPosition == 0 || !(path.movements().get(pathPosition - 1) instanceof MovementFall)) { // might have overshot the landing
displayChatMessageRaw("too far from path");
pathPosition = path.length() + 3;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
failed = true;
return false;
}
}
}
//this commented block is literally cursed.
/*Out.log(actions.get(pathPosition));
if (pathPosition < actions.size() - 1) {//if there are two ActionBridges in a row and they are at right angles, walk diagonally. This makes it so you walk at 45 degrees along a zigzag path instead of doing inefficient zigging and zagging
@@ -160,7 +174,7 @@ public class PathExecutor implements Helper {
}
}
}*/
long start = System.currentTimeMillis();
long start = System.nanoTime() / 1000000L;
for (int i = pathPosition - 10; i < pathPosition + 10; i++) {
if (i >= 0 && i < path.movements().size()) {
Movement m = path.movements().get(i);
@@ -195,11 +209,25 @@ public class PathExecutor implements Helper {
toWalkInto = newWalkInto;
recalcBP = false;
}
long end = System.currentTimeMillis();
long end = System.nanoTime() / 1000000L;
if (end - start > 0) {
//displayChatMessageRaw("Recalculating break and place took " + (end - start) + "ms");
}
Movement movement = path.movements().get(pathPosition);
if (costEstimateIndex == null || costEstimateIndex != pathPosition) {
costEstimateIndex = pathPosition;
// do this only once, when the movement starts, and deliberately get the cost as cached when this path was calculated, not the cost as it is right now
currentMovementInitialCostEstimate = movement.getCost(null);
for (int i = 1; i < Baritone.settings().costVerificationLookahead.get() && pathPosition + i < path.length() - 1; i++) {
if (path.movements().get(pathPosition + i).calculateCostWithoutCaching() >= ActionCosts.COST_INF) {
displayChatMessageRaw("Something has changed in the world and a future movement has become impossible. Cancelling.");
pathPosition = path.length() + 3;
failed = true;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
return true;
}
}
}
double currentCost = movement.recalculateCost();
if (currentCost >= ActionCosts.COST_INF) {
displayChatMessageRaw("Something has changed in the world and this movement has become impossible. Cancelling.");
@@ -208,10 +236,6 @@ public class PathExecutor implements Helper {
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
return true;
}
if (costEstimateIndex == null || costEstimateIndex != pathPosition) {
costEstimateIndex = pathPosition;
currentMovementInitialCostEstimate = currentCost; // do this only once, when the movement starts
}
MovementState.MovementStatus movementStatus = movement.update();
if (movementStatus == UNREACHABLE || movementStatus == FAILED) {
displayChatMessageRaw("Movement returns status " + movementStatus);
@@ -228,6 +252,7 @@ public class PathExecutor implements Helper {
onTick(event);
return true;
} else {
sprintIfRequested();
ticksOnCurrent++;
if (ticksOnCurrent > currentMovementInitialCostEstimate + Baritone.settings().movementTimeoutTicks.get()) {
// only fail if the total time has exceeded the initial estimate
@@ -245,6 +270,59 @@ public class PathExecutor implements Helper {
return false; // movement is in progress
}
private void sprintIfRequested() {
if (!new CalculationContext().canSprint()) {
player().setSprinting(false);
return;
}
if (Baritone.INSTANCE.getInputOverrideHandler().isInputForcedDown(mc.gameSettings.keyBindSprint)) {
if (!player().isSprinting()) {
player().setSprinting(true);
}
return;
}
Movement movement = path.movements().get(pathPosition);
if (movement instanceof MovementDescend && pathPosition < path.length() - 2) {
Movement next = path.movements().get(pathPosition + 1);
if (next instanceof MovementDescend) {
if (next.getDirection().equals(movement.getDirection())) {
if (playerFeet().equals(movement.getDest())) {
pathPosition++;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
}
if (!player().isSprinting()) {
player().setSprinting(true);
}
return;
}
}
if (next instanceof MovementTraverse) {
if (next.getDirection().down().equals(movement.getDirection()) && MovementHelper.canWalkOn(next.getDest().down())) {
if (playerFeet().equals(movement.getDest())) {
pathPosition++;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
}
if (!player().isSprinting()) {
player().setSprinting(true);
}
return;
}
}
if (next instanceof MovementDiagonal && Baritone.settings().allowOvershootDiagonalDescend.get()) {
if (playerFeet().equals(movement.getDest())) {
pathPosition++;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
}
if (!player().isSprinting()) {
player().setSprinting(true);
}
return;
}
//displayChatMessageRaw("Turning off sprinting " + movement + " " + next + " " + movement.getDirection() + " " + next.getDirection().down() + " " + next.getDirection().down().equals(movement.getDirection()));
}
player().setSprinting(false);
}
public int getPosition() {
return pathPosition;
}

View File

@@ -30,6 +30,8 @@ import net.minecraft.world.chunk.Chunk;
public class BlockStateInterface implements Helper {
private static Chunk prev = null;
public static IBlockState get(BlockPos pos) { // wrappers for chunk caching capability
// Invalid vertical position
@@ -37,8 +39,18 @@ public class BlockStateInterface implements Helper {
return Blocks.AIR.getDefaultState();
if (!Baritone.settings().pathThroughCachedOnly.get()) {
Chunk cached = prev;
// there's great cache locality in block state lookups
// generally it's within each movement
// if it's the same chunk as last time
// we can just skip the mc.world.getChunk lookup
// which is a Long2ObjectOpenHashMap.get
if (cached != null && cached.x == pos.getX() >> 4 && cached.z == pos.getZ() >> 4) {
return cached.getBlockState(pos);
}
Chunk chunk = mc.world.getChunk(pos);
if (chunk.isLoaded()) {
prev = chunk;
return chunk.getBlockState(pos);
}
}
@@ -54,6 +66,10 @@ public class BlockStateInterface implements Helper {
return Blocks.AIR.getDefaultState();
}
public static void clearCachedChunk() {
prev = null;
}
public static Block getBlock(BlockPos pos) {
return get(pos).getBlock();
}

View File

@@ -19,24 +19,27 @@ package baritone.utils;
import baritone.Baritone;
import baritone.Settings;
import baritone.api.event.events.ChatEvent;
import baritone.behavior.Behavior;
import baritone.behavior.impl.FollowBehavior;
import baritone.behavior.impl.MineBehavior;
import baritone.behavior.impl.PathingBehavior;
import baritone.chunk.ChunkPacker;
import baritone.chunk.Waypoint;
import baritone.chunk.WorldProvider;
import baritone.event.events.ChatEvent;
import baritone.pathing.calc.AStarPathFinder;
import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.goals.*;
import baritone.pathing.movement.ActionCosts;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.*;
import java.util.stream.Collectors;
public class ExampleBaritoneControl extends Behavior {
public static ExampleBaritoneControl INSTANCE = new ExampleBaritoneControl();
@@ -52,7 +55,9 @@ public class ExampleBaritoneControl extends Behavior {
@Override
public void onSendChatMessage(ChatEvent event) {
if (!Baritone.settings().chatControl.get()) {
return;
if (!Baritone.settings().removePrefix.get()) {
return;
}
}
String msg = event.getMessage();
if (Baritone.settings().prefix.get()) {
@@ -99,16 +104,30 @@ public class ExampleBaritoneControl extends Behavior {
return;
}
if (msg.equals("path")) {
PathingBehavior.INSTANCE.path();
if (!PathingBehavior.INSTANCE.path()) {
if (PathingBehavior.INSTANCE.getGoal() == null) {
displayChatMessageRaw("No goal.");
} else {
displayChatMessageRaw("Currently executing a path. Please cancel it first.");
}
}
event.cancel();
return;
}
if (msg.toLowerCase().equals("cancel")) {
PathingBehavior.INSTANCE.cancel();
FollowBehavior.INSTANCE.cancel();
MineBehavior.INSTANCE.cancel();
event.cancel();
displayChatMessageRaw("ok canceled");
return;
}
if (msg.toLowerCase().equals("forcecancel")) {
AbstractNodeCostSearch.forceCancel();
event.cancel();
displayChatMessageRaw("ok force canceled");
return;
}
if (msg.toLowerCase().equals("invert")) {
Goal goal = PathingBehavior.INSTANCE.getGoal();
BlockPos runAwayFrom;
@@ -127,7 +146,21 @@ public class ExampleBaritoneControl extends Behavior {
return false;
}
});
PathingBehavior.INSTANCE.path();
if (!PathingBehavior.INSTANCE.path()) {
displayChatMessageRaw("Currently executing a path. Please cancel it first.");
}
event.cancel();
return;
}
if (msg.toLowerCase().equals("follow")) {
Optional<Entity> entity = MovementHelper.whatEntityAmILookingAt();
if (!entity.isPresent()) {
displayChatMessageRaw("You aren't looking at an entity bruh");
event.cancel();
return;
}
FollowBehavior.INSTANCE.follow(entity.get());
displayChatMessageRaw("Following " + entity.get());
event.cancel();
return;
}
@@ -157,28 +190,16 @@ public class ExampleBaritoneControl extends Behavior {
return;
}
if (msg.toLowerCase().startsWith("mine")) {
String blockType = msg.toLowerCase().substring(4).trim();
List<BlockPos> locs = new ArrayList<>(WorldProvider.INSTANCE.getCurrentWorld().cache.getLocationsOf(blockType, 1, 1));
if (locs.isEmpty()) {
displayChatMessageRaw("No locations known");
event.cancel();
return;
String[] blockTypes = msg.toLowerCase().substring(4).trim().split(" ");
for (String s : blockTypes) {
if (ChunkPacker.stringToBlock(s) == null) {
displayChatMessageRaw(s + " isn't a valid block name");
event.cancel();
return;
}
}
BlockPos playerFeet = playerFeet();
locs.sort(Comparator.comparingDouble(playerFeet::distanceSq));
// remove any that are within loaded chunks that aren't actually what we want
locs.removeAll(locs.stream()
.filter(pos -> !(world().getChunk(pos) instanceof EmptyChunk))
.filter(pos -> !ChunkPacker.blockToString(BlockStateInterface.get(pos).getBlock()).equalsIgnoreCase(blockType))
.collect(Collectors.toList()));
if (locs.size() > 30) {
displayChatMessageRaw("Pathing to any of closest 30");
locs = locs.subList(0, 30);
}
PathingBehavior.INSTANCE.setGoal(new GoalComposite(locs.stream().map(GoalTwoBlocks::new).toArray(Goal[]::new)));
PathingBehavior.INSTANCE.path();
MineBehavior.INSTANCE.mine(blockTypes);
displayChatMessageRaw("Started mining blocks of type " + Arrays.toString(blockTypes));
event.cancel();
return;
}
@@ -195,7 +216,7 @@ public class ExampleBaritoneControl extends Behavior {
// for example, "show deaths"
waypointType = waypointType.substring(0, waypointType.length() - 1);
}
Waypoint.Tag tag = Waypoint.TAG_MAP.get(waypointType);
Waypoint.Tag tag = Waypoint.Tag.fromString(waypointType);
if (tag == null) {
displayChatMessageRaw("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase());
event.cancel();
@@ -214,14 +235,26 @@ public class ExampleBaritoneControl extends Behavior {
}
if (msg.toLowerCase().startsWith("goto")) {
String waypointType = msg.toLowerCase().substring(4).trim();
if (waypointType.endsWith("s")) {
if (waypointType.endsWith("s") && Waypoint.Tag.fromString(waypointType.substring(0, waypointType.length() - 1)) != null) {
// for example, "show deaths"
waypointType = waypointType.substring(0, waypointType.length() - 1);
}
Waypoint.Tag tag = Waypoint.TAG_MAP.get(waypointType);
Waypoint.Tag tag = Waypoint.Tag.fromString(waypointType);
if (tag == null) {
displayChatMessageRaw("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase());
String mining = waypointType;
//displayChatMessageRaw("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase());
event.cancel();
if (ChunkPacker.stringToBlock(mining) == null) {
displayChatMessageRaw("No locations for " + mining + " known, cancelling");
return;
}
List<BlockPos> locs = MineBehavior.scanFor(Arrays.asList(mining), 64);
if (locs.isEmpty()) {
displayChatMessageRaw("No locations for " + mining + " known, cancelling");
return;
}
PathingBehavior.INSTANCE.setGoal(new GoalComposite(locs.stream().map(GoalGetToBlock::new).toArray(Goal[]::new)));
PathingBehavior.INSTANCE.path();
return;
}
Waypoint waypoint = WorldProvider.INSTANCE.getCurrentWorld().waypoints.getMostRecentByTag(tag);
@@ -232,7 +265,9 @@ public class ExampleBaritoneControl extends Behavior {
}
Goal goal = new GoalBlock(waypoint.location);
PathingBehavior.INSTANCE.setGoal(goal);
PathingBehavior.INSTANCE.path();
if (!PathingBehavior.INSTANCE.path()) {
displayChatMessageRaw("Currently executing a path. Please cancel it first.");
}
event.cancel();
return;
}
@@ -286,7 +321,7 @@ public class ExampleBaritoneControl extends Behavior {
event.cancel();
return;
}
List<Settings.Setting<Boolean>> toggleable = Baritone.settings().getByValueType(Boolean.class);
List<Settings.Setting<Boolean>> toggleable = Baritone.settings().getAllValuesByType(Boolean.class);
for (Settings.Setting<Boolean> setting : toggleable) {
if (msg.equalsIgnoreCase(setting.getName())) {
setting.value ^= true;

View File

@@ -18,6 +18,7 @@
package baritone.utils;
import baritone.Baritone;
import net.minecraft.block.BlockSlab;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.multiplayer.WorldClient;
@@ -33,7 +34,13 @@ import net.minecraft.util.text.TextFormatting;
*/
public interface Helper {
ITextComponent MESSAGE_PREFIX = new TextComponentString("§5[§dBaritone§5]§7");
ITextComponent MESSAGE_PREFIX = new TextComponentString(String.format(
"%s[%sBaritone%s]%s",
TextFormatting.DARK_PURPLE,
TextFormatting.LIGHT_PURPLE,
TextFormatting.DARK_PURPLE,
TextFormatting.GRAY
));
Minecraft mc = Minecraft.getMinecraft();
@@ -47,10 +54,11 @@ public interface Helper {
default BlockPos playerFeet() {
// TODO find a better way to deal with soul sand!!!!!
return new BlockPos(player().posX, player().posY + 0.1251, player().posZ);
/*if (BlockStateInterface.get(feet).getBlock().equals(Blocks.SOUL_SAND) && player().posY > feet.getY() + 0.874999) {
BlockPos feet = new BlockPos(player().posX, player().posY + 0.1251, player().posZ);
if (BlockStateInterface.get(feet).getBlock() instanceof BlockSlab) {
return feet.up();
}*/
}
return feet;
}
default Vec3d playerFeetAsVec() {

View File

@@ -34,6 +34,7 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import java.awt.*;
import java.util.Collection;
@@ -188,7 +189,7 @@ public final class PathRenderer implements Helper {
maxX = goalPos.getX() + 1 - 0.002 - renderPosX;
minZ = goalPos.getZ() + 0.002 - renderPosZ;
maxZ = goalPos.getZ() + 1 - 0.002 - renderPosZ;
double y = Math.sin((System.currentTimeMillis() % 2000L) / 2000F * Math.PI * 2);
double y = MathHelper.sin((float) (((float) (System.nanoTime() / 1000000L) % 2000L) / 2000F * Math.PI * 2));
y1 = 1 + y + goalPos.getY() - renderPosY;
y2 = 1 - y + goalPos.getY() - renderPosY;
minY = goalPos.getY() - renderPosY;

View File

@@ -18,6 +18,9 @@
package baritone.utils;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import static baritone.behavior.impl.LookBehaviorUtils.calcVec3dFromRotation;
/**
* @author Brady
@@ -44,4 +47,16 @@ public final class RayTraceUtils implements Helper {
return result;
}
public static RayTraceResult rayTraceTowards(Rotation rotation) {
double blockReachDistance = mc.playerController.getBlockReachDistance();
Vec3d start = mc.player.getPositionEyes(1.0F);
Vec3d direction = calcVec3dFromRotation(rotation);
Vec3d end = start.add(
direction.x * blockReachDistance,
direction.y * blockReachDistance,
direction.z * blockReachDistance
);
return mc.world.rayTraceBlocks(start, end, false, false, true);
}
}

View File

@@ -18,92 +18,33 @@
package baritone.utils;
import baritone.Baritone;
import baritone.event.events.ItemSlotEvent;
import baritone.event.listener.AbstractGameEventListener;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.item.Item;
import net.minecraft.item.ItemAir;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.init.Enchantments;
import net.minecraft.init.MobEffects;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemTool;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A cached list of the best tools on the hotbar for any block
*
* @author avecowa, Brady
* @author avecowa, Brady, leijurv
*/
public class ToolSet implements Helper {
/**
* Instance of the internal event listener used to hook into Baritone's event bus
*/
private static final InternalEventListener INTERNAL_EVENT_LISTENER = new InternalEventListener();
static {
Baritone.INSTANCE.getGameEventHandler().registerEventListener(INTERNAL_EVENT_LISTENER);
}
/**
* A list of tools on the hotbar that should be considered.
* Note that if there are no tools on the hotbar this list will still have one (null) entry.
*/
private List<ItemTool> tools;
/**
* A mapping from the tools array to what hotbar slots the tool is actually in.
* tools.get(i) will be on your hotbar in slot slots.get(i)
*/
private List<Byte> slots;
/**
* A mapping from a block to which tool index is best for it.
* The values in this map are *not* hotbar slots indexes, they need to be looked up in slots
* in order to be converted into hotbar slots.
*/
private Map<Block, Byte> slotCache = new HashMap<>();
/**
* A cache mapping a {@link IBlockState} to how long it will take to break
* A cache mapping a {@link Block} to how long it will take to break
* with this toolset, given the optimum tool is used.
*/
private Map<IBlockState, Double> breakStrengthCache = new HashMap<>();
private Map<Block, Double> breakStrengthCache = new HashMap<>();
/**
* Create a toolset from the current player's inventory (but don't calculate any hardness values just yet)
*/
public ToolSet() {
EntityPlayerSP p = Minecraft.getMinecraft().player;
NonNullList<ItemStack> inv = p.inventory.mainInventory;
tools = new ArrayList<>();
slots = new ArrayList<>();
boolean fnull = false;
for (byte i = 0; i < 9; i++) {
if (!fnull || ((!(inv.get(i).getItem() instanceof ItemAir)) && inv.get(i).getItem() instanceof ItemTool)) {
tools.add(inv.get(i).getItem() instanceof ItemTool ? (ItemTool) inv.get(i).getItem() : null);
slots.add(i);
fnull |= (inv.get(i).getItem() instanceof ItemAir) || (!inv.get(i).getItem().isDamageable());
}
}
}
/**
* A caching wrapper around getBestToolIndex
*
* @param state the blockstate to be mined
* @return get which tool on the hotbar is best for mining it
*/
public Item getBestTool(IBlockState state) {
return tools.get(slotCache.computeIfAbsent(state.getBlock(), block -> getBestToolIndex(state)));
}
public ToolSet() {}
/**
* Calculate which tool on the hotbar is best for mining
@@ -111,15 +52,11 @@ public class ToolSet implements Helper {
* @param b the blockstate to be mined
* @return a byte indicating the index in the tools array that worked best
*/
private byte getBestToolIndex(IBlockState b) {
public byte getBestSlot(IBlockState b) {
byte best = 0;
float value = -1;
for (byte i = 0; i < tools.size(); i++) {
Item item = tools.get(i);
if (item == null)
continue;
float v = item.getDestroySpeed(new ItemStack(item), b);
double value = -1;
for (byte i = 0; i < 9; i++) {
double v = calculateStrVsBlock(i, b);
if (v > value || value == -1) {
value = v;
best = i;
@@ -128,62 +65,65 @@ public class ToolSet implements Helper {
return best;
}
/**
* Get which hotbar slot should be selected for fastest mining
*
* @param state the blockstate to be mined
* @return a byte indicating which hotbar slot worked best
*/
public byte getBestSlot(IBlockState state) {
return slots.get(slotCache.computeIfAbsent(state.getBlock(), block -> getBestToolIndex(state)));
}
/**
* Using the best tool on the hotbar, how long would it take to mine this block
*
* @param state the blockstate to be mined
* @param pos the blockpos to be mined
* @return how long it would take in ticks
*/
public double getStrVsBlock(IBlockState state, BlockPos pos) {
return this.breakStrengthCache.computeIfAbsent(state, s -> calculateStrVsBlock(s, pos));
public double getStrVsBlock(IBlockState state) {
return this.breakStrengthCache.computeIfAbsent(state.getBlock(), b -> calculateStrVsBlock(getBestSlot(state), state));
}
/**
* Calculates how long would it take to mine the specified block given the best tool
* in this toolset is used.
* in this toolset is used. A negative value is returned if the specified block is unbreakable.
*
* @param state the blockstate to be mined
* @param pos the blockpos to be mined
* @return how long it would take in ticks
*/
private double calculateStrVsBlock(IBlockState state, BlockPos pos) {
private double calculateStrVsBlock(byte slot, IBlockState state) {
// Calculate the slot with the best item
byte slot = this.getBestSlot(state);
ItemStack contents = player().inventory.getStackInSlot(slot);
INTERNAL_EVENT_LISTENER.setOverrideSlot(slot);
float blockHard = state.getBlockHardness(null, null);
if (blockHard < 0)
return -1;
// Calculate the relative hardness of the block to the player
float hardness = state.getPlayerRelativeBlockHardness(player(), world(), pos);
// Restore the old slot
INTERNAL_EVENT_LISTENER.setOverrideSlot(-1);
return hardness;
}
private static final class InternalEventListener implements AbstractGameEventListener {
private int overrideSlot;
@Override
public void onQueryItemSlotForBlocks(ItemSlotEvent event) {
if (this.overrideSlot >= 0)
event.setSlot(this.overrideSlot);
float speed = contents.getDestroySpeed(state);
if (speed > 1) {
int effLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, contents);
if (effLevel > 0 && !contents.isEmpty()) {
speed += effLevel * effLevel + 1;
}
}
final void setOverrideSlot(int overrideSlot) {
this.overrideSlot = overrideSlot;
if (Baritone.settings().considerPotionEffects.get()) {
if (player().isPotionActive(MobEffects.HASTE)) {
speed *= 1 + (player().getActivePotionEffect(MobEffects.HASTE).getAmplifier() + 1) * 0.2;
}
if (player().isPotionActive(MobEffects.MINING_FATIGUE)) {
switch (player().getActivePotionEffect(MobEffects.MINING_FATIGUE).getAmplifier()) {
case 0:
speed *= 0.3;
break;
case 1:
speed *= 0.09;
break;
case 2:
speed *= 0.0027;
break;
default:
speed *= 0.00081;
break;
}
}
}
speed /= blockHard;
if (state.getMaterial().isToolNotRequired() || (!contents.isEmpty() && contents.canHarvestBlock(state))) {
return speed / 30;
} else {
return speed / 100;
}
}
}

View File

@@ -54,9 +54,9 @@ public final class Utils {
*/
public static Rotation calcRotationFromVec3d(Vec3d orig, Vec3d dest) {
double[] delta = {orig.x - dest.x, orig.y - dest.y, orig.z - dest.z};
double yaw = Math.atan2(delta[0], -delta[2]);
double yaw = MathHelper.atan2(delta[0], -delta[2]);
double dist = Math.sqrt(delta[0] * delta[0] + delta[2] * delta[2]);
double pitch = Math.atan2(delta[1], dist);
double pitch = MathHelper.atan2(delta[1], dist);
return new Rotation(
(float) radToDeg(yaw),
(float) radToDeg(pitch)

View File

@@ -15,11 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins.accessor;
import net.minecraft.world.chunk.storage.AnvilChunkLoader;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
package baritone.utils.accessor;
import java.io.File;
@@ -27,8 +23,7 @@ import java.io.File;
* @author Brady
* @since 8/4/2018 11:36 AM
*/
@Mixin(AnvilChunkLoader.class)
public interface IAnvilChunkLoader {
@Accessor File getChunkSaveLocation();
File getChunkSaveLocation();
}

View File

@@ -15,19 +15,15 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins.accessor;
package baritone.utils.accessor;
import net.minecraft.world.chunk.storage.IChunkLoader;
import net.minecraft.world.gen.ChunkProviderServer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
/**
* @author Brady
* @since 8/4/2018 11:33 AM
*/
@Mixin(ChunkProviderServer.class)
public interface IChunkProviderServer {
@Accessor IChunkLoader getChunkLoader();
IChunkLoader getChunkLoader();
}

View File

@@ -26,11 +26,11 @@ import net.minecraft.util.math.Vec3i;
*
* @author leijurv
*/
public class BetterBlockPos extends BlockPos {
private final int x;
private final int y;
private final int z;
private final int hashCode;
public final class BetterBlockPos extends BlockPos {
public final int x;
public final int y;
public final int z;
public final long hashCode;
public BetterBlockPos(int x, int y, int z) {
super(x, y, z);
@@ -48,10 +48,10 @@ public class BetterBlockPos extends BlockPos {
*
* That's why we grab out the X, Y, Z and calculate our own hashcode
*/
int hash = 3241;
hash = 3457689 * hash + x;
hash = 8734625 * hash + y;
hash = 2873465 * hash + z;
long hash = 3241;
hash = 3457689L * hash + x;
hash = 8734625L * hash + y;
hash = 2873465L * hash + z;
this.hashCode = hash;
}
@@ -61,7 +61,7 @@ public class BetterBlockPos extends BlockPos {
@Override
public final int hashCode() {
return hashCode;
return (int) hashCode;
}
@Override

View File

@@ -23,7 +23,7 @@ package baritone.utils.pathing;
*/
public enum PathingBlockType {
AIR (0b00),
AIR(0b00),
WATER(0b01),
AVOID(0b10),
SOLID(0b11);
@@ -31,7 +31,7 @@ public enum PathingBlockType {
private final boolean[] bits;
PathingBlockType(int bits) {
this.bits = new boolean[] {
this.bits = new boolean[]{
(bits & 0b10) != 0,
(bits & 0b01) != 0
};
@@ -42,11 +42,18 @@ public enum PathingBlockType {
}
public static PathingBlockType fromBits(boolean b1, boolean b2) {
for (PathingBlockType type : values())
if (type.bits[0] == b1 && type.bits[1] == b2)
return type;
// This will never happen, but if it does, assume it's just AIR
return PathingBlockType.AIR;
if (b1) {
if (b2) {
return PathingBlockType.SOLID;
} else {
return PathingBlockType.AVOID;
}
} else {
if (b2) {
return PathingBlockType.WATER;
} else {
return PathingBlockType.AIR;
}
}
}
}

View File

@@ -33,10 +33,7 @@ public class CachedRegionTest {
byte xz = part1;
int X = xz & 0x0f;
int Z = (xz >>> 4) & 0x0f;
int Y = (int) part2;
if (Y < 0) {
Y += 256;
}
int Y = part2 & 0xff;
if (x != X || y != Y || z != Z) {
System.out.println(x + " " + X + " " + y + " " + Y + " " + z + " " + Z);
}

View File

@@ -42,7 +42,7 @@ public class OpenSetsTest {
public void removeAndTest(int amount, IOpenSet[] test, Optional<Collection<PathNode>> mustContain) {
double[][] results = new double[test.length][amount];
for (int i = 0; i < test.length; i++) {
long before = System.currentTimeMillis();
long before = System.nanoTime() / 1000000L;
for (int j = 0; j < amount; j++) {
PathNode pn = test[i].removeLowest();
if (mustContain.isPresent() && !mustContain.get().contains(pn)) {
@@ -50,7 +50,7 @@ public class OpenSetsTest {
}
results[i][j] = pn.combinedCost;
}
System.out.println(test[i].getClass() + " " + (System.currentTimeMillis() - before));
System.out.println(test[i].getClass() + " " + (System.nanoTime() / 1000000L - before));
}
for (int j = 0; j < amount; j++) {
for (int i = 1; i < test.length; i++) {
@@ -104,10 +104,10 @@ public class OpenSetsTest {
System.out.println("Insertion");
for (IOpenSet set : test) {
long before = System.currentTimeMillis();
long before = System.nanoTime() / 1000000L;
for (int i = 0; i < size; i++)
set.insert(toInsert[i]);
System.out.println(set.getClass() + " " + (System.currentTimeMillis() - before));
System.out.println(set.getClass() + " " + (System.nanoTime() / 1000000L - before));
//all three take either 0 or 1ms to insert up to 10,000 nodes
//linkedlist takes 0ms most often (because there's no array resizing or allocation there, just pointer shuffling)
}

View File

@@ -0,0 +1,49 @@
/*
* This file is part of Baritone.
*
* Baritone 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.
*
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.pathing.goals;
import net.minecraft.util.math.BlockPos;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertTrue;
public class GoalGetToBlockTest {
@Test
public void isInGoal() {
List<String> acceptableOffsets = new ArrayList<>(Arrays.asList("0,0,0", "0,0,1", "0,0,-1", "1,0,0", "-1,0,0", "0,-1,1", "0,-1,-1", "1,-1,0", "-1,-1,0", "0,1,0", "0,-1,0", "0,-2,0"));
for (int x = -10; x <= 10; x++) {
for (int y = -10; y <= 10; y++) {
for (int z = -10; z <= 10; z++) {
boolean inGoal = new GoalGetToBlock(new BlockPos(0, 0, 0)).isInGoal(new BlockPos(x, y, z));
String repr = x + "," + y + "," + z;
System.out.println(repr + " " + inGoal);
if (inGoal) {
assertTrue(repr, acceptableOffsets.contains(repr));
acceptableOffsets.remove(repr);
}
}
}
}
assertTrue(acceptableOffsets.toString(), acceptableOffsets.isEmpty());
}
}

View File

@@ -44,21 +44,21 @@ public class BetterBlockPosTest {
} catch (InterruptedException e) {
e.printStackTrace();
}
long before1 = System.currentTimeMillis();
long before1 = System.nanoTime() / 1000000L;
for (int i = 0; i < 1000000; i++) {
pos.up();
}
long after1 = System.currentTimeMillis();
long after1 = System.nanoTime() / 1000000L;
try {
Thread.sleep(1000); // give GC some time
} catch (InterruptedException e) {
e.printStackTrace();
}
long before2 = System.currentTimeMillis();
long before2 = System.nanoTime() / 1000000L;
for (int i = 0; i < 1000000; i++) {
pos2.up();
}
long after2 = System.currentTimeMillis();
long after2 = System.nanoTime() / 1000000L;
System.out.println((after1 - before1) + " " + (after2 - before2));
}
@@ -70,7 +70,7 @@ public class BetterBlockPosTest {
} catch (InterruptedException e) {
e.printStackTrace();
}
long before1 = System.currentTimeMillis();
long before1 = System.nanoTime() / 1000000L;
for (int i = 0; i < 1000000; i++) {
pos.up(0);
pos.up(1);
@@ -78,13 +78,13 @@ public class BetterBlockPosTest {
pos.up(3);
pos.up(4);
}
long after1 = System.currentTimeMillis();
long after1 = System.nanoTime() / 1000000L;
try {
Thread.sleep(1000); // give GC some time
} catch (InterruptedException e) {
e.printStackTrace();
}
long before2 = System.currentTimeMillis();
long before2 = System.nanoTime() / 1000000L;
for (int i = 0; i < 1000000; i++) {
pos2.up(0);
pos2.up(1);
@@ -92,7 +92,7 @@ public class BetterBlockPosTest {
pos2.up(3);
pos2.up(4);
}
long after2 = System.currentTimeMillis();
long after2 = System.nanoTime() / 1000000L;
System.out.println((after1 - before1) + " " + (after2 - before2));
}
}