# Utilities and Common APIs

The Hytale server provides a comprehensive set of utility classes and common APIs. This guide covers the most useful utilities for mod development.

## Math Utilities

### Vectors

The math package provides vector classes for 2D and 3D operations:

```java
// 3D Vectors
Vector3d posD = new Vector3d(1.5, 2.5, 3.5);  // double precision
Vector3f posF = new Vector3f(1.5f, 2.5f, 3.5f);  // float precision
Vector3i posI = new Vector3i(1, 2, 3);  // integer

// 2D Vectors
Vector2d pos2D = new Vector2d(1.5, 2.5);
Vector2i pos2I = new Vector2i(1, 2);

// Vector operations
Vector3d a = new Vector3d(1, 2, 3);
Vector3d b = new Vector3d(4, 5, 6);

Vector3d sum = a.add(b);           // (5, 7, 9)
Vector3d diff = a.subtract(b);      // (-3, -3, -3)
Vector3d scaled = a.multiply(2);    // (2, 4, 6)
double dot = a.dot(b);              // 32
Vector3d cross = a.cross(b);        // (-3, 6, -3)
double length = a.length();         // ~3.74
Vector3d normalized = a.normalize(); // unit vector
double distance = a.distance(b);    // distance between points
```

### Vector Codecs

```java
// Serialization
Vector3d.CODEC  // {"x": 1.0, "y": 2.0, "z": 3.0}
Vector3i.CODEC  // {"x": 1, "y": 2, "z": 3}
Vector2d.CODEC  // {"x": 1.0, "y": 2.0}
```

### Shapes

```java
// Bounding box
Box box = new Box(minPoint, maxPoint);
boolean contains = box.contains(point);
boolean intersects = box.intersects(otherBox);
Vector3d center = box.getCenter();
Vector3d size = box.getSize();

// Sphere/Ellipsoid
Ellipsoid sphere = new Ellipsoid(center, radius, radius, radius);
boolean inSphere = sphere.contains(point);

// Cylinder
Cylinder cyl = new Cylinder(base, height, radius);
```

### Transform

```java
// Transform with position and rotation
Transform transform = new Transform(position, rotation);
Vector3d worldPos = transform.toWorld(localPos);
Vector3d localPos = transform.toLocal(worldPos);
```

### Location

```java
// Location combines world, position, and rotation
Location loc = new Location(world, position, yaw, pitch);
World world = loc.getWorld();
Vector3d pos = loc.getPosition();
```

### Math Utilities

```java
// MathUtil
double clamped = MathUtil.clamp(value, min, max);
double lerp = MathUtil.lerp(start, end, t);
int floor = MathUtil.floor(3.7);  // 3
int ceil = MathUtil.ceil(3.1);    // 4
double wrap = MathUtil.wrap(angle, 0, 360);

// TrigMathUtil
double sin = TrigMathUtil.sin(angle);
double cos = TrigMathUtil.cos(angle);
double atan2 = TrigMathUtil.atan2(y, x);
```

## Collection Utilities

### ArrayUtil

```java
// Array operations
String[] combined = ArrayUtil.combine(array1, array2);
int index = ArrayUtil.indexOf(array, element);
boolean contains = ArrayUtil.contains(array, element);
String[] filtered = ArrayUtil.filter(array, predicate);
```

### ListUtil

```java
// List operations
List<String> shuffled = ListUtil.shuffle(list);
List<String> filtered = ListUtil.filter(list, predicate);
Optional<String> random = ListUtil.random(list);
List<List<String>> partitioned = ListUtil.partition(list, 10);
```

### MapUtil

```java
// Map operations
Map<K, V> filtered = MapUtil.filter(map, predicate);
Map<K, V> merged = MapUtil.merge(map1, map2);
<K, V> V getOrCreate(Map<K, V> map, K key, Supplier<V> creator);
```

### WeightedMap

For weighted random selection:

```java
WeightedMap<String> lootTable = new WeightedMap<>();
lootTable.add("common_item", 70);
lootTable.add("rare_item", 25);
lootTable.add("epic_item", 5);

// Random selection based on weights
String selected = lootTable.random();  // 70% common, 25% rare, 5% epic
```

## String Utilities

### StringUtil

```java
// String operations
boolean isEmpty = StringUtil.isEmpty(str);
boolean isBlank = StringUtil.isBlank(str);
String trimmed = StringUtil.trim(str);
String capitalized = StringUtil.capitalize("hello");  // "Hello"
String joined = StringUtil.join(list, ", ");
List<String> split = StringUtil.split(str, ",");

// Formatting
String formatted = StringUtil.format("{0} has {1} items", player, count);
```

### FormatUtil

```java
// Number formatting
String formatted = FormatUtil.formatNumber(1234567);  // "1,234,567"
String decimal = FormatUtil.formatDecimal(3.14159, 2);  // "3.14"
String percent = FormatUtil.formatPercent(0.75);  // "75%"

// Time formatting
String duration = FormatUtil.formatDuration(3661000);  // "1h 1m 1s"
String time = FormatUtil.formatTime(timestamp);
```

## Time Utilities

### TimeUtil

```java
// Time conversions
long ticks = TimeUtil.secondsToTicks(5);  // 100 ticks
long seconds = TimeUtil.ticksToSeconds(100);  // 5 seconds
long millis = TimeUtil.ticksToMillis(20);  // 1000ms

// Current time
long now = TimeUtil.now();
long serverTick = TimeUtil.currentTick();

// Duration parsing
Duration duration = TimeUtil.parseDuration("1h30m");
```

