Compare commits

..

152 Commits

Author SHA1 Message Date
Brady
2e8327cd8a Wrong command... 2023-08-11 21:54:56 -05:00
Brady
ac72ad717b bot execute and bot say 2023-06-28 00:09:53 -05:00
Brady
a3df7ebd4c Always render nametag 2023-06-27 23:47:24 -05:00
Brady
d24cd263bf Fix rendering bot player in gui 2023-06-27 23:37:47 -05:00
Brady
5878c255e2 Manage bot inventories with gui 2023-06-27 23:29:15 -05:00
Brady
ab54114bee I think it works again 2023-06-26 21:04:19 -05:00
Brady
4441f644c3 Revert more changes not relevant to PR 2023-06-26 20:33:00 -05:00
Brady
4899b4a3d0 De-bloat 2023-06-26 20:30:37 -05:00
Brady
2670f4a1f9 Merge branch 'master' into bot-system 2023-06-26 20:04:42 -05:00
Brady
5edada6111 Reorganize code 2023-06-13 11:45:58 -05:00
Brady
efa4dc1d04 Use inner class implementation for getAllBaritones
`this.new` 😻
2023-06-13 11:36:24 -05:00
Brady
b25d1a44a2 Fix NPE on bot respawn 2023-06-13 11:34:23 -05:00
Brady
c8de6c027a Rename spec package to impl 2023-06-13 10:59:08 -05:00
Brady
08c8a772a8 Merge branch 'master' into bot-system
# Conflicts:
#	src/api/java/baritone/api/Settings.java
#	src/launch/java/baritone/launch/mixins/MixinNetHandlerPlayClient.java
#	src/main/java/baritone/Baritone.java
#	src/main/java/baritone/BaritoneProvider.java
2023-06-13 00:52:06 -05:00
Brady
9e225949ea Don't dispatch RenderEvent if bot isn't in same dimension 2020-03-13 16:17:54 -05:00
Brady
5b1340e362 Fix bot removal 2020-03-13 08:38:46 -05:00
Brady
dee737689d Initialization consistency 2020-03-12 17:01:10 -05:00
Brady
f0fd30080e Better 2020-03-12 16:54:26 -05:00
Brady
5e316d094d Fix runtime error and change getEntity to getPlayer 2020-03-12 16:50:34 -05:00
Brady
191add6ce5 Better bot tick handling 2020-03-12 16:42:36 -05:00
Brady
9951d37e3b Additional Entity handing for Bot Worlds
+ Some minor cleanups that make the PR more favorable
2020-03-12 08:55:22 -05:00
Brady
29f700d1c9 Naming consistency 2020-03-09 21:27:52 -05:00
Brady
22ed50a739 Chunk management 2020-03-09 20:34:14 -05:00
Brady
b9069a68dc Run on main thread 2020-03-08 17:33:22 -05:00
Brady
881ce738d9 Respect game state changes 2020-03-08 17:32:52 -05:00
Brady
35e4460fb1 Fix NPE 2020-03-08 16:40:26 -05:00
Brady
d25e9a6047 More NetHandlerPlayClient utilization 2020-03-08 03:10:44 -05:00
Brady
05af906a3c Remove MemoryBehavior changes 2020-03-08 01:48:37 -06:00
Brady
aa95cbe0e4 Update goals and remove unnecessary override 2020-03-08 01:44:50 -06:00
Brady
9f20ce9e18 Add some clarification 2020-03-08 01:40:08 -06:00
Brady
e6b409c0da Merge branch 'master' into bot-system 2020-03-08 01:36:25 -06:00
Brady
ec427e6b74 Insane cleanups 2020-03-08 01:32:52 -06:00
Brady
3ddd1c38f5 Add disconnect command for bots, fix sound crash 2020-03-07 20:08:29 -06:00
Brady
60c0fff016 Fix bot entity removal 2020-03-07 14:30:21 -06:00
Brady
180d55b9c5 Fix some entity list scuff 2020-03-06 20:06:36 -06:00
Brady
a6ea5c8df1 Utilize sendSettingsToServer 2020-03-06 16:25:34 -06:00
Brady
7940eca11e Reduce potential outbound packet loss 2020-03-05 23:50:31 -06:00
Brady
cffe907c76 Centralize disconnect handling 2020-03-05 23:48:42 -06:00
Brady
51840df97d Fix Bot GameSettings overriding KeyBindings 2020-03-05 23:24:37 -06:00
Brady
4762d3f28f Separate GameSettings for bots 2020-03-05 16:52:58 -06:00
Brady
255e70fd7e Separate cache for bots 2020-03-04 15:41:34 -06:00
Brady
8f4e3fbc0e Might as well populate the server name 2020-03-04 11:35:11 -06:00
Brady
b038cedfc5 LAN support in production 2020-03-04 11:12:07 -06:00
Brady
b34ad03bcc final final final (2) 2020-03-04 00:14:16 -06:00
Brady
554fe87789 final final final 2020-03-04 00:12:51 -06:00
Brady
175a44f4ac Fix LAN world support 2020-03-04 00:12:22 -06:00
Brady
0bafcef2a1 Block placing for bots 2020-03-03 23:26:19 -06:00
Brady
f83262be23 Test compatible: Commands are forwarded to bots 2020-03-03 21:58:03 -06:00
Brady
15c0dc3fa5 Fix bad thread check 2020-03-03 16:01:14 -06:00
Brady
6844bc0922 Allocation time 2020-03-03 14:47:50 -06:00
Brady
d82fd04f5f reorder lol 2020-03-02 17:12:27 -06:00
Brady
9130734a9f Remove PROTOCOL.md 2020-03-02 13:50:46 -06:00
Brady
d4d2e1ea50 Merge branch 'master' into bot-system 2020-03-02 13:46:43 -06:00
Brady
9a33c5cd9f Merge branch 'master' into bot-system 2020-01-01 19:23:01 -06:00
Brady
9f5f275a17 Merge branch 'master' into bot-system 2019-10-07 09:42:35 -05:00
Brady
ac4895823e Remove comms 2019-10-04 15:52:08 -05:00
Brady
62cea04080 Fix compiler errors 2019-10-04 15:51:44 -05:00
Brady
d772a97a0b Fix 2019-10-04 10:22:06 -05:00
Brady
7af0ed6ea1 Merge conflicts 2019-10-04 10:19:35 -05:00
Brady
fe3f3a66ce Format bot code 2019-01-22 13:30:11 -06:00
Brady
9c5f82c814 Merge branch 'master' into bot-system 2019-01-18 13:52:22 -06:00
Brady
7c66762f48 Bot system API exposure 2019-01-17 14:43:44 -06:00
Leijurv
830c8190de Merge branch 'comms' into bot-system 2019-01-17 12:18:27 -08:00
Leijurv
47b258d7a4 Merge branch 'master' into comms 2019-01-17 12:16:45 -08:00
Brady
df80858c49 Remove duplicate MovementInput implementation, Fixes #312 2019-01-16 13:55:24 -06:00
Brady
5dec544802 Minor fix LOL 2019-01-15 14:59:56 -06:00
Brady
494c056613 Resolve merge conflicts 2019-01-15 14:53:05 -06:00
Brady
c0e947f016 Clean up canBreak 2018-12-24 12:23:57 -06:00
Brady
c6ce5ea160 Nobody cares about creative mode 2018-12-24 12:19:09 -06:00
Brady
7b2930d5e5 Bot Breaking that is moderately cursed
DMCA gang
2018-12-24 12:11:28 -06:00
Brady
44ca284717 Merge branch 'master' into bot-system 2018-12-18 19:36:10 -06:00
Leijurv
380a645a6c only report items that are actually in the echest 2018-12-17 19:51:24 -08:00
Leijurv
0249bd5dd7 a few more packets, and consistent indexing 2018-12-17 15:15:20 -08:00
Leijurv
8cd8a95763 little fix 2018-12-16 20:14:07 -08:00
Brady
029a2b7f3e Fix NullPointerException 2018-12-15 12:27:19 -06:00
Leijurv
767d0c8ec1 better reporting 2018-12-14 21:57:20 -08:00
Brady
8febed2e42 Remove dependency for PlayerControllerMP implementation 2018-12-14 17:24:07 -06:00
Leijurv
37b1604e5d Merge branch 'master' into comms 2018-12-14 09:38:40 -08:00
Leijurv
82d15570f3 fix rare exception 2018-12-02 16:05:21 -08:00
Leijurv
2c2c420b3a Merge branch 'comms' into bot-system 2018-12-02 13:35:40 -08:00
Leijurv
1422b0a149 Merge branch 'master' into bot-system 2018-12-02 13:35:23 -08:00
Leijurv
6b6dd916b4 Merge branch 'calc-request' into comms 2018-11-23 19:09:01 -08:00
Leijurv
11e44acf65 helper to handle pending msgs 2018-11-23 16:35:03 -08:00
Leijurv
16fec4a1a0 buffered connection creation helper 2018-11-23 16:09:59 -08:00
Leijurv
bbded21afb Merge branch 'master' into bot-system 2018-11-23 14:12:02 -08:00
Leijurv
5ae4f23886 Merge branch 'comms' into calc-request 2018-11-23 13:34:48 -08:00
Leijurv
f222980a1a move comms to cabaletta.comms 2018-11-23 13:32:18 -08:00
Leijurv
c57f65f832 complete new segmented calculation system 2018-11-23 13:17:03 -08:00
Leijurv
85a6ec022e Merge branch 'comms' into calc-request 2018-11-23 13:13:35 -08:00
Leijurv
c1032da828 Merge branch 'master' into comms 2018-11-23 13:12:38 -08:00
Leijurv
e0d894d296 computation request and response 2018-11-23 12:09:35 -08:00
Leijurv
27c818f873 Merge branch 'comms' into calc-request 2018-11-23 11:49:49 -08:00
Leijurv
fdd758bc90 too much log spam 2018-11-23 11:48:01 -08:00
Leijurv
3a2620192b too much log spam 2018-11-23 11:46:47 -08:00
Leijurv
c423d5f575 report path start position 2018-11-23 11:35:13 -08:00
Leijurv
81a9b71429 Merge branch 'segment-calculation' into comms 2018-11-23 10:36:56 -08:00
Leijurv
81ecc209d3 synchronize partial reads and writes to a socket 2018-11-23 10:09:13 -08:00
Leijurv
0dc67593bb lots more status 2018-11-18 21:56:46 -08:00
Leijurv
2e180e81ed Merge branch 'comms' of github.com:cabaletta/baritone into comms 2018-11-18 21:42:04 -08:00
Leijurv
0b11057449 Merge branch 'master' into comms 2018-11-18 21:41:50 -08:00
Brady
186652a8d8 Protocol lol 2018-11-18 19:52:11 -06:00
Leijurv
168c151901 Merge branch 'comms' into bot-system 2018-11-18 17:39:35 -08:00
Leijurv
18d8cfb6de Merge branch 'master' into comms 2018-11-18 17:39:26 -08:00
Leijurv
f99befd307 oh thats important 2018-11-18 12:04:37 -08:00
Leijurv
9ad35dbf28 remove the useless stuff 2018-11-18 11:35:54 -08:00
Leijurv
dfb49179c5 not a handler lol 2018-11-18 11:27:53 -08:00
Brady
3c913a7b85 Fix jar export 2018-11-18 13:27:25 -06:00
Leijurv
f01cf669e8 wtf 2018-11-18 11:06:40 -08:00
Leijurv
2d87033f49 f 2018-11-18 11:06:11 -08:00
Leijurv
f014e42aa4 initial comms 2018-11-18 11:01:46 -08:00
Brady
46de72e28c Comms Sourceset 2018-11-17 18:07:16 -06:00
Brady
3d5cf9772e Less cancer 2018-11-14 20:55:37 -06:00
Leijurv
7cb38352ac bots 2018-11-14 17:17:52 -08:00
Leijurv
42c78337c7 Merge branch 'master' into bot-system 2018-11-14 16:41:52 -08:00
Brady
0f81212f17 Compile fix 2018-11-13 21:41:52 -06:00
Brady
ad0041c2c5 Merge branch 'master' into bot-system 2018-11-13 17:14:29 -06:00
Brady
19e7585cd2 Merge branch 'master' into bot-system 2018-11-11 16:23:47 -06:00
Brady
3aeb29ab22 Merge branch 'master' into bot-system 2018-11-11 13:36:22 -06:00
Brady
8dfe5dfd32 Fix jce.jar not being included as library jar in proguard config 2018-11-09 22:43:00 -06:00
Brady
90236962c4 nice 2018-11-09 22:17:00 -06:00
Brady
2e9e8c1ea1 Actually entirely epic, we're okay 2018-11-09 22:00:11 -06:00
Brady
4bf659e14e Fix ConcurrentModificationException 2018-11-09 21:10:49 -06:00
Brady
ceca258867 MORE handlers
also removed scoreboard handlers because lol
2018-11-09 20:50:43 -06:00
Leijurv
abda4b3a31 begone 2018-11-09 13:28:49 -08:00
Brady
98664540e2 Merge branch 'master' into bot-system 2018-11-09 14:42:23 -06:00
Brady
484dac66b7 JUMP 2018-11-09 13:58:55 -06:00
Brady
40282cd140 Automatic Disconnect 2018-11-07 16:53:32 -06:00
Brady
41c74cb08c More handlers 2018-11-07 12:23:28 -06:00
Brady
7c92817801 Offline bot testing 2018-11-07 12:01:26 -06:00
Brady
1d56585c67 Fix success connection result 2018-11-06 16:22:24 -06:00
Brady
a4ac9c6f8d Bot Connecting 2018-11-06 15:25:25 -06:00
Brady
42d15a7b93 Merge branch 'master' into bot-system 2018-11-06 14:10:11 -06:00
Brady
335c97bae6 Merge branch 'master' into bot-system 2018-11-05 16:06:53 -06:00
Brady
8a8afddce3 Fix bad stack overflow error 2018-10-30 13:57:50 -05:00
Brady
c3f6ee87b3 Feed codacy 2018-10-29 23:27:54 -05:00
Brady
f45fb3cd8c Add reminder lol 2018-10-29 23:20:11 -05:00
Brady
71c7ed54e5 Reverse increment/decrement 2018-10-29 23:10:46 -05:00
Brady
4f978be2a2 Begin MovementInput implementation 2018-10-29 23:04:26 -05:00
Brady
133d956b3a Create login handler 2018-10-29 22:43:36 -05:00
Brady
095e452632 Merge branch 'master' into bot-system 2018-10-29 22:08:29 -05:00
Brady
047d7f06b8 More handlers 2018-10-26 11:38:52 -05:00
Brady
09a119c4ca More handlers 2018-10-24 20:51:01 -05:00
Brady
746e1f6652 handleTimeUpdate 2018-10-24 19:04:49 -05:00
Brady
1d22cf63f0 Lol 2018-10-23 23:08:43 -05:00
Brady
d4b3e71694 handleCombatEvent 2018-10-23 23:07:58 -05:00
Brady
a08b406af9 handleCooldown 2018-10-23 23:04:13 -05:00
Brady
1afd367e53 handleResourcePack 2018-10-23 23:00:58 -05:00
Brady
59e920b7b1 Meme 3 2018-10-23 09:58:36 -05:00
Brady
79d230d924 another thought 2018-10-23 00:49:38 -05:00
Brady
29cf79fe17 We don't need the connection handler from the user 2018-10-23 00:46:31 -05:00
Brady
8e75817e29 Meme 2 2018-10-23 00:29:30 -05:00
Brady
c6bd3f4f00 Meme 2018-10-23 00:05:48 -05:00
54 changed files with 2684 additions and 790 deletions

