# Getting Started ## What is **Actor** **Actor** is an API that allows you to script Player Interactions like Movement, Block Placing, etc. all while ensuring that the behaviour stays compatible with Servers (meaning that **Actor** adheres to limitations on the client side).

Therefore **Actor** is the optimal library to use when you want to write deterministic [TAS](https://en.wikipedia.org/wiki/Tool-assisted_speedrun) tools or other mods where you want the player to behave "like normal", while having full programmatic control. ::: tip New to modding? If you are new to Minecraft modding, follow your loader's basic setup guide first. ::: ## About the Documentation **The Docs** will help you set up **Actor** and write your first simple control script.
This will also be useful if you're looking for a specific feature in the future or don't remember how to do a certain thing.
If you're too lazy to read *everything* you can also skip sections, or paste the link of the docs into the LLM provider of your choice and ask them to summarize the contents. ### What you will do - Add Actor to your dev environment - Attach an Actor to a Player - Automate actions via the **Actor API** ## Supported Environments Actor generally supports every major Mod Loader ([Fabric](https://fabricmc.net/), [Quilt](https://quiltmc.org/), [Forge](https://files.minecraftforge.net/) and [NeoForge](https://neoforged.net/)) and mapping setups. ## Contributing **Actor** is open source, so if you have any trouble or issues using it, feel free to [open an Issue](https://github.com/1TheCrazy/Actor/issues/new) on the [GitHub Page](https://github.com/1TheCrazy/Actor/).
If you have an idea that could improve **Actor** you can at any time [fork the Repo](https://github.com/1TheCrazy/Actor/fork) and submit a pull request.
You may also just [open an Issue](https://github.com/1TheCrazy/Actor/issues/new) and propose a new idea there. ## Sources The Documentation uses [VitePress](https://vitepress.dev/).
The Mod itself uses [this Multiloader Template](https://github.com/jaredlll08/MultiLoader-Template) from [mctemplates.net](https://mctemplates.net). # Installing **Actor** Installing **Actor** is simple and straightforward.
You just have to add **Actor** as a dependency in the module where you write your mod code. ## How to add the Dependency Generally you could download the `.jar` from [Modrinth](https://modrinth.com/mod/actor) and place it in your environment's `mods` folder.
But this is generally not good practice and it's way more elegant to add it as a dependency in your `build.gradle` file.

First you want to look up your version string on [Modrinth](https://modrinth.com/mod/actor).
This string depends on your Minecraft version and the Mod Loader you use.
Such a string may look like this: `Actor-v1.0.0-fabric+mc1.21.11`.
If you found your version string, these next few steps are recommended:

Edit your `gradle.properties` to include this line: ```properties actor_version=YOUR_VERSION_STRING ```

Edit your `build.gradle` to include this: ```properties repositories { // ... Other Repos maven { url = "https://api.modrinth.com/maven" } } dependencies { // ... Other Dependencies modImplementation "maven.modrinth:actor:${actor_version}" // Fabric / Quilt implementation "maven.modrinth:actor:${actor_version}" // Forge / NeoForge } ``` And that's it.
Now you just have to refresh your Gradle Project and you should be able to use **Actor** in your mod.
::: warning If you plan on publishing your mod, you should add **Actor** as a required dependency of your mod.
Adding sub-mods (dependencies) is loader-specific and will not be discussed here.
For that please refer to the docs of the Mod Loader of your choice. ::: # About the API An API is a set of types and methods you call from your own code. **Actor** keeps that surface small on purpose, so you can discover everything quickly without digging through internals.
By design, **Actor** is a pretty heavy abstraction and does not provide customization beyond the methods it exposes. ## What you get **Actor** exposes three main control areas: - [Movement](/develop/v1/using-actor/movement) - [Orientation (Camera look)](/develop/v1/using-actor/orientation) - [Interaction (use or attack)](/develop/v1/using-actor/interaction) Each area is documented with Javadocs in the source.
Scrolling through the methods in your IDE is often the fastest way to understand every available option and discover the methods that you can use.
**Actor** also exposes a [Ticking API](/develop/v1/using-actor/ticking) that can be a very powerful utility. ## Mappings and loaders Actor supports every major loader ([Fabric](https://fabricmc.net/), [Quilt](https://quiltmc.org/), [Forge](https://files.minecraftforge.net/) and [NeoForge](https://neoforged.net/)) and mapping setups.
You might see different class names for the vanilla classes depending on your mappings (e.g., Yarn may use `ClientPlayerEntity` where Mojang Mappings use `LocalPlayer`).
The **Actor API** itself stays the same across loaders. # Attaching to a Player If you want to automate or control a Player, you have to *attach* an **Actor** to that Player. You attach Actor to the local player through `IPlayerActor`. This gives you an `IActor` that exposes movement, orientation, and interaction. You can then use the `IActor` to control the Player. ## The basic flow 1. Get the local Player instance 2. Attach an Actor 3. Grab the control interfaces you need 4. Detach from your Player when you're done ## Attaching ```java var player = Minecraft.getInstance().player; // Make sure player is not null assert player != null; var actor = ((IPlayerActor) player).actor$attach(); ``` Now you have attached an `Actor`.
You should keep track of that **`IActor`** instance, as you will use this to control the Player. :::warning You should NOT attach multiple **Actors** to a single Player.
This will result in an error. ::: ### Check if an **Actor** is attached If you want to find out whether an **Actor** is already attached to a Player (e.g. because you didn't keep track of your **Actor** instance), you can use the following method: ```java var existing = ((IPlayerActor) player).actor$getActor(); if (existing != null) // Reuse old else // Attach new ``` ### Detaching an **Actor** If you're done with your **Actor** you can just detach from the Player. ::: tip When should I detach? Detach when your feature finishes so the player can regain full control. ::: ```java ((IPlayerActor) player).actor$detach(); ``` :::warning Make sure you don't use your **Actor** instance anymore after detaching, as this may result in an error. ::: ### API Entry Points After attaching to a Player and retrieving your **`IActor`** instance, you can use these methods to access their respective APIs: ```java var movement = actor.getMovement(); var orientation = actor.getOrientation(); var interaction = actor.getInteraction(); ``` ## Actor Priorities Priorities are an important concept when using **Actor**.
They decide when to use the **Actor**'s input and when the user's input. ### What priorities exist | Priority | What it means | |:-----:|:------| | `ActorPriority.ACTOR` | The **Actor**'s inputs (the things your program controls) are used at all times.
The user does NOT have ANY control. | | `ActorPriority.USER` | The **User**'s inputs (e.g. keyboard or mouse inputs) when the **Actor** does not currently control these specific inputs. | :::warning You should think about what priority you want to use, as `USER` may result in a non-deterministic and not fully controllable program, whereas `ACTOR` doesn't give the User any freedom. ::: ### How to use Priorities By default `((IPlayerActor) player).actor$attach()` uses `ACTOR` as a priority.
If you want to use `USER` or use custom logic to decide which priority to use, you can attach with a priority like this: ```java var actor = ((IPlayerActor) player).actor$attach(ActorPriority.USER); // OR var actor = ((IPlayerActor) player).actor$attach(ActorPriority.ACTOR); ``` # Attaching to a Player If you want to automate or control a Player, you have to *attach* an **Actor** to that Player. You attach Actor to the local player through `IPlayerActor`. This gives you an `IActor` that exposes movement, orientation, and interaction. You can then use the `IActor` to control the Player. ## The basic flow 1. Get the local Player instance 2. Attach an Actor 3. Grab the control interfaces you need 4. Detach from your Player when you're done ## Attaching ```java var player = Minecraft.getInstance().player; // Make sure player is not null assert player != null; var actor = ((IPlayerActor) player).actor$attach(); ``` Now you have attached an `Actor`.
You should keep track of that **`IActor`** instance, as you will use this to control the Player. :::warning You should NOT attach multiple **Actors** to a single Player.
This will result in an error. ::: ### Check if an **Actor** is attached If you want to find out whether an **Actor** is already attached to a Player (e.g. because you didn't keep track of your **Actor** instance), you can use the following method: ```java var existing = ((IPlayerActor) player).actor$getActor(); if (existing != null) // Reuse old else // Attach new ``` ### Detaching an **Actor** If you're done with your **Actor** you can just detach from the Player. ::: tip When should I detach? Detach when your feature finishes so the player can regain full control. ::: ```java ((IPlayerActor) player).actor$detach(); ``` :::warning Make sure you don't use your **Actor** instance anymore after detaching, as this may result in an error. ::: ### API Entry Points After attaching to a Player and retrieving your **`IActor`** instance, you can use these methods to access their respective APIs: ```java var movement = actor.getMovement(); var orientation = actor.getOrientation(); var interaction = actor.getInteraction(); ``` ## Actor Priorities Priorities are an important concept when using **Actor**.
They decide when to use the **Actor**'s input and when the user's input. ### What priorities exist | Priority | What it means | |:-----:|:------| | `ActorPriority.ACTOR` | The **Actor**'s inputs (the things your program controls) are used at all times.
The user does NOT have ANY control. | | `ActorPriority.USER` | The **User**'s inputs (e.g. keyboard or mouse inputs) when the **Actor** does not currently control these specific inputs. | :::warning You should think about what priority you want to use, as `USER` may result in a non-deterministic and not fully controllable program, whereas `ACTOR` doesn't give the User any freedom. ::: ### How to use Priorities By default `((IPlayerActor) player).actor$attach()` uses `ACTOR` as a priority.
If you want to use `USER` or use custom logic to decide which priority to use, you can attach with a priority like this: ```java var actor = ((IPlayerActor) player).actor$attach(ActorPriority.USER); // OR var actor = ((IPlayerActor) player).actor$attach(ActorPriority.ACTOR); ``` # Interaction API The Interaction API lets you control any interaction. This includes block placing, attacking, etc. If you're here to search for a specific method or just a quick explanation of how something works, you may find it useful to scroll through your IDE tooltips of your `Interaction` instance. This is a good method for discovering all possibilities you have, as Actor also has extensive Javadocs. ## Obtaining the Interaction You can obtain the API surface like this: ```java var interaction = YOUR_ACTOR.getInteraction(); ``` ## Using the Interaction Here is some info on how to use the Interaction API: :::warning Generally, when using the Interaction API and you activate it through a [Command](https://minecraft.wiki/w/Commands), you may want to wait for a single tick before executing your logic, since Minecraft ensures you can't interact after closing a GUI if the interaction started inside the GUI. ::: ### Interacting You can interact (right click) once like this: ```java interaction.interact(); ``` This will make you able to use rockets, place a block, etc.
If you want to interact for a specified amount of ticks or while a boolean supplier returns true, you can use this: ```java // Interact for 20 ticks interaction.interact(20); // OR // Interact while the player is on ground interaction.interact(() -> player.onGround()); ``` :::warning The above methods will make the Player **spam** interact every tick and not hold an interaction.
To **hold** an interaction you must use different methods. ::: You can hold interact (right click) like this: ```java // Hold interact for 20 ticks interaction.holdInteract(20); // OR // Hold interact while the player is on ground interaction.holdInteract(() -> player.onGround()); ``` This will make you block with a shield, eat food, load a bow, etc. ### Attacking You can attack (left click) once like this: ```java interaction.attack(); ``` This will make the Player destroy a block (if the block is minable in 1 tick), etc.
If you want to attack for a specified amount of ticks or while a boolean supplier returns true, you can use this: ```java // Attack for 20 ticks interaction.attack(20); // OR // Attack while the player is in creative mode interaction.attack(() -> player.isCreative()); ``` :::warning The above methods will make the Player **spam** attack every tick and not hold attack.
To **hold** an attack you must use different methods. ::: You can hold attack (left click) like this: ```java // Hold attack for 20 ticks interaction.holdAttack(20); // OR // Hold attack while the player is in creative mode interaction.holdAttack(() -> player.isCreative()); ``` This will make the Player destroy blocks that take longer than 1 tick to mine, etc. ### Persistent flags You also have the option to set an interaction flag once and make every tick after that subject to that flag. These flags stay active until you change them. ```java interaction.setInteracting(true); interaction.setAttacking(true); // AND interaction.setHoldingInteract(true); interaction.setHoldingAttack(true); ``` The `boolean` you pass is just whether the flag should be `true` or `false` (e.g. attacking or not attacking). # Movement API The Movement API is there to make the Player move. You have full control over the Player, yet you can only move the Player like a normal Client could.
Therefore this library does **NOT** enable you to code (e.g.) any flight cheats or similar.
Every action is subject to normal Client behaviour.

If you're here to search for a specific method or just a quick explanation of how something works, you may find it useful to scroll through your **IDE** tooltips of your `IMovement` instance. This is a good method for discovering all possibilities you have, as **Actor** also has extensive Javadocs. ## Obtaining the Movement You can obtain the API surface like this: ```java var movement = YOUR_ACTOR.getMovement(); ``` ## Using the Movement Here is some info on how to use the Movement API: ### Move directions When executing any *walk* action, you have to pass an `EnumSet` of directions to walk to. ```java movement.walk(EnumSet.of(MoveDirection.RELATIVE_FRONT)); ``` :::tip Move directions are labeled as relative. That means that a Player can only move *relative* to that player's rotation.
E.g. if the player is looking in ANY direction, `MoveDirection.RELATIVE_FRONT` will move the Player forward relative to that "looking direction" and not in a fixed direction of `SOUTH`, `NORTH`, ... . ::: You can combine directions like this: ```java movement.walk(EnumSet.of(MoveDirection.RELATIVE_FRONT, MoveDirection.RELATIVE_LEFT)); ``` This will make the Player strafe to the front left relative to where the Player is looking.
:::warning Opposing `MoveDirection`s will cancel.
E.g. `movement.walk(EnumSet.of(MoveDirection.RELATIVE_FRONT, MoveDirection.RELATIVE_BACK));` will result in no movement on the front-back-axis. ::: ### Duration options The above examples will only walk the Player for a single tick.
To give you, the programmer, more flexibility most movement actions have three overloads: 1. Once (single tick) 2. For a number of ticks 3. While a `BooleanSupplier` returns true ```java // Walk for 20 ticks movement.walk(EnumSet.of(MoveDirection.RELATIVE_FRONT), 20); // Walk while the Player is in water movement.walk(EnumSet.of(MoveDirection.RELATIVE_FRONT), () -> player.isInWater()); ``` ::: tip Indefinite actions If you want your action to move indefinitely, you can do the following: Pass `-1` as the number of ticks to keep an action running until you change it. ```java // Walk forever movement.walk(EnumSet.of(MoveDirection.RELATIVE_FRONT), -1); ``` ::: ### Movement States Besides walking, you also control movement flags such as whether the Player is sprinting, jumping or sneaking.
These generally default to `false`.
You can control these in the same way you can control walking: ```java // Jump while the player is on the ground movement.jump(() -> player.onGround()); // Sneak for 50 ticks movement.sneak(50); // Sprint for a single tick movement.sprint(); ``` Here's a quick list of methods you can use to control a player's movement: ```java // walk void walk(EnumSet dirs); void walk(EnumSet dirs, int ticks); void walk(EnumSet dirs, BooleanSupplier active); // sprint void sprint(); void sprint(int ticks); void sprint(BooleanSupplier active); // sneak void sneak(); void sneak(int ticks); void sneak(BooleanSupplier active); // jump void jump(); void jump(int ticks); void jump(BooleanSupplier active); ``` ### Persistent movement flags You also have the option to set a movement flag once and make every movement action after that subject to that flag.
These flags stay active until you change them. ```java // Player is now always sprinting movement.setSprinting(true); // Sprint for 20 ticks movement.walk(EnumSet.of(MoveDirection.RELATIVE_FRONT), 20); ``` The same applies to sneaking and jumping: ```java movement.setJumping(true); movement.setSneaking(true); movement.setSprinting(true); ``` The `boolean` you pass is just whether the flag should be `true` or `false` (e.g. jumping or not jumping). # Orientation API The Orientation API enables you to control the player's rotation.

If you're here to search for a specific method or just a quick explanation of how something works, you may find it useful to scroll through your IDE tooltips of your `IOrientation` instance. This is a good method for discovering all possibilities you have, as Actor also has extensive Javadocs. :::info Orientation (rotation) is only set every ClientTick. Yet the player can rotate in sub-ticks using their mouse.
This may result in a blocky/snappy feel when setting or supplying rotation, but this is completely normal and the game does not care. ::: ## Obtaining the Orientation You can obtain the API surface like this: ```java var orientation = YOUR_ACTOR.getOrientation(); ``` ### Using the Orientation Here is some info on how to use the Orientation API: ### Setting rotation ```java // (yaw, pitch) orientation.setRotation(90.0f, 0.0f); // OR orientation.setYaw(90.0f); orientation.setPitch(0.0f); ``` :::tip Yaw is looking left/right and pitch is looking up/down.
Pitch is expected to be between -90 and 90. ::: ### Adding rotation Instead of setting rotation directly, you can add it to the current player's rotation. ```java orientation.addRotation(15.0f, -10.0f); // OR orientation.addYaw(15.0f); orientation.addPitch(-10.0f); ``` ### Supply rotation You can also supply a player's rotation. This means passing a `Supplier` which should return the rotation (or yaw/pitch) the player should have.
These suppliers are queried every ClientTick. ```java AtomicInteger ticks = new AtomicInteger(); // Turn right and look up/down in a *sin* pattern orientation.supplyRotation( () -> ticks.getAndIncrement() * 5f, // Yaw () -> (float) (Math.sin(ticks.get()*0.05f) * 40f) // Pitch ); ``` You can also supply both rotations separately: ```java orientation.supplyYaw(() -> 180.0f); orientation.supplyPitch(() -> 0.0f); ``` # Ticking API If you're working with tick-based automations (e.g. walk for a certain number of ticks, ...), **Actor** has a comprehensive API built around `ClientTick`s.
If you're unfamiliar with Minecraft Ticks, see [the Minecraft Wiki](https://minecraft.wiki/w/Tick). ## ClientTickBus **Actor** provides a `ClientTickBus` in order to deliver ticks to internal implementations, but also to you, the user. ### Adding Tick Listeners For various reasons, you may want to execute code every `ClientTick` (20 times per second).
For that, you can either use the `TickEvent` of the Mod Loader of your choice, or use the functionality **Actor** delivers out of the box.
To add a tick listener, you can do the following: ```java var tickProvider = ClientTickBus.getInstance(); Runnable LOG = () -> MY_LOGGER.info("Hello from a ClientTick"); tickProvider.onTick(LOG); ``` In the `onTick()` method, you can provide any `Runnable` (or function reference) you'd like to execute on each `ClientTick`.
You can also remove a listener if you decide it's not useful anymore: ```java tickProvider.removeTick(LOG); ``` For that you just need to pass a reference to the original `Runnable` you submitted. ::: warning It is NOT recommended to implement `IClientTickBus` yourself, **Actor** takes care of that.
You should only ever use `ClientTickBus.getInstance()` ::: ## WaitableTask Another really useful feature of **Actor** is `WaitableTask`s.
These represent tasks that are executed every `ClientTick` but are capable of being suspended for a specified amount of ticks.
This leads to easier handling of tick-based automations. ```java private static void jump(IWaitableTask instance){ var actor = YOUR_ACTOR; var mov = actor.getMovement(); mov.setJumping(true); instance.WaitForTicks(20); // Jump for 20 ticks mov.setJumping(false); } // Any Method you call when initializing your Actor private void init(){ ClientTickBus.getInstance().submitWaitable(WaitableTask.create(YourClass::jump)); } ``` This is especially useful when you need a lot of changing states that are based on ticks that pass.
Just be careful to make sure your method that uses `WaitForTicks()` always takes **exactly** one argument, an `IWaitableTask`, otherwise you won't be able to use this feature.
You may also use a `Consumer` or declare the function inline: ```java Consumer jump = (instance) -> { mov.setJumping(true); instance.WaitForTicks(20); // Jump for 20 ticks mov.setJumping(false); }; ClientTickBus.getInstance().submitWaitable(new WaitableTask(jump)); // OR ClientTickBus.getInstance().submitWaitable(new WaitableTask(instance -> { mov.setJumping(true); instance.WaitForTicks(20); // Jump for 20 ticks mov.setJumping(false); })); ``` ::: warning Do NOT try to obtain a `WaitableTask` instance in any other way, as this may break things.
It is designed to be used like in the examples provided.
STRICTLY use either `new WaitableTask(Consumer action)` or `WaitableTask.create(Consumer action)` :::