### Tickable Interface

```java
public interface Tickable {
    void tick();
}

// Implement for objects that update each tick
public class MyTickable implements Tickable {
    @Override
    public void tick() {
        // Update logic
    }
}
```

## Version Management

### Semver

```java
// Semantic versioning
Semver version = Semver.parse("1.2.3");
int major = version.getMajor();  // 1
int minor = version.getMinor();  // 2
int patch = version.getPatch();  // 3

// Comparison
boolean isNewer = version.isNewerThan(Semver.parse("1.2.0"));
boolean isCompatible = version.isCompatibleWith(Semver.parse("1.0.0"));
```

### SemverRange

```java
// Version ranges
SemverRange range = SemverRange.parse(">=1.0.0 <2.0.0");
boolean matches = range.matches(Semver.parse("1.5.0"));  // true
boolean matches2 = range.matches(Semver.parse("2.0.0"));  // false

// Common patterns
SemverRange.parse(">=1.0.0");   // 1.0.0 and above
SemverRange.parse("~1.2.3");    // >=1.2.3 <1.3.0
SemverRange.parse("^1.2.3");    // >=1.2.3 <2.0.0
```

## Random Utilities

### Random Number Generation

```java
// Thread-safe random
Random random = RandomUtil.getRandom();
int randInt = random.nextInt(100);
double randDouble = random.nextDouble();
boolean randBool = random.nextBoolean();

// Range-based random
int inRange = RandomUtil.nextInt(10, 20);  // 10-19
double inRangeD = RandomUtil.nextDouble(1.0, 5.0);

// Random selection
String selected = RandomUtil.select(list);
String[] selectedMultiple = RandomUtil.select(list, 3);
```

## Logging

### Logger Access

```java
// In your plugin
Logger logger = getLogger();

logger.info("Information message");
logger.warn("Warning message");
logger.error("Error message");
logger.debug("Debug message");

// With formatting
logger.info("Player {} joined from {}", playerName, ip);

// With exception
try {
    // ...
} catch (Exception e) {
    logger.error("Operation failed", e);
}
```

### Log Levels

Log levels can be configured per-package in server config:

```json
{
    "logLevels": {
        "com.example.myplugin": "DEBUG",
        "com.hypixel.hytale.server": "INFO"
    }
}
```

## Functional Interfaces

### Common Functional Interfaces

```java
// Consumers
Consumer<Player> playerHandler = player -> { /* handle */ };
BiConsumer<Player, String> messageHandler = (player, msg) -> { /* handle */ };

// Suppliers
Supplier<World> worldSupplier = () -> Universe.get().getWorld("default");

// Predicates
Predicate<Entity> isPlayer = entity -> entity instanceof Player;
BiPredicate<Player, String> hasPermission = Player::hasPermission;

// Functions
Function<String, Player> findPlayer = Universe.get()::getPlayer;
```

## Task Scheduling

### Task Registry

```java
// Register a recurring task
getTaskRegistry().register(new MyTask());

public class MyTask implements Task {
    @Override
    public void tick() {
        // Called every server tick
    }
    
    @Override
    public int getInterval() {
        return 20;  // Run every 20 ticks (1 second)
    }
}
```

### Delayed Execution

```java
// Schedule for later
getTaskRegistry().runLater(() -> {
    // Execute after delay
}, 100);  // 100 ticks = 5 seconds

// Schedule repeating
getTaskRegistry().runRepeating(() -> {
    // Execute repeatedly
}, 0, 20);  // Start immediately, repeat every 20 ticks
```

## Data Persistence

### IndexedStorageFile

For storing data in indexed files:

```java
IndexedStorageFile<MyData> storage = new IndexedStorageFile<>(
    path,
    MyData.CODEC
);

// Write data
storage.write("key1", data1);
storage.write("key2", data2);

// Read data
MyData data = storage.read("key1");

// Check existence
boolean exists = storage.exists("key1");

// Delete
storage.delete("key1");
```

## UUID Utilities

```java
// UUID operations
UUID uuid = UUID.randomUUID();
String uuidString = uuid.toString();
UUID parsed = UUID.fromString(uuidString);

// Offline UUID (name-based)
UUID offlineUUID = UUIDUtil.getOfflineUUID("PlayerName");
```

## Reflection Utilities (Unsafe)

The `unsafe` package provides low-level utilities:

```java
// Use with caution - for advanced use cases only
UnsafeUtil.allocateInstance(MyClass.class);
```

## Exception Handling

### SneakyThrow

For throwing checked exceptions without declaring them:

```java
// Throw checked exception without declaring
SneakyThrow.sneakyThrow(new IOException("Error"));
```

## Best Practices

1. **Use provided utilities** - Don't reinvent the wheel
2. **Prefer immutable types** - Use Vector3d over mutable alternatives
3. **Use codecs** - Serialize with built-in codecs when possible
4. **Handle nulls** - Check for null returns from utility methods
5. **Log appropriately** - Use correct log levels
6. **Cache computations** - Don't recalculate expensive operations
7. **Use thread-safe utilities** - RandomUtil is thread-safe
8. **Validate input** - Use MathUtil.clamp for ranges
9. **Format consistently** - Use FormatUtil for user-facing strings
10. **Test thoroughly** - Utility edge cases can cause subtle bugs