View File

@@ -42,6 +42,7 @@ import java.lang.reflect.Field;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -216,6 +217,7 @@ public class ProguardTask extends BaritoneGradleTask {
Process p = new ProcessBuilder(this.getJavaBinPathForProguard(), "-verbose").start();
String out = IOUtils.toString(p.getInputStream(), "UTF-8").split("\n")[0].split("Opened ")[1].replace("]", "");
template.add(2, "-libraryjars '" + out + "'");
template.add(3, "-libraryjars '" + Paths.get(out).resolveSibling("jce.jar") + "'");
// API config doesn't require any changes from the changes that we made to the template
Files.write(getTemporaryFile(PROGUARD_API_CONFIG), template);

View File

@@ -17,6 +17,7 @@
package baritone.api;
import baritone.api.bot.IUserManager;
import baritone.api.cache.IWorldScanner;
import baritone.api.command.ICommand;
import baritone.api.command.ICommandSystem;
@@ -108,6 +109,11 @@ public interface IBaritoneProvider {
*/
IWorldScanner getWorldScanner();
/**
* @return The {@link IUserManager} instance.
*/
IUserManager getUserManager();
/**
* Returns the {@link ICommandSystem} instance. This is not bound to a specific {@link IBaritone}
* instance because {@link ICommandSystem} itself controls global behavior for {@link ICommand}s.

View File

@@ -73,13 +73,6 @@ public final class Settings {
*/
public final Setting<Boolean> allowInventory = new Setting<>(false);
/**
* Allow Baritone to automatically put useful items (such as tools and throwaway blocks) on the hotbar while
* pathing. This can reduce delays when retrieving items due settings like {@link #ticksBetweenInventoryMoves} and
* {@link #inventoryMoveOnlyIfStationary}. Requires {@link #allowInventory}.
*/
public final Setting<Boolean> allowHotbarManagement = new Setting<>(false);
/**
* Wait this many ticks between InventoryBehavior moving inventory items
*/
@@ -629,13 +622,6 @@ public final class Settings {
*/
public final Setting<Boolean> pruneRegionsFromRAM = new Setting<>(true);
/**
* The chunk packer queue can never grow to larger than this, if it does, the oldest chunks are discarded
* <p>
* The newest chunks are kept, so that if you're moving in a straight line quickly then stop, your immediate render distance is still included
*/
public final Setting<Integer> chunkPackerQueueMaxSize = new Setting<>(2000);
/**
* Fill in blocks behind you
*/
@@ -1303,6 +1289,13 @@ public final class Settings {
*/
public final Setting<Boolean> desktopNotifications = new Setting<>(false);
/**
* Having this setting enabled keeps vanilla collision working. If disabled, bots will ignore
* collision boxes and be able to walk inside each other without issues. This should only be
* disabled when multiple bots are are needed to simultaneously use narrow tunnels.
*/
public final Setting<Boolean> botCollision = new Setting<>(true);
/**
* Desktop notification on path complete
*/

View File

@@ -0,0 +1,68 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.bot;
import baritone.api.IBaritone;
import baritone.api.utils.IPlayerContext;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.NetworkManager;
import net.minecraft.util.Session;
/**
* @author Brady
* @since 10/23/2018
*/
public interface IBaritoneUser {
/**
* @return The Baritone instance
*/
IBaritone getBaritone();
/**
* Returns the player context. Equivalent to {@code getBaritone().getPlayerContext()}.
*
* @return The player context
*/
IPlayerContext getPlayerContext();
/**
* @return The network manager that is responsible for the current connection.
*/
NetworkManager getNetworkManager();
/**
* Returns the user login session. Should never be {@code null}, as this should be set when the
* user is constructed.
*
* @return This users's login session
*/
Session getSession();
/**
* Returns the game profile for the account represented by this user.
*
* @return This users's profile.
*/
GameProfile getProfile();
/**
* @return The manager that spawned this {@link IBaritoneUser}.
*/
IUserManager getManager();
}

View File

@@ -0,0 +1,97 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.bot;
import baritone.api.bot.connect.ConnectionStatus;
import baritone.api.bot.connect.IConnectionResult;
import baritone.api.event.events.TickEvent;
import com.mojang.authlib.GameProfile;
import net.minecraft.util.Session;
import net.minecraft.util.text.ITextComponent;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
/**
* @author Brady
* @since 1/17/2019
*/
public interface IUserManager {
/**
* Connects a new user with the specified {@link Session} to the current server. Returns
* a {@link IConnectionResult} describing the result of the attempted connection as well
* as a {@link IBaritoneUser} instance if it was {@link ConnectionStatus#SUCCESS}.
*
* @param session The user session
* @return The result of the attempted connection
*/
IConnectionResult connect(Session session);
/**
* Disconnects the specified {@link IBaritoneUser} from its current server. All valid users
* are automatically disconnected when the current game state becomes {@link TickEvent.Type#OUT}.
* A reason may be specified, but is more widely used in server-initiated disconnects.
*
* @param user The user to disconnect
* @param reason The reason for the disconnect, may be {@code null}
*/
void disconnect(IBaritoneUser user, ITextComponent reason);
/**
* Finds the {@link IBaritoneUser} associated with the specified {@link GameProfile}
*
* @param profile The game profile of the user
* @return The user, {@link Optional#empty()} if no match or {@code profile} is {@code null}
*/
default Optional<IBaritoneUser> getUserByProfile(GameProfile profile) {
return profile == null
? Optional.empty()
: this.getUsers().stream().filter(user -> user.getProfile().equals(profile)).findFirst();
}
/**
* Finds the {@link IBaritoneUser} associated with the specified {@link UUID}
*
* @param uuid The uuid of the user
* @return The user, {@link Optional#empty()} if no match or {@code uuid} is {@code null}
*/
default Optional<IBaritoneUser> getUserByUUID(UUID uuid) {
return uuid == null
? Optional.empty()
: this.getUsers().stream().filter(user -> user.getProfile().getId().equals(uuid)).findFirst();
}
/**
* Finds the {@link IBaritoneUser} associated with the specified username
*
* @param username The username of the user
* @return The user, {@link Optional#empty()} if no match or {@code uuid} is {@code null}
*/
default Optional<IBaritoneUser> getUserByName(String username) {
return username == null || username.isEmpty()
? Optional.empty()
: this.getUsers().stream().filter(user -> user.getProfile().getName().equalsIgnoreCase(username)).findFirst();
}
/**
* @return All of the users held by this manager
*/
List<IBaritoneUser> getUsers();
}

View File

@@ -15,22 +15,36 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone;
import baritone.pathing.movement.CalculationContext;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
package baritone.api.bot.connect;
/**
* Annotation that should be used on methods which are performance critical (i.e. called millions of times per second
* by the pathfinder) and should be modified with care. Particularly useful for methods for which this fact is not
* obvious, such as those which don't have a {@link CalculationContext} parameter.
*
* @author Brady
* @since 11/6/2018
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface PerformanceCritical {}
public enum ConnectionStatus {
/**
* The local player is not connected to a server, therefore, there is no target server to connect to.
*/
NO_CURRENT_CONNECTION,
/**
* The IP of the targetted address to connect to could not be resolved.
*/
CANT_RESOLVE_HOST,
/**
* The port for the detected LAN server could not be resolved.
*/
CANT_RESOLVE_LAN,
/**
* The connection initialization failed.
*/
CONNECTION_FAILED,
/**
* The connection was a success
*/
SUCCESS
}

View File

@@ -0,0 +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 Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.bot.connect;
import baritone.api.bot.IBaritoneUser;
import java.util.Optional;
/**
* @author Brady
* @since 1/17/2019
*/
public interface IConnectionResult {
/**
* @return The actual status of the connection attempt.
* @see ConnectionStatus
*/
ConnectionStatus getStatus();
/**
* Returns the user that was created in this connection this result reflects, if
* {@link #getStatus()} is {@link ConnectionStatus#SUCCESS}, otherwise it will
* return {@link Optional#empty()}.
*
* @return The user created in the connection
*/
Optional<IBaritoneUser> getUser();
}

View File

@@ -1,47 +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 Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.utils;
import net.minecraft.item.ItemStack;
import java.util.stream.Stream;
/**
* @author Brady
*/
public interface IBaritoneInventory {
/**
* Returns a stream containing all the player's regular inventory slots and items. The elements of the stream are in
* the order of hotbar, offhand, then main inventory, for a total of 37 slots. This explicitly does not contain the
* armor slots or crafting grid, which may otherwise be accessed with {@link #armorSlots()} and/or {@link #itemAt}.
*
* @return All the player's inventory slots and items
*/
Stream<Pair<InventorySlot, ItemStack>> allSlots();
Stream<Pair<InventorySlot, ItemStack>> hotbarSlots();
Stream<Pair<InventorySlot, ItemStack>> inventorySlots();
Pair<InventorySlot, ItemStack> offhand();
Stream<Pair<InventorySlot, ItemStack>> armorSlots();
ItemStack itemAt(InventorySlot slot);
}

View File

@@ -17,7 +17,6 @@
package baritone.api.utils;
import baritone.api.IBaritone;
import baritone.api.cache.IWorldData;
import net.minecraft.block.BlockSlab;
import net.minecraft.client.Minecraft;
@@ -35,16 +34,12 @@ import java.util.Optional;
*/
public interface IPlayerContext {
IBaritone baritone();
Minecraft minecraft();
EntityPlayerSP player();
IPlayerController playerController();
IBaritoneInventory inventory();
World world();
IWorldData worldData();

View File

@@ -46,6 +46,8 @@ public interface IPlayerController {
ItemStack windowClick(int windowId, int slotId, int mouseButton, ClickType type, EntityPlayer player);
void setGameType(GameType type);
GameType getGameType();
EnumActionResult processRightClickBlock(EntityPlayerSP player, World world, BlockPos pos, EnumFacing direction, Vec3d vec, EnumHand hand);

View File

@@ -1,129 +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 Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.utils;
import java.util.function.ObjIntConsumer;
/**
* @author Brady
*/
public final class InventorySlot {
/**
* Maps directly to the slot ids of the player's inventory container.
* <table width="100%">
* <tr>
* <th width="10%">Index</th>
* <th>Description</th>
* </tr>
* <tr><td>0</td><td>crafting output</td></tr>
* <tr><td>1-4</td><td>crafting grid</td></tr>
* <tr><td>5-8</td><td>armor</td></tr>
* <tr><td>9-35</td><td>inventory (index 9-35)</td></tr>
* <tr><td>36-44</td><td>hotbar (index 0-8)</td></tr>
* <tr><td>45</td><td>off-hand</td></tr>
* </table>
*/
private static final InventorySlot[] SLOTS = new InventorySlot[46];
static {
final ObjIntConsumer<Type> populate = new ObjIntConsumer<Type>() {
private int index;
@Override
public void accept(Type type, int count) {
for (int i = 0; i < count; i++) {
SLOTS[this.index] = new InventorySlot(this.index, type);
this.index++;
}
}
};
populate.accept(Type.CRAFTING_OUTPUT, 1);
populate.accept(Type.CRAFTING_GRID, 4);
populate.accept(Type.ARMOR, 4);
populate.accept(Type.INVENTORY, 27);
populate.accept(Type.HOTBAR, 9);
populate.accept(Type.OFFHAND, 1);
}
private final int slotId;
private final Type type;
private InventorySlot(int slotId, Type type) {
this.slotId = slotId;
this.type = type;
}
/**
* @return The ID of this slot, as used by {@code ContainerPlayer}
*/
public int getSlotId() {
return this.slotId;
}
public Type getType() {
return this.type;
}
/**
* Returns the index of this slot in {@code mainInventory}. If this slot does not correspond to an index into
* {@code mainInventory}, then an {@link IllegalArgumentException} is thrown.
*
* @return The index of this slot in the player's {@code mainInventory}
* @throws IllegalArgumentException if type is not {@link Type#HOTBAR} or {@link Type#INVENTORY}
*/
public int getInventoryIndex() {
switch (this.getType()) {
case HOTBAR:
return this.slotId - 36;
case INVENTORY:
return this.slotId;
default:
throw new IllegalStateException("Slot type must be either HOTBAR or INVENTORY");
}
}
public static InventorySlot inventory(final int index) {
if (index >= 0 && index < 9) {
return SLOTS[index + 36]; // HOTBAR
} else if (index >= 9 && index < 36) {
return SLOTS[index]; // INVENTORY
}
throw new IllegalArgumentException();
}
public static InventorySlot armor(final int index) {
if (index < 0 || index >= 4) {
throw new IllegalArgumentException();
}
return SLOTS[index + 5];
}
public static InventorySlot offhand() {
return SLOTS[45];
}
public enum Type {
CRAFTING_OUTPUT,
CRAFTING_GRID,
ARMOR,
INVENTORY,
HOTBAR,
OFFHAND
}
}

View File

@@ -21,6 +21,7 @@ import baritone.api.BaritoneAPI;
import baritone.api.IBaritone;
import baritone.api.event.events.RenderEvent;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -38,7 +39,13 @@ public class MixinEntityRenderer {
)
)
private void renderWorldPass(int pass, float partialTicks, long finishTimeNano, CallbackInfo ci) {
int renderViewDimension = BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext().world().provider.getDimensionType().getId();
for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) {
World world = ibaritone.getPlayerContext().world();
if (world == null || world.provider.getDimensionType().getId() != renderViewDimension) {
continue;
}
ibaritone.getGameEventHandler().onRenderPass(new RenderEvent(partialTicks));
}
}

View File

@@ -0,0 +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 Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.utils.accessor.IGameSettings;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.entity.player.EnumPlayerModelParts;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Set;
/**
* @author Brady
* @since 3/6/2020
*/
@Mixin(GameSettings.class)
public abstract class MixinGameSettings implements IGameSettings {
@Accessor
@Override
public abstract void setSetModelParts(Set<EnumPlayerModelParts> setModelParts);
@Accessor
@Override
public abstract void setMc(Minecraft mc);
}

View File

@@ -0,0 +1,36 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.utils.accessor.IIntegratedServer;
import net.minecraft.client.multiplayer.ThreadLanServerPing;
import net.minecraft.server.integrated.IntegratedServer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
/**
* @author Brady
* @since 3/4/2020
*/
@Mixin(IntegratedServer.class)
public abstract class MixinIntegratedServer implements IIntegratedServer {
@Accessor
@Override
public abstract ThreadLanServerPing getLanServerPing();
}

View File

@@ -24,6 +24,7 @@ import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.TickEvent;
import baritone.api.event.events.WorldEvent;
import baritone.api.event.events.type.EventState;
import baritone.utils.accessor.IMinecraft;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiScreen;
@@ -33,7 +34,9 @@ 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.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -41,6 +44,7 @@ import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.io.File;
import java.util.function.BiFunction;
/**
@@ -48,13 +52,19 @@ import java.util.function.BiFunction;
* @since 7/31/2018
*/
@Mixin(Minecraft.class)
public class MixinMinecraft {
public class MixinMinecraft implements IMinecraft {
@Shadow
public EntityPlayerSP player;
@Shadow
public WorldClient world;
@Shadow
@Final
@Mutable
public File gameDir;
@Inject(
method = "init",
at = @At("RETURN")
@@ -176,4 +186,9 @@ public class MixinMinecraft {
// rightClickMouse is only for the main player
BaritoneAPI.getProvider().getPrimaryBaritone().getGameEventHandler().onBlockInteract(new BlockInteractEvent(blockpos, BlockInteractEvent.Type.USE));
}
@Override
public void setGameDir(File gameDir) {
this.gameDir = gameDir;
}
}

View File

@@ -23,7 +23,9 @@ import baritone.api.IBaritone;
import baritone.api.event.events.ChunkEvent;
import baritone.api.event.events.type.EventState;
import baritone.cache.CachedChunk;
import baritone.utils.accessor.INetHandlerPlayClient;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.network.play.server.SPacketBlockChange;
import net.minecraft.network.play.server.SPacketChunkData;
@@ -31,6 +33,7 @@ import net.minecraft.network.play.server.SPacketCombatEvent;
import net.minecraft.network.play.server.SPacketMultiBlockChange;
import net.minecraft.util.math.ChunkPos;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -40,7 +43,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
* @since 8/3/2018
*/
@Mixin(NetHandlerPlayClient.class)
public class MixinNetHandlerPlayClient {
public abstract class MixinNetHandlerPlayClient implements INetHandlerPlayClient {
@Accessor
@Override
public abstract void setWorld(WorldClient world);
@Inject(
method = "handleChunkData",

View File

@@ -0,0 +1,39 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch.mixins;
import baritone.utils.accessor.IThreadLanServerPing;
import net.minecraft.client.multiplayer.ThreadLanServerPing;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
/**
* @author Brady
* @since 3/4/2020
*/
@Mixin(ThreadLanServerPing.class)
public abstract class MixinThreadLanServerPing implements IThreadLanServerPing {
@Accessor
@Override
public abstract String getMotd();
@Accessor
@Override
public abstract String getAddress();
}

View File

@@ -19,7 +19,9 @@
"MixinEntityLivingBase",
"MixinEntityPlayerSP",
"MixinEntityRenderer",
"MixinGameSettings",
"MixinGuiScreen",
"MixinIntegratedServer",
"MixinItemStack",
"MixinItemTool",
"MixinMinecraft",
@@ -31,6 +33,7 @@
"MixinRenderList",
"MixinStateImplementation",
"MixinTabCompleter",
"MixinThreadLanServerPing",
"MixinVboRenderList",
"MixinWorldClient"
]

View File

@@ -26,6 +26,7 @@ import baritone.api.process.IBaritoneProcess;
import baritone.api.utils.IPlayerContext;
import baritone.behavior.*;
import baritone.cache.WorldProvider;
import baritone.command.ExampleBaritoneControl;
import baritone.command.manager.CommandManager;
import baritone.event.GameEventHandler;
import baritone.process.*;
@@ -36,6 +37,7 @@ import baritone.utils.InputOverrideHandler;
import baritone.utils.PathingControlManager;
import baritone.utils.player.BaritonePlayerContext;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import java.io.IOException;
import java.nio.file.Files;
@@ -232,10 +234,14 @@ public class Baritone implements IBaritone {
@Override
public void openClick() {
this.showScreen(new GuiClick());
}
public void showScreen(GuiScreen screen) {
new Thread(() -> {
try {
Thread.sleep(100);
mc.addScheduledTask(() -> mc.displayGuiScreen(new GuiClick()));
mc.addScheduledTask(() -> mc.displayGuiScreen(screen));
} catch (Exception ignored) {}
}).start();
}

View File

@@ -19,9 +19,11 @@ package baritone;
import baritone.api.IBaritone;
import baritone.api.IBaritoneProvider;
import baritone.api.bot.IUserManager;
import baritone.api.cache.IWorldScanner;
import baritone.api.command.ICommandSystem;
import baritone.api.schematic.ISchematicSystem;
import baritone.bot.UserManager;
import baritone.cache.FasterWorldScanner;
import baritone.command.CommandSystem;
import baritone.command.ExampleBaritoneControl;
@@ -79,6 +81,11 @@ public final class BaritoneProvider implements IBaritoneProvider {
return FasterWorldScanner.INSTANCE;
}
@Override
public IUserManager getUserManager() {
return UserManager.INSTANCE;
}
@Override
public ICommandSystem getCommandSystem() {
return CommandSystem.INSTANCE;

View File

@@ -20,29 +20,25 @@ package baritone.behavior;
import baritone.Baritone;
import baritone.api.event.events.TickEvent;
import baritone.api.utils.Helper;
import baritone.api.utils.InventorySlot;
import baritone.api.utils.Pair;
import baritone.utils.ItemInteractionHelper;
import baritone.utils.ToolSet;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.init.Blocks;
import net.minecraft.inventory.ClickType;
import net.minecraft.item.*;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.OptionalInt;
import java.util.Random;
import java.util.function.IntPredicate;
import java.util.function.Predicate;
import java.util.stream.Stream;
public final class InventoryBehavior extends Behavior implements Helper {
private int ticksSinceLastInventoryMove;
private int[] lastTickRequestedMove; // not everything asks every tick, so remember the request while coming to a halt
int ticksSinceLastInventoryMove;
int[] lastTickRequestedMove; // not everything asks every tick, so remember the request while coming to a halt
public InventoryBehavior(Baritone baritone) {
super(baritone);
@@ -50,51 +46,31 @@ public final class InventoryBehavior extends Behavior implements Helper {
@Override
public void onTick(TickEvent event) {
if (event.getType() == TickEvent.Type.OUT) {
if (!Baritone.settings().allowInventory.value) {
return;
}
ticksSinceLastInventoryMove++;
// TODO: Move these checks into "requestSwapWithHotBar" or whatever supersedes it
if (!this.canAccessInventory()) {
if (event.getType() == TickEvent.Type.OUT) {
return;
}
if (ctx.player().openContainer != ctx.player().inventoryContainer) {
// we have a crafting table or a chest or something open
return;
}
if (Baritone.settings().allowHotbarManagement.value && baritone.getPathingBehavior().isPathing()) {
this.setupHotbar();
ticksSinceLastInventoryMove++;
if (firstValidThrowaway() >= 9) { // aka there are none on the hotbar, but there are some in main inventory
requestSwapWithHotBar(firstValidThrowaway(), 8);
}
int pick = bestToolAgainst(Blocks.STONE, ItemPickaxe.class);
if (pick >= 9) {
requestSwapWithHotBar(pick, 0);
}
if (lastTickRequestedMove != null) {
logDebug("Remembering to move " + lastTickRequestedMove[0] + " " + lastTickRequestedMove[1] + " from a previous tick");
requestSwapWithHotBar(lastTickRequestedMove[0], lastTickRequestedMove[1]);
}
}
private void setupHotbar() {
// TODO: Some way of indicating which slots are currently reserved by this setting
final InventorySlot throwaway = this.findSlotMatching(this::isThrowawayItem);
if (throwaway != null && throwaway.getType() == InventorySlot.Type.INVENTORY) {
// aka there are none on the hotbar, but there are some in main inventory
this.requestSwapWithHotBar(throwaway.getInventoryIndex(), 8);
return;
}
final InventorySlot pick = this.bestToolAgainst(Blocks.STONE, ItemPickaxe.class);
if (pick != null && pick.getType() == InventorySlot.Type.INVENTORY) {
this.requestSwapWithHotBar(pick.getInventoryIndex(), 0);
}
}
private InventorySlot bestToolAgainst(final Block against, final Class<? extends ItemTool> cla$$) {
return new ToolSet(ctx).getBestSlot(against.getDefaultState(), Baritone.settings().preferSilkTouch.value, stack -> cla$$.isInstance(stack.getItem()));
}
public boolean attemptToPutOnHotbar(int inMainInvy, IntPredicate disallowedHotbar) {
public boolean attemptToPutOnHotbar(int inMainInvy, Predicate<Integer> disallowedHotbar) {
OptionalInt destination = getTempHotbarSlot(disallowedHotbar);
if (destination.isPresent()) {
if (!requestSwapWithHotBar(inMainInvy, destination.getAsInt())) {
@@ -104,7 +80,7 @@ public final class InventoryBehavior extends Behavior implements Helper {
return true;
}
public OptionalInt getTempHotbarSlot(IntPredicate disallowedHotbar) {
public OptionalInt getTempHotbarSlot(Predicate<Integer> disallowedHotbar) {
// we're using 0 and 8 for pickaxe and throwaway
ArrayList<Integer> candidates = new ArrayList<>();
for (int i = 1; i < 8; i++) {
@@ -141,172 +117,114 @@ public final class InventoryBehavior extends Behavior implements Helper {
return true;
}
public boolean hasGenericThrowaway() {
return this.canSelectItem(this::isThrowawayItem);
}
public boolean selectThrowawayForLocation(boolean select, int x, int y, int z) {
final Predicate<Predicate<? super ItemStack>> op = select ? this::trySelectItem : this::canSelectItem;
final IBlockState maybe = baritone.getBuilderProcess().placeAt(x, y, z, baritone.bsi.get0(x, y, z));
if (maybe != null) {
return op.test(stack -> {
if (!(stack.getItem() instanceof ItemBlock)) {
return false;
}
Block block = ((ItemBlock) stack.getItem()).getBlock();
return maybe.equals(block.getStateForPlacement(
ctx.world(),
ctx.playerFeet(),
EnumFacing.UP,
0.5f, 1.0f, 0.5f,
stack.getItem().getMetadata(stack.getMetadata()),
ctx.player()
));
}) || op.test(stack -> {
// Since a stack didn't match the desired block state, accept a match of just the block
return stack.getItem() instanceof ItemBlock
&& ((ItemBlock) stack.getItem()).getBlock().equals(maybe.getBlock());
});
private int firstValidThrowaway() { // TODO offhand idk
NonNullList<ItemStack> invy = ctx.player().inventory.mainInventory;
for (int i = 0; i < invy.size(); i++) {
if (Baritone.settings().acceptableThrowawayItems.value.contains(invy.get(i).getItem())) {
return i;
}
}
return op.test(this::isThrowawayItem);
return -1;
}
public boolean canSelectItem(Predicate<? super ItemStack> desired) {
return this.resolveSelectionStrategy(this.findSlotMatching(desired)) != null;
private int bestToolAgainst(Block against, Class<? extends ItemTool> cla$$) {
NonNullList<ItemStack> invy = ctx.player().inventory.mainInventory;
int bestInd = -1;
double bestSpeed = -1;
for (int i = 0; i < invy.size(); i++) {
ItemStack stack = invy.get(i);
if (stack.isEmpty()) {
continue;
}
if (Baritone.settings().itemSaver.value && (stack.getItemDamage() + Baritone.settings().itemSaverThreshold.value) >= stack.getMaxDamage() && stack.getMaxDamage() > 1) {
continue;
}
if (cla$$.isInstance(stack.getItem())) {
double speed = ToolSet.calculateSpeedVsBlock(stack, against.getDefaultState()); // takes into account enchants
if (speed > bestSpeed) {
bestSpeed = speed;
bestInd = i;
}
}
}
return bestInd;
}
public boolean trySelectItem(Predicate<? super ItemStack> desired) {
final SelectionStrategy strategy = this.resolveSelectionStrategy(this.findSlotMatching(desired));
if (strategy != null) {
strategy.run();
// TODO: Consider cases where returning the SelectionType is needed/useful to the caller
return true;
public boolean hasGenericThrowaway() {
for (Item item : Baritone.settings().acceptableThrowawayItems.value) {
if (throwaway(false, stack -> item.equals(stack.getItem()))) {
return true;
}
}
return false;
}
public SelectionStrategy resolveSelectionStrategy(final InventorySlot slot) {
if (slot != null) {
switch (slot.getType()) {
case HOTBAR:
return SelectionStrategy.of(SelectionType.IMMEDIATE, () ->
ctx.player().inventory.currentItem = slot.getInventoryIndex());
case OFFHAND:
// TODO: It's probably worth adding a parameter to this method so that the caller can indicate what
// the purpose of the item is. For example, attacks are always done using the main hand, so
// just switching to a non-interacting hotbar item isn't sufficient.
final ItemStack heldItem = ctx.player().inventory.getCurrentItem();
if (!ItemInteractionHelper.couldInteract(heldItem)) {
// Don't need to do anything, the item held in the main hand doesn't have any interaction.
return SelectionStrategy.of(SelectionType.IMMEDIATE, () -> {});
}
final InventorySlot hotbar = this.findHotbarMatching(item -> !ItemInteractionHelper.couldInteract(item));
if (hotbar != null) {
return SelectionStrategy.of(SelectionType.IMMEDIATE, () ->
ctx.player().inventory.currentItem = hotbar.getInventoryIndex());
}
// TODO: Swap offhand with an unimportant item
break;
case INVENTORY:
if (this.canAccessInventory()) {
return SelectionStrategy.of(SelectionType.ENQUEUED, () -> {
// TODO: Determine if hotbar swap can be immediate, and return type accordingly
// Also don't only swap into slot 7 that's silly
requestSwapWithHotBar(slot.getInventoryIndex(), 7);
ctx.player().inventory.currentItem = 7;
});
}
break;
default:
break;
public boolean selectThrowawayForLocation(boolean select, int x, int y, int z) {
IBlockState maybe = baritone.getBuilderProcess().placeAt(x, y, z, baritone.bsi.get0(x, y, z));
if (maybe != null && throwaway(select, stack -> stack.getItem() instanceof ItemBlock && maybe.equals(((ItemBlock) stack.getItem()).getBlock().getStateForPlacement(ctx.world(), ctx.playerFeet(), EnumFacing.UP, (float) ctx.player().posX, (float) ctx.player().posY, (float) ctx.player().posZ, stack.getItem().getMetadata(stack.getMetadata()), ctx.player())))) {
return true; // gotem
}
if (maybe != null && throwaway(select, stack -> stack.getItem() instanceof ItemBlock && ((ItemBlock) stack.getItem()).getBlock().equals(maybe.getBlock()))) {
return true;
}
for (Item item : Baritone.settings().acceptableThrowawayItems.value) {
if (throwaway(select, stack -> item.equals(stack.getItem()))) {
return true;
}
}
return null;
return false;
}
public InventorySlot findBestAccessibleMatching(final Comparator<? super ItemStack> comparator,
final Predicate<? super ItemStack> filter) {
final Stream<Pair<InventorySlot, ItemStack>> accessible = this.canAccessInventory()
? ctx.inventory().allSlots()
: Stream.concat(ctx.inventory().hotbarSlots(), Stream.of(ctx.inventory().offhand()));
return this.findBestMatching0(accessible, comparator, filter);
public boolean throwaway(boolean select, Predicate<? super ItemStack> desired) {
return throwaway(select, desired, Baritone.settings().allowInventory.value);
}
public InventorySlot findSlotMatching(final Predicate<? super ItemStack> filter) {
return this.findBestSlotMatching(null, filter);
}
/**
* Returns an {@link InventorySlot} that contains a stack matching the given predicate. A comparator may be
* specified to prioritize slot selection. The comparator may be {@code null}, in which case, the first slot
* matching the predicate is returned. The considered slots are in the order of hotbar, offhand, and finally the
* main inventory (if {@link #canAccessInventory()} is {@code true}).
*
* @param comparator A comparator to find the best element, may be {@code null}
* @param filter The predicate to match
* @return A matching slot, or {@code null} if none.
*/
public InventorySlot findBestSlotMatching(final Comparator<? super ItemStack> comparator, final Predicate<? super ItemStack> filter) {
return this.findBestMatching0(ctx.inventory().allSlots(), comparator, filter);
}
public InventorySlot findHotbarMatching(final Predicate<? super ItemStack> filter) {
return this.findBestHotbarMatching(null, filter);
}
public InventorySlot findBestHotbarMatching(final Comparator<? super ItemStack> comparator, final Predicate<? super ItemStack> filter) {
return this.findBestMatching0(ctx.inventory().hotbarSlots(), comparator, filter);
}
private InventorySlot findBestMatching0(final Stream<Pair<InventorySlot, ItemStack>> slots,
final Comparator<? super ItemStack> comparator,
final Predicate<? super ItemStack> filter) {
final Stream<Pair<InventorySlot, ItemStack>> filtered = slots.filter(slot -> filter.test(slot.second()));
return (comparator != null
? filtered.max((a, b) -> comparator.compare(a.second(), b.second()))
: filtered.findFirst()
).map(Pair::first).orElse(null);
}
public boolean canAccessInventory() {
return Baritone.settings().allowInventory.value;
}
public boolean isThrowawayItem(ItemStack stack) {
return this.isThrowawayItem(stack.getItem());
}
public boolean isThrowawayItem(Item item) {
return Baritone.settings().acceptableThrowawayItems.value.contains(item);
}
public interface SelectionStrategy extends Runnable {
@Override
void run();
SelectionType getType();
static SelectionStrategy of(final SelectionType type, final Runnable runnable) {
return new SelectionStrategy() {
@Override
public void run() {
runnable.run();
public boolean throwaway(boolean select, Predicate<? super ItemStack> desired, boolean allowInventory) {
EntityPlayerSP p = ctx.player();
NonNullList<ItemStack> inv = p.inventory.mainInventory;
for (int i = 0; i < 9; i++) {
ItemStack item = inv.get(i);
// this usage of settings() is okay because it's only called once during pathing
// (while creating the CalculationContext at the very beginning)
// and then it's called during execution
// since this function is never called during cost calculation, we don't need to migrate
// acceptableThrowawayItems to the CalculationContext
if (desired.test(item)) {
if (select) {
p.inventory.currentItem = i;
}
@Override
public SelectionType getType() {
return type;
}
};
return true;
}
}
if (desired.test(p.inventory.offHandInventory.get(0))) {
// main hand takes precedence over off hand
// that means that if we have block A selected in main hand and block B in off hand, right clicking places block B
// we've already checked above ^ and the main hand can't possible have an acceptablethrowawayitem
// so we need to select in the main hand something that doesn't right click
// so not a shovel, not a hoe, not a block, etc
for (int i = 0; i < 9; i++) {
ItemStack item = inv.get(i);
if (item.isEmpty() || item.getItem() instanceof ItemPickaxe) {
if (select) {
p.inventory.currentItem = i;
}
return true;
}
}
}
}
public enum SelectionType {
IMMEDIATE, ENQUEUED
if (allowInventory) {
for (int i = 9; i < 36; i++) {
if (desired.test(inv.get(i))) {
if (select) {
requestSwapWithHotBar(i, 7);
p.inventory.currentItem = 7;
}
return true;
}
}
}
return false;
}
}

View File

@@ -0,0 +1,107 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.bot;
import baritone.Baritone;
import baritone.api.BaritoneAPI;
import baritone.api.IBaritone;
import baritone.api.bot.IBaritoneUser;
import baritone.api.event.events.WorldEvent;
import baritone.api.event.events.type.EventState;
import baritone.api.utils.IPlayerContext;
import baritone.bot.impl.BotMinecraft;
import baritone.bot.impl.BotWorld;
import baritone.bot.impl.BotPlayer;
import baritone.command.ExampleBaritoneControl;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.multiplayer.PlayerControllerMP;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.network.NetworkManager;
import net.minecraft.util.Session;
/**
* Implementation of {@link IBaritoneUser}
*
* @author Brady
* @since 11/6/2018
*/
public final class BaritoneUser implements IBaritoneUser {
private final BotMinecraft mc;
private final UserManager manager;
private final NetworkManager networkManager;
private final Session session;
private final Baritone baritone;
private GameProfile profile;
BaritoneUser(UserManager manager, NetworkManager networkManager, Session session, ServerData serverData) {
this.mc = BotMinecraft.allocate(this);
this.mc.setServerData(serverData);
this.manager = manager;
this.networkManager = networkManager;
this.session = session;
this.profile = session.getProfile();
this.baritone = (Baritone) BaritoneAPI.getProvider().createBaritone(this.mc);
this.baritone.registerBehavior(ExampleBaritoneControl::new);
}
public void onLoginSuccess(GameProfile profile) {
this.profile = profile;
}
public void onWorldLoad(BotWorld world, BotPlayer player, PlayerControllerMP playerController) {
this.baritone.getGameEventHandler().onWorldEvent(new WorldEvent(world, EventState.PRE));
this.mc.player = player;
this.mc.world = world;
this.mc.playerController = playerController;
this.baritone.getGameEventHandler().onWorldEvent(new WorldEvent(world, EventState.POST));
}
@Override
public IBaritone getBaritone() {
return this.baritone;
}
@Override
public IPlayerContext getPlayerContext() {
return this.baritone.getPlayerContext();
}
@Override
public NetworkManager getNetworkManager() {
return this.networkManager;
}
@Override
public Session getSession() {
return this.session;
}
@Override
public GameProfile getProfile() {
return this.profile;
}
@Override
public UserManager getManager() {
return this.manager;
}
}

View File

@@ -0,0 +1,66 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.bot;
import baritone.bot.impl.BotWorld;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.world.GameType;
import net.minecraft.world.WorldSettings;
import net.minecraft.world.WorldType;
/**
* @author Brady
* @since 11/7/2018
*/
public final class BotWorldProvider {
/**
* Generic world settings for a typical survival world.
*/
private static final WorldSettings GENERIC_WORLD_SETTINGS = new WorldSettings(0L, GameType.SURVIVAL, true, false, WorldType.DEFAULT);
/**
* All of the dimensions mapped to their respective worlds.
*/
private final Int2ObjectMap<BotWorld> worlds = new Int2ObjectArrayMap<>();
/**
* Gets or creates the {@link BotWorld} for the specified dimension
*
* @param dimension The dimension id
* @return The world
*/
public BotWorld getWorld(int dimension) {
return worlds.computeIfAbsent(dimension, this::createWorldForDim);
}
/**
* Creates a new {@link BotWorld} for the given dimension id.
*
* @param dimension The dimension id
* @return The new world
*/
private BotWorld createWorldForDim(int dimension) {
return new BotWorld(GENERIC_WORLD_SETTINGS, dimension);
}
public void tick() {
this.worlds.forEach((dim, world) -> world.updateEntities());
}
}

View File

@@ -0,0 +1,203 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.bot;
import baritone.api.BaritoneAPI;
import baritone.api.bot.IBaritoneUser;
import baritone.api.bot.IUserManager;
import baritone.api.bot.connect.IConnectionResult;
import baritone.api.event.events.TickEvent;
import baritone.api.event.events.type.EventState;
import baritone.api.event.listener.AbstractGameEventListener;
import baritone.api.utils.Helper;
import baritone.api.utils.IPlayerContext;
import baritone.bot.connect.ConnectionResult;
import baritone.bot.handler.BotNetHandlerLoginClient;
import baritone.bot.impl.BotPlayer;
import baritone.bot.impl.BotWorld;
import baritone.utils.accessor.IIntegratedServer;
import baritone.utils.accessor.IThreadLanServerPing;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ServerAddress;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.network.EnumConnectionState;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.handshake.client.C00Handshake;
import net.minecraft.network.login.client.CPacketLoginStart;
import net.minecraft.util.Session;
import net.minecraft.util.text.ITextComponent;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import static baritone.api.bot.connect.ConnectionStatus.*;
/**
* @author Brady
* @since 11/6/2018
*/
public enum UserManager implements IUserManager, AbstractGameEventListener {
INSTANCE;
private static final Minecraft mc = Minecraft.getMinecraft();
private final List<IBaritoneUser> users;
private final BotWorldProvider worldProvider;
UserManager() {
BaritoneAPI.getProvider().getPrimaryBaritone().getGameEventHandler().registerEventListener(this);
this.users = new CopyOnWriteArrayList<>();
this.worldProvider = new BotWorldProvider();
}
@Override
public void onTick(TickEvent event) {
if (event.getState() != EventState.PRE) {
return;
}
this.users.forEach(user -> {
switch (event.getType()) {
case IN: {
final IPlayerContext ctx = user.getPlayerContext();
if (ctx.player() != null) {
ctx.playerController().syncHeldItem();
}
if (user.getNetworkManager().isChannelOpen()) {
user.getNetworkManager().processReceivedPackets();
} else {
user.getNetworkManager().handleDisconnection();
}
break;
}
case OUT: {
this.disconnect(user, null);
break;
}
}
});
this.worldProvider.tick();
}
/**
* Connects a new user with the specified {@link Session} to the current server.
*
* @param session The user session
* @return The result of the attempted connection
*/
@Override
public final IConnectionResult connect(Session session) {
if (mc.getIntegratedServer() != null && mc.getIntegratedServer().getPublic()) {
try {
IIntegratedServer integratedServer = (IIntegratedServer) mc.getIntegratedServer();
IThreadLanServerPing lanServerPing = (IThreadLanServerPing) integratedServer.getLanServerPing();
int port = Integer.parseInt(lanServerPing.getAddress());
return connect0(session, new ServerData(lanServerPing.getMotd(), "localhost:" + port, true));
} catch (Exception e) {
e.printStackTrace();
return ConnectionResult.failed(CANT_RESOLVE_LAN);
}
}
ServerData data = mc.getCurrentServerData();
if (data == null) {
return ConnectionResult.failed(NO_CURRENT_CONNECTION);
}
// Connect to the server from the parsed server data
return connect0(session, data);
}
/**
* Connects a new user with the specified {@link Session} to the specified server.
* <p>
* Hi Mickey :)
*
* @param session The user session
* @param data The address of the server to connect to
* @return The result of the attempted connection
*/
private IConnectionResult connect0(Session session, ServerData data) {
ServerAddress address = ServerAddress.fromString(data.serverIP);
InetAddress inetAddress;
try {
inetAddress = InetAddress.getByName(address.getIP());
} catch (UnknownHostException e) {
return ConnectionResult.failed(CANT_RESOLVE_HOST);
}
try {
// Initialize Connection
NetworkManager networkManager = NetworkManager.createNetworkManagerAndConnect(
inetAddress,
address.getPort(),
mc.gameSettings.isUsingNativeTransport()
);
// Create User
BaritoneUser user = new BaritoneUser(this, networkManager, session, data);
this.users.add(user);
// Setup login handler and send connection packets
networkManager.setNetHandler(new BotNetHandlerLoginClient(networkManager, user));
networkManager.sendPacket(new C00Handshake(address.getIP(), address.getPort(), EnumConnectionState.LOGIN));
networkManager.sendPacket(new CPacketLoginStart(session.getProfile()));
return ConnectionResult.success(user);
} catch (Exception e) {
e.printStackTrace();
return ConnectionResult.failed(CONNECTION_FAILED);
}
}
/**
* @return The bot world provider
*/
public final BotWorldProvider getWorldProvider() {
return this.worldProvider;
}
@Override
public final void disconnect(IBaritoneUser user, ITextComponent reason) {
if (this.users.contains(user)) {
if (user.getNetworkManager().isChannelOpen()) {
user.getNetworkManager().closeChannel(reason);
}
BaritoneAPI.getProvider().destroyBaritone(user.getBaritone());
this.users.remove(user);
Helper.HELPER.logDirect(user.getSession().getUsername() + " Disconnected: " +
(reason == null ? "Unknown" : reason.getUnformattedText()));
final IPlayerContext ctx = user.getPlayerContext();
if (ctx.player() != null && ctx.world() != null) {
((BotWorld) ctx.world()).handleWorldRemove((BotPlayer) ctx.player());
}
}
}
@Override
public final List<IBaritoneUser> getUsers() {
return Collections.unmodifiableList(this.users);
}
}

View File

@@ -0,0 +1,95 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.bot.connect;
import baritone.api.bot.IBaritoneUser;
import baritone.api.bot.connect.ConnectionStatus;
import baritone.api.bot.connect.IConnectionResult;
import java.util.Objects;
import java.util.Optional;
import static baritone.api.bot.connect.ConnectionStatus.SUCCESS;
/**
* @author Brady
* @since 11/6/2018
*/
public final class ConnectionResult implements IConnectionResult {
/**
* The result status
*/
private final ConnectionStatus status;
/**
* The user created, if the status is {@link ConnectionStatus#SUCCESS}
*/
private final IBaritoneUser user;
private ConnectionResult(ConnectionStatus status, IBaritoneUser user) {
this.status = status;
this.user = user;
}
@Override
public ConnectionStatus getStatus() {
return this.status;
}
@Override
public Optional<IBaritoneUser> getUser() {
return Optional.ofNullable(user);
}
/**
* Creates a new failed {@link ConnectionResult}.
*
* @param status The failed connection status
* @return The connection result
* @throws IllegalArgumentException if {@code status} is {@link ConnectionStatus#SUCCESS}
*/
public static ConnectionResult failed(ConnectionStatus status) {
if (status == SUCCESS) {
throw new IllegalArgumentException("Status must be a failure type");
}
return new ConnectionResult(status, null);
}
/**
* Creates a new success {@link ConnectionResult}.
*
* @param user The user created
* @return The connection result
* @throws IllegalArgumentException if {@code user} is {@code null}
*/
public static ConnectionResult success(IBaritoneUser user) {
Objects.requireNonNull(user);
return new ConnectionResult(SUCCESS, user);
}
@Override
public String toString() {
return "ConnectionResult{" +
"status=" + status +
", user=" + user +
'}';
}
}

View File

@@ -0,0 +1,72 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.bot.handler;
import baritone.bot.BaritoneUser;
import baritone.bot.impl.BotMinecraft;
import net.minecraft.client.Minecraft;
import net.minecraft.client.network.NetHandlerLoginClient;
import net.minecraft.network.EnumConnectionState;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.login.server.SPacketLoginSuccess;
import net.minecraft.util.text.ITextComponent;
import javax.annotation.Nonnull;
/**
* Handles the login stage when connecting to a server.
*
* @author Brady
* @since 10/29/2018
*/
public final class BotNetHandlerLoginClient extends NetHandlerLoginClient {
/**
* The {@link NetworkManager} that is managing the connection with the server.
*/
private final NetworkManager networkManager;
/**
* The {@link Minecraft} game instance
*/
private final BotMinecraft mc;
/**
* The bot of this connection
*/
private final BaritoneUser user;
public BotNetHandlerLoginClient(NetworkManager networkManager, BaritoneUser user) {
super(networkManager, user.getPlayerContext().minecraft(), null);
this.networkManager = networkManager;
this.mc = (BotMinecraft) user.getPlayerContext().minecraft();
this.user = user;
}
@Override
public void handleLoginSuccess(SPacketLoginSuccess packetIn) {
this.networkManager.setConnectionState(EnumConnectionState.PLAY);
this.networkManager.setNetHandler(new BotNetHandlerPlayClient(this.networkManager, this.user, this.mc, packetIn.getProfile()));
}
@Override
public void onDisconnect(@Nonnull ITextComponent reason) {
// It's important that we don't call the superclass method because that would mess up GUIs and make us upset
this.user.getManager().disconnect(this.user, reason);
}
}

View File

@@ -0,0 +1,521 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.bot.handler;
import baritone.api.utils.Helper;
import baritone.bot.BaritoneUser;
import baritone.bot.impl.BotPlayer;
import baritone.bot.impl.BotMinecraft;
import baritone.bot.impl.BotWorld;
import baritone.utils.accessor.INetHandlerPlayClient;
import com.mojang.authlib.GameProfile;
import io.netty.buffer.Unpooled;
import net.minecraft.client.multiplayer.ClientAdvancementManager;
import net.minecraft.client.multiplayer.PlayerControllerMP;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.client.util.RecipeBookClient;
import net.minecraft.entity.Entity;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.PacketThreadUtil;
import net.minecraft.network.play.client.CPacketClientStatus;
import net.minecraft.network.play.client.CPacketCustomPayload;
import net.minecraft.network.play.client.CPacketResourcePackStatus;
import net.minecraft.network.play.server.*;
import net.minecraft.stats.StatisticsManager;
import net.minecraft.util.text.ITextComponent;
import javax.annotation.Nonnull;
// Notes
// - Make some sort of system that prevents repetition of entity info updating
// - For some packets, such as ones that modify position, we can check if the existing server state matches the packet proposed state
// - For other things, we'll actually need the system
/**
* @author Brady
* @since 10/22/2018
*/
public final class BotNetHandlerPlayClient extends NetHandlerPlayClient {
/**
* The {@link NetworkManager} that is managing the connection with the server.
*/
private final NetworkManager networkManager;
/**
* The bot's minecraft game instance
*/
private final BotMinecraft client;
/**
* The bot of this connection
*/
private final BaritoneUser user;
/**
* The bot player
*/
private BotPlayer player;
/**
* The current world.
*/
private BotWorld world;
/**
* The current player controller
*/
private PlayerControllerMP playerController;
BotNetHandlerPlayClient(NetworkManager networkManager, BaritoneUser user, BotMinecraft client, GameProfile profile) {
// noinspection ConstantConditions
super(client, null, networkManager, profile);
this.networkManager = networkManager;
this.client = client;
this.user = user;
// Notify the user that we're ingame
this.user.onLoginSuccess(profile);
}
@Override
public void handleSpawnObject(@Nonnull SPacketSpawnObject packetIn) {
super.handleSpawnObject(packetIn);
}
@Override
public void handleSpawnExperienceOrb(@Nonnull SPacketSpawnExperienceOrb packetIn) {
super.handleSpawnExperienceOrb(packetIn);
}
@Override
public void handleSpawnGlobalEntity(@Nonnull SPacketSpawnGlobalEntity packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
if (this.world != null) {
if (this.world.weatherEffects.stream().noneMatch(entity -> entity.getEntityId() == packetIn.getEntityId())) {
super.handleSpawnGlobalEntity(packetIn);
}
}
}
@Override
public void handleSpawnMob(@Nonnull SPacketSpawnMob packetIn) {}
@Override
public void handleScoreboardObjective(@Nonnull SPacketScoreboardObjective packetIn) {}
@Override
public void handleSpawnPainting(@Nonnull SPacketSpawnPainting packetIn) {}
@Override
public void handleSpawnPlayer(@Nonnull SPacketSpawnPlayer packetIn) {}
@Override
public void handleAnimation(@Nonnull SPacketAnimation packetIn) {
super.handleAnimation(packetIn);
}
@Override
public void handleStatistics(@Nonnull SPacketStatistics packetIn) {
super.handleStatistics(packetIn);
}
@Override
public void handleRecipeBook(@Nonnull SPacketRecipeBook packetIn) {}
@Override
public void handleBlockBreakAnim(@Nonnull SPacketBlockBreakAnim packetIn) {
super.handleBlockBreakAnim(packetIn);
}
@Override
public void handleSignEditorOpen(@Nonnull SPacketSignEditorOpen packetIn) {}
@Override
public void handleUpdateTileEntity(@Nonnull SPacketUpdateTileEntity packetIn) {}
@Override
public void handleBlockAction(@Nonnull SPacketBlockAction packetIn) {}
@Override
public void handleBlockChange(@Nonnull SPacketBlockChange packetIn) {
super.handleBlockChange(packetIn);
}
@Override
public void handleChat(@Nonnull SPacketChat packetIn) {}
@Override
public void handleTabComplete(@Nonnull SPacketTabComplete packetIn) {}
@Override
public void handleMultiBlockChange(@Nonnull SPacketMultiBlockChange packetIn) {
super.handleMultiBlockChange(packetIn);
}
@Override
public void handleMaps(@Nonnull SPacketMaps packetIn) {}
@Override
public void handleConfirmTransaction(@Nonnull SPacketConfirmTransaction packetIn) {
super.handleConfirmTransaction(packetIn);
}
@Override
public void handleCloseWindow(@Nonnull SPacketCloseWindow packetIn) {
super.handleCloseWindow(packetIn);
}
@Override
public void handleWindowItems(@Nonnull SPacketWindowItems packetIn) {
super.handleWindowItems(packetIn);
}
@Override
public void handleOpenWindow(@Nonnull SPacketOpenWindow packetIn) {}
@Override
public void handleWindowProperty(@Nonnull SPacketWindowProperty packetIn) {
super.handleWindowProperty(packetIn);
}
@Override
public void handleSetSlot(@Nonnull SPacketSetSlot packetIn) {
super.handleSetSlot(packetIn);
}
@Override
public void handleCustomPayload(@Nonnull SPacketCustomPayload packetIn) {}
@Override
public void handleDisconnect(@Nonnull SPacketDisconnect packetIn) {
super.handleDisconnect(packetIn);
}
@Override
public void handleUseBed(@Nonnull SPacketUseBed packetIn) {}
@Override
public void handleEntityStatus(@Nonnull SPacketEntityStatus packetIn) {
super.handleEntityStatus(packetIn);
}
@Override
public void handleEntityAttach(@Nonnull SPacketEntityAttach packetIn) {
super.handleEntityAttach(packetIn);
}
@Override
public void handleSetPassengers(@Nonnull SPacketSetPassengers packetIn) {}
@Override
public void handleExplosion(@Nonnull SPacketExplosion packetIn) {
super.handleExplosion(packetIn);
}
@Override
public void handleChangeGameState(@Nonnull SPacketChangeGameState packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
if (packetIn.getGameState() == 4) {
this.client.player.connection.sendPacket(new CPacketClientStatus(CPacketClientStatus.State.PERFORM_RESPAWN));
} else if (packetIn.getGameState() != 5) {
super.handleChangeGameState(packetIn);
}
}
@Override
public void handleKeepAlive(@Nonnull SPacketKeepAlive packetIn) {
super.handleKeepAlive(packetIn);
}
@Override
public void handleChunkData(@Nonnull SPacketChunkData packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
if (packetIn.isFullChunk()) {
if (!this.world.handlePreChunk(this.player, packetIn.getChunkX(), packetIn.getChunkZ(), true)) {
return;
}
}
super.handleChunkData(packetIn);
}
@Override
public void processChunkUnload(@Nonnull SPacketUnloadChunk packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
if (this.world.handlePreChunk(this.player, packetIn.getX(), packetIn.getZ(), false)) {
super.processChunkUnload(packetIn);
}
}
@Override
public void handleEffect(@Nonnull SPacketEffect packetIn) {}
@Override
public void handleJoinGame(@Nonnull SPacketJoinGame packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
this.playerController = new PlayerControllerMP(this.user.getPlayerContext().minecraft(), this);
this.world = this.user.getManager().getWorldProvider().getWorld(packetIn.getDimension());
((INetHandlerPlayClient) (Object) this).setWorld(this.world);
this.player = new BotPlayer(this.user, this.client, this.world, this, new StatisticsManager(), new RecipeBookClient());
this.user.onWorldLoad(this.world, this.player, this.playerController);
this.player.preparePlayerToSpawn();
this.player.setEntityId(packetIn.getPlayerId());
this.player.dimension = packetIn.getDimension();
this.world.addEntityToWorld(packetIn.getPlayerId(), this.player);
this.playerController.setGameType(packetIn.getGameType());
packetIn.getGameType().configurePlayerCapabilities(this.player.capabilities);
this.client.gameSettings.sendSettingsToServer();
this.networkManager.sendPacket(new CPacketCustomPayload("MC|Brand", new PacketBuffer(Unpooled.buffer()).writeString("vanilla")));
Helper.HELPER.logDirect("Initialized Player and World");
}
@Override
public void handleEntityMovement(@Nonnull SPacketEntity packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
Entity e = packetIn.getEntity(this.world);
if (e instanceof BotPlayer && !e.equals(this.player)) {
return;
}
super.handleEntityMovement(packetIn);
}
@Override
public void handlePlayerPosLook(@Nonnull SPacketPlayerPosLook packetIn) {
super.handlePlayerPosLook(packetIn);
}
@Override
public void handleParticles(@Nonnull SPacketParticles packetIn) {}
@Override
public void handlePlayerAbilities(@Nonnull SPacketPlayerAbilities packetIn) {
super.handlePlayerAbilities(packetIn);
}
@Override
public void handlePlayerListItem(@Nonnull SPacketPlayerListItem packetIn) {
super.handlePlayerListItem(packetIn);
}
@Override
public void handleDestroyEntities(@Nonnull SPacketDestroyEntities packetIn) {
super.handleDestroyEntities(packetIn);
}
@Override
public void handleRemoveEntityEffect(@Nonnull SPacketRemoveEntityEffect packetIn) {
super.handleRemoveEntityEffect(packetIn);
}
@Override
public void handleRespawn(@Nonnull SPacketRespawn packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
if (packetIn.getDimensionID() != this.player.dimension) {
this.world.handleWorldRemove(this.player);
this.world = this.user.getManager().getWorldProvider().getWorld(packetIn.getDimensionID());
((INetHandlerPlayClient) (Object) this).setWorld(this.world);
}
BotPlayer prev = this.player;
this.player = new BotPlayer(this.user, this.client, this.world, this, prev.getStatFileWriter(), prev.getRecipeBook());
this.user.onWorldLoad(this.world, this.player, this.playerController);
// noinspection ConstantConditions
this.player.getDataManager().setEntryValues(prev.getDataManager().getAll());
this.player.preparePlayerToSpawn();
this.player.setEntityId(prev.getEntityId());
this.player.dimension = packetIn.getDimensionID();
this.player.setServerBrand(prev.getServerBrand());
this.world.addEntityToWorld(prev.getEntityId(), this.player);
this.playerController.setGameType(packetIn.getGameType());
}
@Override
public void handleEntityHeadLook(@Nonnull SPacketEntityHeadLook packetIn) {}
@Override
public void handleHeldItemChange(@Nonnull SPacketHeldItemChange packetIn) {
super.handleHeldItemChange(packetIn);
}
@Override
public void handleDisplayObjective(@Nonnull SPacketDisplayObjective packetIn) {}
@Override
public void handleEntityMetadata(@Nonnull SPacketEntityMetadata packetIn) {
super.handleEntityMetadata(packetIn);
}
@Override
public void handleEntityVelocity(@Nonnull SPacketEntityVelocity packetIn) {
super.handleEntityVelocity(packetIn);
}
@Override
public void handleEntityEquipment(@Nonnull SPacketEntityEquipment packetIn) {
super.handleEntityEquipment(packetIn);
}
@Override
public void handleSetExperience(@Nonnull SPacketSetExperience packetIn) {
super.handleSetExperience(packetIn);
}
@Override
public void handleUpdateHealth(@Nonnull SPacketUpdateHealth packetIn) {
super.handleUpdateHealth(packetIn);
}
@Override
public void handleTeams(@Nonnull SPacketTeams packetIn) {}
@Override
public void handleUpdateScore(@Nonnull SPacketUpdateScore packetIn) {}
@Override
public void handleSpawnPosition(@Nonnull SPacketSpawnPosition packetIn) { /* We probably don't need to know this, the server handles everything related to spawn psoition? */ }
@Override
public void handleTimeUpdate(@Nonnull SPacketTimeUpdate packetIn) {
super.handleTimeUpdate(packetIn);
}
@Override
public void handleSoundEffect(@Nonnull SPacketSoundEffect packetIn) {}
@Override
public void handleCustomSound(@Nonnull SPacketCustomSound packetIn) {}
@Override
public void handleCollectItem(@Nonnull SPacketCollectItem packetIn) {
super.handleCollectItem(packetIn);
}
@Override
public void handleEntityTeleport(@Nonnull SPacketEntityTeleport packetIn) {
super.handleEntityTeleport(packetIn);
}
@Override
public void handleEntityProperties(@Nonnull SPacketEntityProperties packetIn) {
super.handleEntityProperties(packetIn);
}
@Override
public void handleEntityEffect(@Nonnull SPacketEntityEffect packetIn) {
super.handleEntityEffect(packetIn);
}
@Override
public void handleCombatEvent(@Nonnull SPacketCombatEvent packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
// We only care if we died
if (packetIn.eventType == SPacketCombatEvent.Event.ENTITY_DIED) {
if (packetIn.playerId == this.player.getEntityId()) {
// Perform an instantaneous respawn
this.networkManager.sendPacket(new CPacketClientStatus(CPacketClientStatus.State.PERFORM_RESPAWN));
user.getBaritone().getGameEventHandler().onPlayerDeath();
}
}
}
@Override
public void handleServerDifficulty(@Nonnull SPacketServerDifficulty packetIn) {}
@Override
public void handleCamera(SPacketCamera packetIn) {}
@Override
public void handleWorldBorder(@Nonnull SPacketWorldBorder packetIn) {
super.handleWorldBorder(packetIn);
}
@Override
public void handleTitle(@Nonnull SPacketTitle packetIn) {}
@Override
public void handlePlayerListHeaderFooter(@Nonnull SPacketPlayerListHeaderFooter packetIn) {}
@Override
public void handleResourcePack(@Nonnull SPacketResourcePackSend packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
// Lie to the server and tell them we accepted it in response
this.networkManager.sendPacket(new CPacketResourcePackStatus(CPacketResourcePackStatus.Action.ACCEPTED));
this.networkManager.sendPacket(new CPacketResourcePackStatus(CPacketResourcePackStatus.Action.SUCCESSFULLY_LOADED));
}
@Override
public void handleUpdateBossInfo(@Nonnull SPacketUpdateBossInfo packetIn) {}
@Override
public void handleCooldown(@Nonnull SPacketCooldown packetIn) {
super.handleCooldown(packetIn);
}
@Override
public void handleMoveVehicle(@Nonnull SPacketMoveVehicle packetIn) {
super.handleMoveVehicle(packetIn);
}
@Override
public void handleAdvancementInfo(@Nonnull SPacketAdvancementInfo packetIn) {
super.handleAdvancementInfo(packetIn);
}
@Override
public void handleSelectAdvancementsTab(@Nonnull SPacketSelectAdvancementsTab packetIn) {
super.handleSelectAdvancementsTab(packetIn);
}
@Override
public void func_194307_a(@Nonnull SPacketPlaceGhostRecipe p_194307_1_) {}
@Override
public void onDisconnect(@Nonnull ITextComponent reason) {
// TODO Maybe more world unloading
this.world.removeEntity(this.player);
this.user.getManager().disconnect(this.user, reason);
}
@Nonnull
@Override
public ClientAdvancementManager getAdvancementManager() {
throw new UnsupportedOperationException("This method shouldn't have been called; That is unepic!");
}
public BotPlayer player() {
return player;
}
public BotWorld world() {
return world;
}
}

View File

@@ -0,0 +1,53 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.bot.impl;
import baritone.api.bot.IBaritoneUser;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiInventory;
import javax.annotation.Nonnull;
/**
* @author Brady
*/
public final class BotGuiInventory extends GuiInventory {
private final IBaritoneUser user;
public BotGuiInventory(IBaritoneUser user) {
super(user.getPlayerContext().player());
this.user = user;
}
@Override
public void setWorldAndResolution(@Nonnull Minecraft primary, int width, int height) {
final Minecraft mc = this.user.getPlayerContext().minecraft();
mc.displayWidth = primary.displayWidth;
mc.displayHeight = primary.displayHeight;
super.setWorldAndResolution(mc, width, height);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
final BotPlayer player = (BotPlayer) this.user.getPlayerContext().player();
player.isUser = false;
super.drawGuiContainerBackgroundLayer(partialTicks, mouseX, mouseY);
player.isUser = true;
}
}

View File

@@ -0,0 +1,187 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.bot.impl;
import baritone.api.bot.IBaritoneUser;
import baritone.utils.ObjectAllocator;
import baritone.utils.accessor.IGameSettings;
import baritone.utils.accessor.IMinecraft;
import com.google.common.util.concurrent.ListenableFuture;
import com.mojang.authlib.minecraft.MinecraftSessionService;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SoundHandler;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.toasts.GuiToast;
import net.minecraft.client.main.GameConfiguration;
import net.minecraft.client.renderer.RenderItem;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.client.tutorial.Tutorial;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumHandSide;
import net.minecraft.util.Session;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashSet;
import java.util.concurrent.Callable;
/**
* "Implementation" of {@link Minecraft} which gets allocated without receiving a constructor call.
* This allows us to avoid the game's setup process (moreso in versions after 1.12 than 1.12 itself).
*
* @author Brady
* @since 3/3/2020
*/
public final class BotMinecraft extends Minecraft {
private static final Minecraft mc = Minecraft.getMinecraft();
private IBaritoneUser user;
private Tutorial tutorial;
private GuiToast toastGui;
private BotMinecraft(GameConfiguration gameConfig) {
super(gameConfig);
}
@Nullable
@Override
public Entity getRenderViewEntity() {
return mc.getRenderViewEntity();
}
@Nonnull
@Override
public Session getSession() {
return this.user.getSession();
}
@Override
public @Nonnull MinecraftSessionService getSessionService() {
return mc.getSessionService();
}
@Override
public <V> @Nonnull ListenableFuture<V> addScheduledTask(@Nonnull Callable<V> callableToSchedule) {
return mc.addScheduledTask(callableToSchedule);
}
@Override
public boolean isCallingFromMinecraftThread() {
return mc.isCallingFromMinecraftThread();
}
@Nonnull
@Override
public Tutorial getTutorial() {
return this.tutorial;
}
@Nonnull
@Override
public SoundHandler getSoundHandler() {
return BotSoundHandler.INSTANCE;
}
@Nonnull
@Override
public GuiToast getToastGui() {
return this.toastGui;
}
@Override
public void displayGuiScreen(@Nullable GuiScreen guiScreenIn) {
// do nothing
if (guiScreenIn == null) {
if (mc.currentScreen instanceof BotGuiInventory) {
mc.displayGuiScreen(null);
}
}
}
@Nonnull
@Override
public TextureManager getTextureManager() {
return mc.getTextureManager();
}
@Nonnull
@Override
public RenderItem getRenderItem() {
return mc.getRenderItem();
}
@Nonnull
@Override
public TextureMap getTextureMapBlocks() {
return mc.getTextureMapBlocks();
}
@Override
public void dispatchKeypresses() {
// Do nothing
}
public static BotMinecraft allocate(IBaritoneUser user) {
BotMinecraft bm = ObjectAllocator.allocate(BotMinecraft.class);
((IMinecraft) (Object) bm).setGameDir(mc.gameDir);
// Gui Compatibility
bm.fontRenderer = mc.fontRenderer;
bm.user = user;
bm.tutorial = new Tutorial(bm);
bm.gameSettings = createGameSettings(bm);
bm.effectRenderer = BotParticleManager.INSTANCE;
bm.toastGui = new GuiToast(bm);
return bm;
}
private static GameSettings createGameSettings(BotMinecraft bm) {
GameSettings settings = ObjectAllocator.allocate(GameSettings.class);
// Settings that get accessed on entity tick
settings.keyBindSprint = ObjectAllocator.allocate(KeyBinding.class);
settings.autoJump = false;
// Settings that are sent to the server
settings.language = "en_us";
settings.renderDistanceChunks = 8;
settings.chatVisibility = EntityPlayer.EnumChatVisibility.FULL;
settings.chatColours = true;
settings.mainHand = EnumHandSide.RIGHT;
// Gui Compatibility
settings.keyBindPickBlock = mc.gameSettings.keyBindPickBlock;
settings.keyBindsHotbar = mc.gameSettings.keyBindsHotbar;
settings.keyBindInventory = mc.gameSettings.keyBindInventory;
settings.keyBindDrop = mc.gameSettings.keyBindDrop;
// Private fields that must be initialized
IGameSettings accessor = (IGameSettings) settings;
accessor.setMc(bm);
accessor.setSetModelParts(new HashSet<>());
return settings;
}
}

View File

@@ -15,45 +15,29 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.utils;
package baritone.bot.impl;
import java.util.Objects;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.entity.Entity;
import net.minecraft.util.EnumParticleTypes;
import javax.annotation.Nonnull;
/**
* @author Brady
* @since 3/8/2020
*/
public final class Pair<A, B> {
public final class BotParticleManager extends ParticleManager {
private final A a;
private final B b;
public static final BotParticleManager INSTANCE = new BotParticleManager();
public Pair(A a, B b) {
this.a = a;
this.b = b;
}
public A first() {
return this.a;
}
public B second() {
return this.b;
private BotParticleManager() {
super(null, null);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || o.getClass() != Pair.class) {
return false;
}
Pair<?, ?> pair = (Pair<?, ?>) o;
return Objects.equals(this.a, pair.a) && Objects.equals(this.b, pair.b);
}
public void emitParticleAtEntity(Entity entityIn, @Nonnull EnumParticleTypes particleTypes) {}
@Override
public int hashCode() {
return 31 * Objects.hashCode(this.a) + Objects.hashCode(this.b);
}
public void emitParticleAtEntity(Entity p_191271_1_, @Nonnull EnumParticleTypes p_191271_2_, int p_191271_3_) {}
}

View File

@@ -0,0 +1,187 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.bot.impl;
import baritone.Baritone;
import baritone.api.bot.IBaritoneUser;
import baritone.utils.PlayerMovementInput;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.client.network.NetworkPlayerInfo;
import net.minecraft.entity.Entity;
import net.minecraft.entity.IMerchant;
import net.minecraft.entity.passive.AbstractHorse;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.stats.RecipeBook;
import net.minecraft.stats.StatisticsManager;
import net.minecraft.tileentity.CommandBlockBaseLogic;
import net.minecraft.tileentity.TileEntityCommandBlock;
import net.minecraft.tileentity.TileEntitySign;
import net.minecraft.tileentity.TileEntityStructure;
import net.minecraft.util.EnumHand;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.GameType;
import net.minecraft.world.IInteractionObject;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
// Some Notes:
// - Inventory handling!
// - If chest deposit gets added it will be most useful for bot-system
/**
* @author Brady
* @since 10/23/2018
*/
@SuppressWarnings("EntityConstructor")
public final class BotPlayer extends EntityPlayerSP {
private final IBaritoneUser user;
private NetworkPlayerInfo playerInfo;
public boolean isUser;
public BotPlayer(IBaritoneUser user, Minecraft mc, World world, NetHandlerPlayClient netHandlerPlayClient, StatisticsManager statisticsManager, RecipeBook recipeBook) {
super(mc, world, netHandlerPlayClient, statisticsManager, recipeBook);
this.user = user;
this.movementInput = new PlayerMovementInput(this.user.getBaritone().getInputOverrideHandler());
this.isUser = true;
}
@Override
public void onUpdate() {
this.entityCollisionReduction = Baritone.settings().botCollision.value ? 0.0F : 1.0F;
super.onUpdate();
}
@Override
public boolean isUser() {
// Used by BotGuiInventory to fix player model rendering in the gui
return this.isUser;
}
@Override
public double getDistanceSq(@Nonnull Entity entityIn) {
if (entityIn == Minecraft.getMinecraft().getRenderViewEntity()) {
// Always render nametag in BotGuiInventory
return 0.0;
} else {
return super.getDistanceSq(entityIn);
}
}
@Override
public void sendStatusMessage(@Nonnull ITextComponent chatComponent, boolean actionBar) {
// TODO: Custom message handling
}
@Override
public void sendMessage(@Nonnull ITextComponent component) {
// TODO: Custom message handling
}
@Override
public void openEditSign(@Nonnull TileEntitySign signTile) {
// TODO: Custom GUI handling
}
@Override
public void displayGuiEditCommandCart(@Nonnull CommandBlockBaseLogic commandBlock) {
// TODO: Custom GUI handling
}
@Override
public void displayGuiCommandBlock(@Nonnull TileEntityCommandBlock commandBlock) {
// TODO: Custom GUI handling
}
@Override
public void openEditStructure(@Nonnull TileEntityStructure structure) {
// TODO: Custom GUI handling
}
@Override
public void openBook(ItemStack stack, EnumHand hand) {
// TODO: Custom GUI handling
}
@Override
public void displayGUIChest(@Nonnull IInventory chestInventory) {
// TODO: Custom GUI handling
}
@Override
public void openGuiHorseInventory(@Nonnull AbstractHorse horse, IInventory inventoryIn) {
// TODO: Custom GUI handling
}
@Override
public void displayGui(IInteractionObject guiOwner) {
// TODO: Custom GUI handling
}
@Override
public void displayVillagerTradeGui(IMerchant villager) {
// TODO: Custom GUI handling
}
@Override
public void onCriticalHit(@Nonnull Entity entityHit) {
// Don't render
}
@Override
public void onEnchantmentCritical(@Nonnull Entity entityHit) {
// Don't render
}
@Override
protected boolean isCurrentViewEntity() {
return true;
}
@Override
public boolean isSpectator() {
NetworkPlayerInfo networkplayerinfo = this.connection.getPlayerInfo(this.getGameProfile().getId());
// noinspection ConstantConditions
return networkplayerinfo != null && networkplayerinfo.getGameType() == GameType.SPECTATOR;
}
@Override
public boolean isCreative() {
NetworkPlayerInfo networkplayerinfo = this.connection.getPlayerInfo(this.getGameProfile().getId());
// noinspection ConstantConditions
return networkplayerinfo != null && networkplayerinfo.getGameType() == GameType.CREATIVE;
}
@Nullable
@Override
protected NetworkPlayerInfo getPlayerInfo() {
return this.playerInfo == null ? (this.playerInfo = this.connection.getPlayerInfo(this.getUniqueID())) : null;
}
@Override
public boolean isAutoJumpEnabled() {
return false;
}
}

View File

@@ -0,0 +1,39 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.bot.impl;
import net.minecraft.client.audio.ISound;
import net.minecraft.client.audio.SoundHandler;
import javax.annotation.Nonnull;
/**
* @author Brady
* @since 3/7/2020
*/
public final class BotSoundHandler extends SoundHandler {
public static final BotSoundHandler INSTANCE = new BotSoundHandler();
private BotSoundHandler() {
super(null, null);
}
@Override
public void playSound(@Nonnull ISound sound) {}
}

View File

@@ -0,0 +1,106 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.bot.impl;
import it.unimi.dsi.fastutil.ints.*;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.entity.Entity;
import net.minecraft.profiler.Profiler;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.WorldSettings;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
/**
* @author Brady
* @since 11/7/2018
*/
public final class BotWorld extends WorldClient {
private static Profiler BOT_WORLD_PROFILER = new Profiler();
private final Map<ChunkPos, IntSet> loadedChunksMap;
public BotWorld(WorldSettings settings, int dimension) {
super(null, settings, dimension, EnumDifficulty.EASY, BOT_WORLD_PROFILER);
this.loadedChunksMap = new HashMap<>();
}
@Override
public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) {
// Do nothing
}
@Override
public void addEntityToWorld(int entityID, Entity entity) {
this.removeEntityFromWorld(entityID);
this.spawnEntity(entity);
this.entitiesById.addKey(entityID, entity);
}
@Override
public Entity removeEntityFromWorld(int entityID) {
Entity entity = this.entitiesById.lookup(entityID);
if (entity != null && !(entity instanceof BotPlayer)) {
this.removeEntity(entity);
this.entitiesById.removeObject(entityID);
}
return entity;
}
@Nullable
@Override
public Entity getEntityByID(int id) {
return this.entitiesById.lookup(id);
}
/**
* @param bot The bot requesting the chunk
* @param chunkX The chunk X position
* @param chunkZ The chunk Z position
* @param load {@code true} if the chunk is being loaded, {@code false} if the chunk is being unloaded.
* @return Whether or not the chunk needs to be loaded or unloaded accordingly.
*/
public boolean handlePreChunk(BotPlayer bot, int chunkX, int chunkZ, boolean load) {
IntSet bots = this.loadedChunksMap.computeIfAbsent(new ChunkPos(chunkX, chunkZ), $ -> new IntArraySet());
if (load) {
boolean wasEmpty = bots.isEmpty();
bots.add(bot.getEntityId());
return wasEmpty;
} else {
bots.remove(bot.getEntityId());
return bots.isEmpty();
}
}
public void handleWorldRemove(BotPlayer bot) {
// Remove Bot from world
this.removeEntity(bot);
this.entitiesById.removeObject(bot.getEntityId());
// Unload all chunks that are no longer loaded by the removed Bot
this.loadedChunksMap.entrySet().stream()
.peek(entry -> entry.getValue().remove(bot.getEntityId()))
.filter(entry -> entry.getValue().isEmpty())
.forEach(entry -> this.doPreChunk(entry.getKey().x, entry.getKey().z, false));
}
}

View File

@@ -307,9 +307,6 @@ public final class CachedWorld implements ICachedWorld, Helper {
try {
ChunkPos pos = toPackQueue.take();
Chunk chunk = toPackMap.remove(pos);
if (toPackQueue.size() > Baritone.settings().chunkPackerQueueMaxSize.value) {
continue;
}
CachedChunk cached = ChunkPacker.pack(chunk);
CachedWorld.this.updateCachedChunk(cached);
//System.out.println("Processed chunk at " + chunk.x + "," + chunk.z);

View File

@@ -18,6 +18,7 @@
package baritone.cache;
import baritone.Baritone;
import baritone.api.BaritoneAPI;
import baritone.api.cache.IWorldProvider;
import baritone.api.utils.IPlayerContext;
import baritone.utils.accessor.IAnvilChunkLoader;
@@ -160,6 +161,10 @@ public class WorldProvider implements IWorldProvider {
readmeDir = baritone.getDirectory();
}
if (this.baritone != BaritoneAPI.getProvider().getPrimaryBaritone()) {
worldDir = worldDir.resolve("bot");
}
return Optional.of(new Tuple<>(worldDir, readmeDir));
}

View File

@@ -0,0 +1,168 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.command.defaults;
import baritone.Baritone;
import baritone.api.IBaritone;
import baritone.api.bot.IBaritoneUser;
import baritone.api.bot.connect.IConnectionResult;
import baritone.api.command.Command;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.command.exception.CommandException;
import baritone.api.command.exception.CommandInvalidTypeException;
import baritone.api.event.events.ChatEvent;
import baritone.bot.UserManager;
import baritone.bot.impl.BotGuiInventory;
import net.minecraft.util.Session;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX;
/**
* @author Brady
* @since 3/2/2020
*/
public class BotCommand extends Command {
public BotCommand(IBaritone baritone) {
super(baritone, "bot");
}
@Override
public void execute(String label, IArgConsumer args) throws CommandException {
final Action action = Action.getByName(args.getString());
if (action == null) {
throw new CommandInvalidTypeException(args.consumed(), "an action");
}
if (action == Action.ADD) {
final String username = args.hasAny() ? args.getString() : "Bot" + System.currentTimeMillis() % 1000;
final Session session = new Session(username, UUID.randomUUID().toString(), "", "");
final IConnectionResult result = UserManager.INSTANCE.connect(session);
logDirect(result.toString());
} else if (action.requiresBotSelector()) {
final String selector = args.getString();
final List<IBaritoneUser> bots;
if (selector.equals("*")) {
bots = UserManager.INSTANCE.getUsers();
} else if (selector.contains(",")) {
bots = Arrays.stream(selector.split(","))
.map(UserManager.INSTANCE::getUserByName)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
} else {
bots = UserManager.INSTANCE.getUserByName(selector)
.map(Collections::singletonList)
.orElseGet(Collections::emptyList);
}
if (bots.isEmpty()) {
throw new CommandInvalidTypeException(args.consumed(), "selector didn't match any bots");
}
if (action == Action.INVENTORY) {
// Only display one inventory lol
final IBaritoneUser bot = bots.get(0);
((Baritone) baritone).showScreen(new BotGuiInventory(bot));
return;
}
switch (action) {
case DISCONNECT: {
bots.forEach(bot -> UserManager.INSTANCE.disconnect(bot, null));
break;
}
case SAY: {
final String message = args.rawRest();
bots.forEach(bot -> bot.getPlayerContext().player().sendChatMessage(message));
break;
}
case EXECUTE: {
final String command = FORCE_COMMAND_PREFIX + args.rawRest();
bots.forEach(bot -> bot.getBaritone().getGameEventHandler().onSendChatMessage(new ChatEvent(command)));
break;
}
}
}
}
@Override
public Stream<String> tabComplete(String label, IArgConsumer args) {
return Stream.empty();
}
@Override
public String getShortDesc() {
return "Manage bots";
}
@Override
public List<String> getLongDesc() {
return Arrays.asList(
"Spawns a bot",
"",
"Usage:",
"> bot add/a <name>",
"> bot inventory/i [bot]",
"> bot disconnect/d [bot]",
"> bot say/s [bot] [args...]",
"> bot execute/e [bot] [args...]"
);
}
private enum Action {
ADD("add", "a"),
INVENTORY("inventory", "i"),
DISCONNECT("disconnect", "d"),
SAY("say", "s"),
EXECUTE("execute", "e");
private final String[] names;
Action(String... names) {
this.names = names;
}
public boolean requiresBotSelector() {
return this == INVENTORY || this == DISCONNECT || this == SAY || this == EXECUTE;
}
public static Action getByName(String name) {
for (Action action : Action.values()) {
for (String alias : action.names) {
if (alias.equalsIgnoreCase(name)) {
return action;
}
}
}
return null;
}
public static String[] getAllNames() {
Set<String> names = new HashSet<>();
for (Action action : Action.values()) {
names.addAll(Arrays.asList(action.names));
}
return names.toArray(new String[0]);
}
}
}

View File

@@ -46,6 +46,7 @@ public final class DefaultCommands {
new LitematicaCommand(baritone),
new ComeCommand(baritone),
new AxisCommand(baritone),
new BotCommand(baritone),
new ForceCancelCommand(baritone),
new GcCommand(baritone),
new InvertCommand(baritone),

View File

@@ -93,7 +93,7 @@ public class CalculationContext {
this.world = baritone.getPlayerContext().world();
this.worldData = (WorldData) baritone.getPlayerContext().worldData();
this.bsi = new BlockStateInterface(baritone.getPlayerContext(), forUseOnAnotherThread);
this.toolSet = new ToolSet(baritone.getPlayerContext());
this.toolSet = new ToolSet(player);
this.hasThrowaway = Baritone.settings().allowPlace.value && ((Baritone) baritone).getInventoryBehavior().hasGenericThrowaway();
this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.value && InventoryPlayer.isHotbar(player.inventory.getSlotFor(STACK_BUCKET_WATER)) && !world.provider.isNether();
this.canSprint = Baritone.settings().allowSprint.value && player.getFoodStats().getFoodLevel() > 6;

View File

@@ -18,12 +18,12 @@
package baritone.pathing.movement;
import baritone.Baritone;
import baritone.api.BaritoneAPI;
import baritone.api.IBaritone;
import baritone.api.pathing.movement.ActionCosts;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.*;
import baritone.api.utils.input.Input;
import baritone.behavior.InventoryBehavior;
import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.pathing.precompute.Ternary;
import baritone.utils.BlockStateInterface;
@@ -577,17 +577,23 @@ public interface MovementHelper extends ActionCosts, Helper {
/**
* AutoTool for a specific block
*
* @param ctx The player context
* @param state The blockstate to mine
* @param ctx The player context
* @param b the blockstate to mine
*/
static void switchToBestToolFor(IPlayerContext ctx, IBlockState state) {
if (ToolSet.isAutoTool()) {
// TODO: Submit through InventoryBehavior, instead of executing the strategy here
final InventorySlot slot = new ToolSet(ctx).getBestSlot(state, Baritone.settings().preferSilkTouch.value, null);
final InventoryBehavior.SelectionStrategy strategy = ((Baritone) ctx.baritone()).getInventoryBehavior().resolveSelectionStrategy(slot);
if (strategy != null) {
strategy.run();
}
static void switchToBestToolFor(IPlayerContext ctx, IBlockState b) {
switchToBestToolFor(ctx, b, new ToolSet(ctx.player()), BaritoneAPI.getSettings().preferSilkTouch.value);
}
/**
* AutoTool for a specific block with precomputed ToolSet data
*
* @param ctx The player context
* @param b the blockstate to mine
* @param ts previously calculated ToolSet
*/
static void switchToBestToolFor(IPlayerContext ctx, IBlockState b, ToolSet ts, boolean preferSilkTouch) {
if (Baritone.settings().autoTool.value && !Baritone.settings().assumeExternalAutoTool.value) {
ctx.player().inventory.currentItem = ts.getBestSlot(b.getBlock(), preferSilkTouch);
}
}

View File

@@ -542,7 +542,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
}
if (baritone.getInventoryBehavior().canAccessInventory()) {
if (Baritone.settings().allowInventory.value) {
ArrayList<Integer> usefulSlots = new ArrayList<>();
List<IBlockState> noValidHotbarOption = new ArrayList<>();
outer:

View File

@@ -269,7 +269,7 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
for (BlockPos pos : both) {
boolean soulsand = openSoulsand.contains(pos);
Optional<Rotation> rot = RotationUtils.reachableOffset(ctx, pos, new Vec3d(pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5), ctx.playerController().getBlockReachDistance(), false);
if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().trySelectItem(soulsand ? this::isNetherWart : this::isPlantable)) {
if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, soulsand ? this::isNetherWart : this::isPlantable)) {
RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), ctx.playerController().getBlockReachDistance());
if (result.typeOfHit == RayTraceResult.Type.BLOCK && result.sideHit == EnumFacing.UP) {
baritone.getLookBehavior().updateTarget(rot.get(), true);
@@ -287,7 +287,7 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
}
Vec3d faceCenter = new Vec3d(pos).add(0.5, 0.5, 0.5).add(new Vec3d(dir.getDirectionVec()).scale(0.5));
Optional<Rotation> rot = RotationUtils.reachableOffset(ctx, pos, faceCenter, ctx.playerController().getBlockReachDistance(), false);
if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().trySelectItem(this::isCocoa)) {
if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, this::isCocoa)) {
RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), ctx.playerController().getBlockReachDistance());
if (result.typeOfHit == RayTraceResult.Type.BLOCK && result.sideHit == dir) {
baritone.getLookBehavior().updateTarget(rot.get(), true);
@@ -301,7 +301,7 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
}
for (BlockPos pos : bonemealable) {
Optional<Rotation> rot = RotationUtils.reachable(ctx, pos);
if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().trySelectItem(this::isBoneMeal)) {
if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, this::isBoneMeal)) {
baritone.getLookBehavior().updateTarget(rot.get(), true);
if (ctx.isLookingAt(pos)) {
baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true);
@@ -323,17 +323,17 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
for (BlockPos pos : toBreak) {
goalz.add(new BuilderProcess.GoalBreak(pos));
}
if (baritone.getInventoryBehavior().canSelectItem(this::isPlantable)) {
if (baritone.getInventoryBehavior().throwaway(false, this::isPlantable)) {
for (BlockPos pos : openFarmland) {
goalz.add(new GoalBlock(pos.up()));
}
}
if (baritone.getInventoryBehavior().canSelectItem(this::isNetherWart)) {
if (baritone.getInventoryBehavior().throwaway(false, this::isNetherWart)) {
for (BlockPos pos : openSoulsand) {
goalz.add(new GoalBlock(pos.up()));
}
}
if (baritone.getInventoryBehavior().canSelectItem(this::isCocoa)) {
if (baritone.getInventoryBehavior().throwaway(false, this::isCocoa)) {
for (BlockPos pos : openLog) {
for (EnumFacing direction : EnumFacing.Plane.HORIZONTAL) {
if (ctx.world().getBlockState(pos.offset(direction)).getBlock() instanceof BlockAir) {
@@ -342,7 +342,7 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
}
}
}
if (baritone.getInventoryBehavior().canSelectItem(this::isBoneMeal)) {
if (baritone.getInventoryBehavior().throwaway(false, this::isBoneMeal)) {
for (BlockPos pos : bonemealable) {
goalz.add(new GoalBlock(pos));
}

View File

@@ -1,100 +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 Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils;
import it.unimi.dsi.fastutil.objects.Reference2BooleanMap;
import it.unimi.dsi.fastutil.objects.Reference2BooleanOpenHashMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.lang.reflect.Method;
/**
* @author Brady
*/
public final class ItemInteractionHelper {
private ItemInteractionHelper() {}
private static final Reference2BooleanMap<Class<? extends Item>> CACHE = new Reference2BooleanOpenHashMap<>();
public static boolean couldInteract(final ItemStack stack) {
if (stack.isEmpty()) {
return false;
}
return CACHE.computeIfAbsent(stack.getItem().getClass(), itemClass -> {
try {
final Method onItemUse = itemClass.getMethod(Helper1.name, Helper1.parameters);
final Method onItemRightClick = itemClass.getMethod(Helper2.name, Helper2.parameters);
// If the declaring class isn't Item, then the method is overridden
return onItemUse.getDeclaringClass() != Item.class
|| onItemRightClick.getDeclaringClass() != Item.class;
} catch (NoSuchMethodException ignored) {
// this shouldn't happen
return true;
}
});
}
private static final class Helper1 extends Item {
public static final String name;
public static final Class<?>[] parameters;
static {
final Method method = Helper1.class.getDeclaredMethods()[0];
name = method.getName();
parameters = method.getParameterTypes();
}
@Nonnull
@Override
public EnumActionResult onItemUse(@Nonnull EntityPlayer player, @Nonnull World worldIn,
@Nonnull BlockPos pos, @Nonnull EnumHand hand,
@Nonnull EnumFacing facing, float hitX, float hitY, float hitZ) {
return super.onItemUse(player, worldIn, pos, hand, facing, hitX, hitY, hitZ);
}
}
private static final class Helper2 extends Item {
public static final String name;
public static final Class<?>[] parameters;
static {
final Method method = Helper2.class.getDeclaredMethods()[0];
name = method.getName();
parameters = method.getParameterTypes();
}
@Nonnull
@Override
public ActionResult<ItemStack> onItemRightClick(@Nonnull World worldIn, @Nonnull EntityPlayer playerIn,
@Nonnull EnumHand handIn) {
return super.onItemRightClick(worldIn, playerIn, handIn);
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
/**
* Hacky util to allocate objects without needing to invoke their constructor.
*
* @author Brady
* @since 3/3/2020
*/
public final class ObjectAllocator {
private static final Unsafe theUnsafe;
static {
try {
Class<?> clazz = Class.forName("sun.misc.Unsafe");
Field field = clazz.getDeclaredField("theUnsafe");
field.setAccessible(true);
theUnsafe = (Unsafe) field.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private ObjectAllocator() {}
public static <T> T allocate(Class<T> clazz) {
try {
// noinspection unchecked
return (T) theUnsafe.allocateInstance(clazz);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -56,7 +56,7 @@ public final class PathRenderer implements IRenderer {
if (ctx.world() == null) {
return;
}
if (ctx.minecraft().currentScreen instanceof GuiClick) {
if (ctx.minecraft().currentScreen instanceof GuiClick && behavior.baritone == BaritoneAPI.getProvider().getPrimaryBaritone()) {
((GuiClick) ctx.minecraft().currentScreen).onRender();
}

View File

@@ -17,14 +17,15 @@
package baritone.utils;
import baritone.api.utils.IInputOverrideHandler;
import baritone.api.utils.input.Input;
import net.minecraft.util.MovementInput;
public class PlayerMovementInput extends MovementInput {
private final InputOverrideHandler handler;
private final IInputOverrideHandler handler;
PlayerMovementInput(InputOverrideHandler handler) {
public PlayerMovementInput(IInputOverrideHandler handler) {
this.handler = handler;
}

View File

@@ -18,78 +18,62 @@
package baritone.utils;
import baritone.Baritone;
import baritone.PerformanceCritical;
import baritone.api.utils.IPlayerContext;
import baritone.api.utils.InventorySlot;
import baritone.utils.accessor.IItemTool;
import it.unimi.dsi.fastutil.HashCommon;
import it.unimi.dsi.fastutil.objects.Reference2DoubleOpenHashMap;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.init.Enchantments;
import net.minecraft.init.MobEffects;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemSword;
import net.minecraft.item.ItemTool;
import java.util.Comparator;
import java.util.function.Predicate;
import java.util.function.ToDoubleFunction;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* A cached list of the best tools on the hotbar for any block
*
* @author Avery, Brady, leijurv
*/
public final class ToolSet {
public class ToolSet {
/**
* A cache mapping a {@link Block} to how long it will take to break
* with this toolset, given the optimum tool is used.
*/
private final Cache breakStrengthCache;
private final Map<Block, Double> breakStrengthCache;
/**
* My buddy leijurv owned me so we have this to not create a new lambda instance.
*/
private final ToDoubleFunction<IBlockState> backendCalculation;
private final Function<Block, Double> backendCalculation;
private final IPlayerContext ctx;
private final EntityPlayerSP player;
public ToolSet(IPlayerContext ctx) {
this.ctx = ctx;
this.breakStrengthCache = new Cache();
public ToolSet(EntityPlayerSP player) {
breakStrengthCache = new HashMap<>();
this.player = player;
if (Baritone.settings().considerPotionEffects.value) {
double amplifier = this.potionAmplifier();
this.backendCalculation = block -> amplifier * this.getBestDestructionSpeed(block);
double amplifier = potionAmplifier();
Function<Double, Double> amplify = x -> amplifier * x;
backendCalculation = amplify.compose(this::getBestDestructionTime);
} else {
this.backendCalculation = this::getBestDestructionSpeed;
backendCalculation = this::getBestDestructionTime;
}
}
/**
* Using the best tool on the hotbar, how fast we can mine this block
*
* @param state the state to be mined
* @param state the blockstate to be mined
* @return the speed of how fast we'll mine it. 1/(time in ticks)
*/
@PerformanceCritical
public double getStrVsBlock(IBlockState state) {
return this.breakStrengthCache.computeIfAbsent(state, this.backendCalculation);
}
/**
* Calculate how effectively a block can be destroyed
*
* @param state the block state to be mined
* @return A double containing the destruction speed with the best tool
*/
private double getBestDestructionSpeed(IBlockState state) {
final ItemStack stack = isAutoTool()
? ctx.inventory().itemAt(this.getBestSlot(state, false, null))
: ctx.player().getHeldItemMainhand();
return calculateSpeedVsBlock(stack, state) * avoidanceMultiplier(state.getBlock());
return breakStrengthCache.computeIfAbsent(state.getBlock(), backendCalculation);
}
/**
@@ -97,55 +81,92 @@ public final class ToolSet {
* harvest level order; there is a chance for multiple at the same with modded tools
* but in that case we don't really care.
*
* @param stack a possibly empty ItemStack
* @return The tool's harvest level, or {@code -1} if the stack isn't a tool
* @param itemStack a possibly empty ItemStack
* @return values from 0 up
*/
private static int getMaterialCost(ItemStack stack) {
if (stack.getItem() instanceof IItemTool) {
return ((IItemTool) stack.getItem()).getHarvestLevel();
private int getMaterialCost(ItemStack itemStack) {
if (itemStack.getItem() instanceof ItemTool) {
ItemTool tool = (ItemTool) itemStack.getItem();
return ((IItemTool) tool).getHarvestLevel();
} else {
return -1;
}
}
public boolean hasSilkTouch(ItemStack stack) {
return EnchantmentHelper.getEnchantmentLevel(Enchantments.SILK_TOUCH, stack) > 0;
}
/**
* Calculate which tool on the hotbar is best for mining, depending on an override setting,
* related to auto tool movement cost, it will either return current selected slot, or the best slot.
*
* @param state the blockstate to be mined
* @param preferSilkTouch whether to prefer silk touch tools
* @param extra An additional filter to apply on top of the default, setting-based ones, may be {@code null}
* @param b the blockstate to be mined
* @return An int containing the index in the tools array that worked best
*/
public InventorySlot getBestSlot(final IBlockState state, final boolean preferSilkTouch,
final Predicate<? super ItemStack> extra) {
final Comparator<ItemStack> compare = Comparator
// Prioritize mining speed over everything
.<ItemStack>comparingDouble(stack -> calculateSpeedVsBlock(stack, state))
// Prioritize silk touch tools, if preferSilkTouch is true, over reduced material cost
.thenComparing(ToolSet::hasSilkTouch, (a, b) -> preferSilkTouch ? Boolean.compare(a, b) : 0)
// Minimize material cost
.thenComparing(Comparator.comparingInt(ToolSet::getMaterialCost).reversed());
return ((Baritone) ctx.baritone()).getInventoryBehavior().findBestAccessibleMatching(
compare,
stack -> {
if (!Baritone.settings().useSwordToMine.value && stack.getItem() instanceof ItemSword) {
return false;
}
if (Baritone.settings().itemSaver.value
&& stack.getItemDamage() + Baritone.settings().itemSaverThreshold.value >= stack.getMaxDamage()
&& stack.getMaxDamage() > 1
) {
return false;
}
return extra == null || extra.test(stack);
}
);
public int getBestSlot(Block b, boolean preferSilkTouch) {
return getBestSlot(b, preferSilkTouch, false);
}
public static boolean isAutoTool() {
return Baritone.settings().autoTool.value && !Baritone.settings().assumeExternalAutoTool.value;
public int getBestSlot(Block b, boolean preferSilkTouch, boolean pathingCalculation) {
/*
If we actually want know what efficiency our held item has instead of the best one
possible, this lets us make pathing depend on the actual tool to be used (if auto tool is disabled)
*/
if (!Baritone.settings().autoTool.value && pathingCalculation) {
return player.inventory.currentItem;
}
int best = 0;
double highestSpeed = Double.NEGATIVE_INFINITY;
int lowestCost = Integer.MIN_VALUE;
boolean bestSilkTouch = false;
IBlockState blockState = b.getDefaultState();
for (int i = 0; i < 9; i++) {
ItemStack itemStack = player.inventory.getStackInSlot(i);
if (!Baritone.settings().useSwordToMine.value && itemStack.getItem() instanceof ItemSword) {
continue;
}
if (Baritone.settings().itemSaver.value && (itemStack.getItemDamage() + Baritone.settings().itemSaverThreshold.value) >= itemStack.getMaxDamage() && itemStack.getMaxDamage() > 1) {
continue;
}
double speed = calculateSpeedVsBlock(itemStack, blockState);
boolean silkTouch = hasSilkTouch(itemStack);
if (speed > highestSpeed) {
highestSpeed = speed;
best = i;
lowestCost = getMaterialCost(itemStack);
bestSilkTouch = silkTouch;
} else if (speed == highestSpeed) {
int cost = getMaterialCost(itemStack);
if ((cost < lowestCost && (silkTouch || !bestSilkTouch)) ||
(preferSilkTouch && !bestSilkTouch && silkTouch)) {
highestSpeed = speed;
best = i;
lowestCost = cost;
bestSilkTouch = silkTouch;
}
}
}
return best;
}
/**
* Calculate how effectively a block can be destroyed
*
* @param b the blockstate to be mined
* @return A double containing the destruction ticks with the best tool
*/
private double getBestDestructionTime(Block b) {
ItemStack stack = player.inventory.getStackInSlot(getBestSlot(b, false, true));
return calculateSpeedVsBlock(stack, b.getDefaultState()) * avoidanceMultiplier(b);
}
private double avoidanceMultiplier(Block b) {
return Baritone.settings().blocksToAvoidBreaking.value.contains(b) ? Baritone.settings().avoidBreakingMultiplier.value : 1;
}
/**
@@ -154,19 +175,10 @@ public final class ToolSet {
*
* @param item the item to mine it with
* @param state the blockstate to be mined
* @return the speed of how fast we'll mine it. 1/(time in ticks)
* @return how long it would take in ticks
*/
public static double calculateSpeedVsBlock(ItemStack item, IBlockState state) {
float hardness;
try {
// noinspection DataFlowIssue
hardness = state.getBlockHardness(null, null);
} catch (NullPointerException ignored) {
// Just catch the exception and act as if the block is unbreakable. Even in situations where we could
// reasonably determine the hardness by passing the correct world/position (not via 'getStrVsBlock' during
// performance critical cost calculation), it's not worth it for the sake of consistency.
return -1;
}
float hardness = state.getBlockHardness(null, null);
if (hardness < 0) {
return -1;
}
@@ -187,15 +199,6 @@ public final class ToolSet {
}
}
private static double avoidanceMultiplier(Block block) {
return Baritone.settings().blocksToAvoidBreaking.value.contains(block)
? Baritone.settings().avoidBreakingMultiplier.value : 1;
}
private static boolean hasSilkTouch(ItemStack stack) {
return EnchantmentHelper.getEnchantmentLevel(Enchantments.SILK_TOUCH, stack) > 0;
}
/**
* Calculates any modifier to breaking time based on status effects.
*
@@ -203,11 +206,11 @@ public final class ToolSet {
*/
private double potionAmplifier() {
double speed = 1;
if (ctx.player().isPotionActive(MobEffects.HASTE)) {
speed *= 1 + (ctx.player().getActivePotionEffect(MobEffects.HASTE).getAmplifier() + 1) * 0.2;
if (player.isPotionActive(MobEffects.HASTE)) {
speed *= 1 + (player.getActivePotionEffect(MobEffects.HASTE).getAmplifier() + 1) * 0.2;
}
if (ctx.player().isPotionActive(MobEffects.MINING_FATIGUE)) {
switch (ctx.player().getActivePotionEffect(MobEffects.MINING_FATIGUE).getAmplifier()) {
if (player.isPotionActive(MobEffects.MINING_FATIGUE)) {
switch (player.getActivePotionEffect(MobEffects.MINING_FATIGUE).getAmplifier()) {
case 0:
speed *= 0.3;
break;
@@ -224,60 +227,4 @@ public final class ToolSet {
}
return speed;
}
/*
* Copyright (C) 2002-2022 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
private static final class Cache extends Reference2DoubleOpenHashMap<IBlockState> {
public double computeIfAbsent(final IBlockState key, final ToDoubleFunction<IBlockState> mappingFunction) {
int pos = this.find(key);
if (pos >= 0) {
return this.value[pos];
} else {
double newValue = mappingFunction.applyAsDouble(key);
this.insert(-pos - 1, key, newValue);
return newValue;
}
}
private int find(final IBlockState k) {
if (((k) == (null))) return containsNullKey ? n : -(n + 1);
Object curr;
final Object[] key = this.key;
int pos;
// The starting point.
if (((curr = key[pos = (HashCommon.mix(System.identityHashCode(k))) & mask]) == (null))) return -(pos + 1);
if (((k) == (curr))) return pos;
// There's always an unused entry.
while (true) {
if (((curr = key[pos = (pos + 1) & mask]) == (null))) return -(pos + 1);
if (((k) == (curr))) return pos;
}
}
private void insert(int pos, IBlockState k, double v) {
if (pos == this.n) {
this.containsNullKey = true;
}
final Object[] key = this.key;
key[pos] = k;
this.value[pos] = v;
if (this.size++ >= this.maxFill) {
this.rehash(HashCommon.arraySize(this.size + 1, this.f));
}
}
}
}

View File

@@ -0,0 +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 Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils.accessor;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EnumPlayerModelParts;
import java.util.Set;
/**
* @author Brady
* @since 3/6/2020
*/
public interface IGameSettings {
void setSetModelParts(Set<EnumPlayerModelParts> setModelParts);
void setMc(Minecraft mc);
}

View File

@@ -0,0 +1,29 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils.accessor;
import net.minecraft.client.multiplayer.ThreadLanServerPing;
/**
* @author Brady
* @since 3/4/2020
*/
public interface IIntegratedServer {
ThreadLanServerPing getLanServerPing();
}

View File

@@ -0,0 +1,28 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils.accessor;
import java.io.File;
/**
* @author Brady
*/
public interface IMinecraft {
void setGameDir(File gameDir);
}

View File

@@ -0,0 +1,29 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils.accessor;
import net.minecraft.client.multiplayer.WorldClient;
/**
* @author Brady
* @since 3/8/2020
*/
public interface INetHandlerPlayClient {
void setWorld(WorldClient world);
}

View File

@@ -0,0 +1,29 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils.accessor;
/**
* @author Brady
* @since 3/4/2020
*/
public interface IThreadLanServerPing {
String getMotd();
String getAddress();
}

View File

@@ -1,73 +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 Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils.player;
import baritone.api.utils.IBaritoneInventory;
import baritone.api.utils.IPlayerContext;
import baritone.api.utils.InventorySlot;
import baritone.api.utils.Pair;
import net.minecraft.item.ItemStack;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* @author Brady
*/
public final class BaritoneInventory implements IBaritoneInventory {
private final IPlayerContext ctx;
public BaritoneInventory(IPlayerContext ctx) {
this.ctx = ctx;
}
@Override
public Stream<Pair<InventorySlot, ItemStack>> allSlots() {
return Stream.concat(this.hotbarSlots(), Stream.concat(Stream.of(this.offhand()), this.inventorySlots()));
}
@Override
public Stream<Pair<InventorySlot, ItemStack>> hotbarSlots() {
return IntStream.range(0, 9).mapToObj(InventorySlot::inventory).map(this::itemSlotPairAt);
}
@Override
public Stream<Pair<InventorySlot, ItemStack>> inventorySlots() {
return IntStream.range(9, 36).mapToObj(InventorySlot::inventory).map(this::itemSlotPairAt);
}
@Override
public Pair<InventorySlot, ItemStack> offhand() {
return new Pair<>(InventorySlot.offhand(), ctx.player().inventory.offHandInventory.get(0));
}
@Override
public Stream<Pair<InventorySlot, ItemStack>> armorSlots() {
return IntStream.range(0, 4).mapToObj(InventorySlot::armor).map(this::itemSlotPairAt);
}
@Override
public ItemStack itemAt(InventorySlot slot) {
return ctx.player().inventoryContainer.getSlot(slot.getSlotId()).getStack();
}
private Pair<InventorySlot, ItemStack> itemSlotPairAt(InventorySlot slot) {
return new Pair<>(slot, this.itemAt(slot));
}
}

View File

@@ -18,7 +18,6 @@
package baritone.utils.player;
import baritone.Baritone;
import baritone.api.IBaritone;
import baritone.api.cache.IWorldData;
import baritone.api.utils.*;
import net.minecraft.client.Minecraft;
@@ -39,18 +38,11 @@ public final class BaritonePlayerContext implements IPlayerContext {
private final Baritone baritone;
private final Minecraft mc;
private final IPlayerController playerController;
private final IBaritoneInventory inventory;
public BaritonePlayerContext(Baritone baritone, Minecraft mc) {
this.baritone = baritone;
this.mc = mc;
this.playerController = new BaritonePlayerController(mc);
this.inventory = new BaritoneInventory(this);
}
@Override
public IBaritone baritone() {
return this.baritone;
}
@Override
@@ -68,11 +60,6 @@ public final class BaritonePlayerContext implements IPlayerContext {
return this.playerController;
}
@Override
public IBaritoneInventory inventory() {
return this.player() == null ? null : this.inventory;
}
@Override
public World world() {
return this.mc.world;

View File

@@ -72,6 +72,11 @@ public final class BaritonePlayerController implements IPlayerController {
return mc.playerController.windowClick(windowId, slotId, mouseButton, type, player);
}
@Override
public void setGameType(GameType type) {
mc.playerController.setGameType(type);
}
@Override
public GameType getGameType() {
return mc.playerController.getCurrentGameType();