# OOP Utilities

> Overview of object-oriented gameplay utilities in the Kore OOP module - entities, teams, scoreboards, items, events, timers, spawners, and state machines.

Updated 2026-10-21. Canonical: https://kore.ayfri.com/docs/oop/oop-utilities

The OOP module provides high-level, object-oriented wrappers around Minecraft systems such as entities, teams,
scoreboards, timers, and gameplay state.
Each feature is documented on its own page - see the links below.

## Install this module

Add the `oop` artifact when you want object-oriented gameplay abstractions on top of the core Kore DSL.

```kotlin
dependencies {
  implementation("io.github.ayfri.kore:oop:2.28.0-26.3")
}
```

Generated resource names for OOP-specific features are centralized in `OopConstants` so they're easy to find and
override.
Helper-specific generated names now live in `HelpersConstants` inside the `helpers` module.

Utility-style features such as renderers, math helpers, raycasts, areas, state delegates, and VFX now live in the
[`helpers` module](https://kore.ayfri.com/docs/helpers/utilities.md).

## All Features

- **[Boss Bars](https://kore.ayfri.com/docs/oop/boss-bars.md)** - Register, configure, and manage boss bars.
- **[Cooldowns](https://kore.ayfri.com/docs/oop/cooldowns.md)** - Scoreboard-based cooldown system that decrements
  every [tick](https://kore.ayfri.com/docs/concepts/time.md).
- **[Dynamic Strings](https://kore.ayfri.com/docs/oop/dynamic-strings.md)** - NBT-backed string handles with a Kotlin-like API (substring, split, replace, trim, pad).
- **[Entities & Players](https://kore.ayfri.com/docs/oop/entities-and-players.md)** - Create entities and players, execute helpers, batch
  commands, entity commands, and entity effects.
- **[Events](https://kore.ayfri.com/docs/oop/events.md)** - Advancement-based event system for player and entity actions.
- **[Game State Machine](https://kore.ayfri.com/docs/oop/game-state-machine.md)** - Scoreboard-based state machine with transition helpers.
- **[Items](https://kore.ayfri.com/docs/oop/items.md)** - Object-oriented item creation and spawning.
- **[Scoreboards](https://kore.ayfri.com/docs/oop/scoreboards.md)** - Objective management and per-entity score operations.
- **[Spawners](https://kore.ayfri.com/docs/oop/spawners.md)** - Reusable entity spawner handles for summoning mobs.
- **[Teams](https://kore.ayfri.com/docs/oop/teams.md)** - Object-oriented team management with colors, collision rules, and nametag visibility.
- **[Timers](https://kore.ayfri.com/docs/oop/timers.md)** - Scoreboard-based timers with optional boss bar integration.

## Why use `oop`

Choose the `oop` module when your datapack starts to revolve around reusable gameplay concepts rather than isolated
commands.

- **Entities and players** become named handles instead of repeated selectors.
- **Systems such as timers, cooldowns, boss bars, and spawners** generate their own supporting commands and objectives.
- **Your Kotlin code reads closer to gameplay intent**, which makes larger datapacks easier to maintain.

You do not have to go "all in": the OOP layer is meant to sit on top of Kore, not replace it.

## Typical workflow

Most OOP utilities follow a common structure:

1. **Register or declare** the gameplay object once (`team(...)`, `registerCooldown(...)`, `registerSpawner(...)`,
   etc.).
2. **Let Kore generate** the supporting commands, objectives, or load/tick handlers.
3. **Use the handle in functions** with concise methods such as `player.giveEffect(...)`, `cooldown.start(...)`, or
   `spawner.spawn()`.

That workflow keeps setup centralized while leaving your gameplay functions focused on intent.

## Vanilla Kore vs OOP Kore

The OOP module wraps the low-level command DSL into object-oriented abstractions.
Here's a complete side-by-side comparison showing how the same mini-game setup looks with each approach.

### Vanilla Kore

```kotlin
dataPack("arena") {
	// --- Scoreboard objectives and teams ---
	function("setup") {
		scoreboard.objectives.add("kills", ScoreboardCriteria.DUMMY, textComponent("Kills"))
		scoreboard.objectives.add("game_state", ScoreboardCriteria.DUMMY)
		scoreboard.objectives.add("cooldown_dash", ScoreboardCriteria.DUMMY)
		teams.add("red")
		teams.modify("red") { color(FormattingColor.RED) }
		teams.modify("red") { collisionRule(CollisionRule.PUSH_OTHER_TEAMS) }
		teams.add("blue")
		teams.modify("blue") { color(FormattingColor.BLUE) }
		teams.modify("blue") { collisionRule(CollisionRule.PUSH_OTHER_TEAMS) }
	}

	// --- Player setup, selector rebuilt in each function ---
	function("join_red") {
		val player = allPlayers {
			limit = 1
			sort = Sort.NEAREST
		}
		teams.join("red", player)
		gamemode(Gamemode.SURVIVAL, player)
		effect(player) { give(Effects.SPEED, duration = 999999, amplifier = 1) }
		scoreboard.players.set(player, "kills", 0)
		scoreboard.players.set(player, "cooldown_dash", 0)
	}

	function("join_blue") {
		val player = allPlayers {
			limit = 1
			sort = Sort.NEAREST
		}
		teams.join("blue", player)
		gamemode(Gamemode.SURVIVAL, player)
		effect(player) { give(Effects.SPEED, duration = 999999, amplifier = 1) }
		scoreboard.players.set(player, "kills", 0)
		scoreboard.players.set(player, "cooldown_dash", 0)
	}

	// --- State transitions, tracked by hand on a fake player ---
	function("start_game") {
		scoreboard.players.set(literal("#game_state"), "game_state", 1)
		execute {
			asTarget(allPlayers())
			run {
				title(self(), TitleLocation.TITLE, textComponent("Game Started!", Color.GREEN) { bold = true })
			}
		}
	}

	// --- Cooldown, decremented manually every tick ---
	function("tick_cooldowns") {
		execute {
			ifCondition {
				score(allPlayers(), "cooldown_dash", rangeOrIntStart(1))
			}
			run {
				scoreboard.players.remove(allPlayers(), "cooldown_dash", 1)
			}
		}
	}

	// --- Spawning ---
	function("spawn_guardian") {
		summon(EntityTypes.IRON_GOLEM, vec3(0, 64, 0))
	}
}
```

### OOP Kore

```kotlin
dataPack("arena") {
	// --- Players as reusable objects ---
	val redPlayer = player("RedPlayer")
	val bluePlayer = player("BluePlayer")

	// --- Teams ---
	val redTeam = team("red")
	val blueTeam = team("blue")
	function("setup_teams") {
		redTeam.ensureExists()
		redTeam.setColor(FormattingColor.RED)
		redTeam.setCollisionRule(CollisionRule.PUSH_OTHER_TEAMS)
		blueTeam.ensureExists()
		blueTeam.setColor(FormattingColor.BLUE)
		blueTeam.setCollisionRule(CollisionRule.PUSH_OTHER_TEAMS)
	}

	// --- Scoreboard ---
	val kills = scoreboard("kills")

	// --- Cooldown, tick function generated for you ---
	val dashCooldown = registerCooldown("dash", 3.seconds)

	// --- Game states ---
	val states = registerGameStates {
		state("lobby")
		state("running")
		state("finished")
	}

	// --- Spawner ---
	val guardian = registerSpawner("guardian", EntityTypes.IRON_GOLEM) {
		position = vec3(0, 64, 0)
	}

	// --- Player setup ---
	function("join_red") {
		redPlayer.joinTeam(redTeam)
		redPlayer.setGamemode(Gamemode.SURVIVAL)
		redPlayer.giveEffect(Effects.SPEED, duration = 999999, amplifier = 1)
		kills.getScore(redPlayer).set(0)
	}

	function("join_blue") {
		bluePlayer.joinTeam(blueTeam)
		bluePlayer.setGamemode(Gamemode.SURVIVAL)
		bluePlayer.giveEffect(Effects.SPEED, duration = 999999, amplifier = 1)
		kills.getScore(bluePlayer).set(0)
	}

	// --- State transition ---
	function("start_game") {
		states.transitionTo("running")
		redPlayer.showTitle(textComponent("Game Started!", Color.GREEN) { bold = true })
		bluePlayer.showTitle(textComponent("Game Started!", Color.GREEN) { bold = true })
	}

	// --- Spawning ---
	function("spawn_guardian") {
		guardian.spawn()
	}
}
```

### Key Differences

| Aspect                | Vanilla Kore                                                                    | OOP Kore                                                                     |
|-----------------------|---------------------------------------------------------------------------------|------------------------------------------------------------------------------|
| **Entity references** | Manual selectors (`allPlayers { ... }`) repeated everywhere                     | Named objects (`player("RedPlayer")`) reused across functions                |
| **Commands**          | Low-level calls like `scoreboard.players.set(...)`, `effect(...) { give(...) }` | Method calls on entities: `player.giveEffect(...)`, `player.joinTeam(...)`   |
| **Game state**        | Manual scoreboard objectives and raw `set` calls                                | `registerGameStates { state("running") }` + `states.transitionTo("running")` |
| **Cooldowns**         | Manual scoreboard decrement loops                                               | `registerCooldown("dash", 3.seconds)` - tick function auto-generated         |
| **Spawning**          | Raw `summon(EntityTypes.X, pos)`                                                | `registerSpawner(...)` + `spawner.spawn()`                                   |
| **Boilerplate**       | Selector construction, objective registration, execute blocks                   | Handled internally by the OOP abstractions                                   |

The OOP module doesn't replace vanilla Kore - it builds on top of it.
You can freely mix both styles, using OOP utilities where they simplify your code and dropping to vanilla commands when
you need fine-grained control.
