# 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)`
:::