Init
This commit is contained in:
86
content/world/entities/npc/_index.en.md
Normal file
86
content/world/entities/npc/_index.en.md
Normal file
@@ -0,0 +1,86 @@
|
||||
---
|
||||
title: NPC System
|
||||
type: docs
|
||||
weight: 10
|
||||
---
|
||||
|
||||
The NPC (Non-Player Character) system provides a complete framework for creating intelligent game characters with autonomous behavior, decision-making, and navigation capabilities.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.npc`
|
||||
|
||||
{{< cards >}}
|
||||
{{< card link="npc-basics" title="NPC Basics" subtitle="Creating and configuring NPCs" >}}
|
||||
{{< card link="npc-components" title="NPC Components" subtitle="Core components and data" >}}
|
||||
{{< card link="npc-ai" title="NPC AI" subtitle="Blackboard, decisions, and sensors" >}}
|
||||
{{< card link="npc-movement" title="NPC Movement" subtitle="Navigation and pathfinding" >}}
|
||||
{{< card link="npc-commands" title="NPC Commands" subtitle="Admin and debug commands" >}}
|
||||
{{< /cards >}}
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
The NPC system is built on several interconnected subsystems:
|
||||
|
||||
```
|
||||
NPCEntity
|
||||
├── Blackboard (shared state/memory)
|
||||
├── Role (behavioral template)
|
||||
│ ├── Instructions (high-level goals)
|
||||
│ ├── Sensors (perception)
|
||||
│ └── Actions (behaviors)
|
||||
├── DecisionMaker (AI logic)
|
||||
│ ├── Evaluators (condition checking)
|
||||
│ └── Options (action selection)
|
||||
└── Movement
|
||||
├── MotionController (movement execution)
|
||||
├── PathFollower (path tracking)
|
||||
└── NavigationGraph (A* pathfinding)
|
||||
```
|
||||
|
||||
## Quick Example
|
||||
|
||||
```java
|
||||
// Register NPC-related event
|
||||
getEventRegistry().register(NPCSpawnEvent.class, event -> {
|
||||
NPCEntity npc = event.getNPC();
|
||||
|
||||
// Access blackboard for state
|
||||
Blackboard blackboard = npc.getBlackboard();
|
||||
|
||||
// Get current role
|
||||
Role role = npc.getRole();
|
||||
|
||||
// Check if NPC has target
|
||||
if (blackboard.hasTarget()) {
|
||||
Entity target = blackboard.getTarget();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Key Classes
|
||||
|
||||
| Class | Description |
|
||||
|-------|-------------|
|
||||
| `NPCEntity` | Base class for all NPCs |
|
||||
| `NPCPlugin` | Plugin entry point for NPC system |
|
||||
| `Blackboard` | Shared state container for NPC data |
|
||||
| `Role` | Defines NPC behavior template |
|
||||
| `DecisionMaker` | AI decision logic |
|
||||
| `MotionController` | Movement execution |
|
||||
| `PathFollower` | Path tracking and following |
|
||||
|
||||
## Subpackages
|
||||
|
||||
| Package | Files | Description |
|
||||
|---------|-------|-------------|
|
||||
| `corecomponents/` | 327 | Core ECS components for NPCs |
|
||||
| `asset/` | 152 | NPC asset configuration |
|
||||
| `util/` | 50 | Utility classes |
|
||||
| `blackboard/` | 30 | State management |
|
||||
| `movement/` | 27 | Movement behaviors |
|
||||
| `systems/` | 25 | ECS systems |
|
||||
| `commands/` | 23 | Admin commands |
|
||||
| `decisionmaker/` | 22 | AI decision logic |
|
||||
| `sensorinfo/` | 20 | Perception system |
|
||||
| `role/` | 17 | Role definitions |
|
||||
| `instructions/` | 14 | High-level behaviors |
|
||||
| `navigation/` | 12 | Pathfinding |
|
||||
86
content/world/entities/npc/_index.fr.md
Normal file
86
content/world/entities/npc/_index.fr.md
Normal file
@@ -0,0 +1,86 @@
|
||||
---
|
||||
title: Système NPC
|
||||
type: docs
|
||||
weight: 10
|
||||
---
|
||||
|
||||
Le système NPC (Non-Player Character) fournit un framework complet pour créer des personnages de jeu intelligents avec un comportement autonome, une prise de décision et des capacités de navigation.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.npc`
|
||||
|
||||
{{< cards >}}
|
||||
{{< card link="npc-basics" title="Bases NPC" subtitle="Création et configuration des NPCs" >}}
|
||||
{{< card link="npc-components" title="Composants NPC" subtitle="Composants de base et données" >}}
|
||||
{{< card link="npc-ai" title="IA NPC" subtitle="Blackboard, décisions et capteurs" >}}
|
||||
{{< card link="npc-movement" title="Mouvement NPC" subtitle="Navigation et pathfinding" >}}
|
||||
{{< card link="npc-commands" title="Commandes NPC" subtitle="Commandes admin et debug" >}}
|
||||
{{< /cards >}}
|
||||
|
||||
## Vue d'Ensemble de l'Architecture
|
||||
|
||||
Le système NPC est construit sur plusieurs sous-systèmes interconnectés :
|
||||
|
||||
```
|
||||
NPCEntity
|
||||
├── Blackboard (état/mémoire partagé)
|
||||
├── Role (template comportemental)
|
||||
│ ├── Instructions (objectifs haut niveau)
|
||||
│ ├── Sensors (perception)
|
||||
│ └── Actions (comportements)
|
||||
├── DecisionMaker (logique IA)
|
||||
│ ├── Evaluators (vérification conditions)
|
||||
│ └── Options (sélection actions)
|
||||
└── Movement
|
||||
├── MotionController (exécution mouvement)
|
||||
├── PathFollower (suivi de chemin)
|
||||
└── NavigationGraph (pathfinding A*)
|
||||
```
|
||||
|
||||
## Exemple Rapide
|
||||
|
||||
```java
|
||||
// Enregistrer un événement lié aux NPCs
|
||||
getEventRegistry().register(NPCSpawnEvent.class, event -> {
|
||||
NPCEntity npc = event.getNPC();
|
||||
|
||||
// Accéder au blackboard pour l'état
|
||||
Blackboard blackboard = npc.getBlackboard();
|
||||
|
||||
// Obtenir le rôle actuel
|
||||
Role role = npc.getRole();
|
||||
|
||||
// Vérifier si le NPC a une cible
|
||||
if (blackboard.hasTarget()) {
|
||||
Entity target = blackboard.getTarget();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Classes Principales
|
||||
|
||||
| Classe | Description |
|
||||
|--------|-------------|
|
||||
| `NPCEntity` | Classe de base pour tous les NPCs |
|
||||
| `NPCPlugin` | Point d'entrée plugin pour le système NPC |
|
||||
| `Blackboard` | Conteneur d'état partagé pour les données NPC |
|
||||
| `Role` | Définit le template de comportement NPC |
|
||||
| `DecisionMaker` | Logique de décision IA |
|
||||
| `MotionController` | Exécution des mouvements |
|
||||
| `PathFollower` | Suivi et parcours de chemin |
|
||||
|
||||
## Sous-packages
|
||||
|
||||
| Package | Fichiers | Description |
|
||||
|---------|----------|-------------|
|
||||
| `corecomponents/` | 327 | Composants ECS de base pour NPCs |
|
||||
| `asset/` | 152 | Configuration des assets NPC |
|
||||
| `util/` | 50 | Classes utilitaires |
|
||||
| `blackboard/` | 30 | Gestion d'état |
|
||||
| `movement/` | 27 | Comportements de mouvement |
|
||||
| `systems/` | 25 | Systèmes ECS |
|
||||
| `commands/` | 23 | Commandes admin |
|
||||
| `decisionmaker/` | 22 | Logique de décision IA |
|
||||
| `sensorinfo/` | 20 | Système de perception |
|
||||
| `role/` | 17 | Définitions de rôles |
|
||||
| `instructions/` | 14 | Comportements haut niveau |
|
||||
| `navigation/` | 12 | Pathfinding |
|
||||
373
content/world/entities/npc/npc-ai.en.md
Normal file
373
content/world/entities/npc/npc-ai.en.md
Normal file
@@ -0,0 +1,373 @@
|
||||
---
|
||||
title: NPC AI
|
||||
type: docs
|
||||
weight: 3
|
||||
---
|
||||
|
||||
The NPC AI system provides intelligent decision-making through blackboards, decision makers, sensors, and instructions.
|
||||
|
||||
**Packages:**
|
||||
- `com.hypixel.hytale.server.npc.blackboard`
|
||||
- `com.hypixel.hytale.server.npc.decisionmaker`
|
||||
- `com.hypixel.hytale.server.npc.sensorinfo`
|
||||
- `com.hypixel.hytale.server.npc.instructions`
|
||||
|
||||
## Blackboard System
|
||||
|
||||
The Blackboard is a shared memory space where NPC components communicate through key-value pairs.
|
||||
|
||||
### Blackboard Class
|
||||
|
||||
```java
|
||||
public class Blackboard {
|
||||
private Map<BlackboardKey<?>, Object> data;
|
||||
|
||||
// Store value
|
||||
public <T> void set(BlackboardKey<T> key, T value);
|
||||
|
||||
// Retrieve value
|
||||
public <T> T get(BlackboardKey<T> key);
|
||||
public <T> T getOrDefault(BlackboardKey<T> key, T defaultValue);
|
||||
|
||||
// Check existence
|
||||
public boolean has(BlackboardKey<?> key);
|
||||
|
||||
// Remove value
|
||||
public void remove(BlackboardKey<?> key);
|
||||
|
||||
// Clear all
|
||||
public void clear();
|
||||
}
|
||||
```
|
||||
|
||||
### BlackboardKey
|
||||
|
||||
Type-safe keys for blackboard access:
|
||||
|
||||
```java
|
||||
// Predefined keys
|
||||
public class BlackboardKeys {
|
||||
public static final BlackboardKey<Entity> TARGET =
|
||||
new BlackboardKey<>("target", Entity.class);
|
||||
public static final BlackboardKey<Vector3d> HOME_POSITION =
|
||||
new BlackboardKey<>("home_position", Vector3d.class);
|
||||
public static final BlackboardKey<Float> ALERT_LEVEL =
|
||||
new BlackboardKey<>("alert_level", Float.class);
|
||||
public static final BlackboardKey<Boolean> IN_COMBAT =
|
||||
new BlackboardKey<>("in_combat", Boolean.class);
|
||||
}
|
||||
|
||||
// Custom keys
|
||||
BlackboardKey<String> CUSTOM_KEY = new BlackboardKey<>("custom_data", String.class);
|
||||
```
|
||||
|
||||
### Using the Blackboard
|
||||
|
||||
```java
|
||||
NPCEntity npc = // get NPC
|
||||
Blackboard bb = npc.getBlackboard();
|
||||
|
||||
// Set target
|
||||
bb.set(BlackboardKeys.TARGET, targetEntity);
|
||||
|
||||
// Get home position
|
||||
Vector3d home = bb.getOrDefault(BlackboardKeys.HOME_POSITION, npc.getPosition());
|
||||
|
||||
// Check combat status
|
||||
if (bb.getOrDefault(BlackboardKeys.IN_COMBAT, false)) {
|
||||
// Handle combat
|
||||
}
|
||||
```
|
||||
|
||||
## Decision Maker System
|
||||
|
||||
The Decision Maker evaluates options and selects the best action for the NPC to take.
|
||||
|
||||
### DecisionMaker Interface
|
||||
|
||||
```java
|
||||
public interface DecisionMaker {
|
||||
// Evaluate and select best option
|
||||
Option evaluate(NPCEntity npc, Blackboard blackboard);
|
||||
|
||||
// Get all available options
|
||||
List<Option> getOptions();
|
||||
|
||||
// Add option
|
||||
void addOption(Option option);
|
||||
}
|
||||
```
|
||||
|
||||
### Option Class
|
||||
|
||||
Options represent possible actions:
|
||||
|
||||
```java
|
||||
public class Option {
|
||||
private String id;
|
||||
private Evaluator evaluator;
|
||||
private Action action;
|
||||
private float basePriority;
|
||||
|
||||
// Calculate score based on context
|
||||
public float evaluate(NPCEntity npc, Blackboard blackboard);
|
||||
|
||||
// Execute the action
|
||||
public void execute(NPCEntity npc, Blackboard blackboard);
|
||||
}
|
||||
```
|
||||
|
||||
### Evaluator Interface
|
||||
|
||||
Evaluators calculate option scores:
|
||||
|
||||
```java
|
||||
public interface Evaluator {
|
||||
// Return score from 0.0 to 1.0
|
||||
float evaluate(NPCEntity npc, Blackboard blackboard);
|
||||
}
|
||||
|
||||
// Built-in evaluators
|
||||
public class Evaluators {
|
||||
// Returns 1.0 if target exists
|
||||
public static final Evaluator HAS_TARGET = (npc, bb) ->
|
||||
bb.has(BlackboardKeys.TARGET) ? 1.0f : 0.0f;
|
||||
|
||||
// Returns health percentage
|
||||
public static final Evaluator HEALTH_PERCENT = (npc, bb) ->
|
||||
npc.getHealth() / npc.getMaxHealth();
|
||||
|
||||
// Returns 1.0 if at home
|
||||
public static final Evaluator AT_HOME = (npc, bb) -> {
|
||||
Vector3d home = bb.get(BlackboardKeys.HOME_POSITION);
|
||||
return npc.getPosition().distance(home) < 5.0 ? 1.0f : 0.0f;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Creating a Decision Maker
|
||||
|
||||
```java
|
||||
DecisionMaker dm = new StandardDecisionMaker();
|
||||
|
||||
// Add attack option
|
||||
dm.addOption(new Option(
|
||||
"attack",
|
||||
Evaluators.HAS_TARGET,
|
||||
new AttackAction(),
|
||||
10.0f // High priority
|
||||
));
|
||||
|
||||
// Add flee option
|
||||
dm.addOption(new Option(
|
||||
"flee",
|
||||
(npc, bb) -> npc.getHealth() < 20 ? 1.0f : 0.0f,
|
||||
new FleeAction(),
|
||||
15.0f // Higher priority when triggered
|
||||
));
|
||||
|
||||
// Add wander option
|
||||
dm.addOption(new Option(
|
||||
"wander",
|
||||
(npc, bb) -> 0.3f, // Low constant score
|
||||
new WanderAction(),
|
||||
1.0f // Low priority fallback
|
||||
));
|
||||
|
||||
npc.setDecisionMaker(dm);
|
||||
```
|
||||
|
||||
## Sensor System
|
||||
|
||||
Sensors gather information about the world and update the blackboard.
|
||||
|
||||
### Sensor Interface
|
||||
|
||||
```java
|
||||
public interface Sensor {
|
||||
// Process sensor input
|
||||
void sense(NPCEntity npc, Blackboard blackboard, float deltaTime);
|
||||
|
||||
// Get sensor type
|
||||
String getSensorType();
|
||||
}
|
||||
```
|
||||
|
||||
### SensorInfo Classes
|
||||
|
||||
Sensor information containers:
|
||||
|
||||
```java
|
||||
// Visual detection info
|
||||
public class VisualSensorInfo {
|
||||
private List<Entity> visibleEntities;
|
||||
private float detectionRange;
|
||||
private float fieldOfView;
|
||||
|
||||
public List<Entity> getVisibleEntities();
|
||||
public boolean canSee(Entity entity);
|
||||
}
|
||||
|
||||
// Audio detection info
|
||||
public class AudioSensorInfo {
|
||||
private List<SoundEvent> heardSounds;
|
||||
private float hearingRange;
|
||||
|
||||
public List<SoundEvent> getHeardSounds();
|
||||
public Vector3d getLoudestSoundPosition();
|
||||
}
|
||||
|
||||
// Threat detection info
|
||||
public class ThreatSensorInfo {
|
||||
private List<Entity> threats;
|
||||
private Entity primaryThreat;
|
||||
private float threatLevel;
|
||||
}
|
||||
```
|
||||
|
||||
### Built-in Sensors
|
||||
|
||||
```java
|
||||
// Visual sensor - detects visible entities
|
||||
public class VisualSensor implements Sensor {
|
||||
private float range = 20.0f;
|
||||
private float fov = 120.0f; // degrees
|
||||
|
||||
@Override
|
||||
public void sense(NPCEntity npc, Blackboard bb, float dt) {
|
||||
List<Entity> visible = findVisibleEntities(npc);
|
||||
bb.set(BlackboardKeys.VISIBLE_ENTITIES, visible);
|
||||
}
|
||||
}
|
||||
|
||||
// Proximity sensor - detects nearby entities
|
||||
public class ProximitySensor implements Sensor {
|
||||
private float range = 5.0f;
|
||||
|
||||
@Override
|
||||
public void sense(NPCEntity npc, Blackboard bb, float dt) {
|
||||
List<Entity> nearby = findNearbyEntities(npc, range);
|
||||
bb.set(BlackboardKeys.NEARBY_ENTITIES, nearby);
|
||||
}
|
||||
}
|
||||
|
||||
// Damage sensor - reacts to damage taken
|
||||
public class DamageSensor implements Sensor {
|
||||
@Override
|
||||
public void sense(NPCEntity npc, Blackboard bb, float dt) {
|
||||
if (npc.wasRecentlyDamaged()) {
|
||||
bb.set(BlackboardKeys.LAST_ATTACKER, npc.getLastAttacker());
|
||||
bb.set(BlackboardKeys.ALERT_LEVEL, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Instruction System
|
||||
|
||||
Instructions define high-level behavioral goals.
|
||||
|
||||
### Instruction Interface
|
||||
|
||||
```java
|
||||
public interface Instruction {
|
||||
// Check if instruction should activate
|
||||
boolean shouldActivate(NPCEntity npc, Blackboard blackboard);
|
||||
|
||||
// Execute instruction logic
|
||||
void execute(NPCEntity npc, Blackboard blackboard, float deltaTime);
|
||||
|
||||
// Check if instruction is complete
|
||||
boolean isComplete(NPCEntity npc, Blackboard blackboard);
|
||||
|
||||
// Get priority
|
||||
float getPriority();
|
||||
}
|
||||
```
|
||||
|
||||
### Built-in Instructions
|
||||
|
||||
```java
|
||||
// Wander instruction
|
||||
public class WanderInstruction implements Instruction {
|
||||
private float wanderRadius;
|
||||
private float minWaitTime;
|
||||
private float maxWaitTime;
|
||||
|
||||
@Override
|
||||
public boolean shouldActivate(NPCEntity npc, Blackboard bb) {
|
||||
return !bb.has(BlackboardKeys.TARGET);
|
||||
}
|
||||
}
|
||||
|
||||
// Guard instruction
|
||||
public class GuardInstruction implements Instruction {
|
||||
private Vector3d guardPosition;
|
||||
private float guardRadius;
|
||||
|
||||
@Override
|
||||
public void execute(NPCEntity npc, Blackboard bb, float dt) {
|
||||
if (npc.getPosition().distance(guardPosition) > guardRadius) {
|
||||
bb.set(BlackboardKeys.MOVE_TARGET, guardPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Follow instruction
|
||||
public class FollowInstruction implements Instruction {
|
||||
private Entity followTarget;
|
||||
private float followDistance;
|
||||
}
|
||||
|
||||
// Patrol instruction
|
||||
public class PatrolInstruction implements Instruction {
|
||||
private List<Vector3d> patrolPoints;
|
||||
private int currentPoint;
|
||||
}
|
||||
```
|
||||
|
||||
## Combining AI Systems
|
||||
|
||||
```java
|
||||
public void setupNPCAI(NPCEntity npc) {
|
||||
// Configure blackboard
|
||||
Blackboard bb = npc.getBlackboard();
|
||||
bb.set(BlackboardKeys.HOME_POSITION, npc.getPosition());
|
||||
bb.set(BlackboardKeys.AGGRO_RANGE, 15.0f);
|
||||
|
||||
// Add sensors
|
||||
npc.addSensor(new VisualSensor(20.0f, 120.0f));
|
||||
npc.addSensor(new ProximitySensor(5.0f));
|
||||
npc.addSensor(new DamageSensor());
|
||||
|
||||
// Configure decision maker
|
||||
DecisionMaker dm = new StandardDecisionMaker();
|
||||
dm.addOption(new Option("attack", hasHostileTarget, attackAction, 10.0f));
|
||||
dm.addOption(new Option("flee", lowHealth, fleeAction, 15.0f));
|
||||
dm.addOption(new Option("patrol", isGuard, patrolAction, 5.0f));
|
||||
dm.addOption(new Option("idle", always, idleAction, 1.0f));
|
||||
npc.setDecisionMaker(dm);
|
||||
|
||||
// Add instructions
|
||||
npc.addInstruction(new GuardInstruction(guardPost, 10.0f));
|
||||
npc.addInstruction(new ReactToThreatInstruction());
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**AI Guidelines:**
|
||||
- Use the Blackboard for all inter-component communication
|
||||
- Keep Evaluators simple and fast - they run frequently
|
||||
- Use appropriate sensor ranges to balance awareness vs performance
|
||||
- Design Instructions to be interruptible
|
||||
- Test AI behavior with various scenarios
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Performance:** Large numbers of NPCs with complex AI can impact performance. Consider:
|
||||
- Reducing sensor update frequency for distant NPCs
|
||||
- Using LOD (Level of Detail) for AI complexity
|
||||
- Limiting pathfinding requests
|
||||
{{< /callout >}}
|
||||
373
content/world/entities/npc/npc-ai.fr.md
Normal file
373
content/world/entities/npc/npc-ai.fr.md
Normal file
@@ -0,0 +1,373 @@
|
||||
---
|
||||
title: IA NPC
|
||||
type: docs
|
||||
weight: 3
|
||||
---
|
||||
|
||||
Le système d'IA NPC fournit une prise de décision intelligente via les blackboards, decision makers, capteurs et instructions.
|
||||
|
||||
**Packages:**
|
||||
- `com.hypixel.hytale.server.npc.blackboard`
|
||||
- `com.hypixel.hytale.server.npc.decisionmaker`
|
||||
- `com.hypixel.hytale.server.npc.sensorinfo`
|
||||
- `com.hypixel.hytale.server.npc.instructions`
|
||||
|
||||
## Système Blackboard
|
||||
|
||||
Le Blackboard est un espace mémoire partagé où les composants NPC communiquent via des paires clé-valeur.
|
||||
|
||||
### Classe Blackboard
|
||||
|
||||
```java
|
||||
public class Blackboard {
|
||||
private Map<BlackboardKey<?>, Object> data;
|
||||
|
||||
// Stocker une valeur
|
||||
public <T> void set(BlackboardKey<T> key, T value);
|
||||
|
||||
// Récupérer une valeur
|
||||
public <T> T get(BlackboardKey<T> key);
|
||||
public <T> T getOrDefault(BlackboardKey<T> key, T defaultValue);
|
||||
|
||||
// Vérifier l'existence
|
||||
public boolean has(BlackboardKey<?> key);
|
||||
|
||||
// Supprimer une valeur
|
||||
public void remove(BlackboardKey<?> key);
|
||||
|
||||
// Tout effacer
|
||||
public void clear();
|
||||
}
|
||||
```
|
||||
|
||||
### BlackboardKey
|
||||
|
||||
Clés typées pour l'accès au blackboard :
|
||||
|
||||
```java
|
||||
// Clés prédéfinies
|
||||
public class BlackboardKeys {
|
||||
public static final BlackboardKey<Entity> TARGET =
|
||||
new BlackboardKey<>("target", Entity.class);
|
||||
public static final BlackboardKey<Vector3d> HOME_POSITION =
|
||||
new BlackboardKey<>("home_position", Vector3d.class);
|
||||
public static final BlackboardKey<Float> ALERT_LEVEL =
|
||||
new BlackboardKey<>("alert_level", Float.class);
|
||||
public static final BlackboardKey<Boolean> IN_COMBAT =
|
||||
new BlackboardKey<>("in_combat", Boolean.class);
|
||||
}
|
||||
|
||||
// Clés personnalisées
|
||||
BlackboardKey<String> CUSTOM_KEY = new BlackboardKey<>("custom_data", String.class);
|
||||
```
|
||||
|
||||
### Utiliser le Blackboard
|
||||
|
||||
```java
|
||||
NPCEntity npc = // obtenir le NPC
|
||||
Blackboard bb = npc.getBlackboard();
|
||||
|
||||
// Définir la cible
|
||||
bb.set(BlackboardKeys.TARGET, targetEntity);
|
||||
|
||||
// Obtenir la position d'origine
|
||||
Vector3d home = bb.getOrDefault(BlackboardKeys.HOME_POSITION, npc.getPosition());
|
||||
|
||||
// Vérifier le statut de combat
|
||||
if (bb.getOrDefault(BlackboardKeys.IN_COMBAT, false)) {
|
||||
// Gérer le combat
|
||||
}
|
||||
```
|
||||
|
||||
## Système Decision Maker
|
||||
|
||||
Le Decision Maker évalue les options et sélectionne la meilleure action pour le NPC.
|
||||
|
||||
### Interface DecisionMaker
|
||||
|
||||
```java
|
||||
public interface DecisionMaker {
|
||||
// Évaluer et sélectionner la meilleure option
|
||||
Option evaluate(NPCEntity npc, Blackboard blackboard);
|
||||
|
||||
// Obtenir toutes les options disponibles
|
||||
List<Option> getOptions();
|
||||
|
||||
// Ajouter une option
|
||||
void addOption(Option option);
|
||||
}
|
||||
```
|
||||
|
||||
### Classe Option
|
||||
|
||||
Les options représentent les actions possibles :
|
||||
|
||||
```java
|
||||
public class Option {
|
||||
private String id;
|
||||
private Evaluator evaluator;
|
||||
private Action action;
|
||||
private float basePriority;
|
||||
|
||||
// Calculer le score selon le contexte
|
||||
public float evaluate(NPCEntity npc, Blackboard blackboard);
|
||||
|
||||
// Exécuter l'action
|
||||
public void execute(NPCEntity npc, Blackboard blackboard);
|
||||
}
|
||||
```
|
||||
|
||||
### Interface Evaluator
|
||||
|
||||
Les évaluateurs calculent les scores des options :
|
||||
|
||||
```java
|
||||
public interface Evaluator {
|
||||
// Retourne un score de 0.0 à 1.0
|
||||
float evaluate(NPCEntity npc, Blackboard blackboard);
|
||||
}
|
||||
|
||||
// Évaluateurs intégrés
|
||||
public class Evaluators {
|
||||
// Retourne 1.0 si une cible existe
|
||||
public static final Evaluator HAS_TARGET = (npc, bb) ->
|
||||
bb.has(BlackboardKeys.TARGET) ? 1.0f : 0.0f;
|
||||
|
||||
// Retourne le pourcentage de vie
|
||||
public static final Evaluator HEALTH_PERCENT = (npc, bb) ->
|
||||
npc.getHealth() / npc.getMaxHealth();
|
||||
|
||||
// Retourne 1.0 si à la maison
|
||||
public static final Evaluator AT_HOME = (npc, bb) -> {
|
||||
Vector3d home = bb.get(BlackboardKeys.HOME_POSITION);
|
||||
return npc.getPosition().distance(home) < 5.0 ? 1.0f : 0.0f;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Créer un Decision Maker
|
||||
|
||||
```java
|
||||
DecisionMaker dm = new StandardDecisionMaker();
|
||||
|
||||
// Ajouter option d'attaque
|
||||
dm.addOption(new Option(
|
||||
"attack",
|
||||
Evaluators.HAS_TARGET,
|
||||
new AttackAction(),
|
||||
10.0f // Haute priorité
|
||||
));
|
||||
|
||||
// Ajouter option de fuite
|
||||
dm.addOption(new Option(
|
||||
"flee",
|
||||
(npc, bb) -> npc.getHealth() < 20 ? 1.0f : 0.0f,
|
||||
new FleeAction(),
|
||||
15.0f // Priorité plus haute quand déclenché
|
||||
));
|
||||
|
||||
// Ajouter option d'errance
|
||||
dm.addOption(new Option(
|
||||
"wander",
|
||||
(npc, bb) -> 0.3f, // Score constant bas
|
||||
new WanderAction(),
|
||||
1.0f // Basse priorité par défaut
|
||||
));
|
||||
|
||||
npc.setDecisionMaker(dm);
|
||||
```
|
||||
|
||||
## Système de Capteurs
|
||||
|
||||
Les capteurs collectent des informations sur le monde et mettent à jour le blackboard.
|
||||
|
||||
### Interface Sensor
|
||||
|
||||
```java
|
||||
public interface Sensor {
|
||||
// Traiter l'entrée du capteur
|
||||
void sense(NPCEntity npc, Blackboard blackboard, float deltaTime);
|
||||
|
||||
// Obtenir le type de capteur
|
||||
String getSensorType();
|
||||
}
|
||||
```
|
||||
|
||||
### Classes SensorInfo
|
||||
|
||||
Conteneurs d'informations de capteurs :
|
||||
|
||||
```java
|
||||
// Info de détection visuelle
|
||||
public class VisualSensorInfo {
|
||||
private List<Entity> visibleEntities;
|
||||
private float detectionRange;
|
||||
private float fieldOfView;
|
||||
|
||||
public List<Entity> getVisibleEntities();
|
||||
public boolean canSee(Entity entity);
|
||||
}
|
||||
|
||||
// Info de détection audio
|
||||
public class AudioSensorInfo {
|
||||
private List<SoundEvent> heardSounds;
|
||||
private float hearingRange;
|
||||
|
||||
public List<SoundEvent> getHeardSounds();
|
||||
public Vector3d getLoudestSoundPosition();
|
||||
}
|
||||
|
||||
// Info de détection de menace
|
||||
public class ThreatSensorInfo {
|
||||
private List<Entity> threats;
|
||||
private Entity primaryThreat;
|
||||
private float threatLevel;
|
||||
}
|
||||
```
|
||||
|
||||
### Capteurs Intégrés
|
||||
|
||||
```java
|
||||
// Capteur visuel - détecte les entités visibles
|
||||
public class VisualSensor implements Sensor {
|
||||
private float range = 20.0f;
|
||||
private float fov = 120.0f; // degrés
|
||||
|
||||
@Override
|
||||
public void sense(NPCEntity npc, Blackboard bb, float dt) {
|
||||
List<Entity> visible = findVisibleEntities(npc);
|
||||
bb.set(BlackboardKeys.VISIBLE_ENTITIES, visible);
|
||||
}
|
||||
}
|
||||
|
||||
// Capteur de proximité - détecte les entités proches
|
||||
public class ProximitySensor implements Sensor {
|
||||
private float range = 5.0f;
|
||||
|
||||
@Override
|
||||
public void sense(NPCEntity npc, Blackboard bb, float dt) {
|
||||
List<Entity> nearby = findNearbyEntities(npc, range);
|
||||
bb.set(BlackboardKeys.NEARBY_ENTITIES, nearby);
|
||||
}
|
||||
}
|
||||
|
||||
// Capteur de dégâts - réagit aux dégâts subis
|
||||
public class DamageSensor implements Sensor {
|
||||
@Override
|
||||
public void sense(NPCEntity npc, Blackboard bb, float dt) {
|
||||
if (npc.wasRecentlyDamaged()) {
|
||||
bb.set(BlackboardKeys.LAST_ATTACKER, npc.getLastAttacker());
|
||||
bb.set(BlackboardKeys.ALERT_LEVEL, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Système d'Instructions
|
||||
|
||||
Les instructions définissent des objectifs comportementaux de haut niveau.
|
||||
|
||||
### Interface Instruction
|
||||
|
||||
```java
|
||||
public interface Instruction {
|
||||
// Vérifier si l'instruction doit s'activer
|
||||
boolean shouldActivate(NPCEntity npc, Blackboard blackboard);
|
||||
|
||||
// Exécuter la logique de l'instruction
|
||||
void execute(NPCEntity npc, Blackboard blackboard, float deltaTime);
|
||||
|
||||
// Vérifier si l'instruction est complète
|
||||
boolean isComplete(NPCEntity npc, Blackboard blackboard);
|
||||
|
||||
// Obtenir la priorité
|
||||
float getPriority();
|
||||
}
|
||||
```
|
||||
|
||||
### Instructions Intégrées
|
||||
|
||||
```java
|
||||
// Instruction d'errance
|
||||
public class WanderInstruction implements Instruction {
|
||||
private float wanderRadius;
|
||||
private float minWaitTime;
|
||||
private float maxWaitTime;
|
||||
|
||||
@Override
|
||||
public boolean shouldActivate(NPCEntity npc, Blackboard bb) {
|
||||
return !bb.has(BlackboardKeys.TARGET);
|
||||
}
|
||||
}
|
||||
|
||||
// Instruction de garde
|
||||
public class GuardInstruction implements Instruction {
|
||||
private Vector3d guardPosition;
|
||||
private float guardRadius;
|
||||
|
||||
@Override
|
||||
public void execute(NPCEntity npc, Blackboard bb, float dt) {
|
||||
if (npc.getPosition().distance(guardPosition) > guardRadius) {
|
||||
bb.set(BlackboardKeys.MOVE_TARGET, guardPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Instruction de suivi
|
||||
public class FollowInstruction implements Instruction {
|
||||
private Entity followTarget;
|
||||
private float followDistance;
|
||||
}
|
||||
|
||||
// Instruction de patrouille
|
||||
public class PatrolInstruction implements Instruction {
|
||||
private List<Vector3d> patrolPoints;
|
||||
private int currentPoint;
|
||||
}
|
||||
```
|
||||
|
||||
## Combiner les Systèmes d'IA
|
||||
|
||||
```java
|
||||
public void setupNPCAI(NPCEntity npc) {
|
||||
// Configurer le blackboard
|
||||
Blackboard bb = npc.getBlackboard();
|
||||
bb.set(BlackboardKeys.HOME_POSITION, npc.getPosition());
|
||||
bb.set(BlackboardKeys.AGGRO_RANGE, 15.0f);
|
||||
|
||||
// Ajouter les capteurs
|
||||
npc.addSensor(new VisualSensor(20.0f, 120.0f));
|
||||
npc.addSensor(new ProximitySensor(5.0f));
|
||||
npc.addSensor(new DamageSensor());
|
||||
|
||||
// Configurer le decision maker
|
||||
DecisionMaker dm = new StandardDecisionMaker();
|
||||
dm.addOption(new Option("attack", hasHostileTarget, attackAction, 10.0f));
|
||||
dm.addOption(new Option("flee", lowHealth, fleeAction, 15.0f));
|
||||
dm.addOption(new Option("patrol", isGuard, patrolAction, 5.0f));
|
||||
dm.addOption(new Option("idle", always, idleAction, 1.0f));
|
||||
npc.setDecisionMaker(dm);
|
||||
|
||||
// Ajouter les instructions
|
||||
npc.addInstruction(new GuardInstruction(guardPost, 10.0f));
|
||||
npc.addInstruction(new ReactToThreatInstruction());
|
||||
}
|
||||
```
|
||||
|
||||
## Bonnes Pratiques
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Directives IA :**
|
||||
- Utilisez le Blackboard pour toute communication inter-composants
|
||||
- Gardez les Évaluateurs simples et rapides - ils s'exécutent fréquemment
|
||||
- Utilisez des portées de capteurs appropriées pour équilibrer conscience vs performance
|
||||
- Concevez les Instructions pour être interruptibles
|
||||
- Testez le comportement IA avec différents scénarios
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Performance :** Un grand nombre de NPCs avec une IA complexe peut impacter les performances. Considérez :
|
||||
- Réduire la fréquence de mise à jour des capteurs pour les NPCs distants
|
||||
- Utiliser le LOD (Level of Detail) pour la complexité IA
|
||||
- Limiter les requêtes de pathfinding
|
||||
{{< /callout >}}
|
||||
217
content/world/entities/npc/npc-basics.en.md
Normal file
217
content/world/entities/npc/npc-basics.en.md
Normal file
@@ -0,0 +1,217 @@
|
||||
---
|
||||
title: NPC Basics
|
||||
type: docs
|
||||
weight: 1
|
||||
---
|
||||
|
||||
This guide covers the fundamentals of creating and configuring NPCs in Hytale.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.npc`
|
||||
|
||||
## NPCEntity Class
|
||||
|
||||
`NPCEntity` is the base class for all non-player characters. It extends the entity hierarchy and provides NPC-specific functionality.
|
||||
|
||||
```java
|
||||
public class NPCEntity extends LivingEntity {
|
||||
// Core NPC functionality
|
||||
private Blackboard blackboard;
|
||||
private Role role;
|
||||
private DecisionMaker decisionMaker;
|
||||
private MotionController motionController;
|
||||
}
|
||||
```
|
||||
|
||||
### Creating an NPC
|
||||
|
||||
NPCs are typically created through the asset system or spawned programmatically:
|
||||
|
||||
```java
|
||||
// Spawn NPC from asset
|
||||
NPCEntity npc = world.spawnNPC("villager", position);
|
||||
|
||||
// Configure NPC after spawn
|
||||
npc.setRole(customRole);
|
||||
npc.getBlackboard().setHomePosition(position);
|
||||
```
|
||||
|
||||
## NPC Assets
|
||||
|
||||
NPC definitions are configured through YAML asset files:
|
||||
|
||||
```yaml
|
||||
# npc/villager.yaml
|
||||
Type: NPC
|
||||
Id: villager
|
||||
DisplayName: "Villager"
|
||||
Model: models/characters/villager
|
||||
Role: roles/villager_role
|
||||
Stats:
|
||||
Health: 100
|
||||
Speed: 3.0
|
||||
Components:
|
||||
- Type: NPCBrain
|
||||
- Type: Interactable
|
||||
- Type: DialogueCapable
|
||||
```
|
||||
|
||||
### Asset Structure
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `Type` | String | Must be "NPC" |
|
||||
| `Id` | String | Unique identifier |
|
||||
| `DisplayName` | String | Display name |
|
||||
| `Model` | String | Model asset reference |
|
||||
| `Role` | String | Default role reference |
|
||||
| `Stats` | Object | Base statistics |
|
||||
| `Components` | Array | Component configurations |
|
||||
|
||||
## NPC Roles
|
||||
|
||||
Roles define the behavioral template for an NPC. They specify what instructions, sensors, and actions the NPC can use.
|
||||
|
||||
```yaml
|
||||
# roles/villager_role.yaml
|
||||
Type: Role
|
||||
Id: villager_role
|
||||
Instructions:
|
||||
- Wander
|
||||
- ReactToThreats
|
||||
- Interact
|
||||
Sensors:
|
||||
- Type: VisualSensor
|
||||
Range: 15.0
|
||||
- Type: AudioSensor
|
||||
Range: 10.0
|
||||
Actions:
|
||||
- Walk
|
||||
- Run
|
||||
- Talk
|
||||
- Trade
|
||||
```
|
||||
|
||||
### Role Components
|
||||
|
||||
```java
|
||||
public class Role {
|
||||
private List<Instruction> instructions;
|
||||
private List<Sensor> sensors;
|
||||
private List<Action> availableActions;
|
||||
|
||||
// Get active instruction
|
||||
public Instruction getCurrentInstruction();
|
||||
|
||||
// Check if action is available
|
||||
public boolean hasAction(String actionId);
|
||||
}
|
||||
```
|
||||
|
||||
## NPC Systems
|
||||
|
||||
The NPC module registers several ECS systems for processing NPC behavior:
|
||||
|
||||
| System | Description |
|
||||
|--------|-------------|
|
||||
| `NPCBrainSystem` | Processes AI decisions |
|
||||
| `NPCMovementSystem` | Handles movement updates |
|
||||
| `NPCSensorSystem` | Processes sensor inputs |
|
||||
| `NPCAnimationSystem` | Updates animations |
|
||||
| `NPCInteractionSystem` | Handles interactions |
|
||||
|
||||
### System Registration
|
||||
|
||||
```java
|
||||
public class NPCPlugin extends JavaPlugin {
|
||||
@Override
|
||||
public void start() {
|
||||
// Systems are auto-registered by NPCPlugin
|
||||
// Custom systems can be added:
|
||||
getEntityStoreRegistry().registerSystem(
|
||||
new CustomNPCSystem()
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## NPC Utilities
|
||||
|
||||
The `util/` package provides helper classes:
|
||||
|
||||
### NPCUtils
|
||||
|
||||
```java
|
||||
// Find nearest NPC
|
||||
NPCEntity nearest = NPCUtils.findNearest(position, world, 50.0);
|
||||
|
||||
// Get all NPCs in area
|
||||
List<NPCEntity> npcsInArea = NPCUtils.getNPCsInRadius(
|
||||
position, world, 25.0
|
||||
);
|
||||
|
||||
// Check line of sight
|
||||
boolean canSee = NPCUtils.hasLineOfSight(npc, target);
|
||||
```
|
||||
|
||||
### NPCSpawner
|
||||
|
||||
```java
|
||||
// Spawn with configuration
|
||||
NPCEntity npc = NPCSpawner.spawn(
|
||||
world,
|
||||
"villager",
|
||||
position,
|
||||
config -> {
|
||||
config.setRole("merchant");
|
||||
config.setFaction("town");
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Setting Up an NPC Shop
|
||||
|
||||
```java
|
||||
NPCEntity merchant = world.spawnNPC("merchant", shopPosition);
|
||||
merchant.getBlackboard().set("shop_inventory", inventory);
|
||||
merchant.getBlackboard().set("is_merchant", true);
|
||||
merchant.setRole(merchantRole);
|
||||
```
|
||||
|
||||
### Creating a Guard NPC
|
||||
|
||||
```java
|
||||
NPCEntity guard = world.spawnNPC("guard", guardPosition);
|
||||
Blackboard bb = guard.getBlackboard();
|
||||
bb.setPatrolPath(patrolWaypoints);
|
||||
bb.setHostileToFactions(List.of("bandits", "monsters"));
|
||||
guard.setRole(guardRole);
|
||||
```
|
||||
|
||||
### NPC with Custom Behavior
|
||||
|
||||
```java
|
||||
NPCEntity custom = world.spawnNPC("custom_npc", position);
|
||||
|
||||
// Add custom component
|
||||
custom.getEntityStore().addComponent(new CustomBehaviorComponent());
|
||||
|
||||
// Set custom decision maker
|
||||
custom.setDecisionMaker(new CustomDecisionMaker());
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**NPC Guidelines:**
|
||||
- Always set a Role for NPCs to define their behavior
|
||||
- Use the Blackboard for all NPC state storage
|
||||
- Configure appropriate sensors for the NPC's awareness needs
|
||||
- Use the asset system for NPC definitions when possible
|
||||
- Consider performance with large numbers of NPCs
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Thread Safety:** NPC operations should be performed on the world's ticking thread. Use `world.isInThread()` to verify before making changes.
|
||||
{{< /callout >}}
|
||||
217
content/world/entities/npc/npc-basics.fr.md
Normal file
217
content/world/entities/npc/npc-basics.fr.md
Normal file
@@ -0,0 +1,217 @@
|
||||
---
|
||||
title: Bases NPC
|
||||
type: docs
|
||||
weight: 1
|
||||
---
|
||||
|
||||
Ce guide couvre les fondamentaux de la création et de la configuration des NPCs dans Hytale.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.npc`
|
||||
|
||||
## Classe NPCEntity
|
||||
|
||||
`NPCEntity` est la classe de base pour tous les personnages non-joueurs. Elle étend la hiérarchie d'entités et fournit des fonctionnalités spécifiques aux NPCs.
|
||||
|
||||
```java
|
||||
public class NPCEntity extends LivingEntity {
|
||||
// Fonctionnalités NPC de base
|
||||
private Blackboard blackboard;
|
||||
private Role role;
|
||||
private DecisionMaker decisionMaker;
|
||||
private MotionController motionController;
|
||||
}
|
||||
```
|
||||
|
||||
### Créer un NPC
|
||||
|
||||
Les NPCs sont généralement créés via le système d'assets ou générés programmatiquement :
|
||||
|
||||
```java
|
||||
// Générer un NPC depuis un asset
|
||||
NPCEntity npc = world.spawnNPC("villager", position);
|
||||
|
||||
// Configurer le NPC après génération
|
||||
npc.setRole(customRole);
|
||||
npc.getBlackboard().setHomePosition(position);
|
||||
```
|
||||
|
||||
## Assets NPC
|
||||
|
||||
Les définitions NPC sont configurées via des fichiers d'assets YAML :
|
||||
|
||||
```yaml
|
||||
# npc/villager.yaml
|
||||
Type: NPC
|
||||
Id: villager
|
||||
DisplayName: "Villageois"
|
||||
Model: models/characters/villager
|
||||
Role: roles/villager_role
|
||||
Stats:
|
||||
Health: 100
|
||||
Speed: 3.0
|
||||
Components:
|
||||
- Type: NPCBrain
|
||||
- Type: Interactable
|
||||
- Type: DialogueCapable
|
||||
```
|
||||
|
||||
### Structure d'Asset
|
||||
|
||||
| Propriété | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `Type` | String | Doit être "NPC" |
|
||||
| `Id` | String | Identifiant unique |
|
||||
| `DisplayName` | String | Nom d'affichage |
|
||||
| `Model` | String | Référence asset modèle |
|
||||
| `Role` | String | Référence rôle par défaut |
|
||||
| `Stats` | Object | Statistiques de base |
|
||||
| `Components` | Array | Configurations de composants |
|
||||
|
||||
## Rôles NPC
|
||||
|
||||
Les rôles définissent le template comportemental d'un NPC. Ils spécifient quelles instructions, capteurs et actions le NPC peut utiliser.
|
||||
|
||||
```yaml
|
||||
# roles/villager_role.yaml
|
||||
Type: Role
|
||||
Id: villager_role
|
||||
Instructions:
|
||||
- Wander
|
||||
- ReactToThreats
|
||||
- Interact
|
||||
Sensors:
|
||||
- Type: VisualSensor
|
||||
Range: 15.0
|
||||
- Type: AudioSensor
|
||||
Range: 10.0
|
||||
Actions:
|
||||
- Walk
|
||||
- Run
|
||||
- Talk
|
||||
- Trade
|
||||
```
|
||||
|
||||
### Composants de Rôle
|
||||
|
||||
```java
|
||||
public class Role {
|
||||
private List<Instruction> instructions;
|
||||
private List<Sensor> sensors;
|
||||
private List<Action> availableActions;
|
||||
|
||||
// Obtenir l'instruction active
|
||||
public Instruction getCurrentInstruction();
|
||||
|
||||
// Vérifier si une action est disponible
|
||||
public boolean hasAction(String actionId);
|
||||
}
|
||||
```
|
||||
|
||||
## Systèmes NPC
|
||||
|
||||
Le module NPC enregistre plusieurs systèmes ECS pour traiter le comportement des NPCs :
|
||||
|
||||
| Système | Description |
|
||||
|---------|-------------|
|
||||
| `NPCBrainSystem` | Traite les décisions IA |
|
||||
| `NPCMovementSystem` | Gère les mises à jour de mouvement |
|
||||
| `NPCSensorSystem` | Traite les entrées des capteurs |
|
||||
| `NPCAnimationSystem` | Met à jour les animations |
|
||||
| `NPCInteractionSystem` | Gère les interactions |
|
||||
|
||||
### Enregistrement des Systèmes
|
||||
|
||||
```java
|
||||
public class NPCPlugin extends JavaPlugin {
|
||||
@Override
|
||||
public void start() {
|
||||
// Les systèmes sont auto-enregistrés par NPCPlugin
|
||||
// Des systèmes personnalisés peuvent être ajoutés :
|
||||
getEntityStoreRegistry().registerSystem(
|
||||
new CustomNPCSystem()
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Utilitaires NPC
|
||||
|
||||
Le package `util/` fournit des classes d'aide :
|
||||
|
||||
### NPCUtils
|
||||
|
||||
```java
|
||||
// Trouver le NPC le plus proche
|
||||
NPCEntity nearest = NPCUtils.findNearest(position, world, 50.0);
|
||||
|
||||
// Obtenir tous les NPCs dans une zone
|
||||
List<NPCEntity> npcsInArea = NPCUtils.getNPCsInRadius(
|
||||
position, world, 25.0
|
||||
);
|
||||
|
||||
// Vérifier la ligne de vue
|
||||
boolean canSee = NPCUtils.hasLineOfSight(npc, target);
|
||||
```
|
||||
|
||||
### NPCSpawner
|
||||
|
||||
```java
|
||||
// Générer avec configuration
|
||||
NPCEntity npc = NPCSpawner.spawn(
|
||||
world,
|
||||
"villager",
|
||||
position,
|
||||
config -> {
|
||||
config.setRole("merchant");
|
||||
config.setFaction("town");
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## Patterns Courants
|
||||
|
||||
### Configurer une Boutique NPC
|
||||
|
||||
```java
|
||||
NPCEntity merchant = world.spawnNPC("merchant", shopPosition);
|
||||
merchant.getBlackboard().set("shop_inventory", inventory);
|
||||
merchant.getBlackboard().set("is_merchant", true);
|
||||
merchant.setRole(merchantRole);
|
||||
```
|
||||
|
||||
### Créer un NPC Garde
|
||||
|
||||
```java
|
||||
NPCEntity guard = world.spawnNPC("guard", guardPosition);
|
||||
Blackboard bb = guard.getBlackboard();
|
||||
bb.setPatrolPath(patrolWaypoints);
|
||||
bb.setHostileToFactions(List.of("bandits", "monsters"));
|
||||
guard.setRole(guardRole);
|
||||
```
|
||||
|
||||
### NPC avec Comportement Personnalisé
|
||||
|
||||
```java
|
||||
NPCEntity custom = world.spawnNPC("custom_npc", position);
|
||||
|
||||
// Ajouter un composant personnalisé
|
||||
custom.getEntityStore().addComponent(new CustomBehaviorComponent());
|
||||
|
||||
// Définir un decision maker personnalisé
|
||||
custom.setDecisionMaker(new CustomDecisionMaker());
|
||||
```
|
||||
|
||||
## Bonnes Pratiques
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Directives NPC :**
|
||||
- Définissez toujours un Rôle pour les NPCs pour définir leur comportement
|
||||
- Utilisez le Blackboard pour tout stockage d'état NPC
|
||||
- Configurez les capteurs appropriés pour les besoins de perception du NPC
|
||||
- Utilisez le système d'assets pour les définitions NPC quand possible
|
||||
- Considérez les performances avec un grand nombre de NPCs
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Thread Safety :** Les opérations NPC doivent être effectuées sur le thread de tick du monde. Utilisez `world.isInThread()` pour vérifier avant de faire des changements.
|
||||
{{< /callout >}}
|
||||
374
content/world/entities/npc/npc-commands.en.md
Normal file
374
content/world/entities/npc/npc-commands.en.md
Normal file
@@ -0,0 +1,374 @@
|
||||
---
|
||||
title: NPC Commands
|
||||
type: docs
|
||||
weight: 5
|
||||
---
|
||||
|
||||
The NPC system includes 23 admin and debug commands for managing and testing NPCs.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.npc.commands`
|
||||
|
||||
## Spawning Commands
|
||||
|
||||
### /npc spawn
|
||||
|
||||
Spawns an NPC at a location:
|
||||
|
||||
```
|
||||
/npc spawn <npc_type> [position] [--role <role>] [--name <name>]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `npc_type` | String | NPC asset ID |
|
||||
| `position` | Position | Spawn location (default: player position) |
|
||||
| `--role` | String | Override default role |
|
||||
| `--name` | String | Custom display name |
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc spawn villager
|
||||
/npc spawn guard ~ ~1 ~ --role patrol_guard
|
||||
/npc spawn merchant --name "Bob the Trader"
|
||||
```
|
||||
|
||||
### /npc despawn
|
||||
|
||||
Removes an NPC:
|
||||
|
||||
```
|
||||
/npc despawn <target>
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `target` | NPC | Target NPC (raycast or selector) |
|
||||
|
||||
### /npc despawnall
|
||||
|
||||
Removes all NPCs in radius:
|
||||
|
||||
```
|
||||
/npc despawnall [radius]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `radius` | Float | Radius in blocks (default: 50) |
|
||||
|
||||
## Information Commands
|
||||
|
||||
### /npc info
|
||||
|
||||
Displays NPC information:
|
||||
|
||||
```
|
||||
/npc info [target]
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
NPC Info: Villager (villager_001)
|
||||
Position: 100.5, 64.0, -200.3
|
||||
Role: villager_role
|
||||
State: IDLE
|
||||
Health: 100/100
|
||||
Target: None
|
||||
Current Instruction: Wander
|
||||
```
|
||||
|
||||
### /npc list
|
||||
|
||||
Lists all NPCs:
|
||||
|
||||
```
|
||||
/npc list [--radius <radius>] [--type <type>]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `--radius` | Float | Search radius |
|
||||
| `--type` | String | Filter by NPC type |
|
||||
|
||||
### /npc debug
|
||||
|
||||
Toggles debug visualization:
|
||||
|
||||
```
|
||||
/npc debug <mode>
|
||||
```
|
||||
|
||||
**Modes:**
|
||||
| Mode | Description |
|
||||
|------|-------------|
|
||||
| `path` | Show pathfinding |
|
||||
| `sensors` | Show sensor ranges |
|
||||
| `state` | Show AI state |
|
||||
| `target` | Show targeting |
|
||||
| `all` | Show everything |
|
||||
| `off` | Disable debug |
|
||||
|
||||
## Behavior Commands
|
||||
|
||||
### /npc role
|
||||
|
||||
Changes NPC role:
|
||||
|
||||
```
|
||||
/npc role <target> <role>
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc role @nearest guard_role
|
||||
/npc role @e[type=villager] merchant_role
|
||||
```
|
||||
|
||||
### /npc state
|
||||
|
||||
Forces NPC state:
|
||||
|
||||
```
|
||||
/npc state <target> <state>
|
||||
```
|
||||
|
||||
**States:**
|
||||
```
|
||||
/npc state @nearest IDLE
|
||||
/npc state @nearest ATTACKING
|
||||
/npc state @nearest FLEEING
|
||||
```
|
||||
|
||||
### /npc target
|
||||
|
||||
Sets NPC target:
|
||||
|
||||
```
|
||||
/npc target <npc> <target_entity>
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc target @nearest @p
|
||||
/npc target guard_01 @e[type=zombie,limit=1]
|
||||
```
|
||||
|
||||
### /npc cleartarget
|
||||
|
||||
Clears NPC target:
|
||||
|
||||
```
|
||||
/npc cleartarget <target>
|
||||
```
|
||||
|
||||
## Movement Commands
|
||||
|
||||
### /npc moveto
|
||||
|
||||
Commands NPC to move to position:
|
||||
|
||||
```
|
||||
/npc moveto <target> <position>
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc moveto @nearest ~ ~ ~10
|
||||
/npc moveto guard_01 100 64 -200
|
||||
```
|
||||
|
||||
### /npc follow
|
||||
|
||||
Commands NPC to follow entity:
|
||||
|
||||
```
|
||||
/npc follow <npc> <target> [distance]
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc follow @nearest @p 3.0
|
||||
```
|
||||
|
||||
### /npc stop
|
||||
|
||||
Stops NPC movement:
|
||||
|
||||
```
|
||||
/npc stop <target>
|
||||
```
|
||||
|
||||
### /npc patrol
|
||||
|
||||
Sets patrol path:
|
||||
|
||||
```
|
||||
/npc patrol <target> <point1> <point2> [point3...]
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc patrol guard_01 0 64 0 10 64 0 10 64 10 0 64 10
|
||||
```
|
||||
|
||||
### /npc home
|
||||
|
||||
Sets NPC home position:
|
||||
|
||||
```
|
||||
/npc home <target> [position]
|
||||
```
|
||||
|
||||
## Blackboard Commands
|
||||
|
||||
### /npc blackboard get
|
||||
|
||||
Gets blackboard value:
|
||||
|
||||
```
|
||||
/npc blackboard get <target> <key>
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc blackboard get @nearest alert_level
|
||||
/npc blackboard get guard_01 home_position
|
||||
```
|
||||
|
||||
### /npc blackboard set
|
||||
|
||||
Sets blackboard value:
|
||||
|
||||
```
|
||||
/npc blackboard set <target> <key> <value>
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc blackboard set @nearest alert_level 1.0
|
||||
/npc blackboard set @nearest is_hostile true
|
||||
```
|
||||
|
||||
### /npc blackboard clear
|
||||
|
||||
Clears blackboard:
|
||||
|
||||
```
|
||||
/npc blackboard clear <target> [key]
|
||||
```
|
||||
|
||||
## AI Commands
|
||||
|
||||
### /npc think
|
||||
|
||||
Forces AI decision cycle:
|
||||
|
||||
```
|
||||
/npc think <target>
|
||||
```
|
||||
|
||||
### /npc instruction
|
||||
|
||||
Forces instruction:
|
||||
|
||||
```
|
||||
/npc instruction <target> <instruction>
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc instruction @nearest flee
|
||||
/npc instruction guard_01 attack
|
||||
```
|
||||
|
||||
### /npc sensor
|
||||
|
||||
Toggles sensor:
|
||||
|
||||
```
|
||||
/npc sensor <target> <sensor> <enabled>
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc sensor @nearest visual false
|
||||
/npc sensor @nearest audio true
|
||||
```
|
||||
|
||||
## Faction Commands
|
||||
|
||||
### /npc faction
|
||||
|
||||
Sets NPC faction:
|
||||
|
||||
```
|
||||
/npc faction <target> <faction>
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc faction @nearest town_guard
|
||||
/npc faction villager_01 merchants
|
||||
```
|
||||
|
||||
### /npc relation
|
||||
|
||||
Sets faction relation:
|
||||
|
||||
```
|
||||
/npc relation <faction1> <faction2> <relation>
|
||||
```
|
||||
|
||||
**Relations:** `ALLIED`, `FRIENDLY`, `NEUTRAL`, `UNFRIENDLY`, `HOSTILE`
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/npc relation guards bandits HOSTILE
|
||||
/npc relation merchants town_guard ALLIED
|
||||
```
|
||||
|
||||
## Command Permissions
|
||||
|
||||
| Command | Permission |
|
||||
|---------|------------|
|
||||
| `/npc spawn` | `hytale.command.npc.spawn` |
|
||||
| `/npc despawn` | `hytale.command.npc.despawn` |
|
||||
| `/npc info` | `hytale.command.npc.info` |
|
||||
| `/npc debug` | `hytale.command.npc.debug` |
|
||||
| `/npc role` | `hytale.command.npc.role` |
|
||||
| `/npc blackboard` | `hytale.command.npc.blackboard` |
|
||||
|
||||
## Registering Custom NPC Commands
|
||||
|
||||
```java
|
||||
public class MyNPCCommand extends AbstractCommand {
|
||||
public MyNPCCommand() {
|
||||
super("npc custom", "Custom NPC command");
|
||||
withRequiredArg("target", "Target NPC", ArgTypes.NPC_REF);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<Void> execute(CommandContext ctx) {
|
||||
NPCEntity npc = ctx.get("target");
|
||||
// Custom logic
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Register in plugin setup
|
||||
getCommandRegistry().register(new MyNPCCommand());
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Command Guidelines:**
|
||||
- Use selectors like `@nearest` for targeting NPCs
|
||||
- Debug commands are invaluable for testing AI
|
||||
- Blackboard commands allow runtime behavior modification
|
||||
- Use permission checks for admin commands
|
||||
{{< /callout >}}
|
||||
374
content/world/entities/npc/npc-commands.fr.md
Normal file
374
content/world/entities/npc/npc-commands.fr.md
Normal file
@@ -0,0 +1,374 @@
|
||||
---
|
||||
title: Commandes NPC
|
||||
type: docs
|
||||
weight: 5
|
||||
---
|
||||
|
||||
Le système NPC inclut 23 commandes admin et debug pour gérer et tester les NPCs.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.npc.commands`
|
||||
|
||||
## Commandes de Spawn
|
||||
|
||||
### /npc spawn
|
||||
|
||||
Fait apparaître un NPC à une position :
|
||||
|
||||
```
|
||||
/npc spawn <npc_type> [position] [--role <role>] [--name <name>]
|
||||
```
|
||||
|
||||
**Arguments :**
|
||||
| Argument | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `npc_type` | String | ID d'asset NPC |
|
||||
| `position` | Position | Position de spawn (défaut: position du joueur) |
|
||||
| `--role` | String | Remplacer le rôle par défaut |
|
||||
| `--name` | String | Nom d'affichage personnalisé |
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc spawn villager
|
||||
/npc spawn guard ~ ~1 ~ --role patrol_guard
|
||||
/npc spawn merchant --name "Bob le Marchand"
|
||||
```
|
||||
|
||||
### /npc despawn
|
||||
|
||||
Supprime un NPC :
|
||||
|
||||
```
|
||||
/npc despawn <target>
|
||||
```
|
||||
|
||||
**Arguments :**
|
||||
| Argument | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `target` | NPC | NPC cible (raycast ou sélecteur) |
|
||||
|
||||
### /npc despawnall
|
||||
|
||||
Supprime tous les NPCs dans un rayon :
|
||||
|
||||
```
|
||||
/npc despawnall [radius]
|
||||
```
|
||||
|
||||
**Arguments :**
|
||||
| Argument | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `radius` | Float | Rayon en blocs (défaut: 50) |
|
||||
|
||||
## Commandes d'Information
|
||||
|
||||
### /npc info
|
||||
|
||||
Affiche les informations d'un NPC :
|
||||
|
||||
```
|
||||
/npc info [target]
|
||||
```
|
||||
|
||||
**Sortie :**
|
||||
```
|
||||
NPC Info: Villageois (villager_001)
|
||||
Position: 100.5, 64.0, -200.3
|
||||
Role: villager_role
|
||||
State: IDLE
|
||||
Health: 100/100
|
||||
Target: None
|
||||
Current Instruction: Wander
|
||||
```
|
||||
|
||||
### /npc list
|
||||
|
||||
Liste tous les NPCs :
|
||||
|
||||
```
|
||||
/npc list [--radius <radius>] [--type <type>]
|
||||
```
|
||||
|
||||
**Arguments :**
|
||||
| Argument | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `--radius` | Float | Rayon de recherche |
|
||||
| `--type` | String | Filtrer par type de NPC |
|
||||
|
||||
### /npc debug
|
||||
|
||||
Active/désactive la visualisation debug :
|
||||
|
||||
```
|
||||
/npc debug <mode>
|
||||
```
|
||||
|
||||
**Modes :**
|
||||
| Mode | Description |
|
||||
|------|-------------|
|
||||
| `path` | Afficher le pathfinding |
|
||||
| `sensors` | Afficher les portées des capteurs |
|
||||
| `state` | Afficher l'état IA |
|
||||
| `target` | Afficher le ciblage |
|
||||
| `all` | Tout afficher |
|
||||
| `off` | Désactiver le debug |
|
||||
|
||||
## Commandes de Comportement
|
||||
|
||||
### /npc role
|
||||
|
||||
Change le rôle du NPC :
|
||||
|
||||
```
|
||||
/npc role <target> <role>
|
||||
```
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc role @nearest guard_role
|
||||
/npc role @e[type=villager] merchant_role
|
||||
```
|
||||
|
||||
### /npc state
|
||||
|
||||
Force l'état du NPC :
|
||||
|
||||
```
|
||||
/npc state <target> <state>
|
||||
```
|
||||
|
||||
**États :**
|
||||
```
|
||||
/npc state @nearest IDLE
|
||||
/npc state @nearest ATTACKING
|
||||
/npc state @nearest FLEEING
|
||||
```
|
||||
|
||||
### /npc target
|
||||
|
||||
Définit la cible du NPC :
|
||||
|
||||
```
|
||||
/npc target <npc> <target_entity>
|
||||
```
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc target @nearest @p
|
||||
/npc target guard_01 @e[type=zombie,limit=1]
|
||||
```
|
||||
|
||||
### /npc cleartarget
|
||||
|
||||
Efface la cible du NPC :
|
||||
|
||||
```
|
||||
/npc cleartarget <target>
|
||||
```
|
||||
|
||||
## Commandes de Mouvement
|
||||
|
||||
### /npc moveto
|
||||
|
||||
Ordonne au NPC de se déplacer vers une position :
|
||||
|
||||
```
|
||||
/npc moveto <target> <position>
|
||||
```
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc moveto @nearest ~ ~ ~10
|
||||
/npc moveto guard_01 100 64 -200
|
||||
```
|
||||
|
||||
### /npc follow
|
||||
|
||||
Ordonne au NPC de suivre une entité :
|
||||
|
||||
```
|
||||
/npc follow <npc> <target> [distance]
|
||||
```
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc follow @nearest @p 3.0
|
||||
```
|
||||
|
||||
### /npc stop
|
||||
|
||||
Arrête le mouvement du NPC :
|
||||
|
||||
```
|
||||
/npc stop <target>
|
||||
```
|
||||
|
||||
### /npc patrol
|
||||
|
||||
Définit un chemin de patrouille :
|
||||
|
||||
```
|
||||
/npc patrol <target> <point1> <point2> [point3...]
|
||||
```
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc patrol guard_01 0 64 0 10 64 0 10 64 10 0 64 10
|
||||
```
|
||||
|
||||
### /npc home
|
||||
|
||||
Définit la position d'origine du NPC :
|
||||
|
||||
```
|
||||
/npc home <target> [position]
|
||||
```
|
||||
|
||||
## Commandes Blackboard
|
||||
|
||||
### /npc blackboard get
|
||||
|
||||
Obtient une valeur du blackboard :
|
||||
|
||||
```
|
||||
/npc blackboard get <target> <key>
|
||||
```
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc blackboard get @nearest alert_level
|
||||
/npc blackboard get guard_01 home_position
|
||||
```
|
||||
|
||||
### /npc blackboard set
|
||||
|
||||
Définit une valeur du blackboard :
|
||||
|
||||
```
|
||||
/npc blackboard set <target> <key> <value>
|
||||
```
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc blackboard set @nearest alert_level 1.0
|
||||
/npc blackboard set @nearest is_hostile true
|
||||
```
|
||||
|
||||
### /npc blackboard clear
|
||||
|
||||
Efface le blackboard :
|
||||
|
||||
```
|
||||
/npc blackboard clear <target> [key]
|
||||
```
|
||||
|
||||
## Commandes IA
|
||||
|
||||
### /npc think
|
||||
|
||||
Force un cycle de décision IA :
|
||||
|
||||
```
|
||||
/npc think <target>
|
||||
```
|
||||
|
||||
### /npc instruction
|
||||
|
||||
Force une instruction :
|
||||
|
||||
```
|
||||
/npc instruction <target> <instruction>
|
||||
```
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc instruction @nearest flee
|
||||
/npc instruction guard_01 attack
|
||||
```
|
||||
|
||||
### /npc sensor
|
||||
|
||||
Active/désactive un capteur :
|
||||
|
||||
```
|
||||
/npc sensor <target> <sensor> <enabled>
|
||||
```
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc sensor @nearest visual false
|
||||
/npc sensor @nearest audio true
|
||||
```
|
||||
|
||||
## Commandes de Faction
|
||||
|
||||
### /npc faction
|
||||
|
||||
Définit la faction du NPC :
|
||||
|
||||
```
|
||||
/npc faction <target> <faction>
|
||||
```
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc faction @nearest town_guard
|
||||
/npc faction villager_01 merchants
|
||||
```
|
||||
|
||||
### /npc relation
|
||||
|
||||
Définit la relation entre factions :
|
||||
|
||||
```
|
||||
/npc relation <faction1> <faction2> <relation>
|
||||
```
|
||||
|
||||
**Relations :** `ALLIED`, `FRIENDLY`, `NEUTRAL`, `UNFRIENDLY`, `HOSTILE`
|
||||
|
||||
**Exemples :**
|
||||
```
|
||||
/npc relation guards bandits HOSTILE
|
||||
/npc relation merchants town_guard ALLIED
|
||||
```
|
||||
|
||||
## Permissions des Commandes
|
||||
|
||||
| Commande | Permission |
|
||||
|----------|------------|
|
||||
| `/npc spawn` | `hytale.command.npc.spawn` |
|
||||
| `/npc despawn` | `hytale.command.npc.despawn` |
|
||||
| `/npc info` | `hytale.command.npc.info` |
|
||||
| `/npc debug` | `hytale.command.npc.debug` |
|
||||
| `/npc role` | `hytale.command.npc.role` |
|
||||
| `/npc blackboard` | `hytale.command.npc.blackboard` |
|
||||
|
||||
## Enregistrer des Commandes NPC Personnalisées
|
||||
|
||||
```java
|
||||
public class MyNPCCommand extends AbstractCommand {
|
||||
public MyNPCCommand() {
|
||||
super("npc custom", "Commande NPC personnalisée");
|
||||
withRequiredArg("target", "NPC cible", ArgTypes.NPC_REF);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<Void> execute(CommandContext ctx) {
|
||||
NPCEntity npc = ctx.get("target");
|
||||
// Logique personnalisée
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Enregistrer dans le setup du plugin
|
||||
getCommandRegistry().register(new MyNPCCommand());
|
||||
```
|
||||
|
||||
## Bonnes Pratiques
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Directives des Commandes :**
|
||||
- Utilisez des sélecteurs comme `@nearest` pour cibler les NPCs
|
||||
- Les commandes debug sont précieuses pour tester l'IA
|
||||
- Les commandes blackboard permettent la modification du comportement à l'exécution
|
||||
- Utilisez les vérifications de permissions pour les commandes admin
|
||||
{{< /callout >}}
|
||||
348
content/world/entities/npc/npc-components.en.md
Normal file
348
content/world/entities/npc/npc-components.en.md
Normal file
@@ -0,0 +1,348 @@
|
||||
---
|
||||
title: NPC Components
|
||||
type: docs
|
||||
weight: 2
|
||||
---
|
||||
|
||||
NPC components are ECS components that store data and state for NPCs. The system includes over 300 core components for various NPC functionalities.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.npc.corecomponents`
|
||||
|
||||
## Core Components Overview
|
||||
|
||||
NPC components follow the ECS pattern where components are pure data containers attached to entity stores.
|
||||
|
||||
```java
|
||||
// Access NPC components
|
||||
EntityStore store = npc.getEntityStore();
|
||||
NPCBrainComponent brain = store.getComponent(NPCBrainComponent.class);
|
||||
```
|
||||
|
||||
## Brain Components
|
||||
|
||||
### NPCBrainComponent
|
||||
|
||||
The main AI processing component:
|
||||
|
||||
```java
|
||||
public class NPCBrainComponent {
|
||||
private DecisionMaker decisionMaker;
|
||||
private float thinkInterval;
|
||||
private float lastThinkTime;
|
||||
|
||||
public void setDecisionMaker(DecisionMaker maker);
|
||||
public DecisionMaker getDecisionMaker();
|
||||
public boolean shouldThink(float currentTime);
|
||||
}
|
||||
```
|
||||
|
||||
### NPCMemoryComponent
|
||||
|
||||
Stores NPC memories and knowledge:
|
||||
|
||||
```java
|
||||
public class NPCMemoryComponent {
|
||||
private Map<String, Memory> memories;
|
||||
private float memoryDuration;
|
||||
|
||||
public void remember(String key, Object value, float duration);
|
||||
public <T> T recall(String key, Class<T> type);
|
||||
public boolean hasMemory(String key);
|
||||
public void forget(String key);
|
||||
}
|
||||
```
|
||||
|
||||
## State Components
|
||||
|
||||
### NPCStateComponent
|
||||
|
||||
Current behavioral state:
|
||||
|
||||
```java
|
||||
public class NPCStateComponent {
|
||||
private NPCState currentState;
|
||||
private NPCState previousState;
|
||||
private float stateEnterTime;
|
||||
|
||||
public enum NPCState {
|
||||
IDLE,
|
||||
WALKING,
|
||||
RUNNING,
|
||||
ATTACKING,
|
||||
FLEEING,
|
||||
INTERACTING,
|
||||
SLEEPING,
|
||||
DEAD
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### NPCAlertComponent
|
||||
|
||||
Alertness and awareness level:
|
||||
|
||||
```java
|
||||
public class NPCAlertComponent {
|
||||
private AlertLevel alertLevel;
|
||||
private float alertDecayRate;
|
||||
private Entity alertSource;
|
||||
|
||||
public enum AlertLevel {
|
||||
RELAXED, // Normal state
|
||||
CURIOUS, // Something caught attention
|
||||
ALERT, // Actively investigating
|
||||
ALARMED, // Threat detected
|
||||
COMBAT // In combat
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Target Components
|
||||
|
||||
### NPCTargetComponent
|
||||
|
||||
Current target tracking:
|
||||
|
||||
```java
|
||||
public class NPCTargetComponent {
|
||||
private Ref<EntityStore> currentTarget;
|
||||
private TargetType targetType;
|
||||
private float targetAcquiredTime;
|
||||
private Vector3d lastKnownPosition;
|
||||
|
||||
public enum TargetType {
|
||||
HOSTILE,
|
||||
FRIENDLY,
|
||||
NEUTRAL,
|
||||
OBJECT
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### NPCFocusComponent
|
||||
|
||||
Visual focus point:
|
||||
|
||||
```java
|
||||
public class NPCFocusComponent {
|
||||
private Vector3d focusPoint;
|
||||
private Ref<EntityStore> focusEntity;
|
||||
private float focusStrength;
|
||||
private boolean shouldLookAt;
|
||||
}
|
||||
```
|
||||
|
||||
## Movement Components
|
||||
|
||||
### NPCMovementComponent
|
||||
|
||||
Movement configuration:
|
||||
|
||||
```java
|
||||
public class NPCMovementComponent {
|
||||
private float walkSpeed;
|
||||
private float runSpeed;
|
||||
private float turnSpeed;
|
||||
private boolean canJump;
|
||||
private boolean canSwim;
|
||||
private boolean canClimb;
|
||||
}
|
||||
```
|
||||
|
||||
### NPCPathComponent
|
||||
|
||||
Path following data:
|
||||
|
||||
```java
|
||||
public class NPCPathComponent {
|
||||
private List<Vector3d> currentPath;
|
||||
private int currentWaypointIndex;
|
||||
private float pathRecalculateInterval;
|
||||
private float lastPathTime;
|
||||
|
||||
public Vector3d getCurrentWaypoint();
|
||||
public Vector3d getNextWaypoint();
|
||||
public boolean hasReachedWaypoint(Vector3d position, float threshold);
|
||||
}
|
||||
```
|
||||
|
||||
### NPCNavigationComponent
|
||||
|
||||
Navigation settings:
|
||||
|
||||
```java
|
||||
public class NPCNavigationComponent {
|
||||
private float avoidanceRadius;
|
||||
private float pathfindingRange;
|
||||
private int maxPathLength;
|
||||
private NavigationFlags flags;
|
||||
|
||||
public static class NavigationFlags {
|
||||
public boolean avoidWater;
|
||||
public boolean avoidFire;
|
||||
public boolean canUseDoors;
|
||||
public boolean canBreakBlocks;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Combat Components
|
||||
|
||||
### NPCCombatComponent
|
||||
|
||||
Combat capabilities:
|
||||
|
||||
```java
|
||||
public class NPCCombatComponent {
|
||||
private float attackRange;
|
||||
private float attackCooldown;
|
||||
private float lastAttackTime;
|
||||
private DamageType preferredDamageType;
|
||||
private List<String> availableAttacks;
|
||||
}
|
||||
```
|
||||
|
||||
### NPCAggroComponent
|
||||
|
||||
Aggression management:
|
||||
|
||||
```java
|
||||
public class NPCAggroComponent {
|
||||
private Map<Ref<EntityStore>, Float> aggroTable;
|
||||
private float aggroDecayRate;
|
||||
private float aggroRange;
|
||||
|
||||
public void addAggro(Ref<EntityStore> entity, float amount);
|
||||
public void removeAggro(Ref<EntityStore> entity);
|
||||
public Ref<EntityStore> getHighestAggroTarget();
|
||||
}
|
||||
```
|
||||
|
||||
## Social Components
|
||||
|
||||
### NPCFactionComponent
|
||||
|
||||
Faction affiliation:
|
||||
|
||||
```java
|
||||
public class NPCFactionComponent {
|
||||
private String factionId;
|
||||
private Map<String, FactionRelation> relations;
|
||||
|
||||
public enum FactionRelation {
|
||||
ALLIED,
|
||||
FRIENDLY,
|
||||
NEUTRAL,
|
||||
UNFRIENDLY,
|
||||
HOSTILE
|
||||
}
|
||||
|
||||
public FactionRelation getRelation(String otherFaction);
|
||||
}
|
||||
```
|
||||
|
||||
### NPCDialogueComponent
|
||||
|
||||
Dialogue capabilities:
|
||||
|
||||
```java
|
||||
public class NPCDialogueComponent {
|
||||
private String dialogueTreeId;
|
||||
private Map<String, Boolean> dialogueFlags;
|
||||
private Ref<EntityStore> currentSpeaker;
|
||||
|
||||
public boolean hasDialogue();
|
||||
public void startDialogue(Player player);
|
||||
}
|
||||
```
|
||||
|
||||
## Utility Components
|
||||
|
||||
### NPCScheduleComponent
|
||||
|
||||
Daily schedule:
|
||||
|
||||
```java
|
||||
public class NPCScheduleComponent {
|
||||
private Map<Integer, ScheduleEntry> schedule;
|
||||
|
||||
public static class ScheduleEntry {
|
||||
public int startHour;
|
||||
public int endHour;
|
||||
public String activity;
|
||||
public Vector3d location;
|
||||
}
|
||||
|
||||
public ScheduleEntry getCurrentActivity(int worldHour);
|
||||
}
|
||||
```
|
||||
|
||||
### NPCInventoryComponent
|
||||
|
||||
NPC inventory:
|
||||
|
||||
```java
|
||||
public class NPCInventoryComponent {
|
||||
private ItemContainer inventory;
|
||||
private ItemStack equippedWeapon;
|
||||
private ItemStack equippedArmor;
|
||||
|
||||
public ItemStack getEquippedWeapon();
|
||||
public void equipItem(ItemStack item);
|
||||
}
|
||||
```
|
||||
|
||||
## Registering Custom Components
|
||||
|
||||
```java
|
||||
public class MyPlugin extends JavaPlugin {
|
||||
@Override
|
||||
public void start() {
|
||||
// Register custom NPC component
|
||||
getEntityStoreRegistry().registerComponent(
|
||||
"custom_npc_data",
|
||||
CustomNPCComponent.class,
|
||||
CustomNPCComponent::new
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public class CustomNPCComponent {
|
||||
private String customData;
|
||||
private int customValue;
|
||||
|
||||
// Component data fields
|
||||
}
|
||||
```
|
||||
|
||||
## Component Access Patterns
|
||||
|
||||
```java
|
||||
// Safe component access
|
||||
public void processNPC(NPCEntity npc) {
|
||||
EntityStore store = npc.getEntityStore();
|
||||
|
||||
// Check if component exists
|
||||
if (store.hasComponent(NPCCombatComponent.class)) {
|
||||
NPCCombatComponent combat = store.getComponent(NPCCombatComponent.class);
|
||||
// Process combat logic
|
||||
}
|
||||
|
||||
// Get or create component
|
||||
NPCStateComponent state = store.getOrCreateComponent(
|
||||
NPCStateComponent.class,
|
||||
NPCStateComponent::new
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Component Guidelines:**
|
||||
- Components should be pure data - no complex logic
|
||||
- Use components for state that needs to persist
|
||||
- Access components through EntityStore, not directly
|
||||
- Check component existence before access
|
||||
- Use appropriate component for each type of data
|
||||
{{< /callout >}}
|
||||
348
content/world/entities/npc/npc-components.fr.md
Normal file
348
content/world/entities/npc/npc-components.fr.md
Normal file
@@ -0,0 +1,348 @@
|
||||
---
|
||||
title: Composants NPC
|
||||
type: docs
|
||||
weight: 2
|
||||
---
|
||||
|
||||
Les composants NPC sont des composants ECS qui stockent les données et l'état des NPCs. Le système inclut plus de 300 composants de base pour diverses fonctionnalités NPC.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.npc.corecomponents`
|
||||
|
||||
## Vue d'Ensemble des Composants
|
||||
|
||||
Les composants NPC suivent le pattern ECS où les composants sont des conteneurs de données pures attachés aux entity stores.
|
||||
|
||||
```java
|
||||
// Accéder aux composants NPC
|
||||
EntityStore store = npc.getEntityStore();
|
||||
NPCBrainComponent brain = store.getComponent(NPCBrainComponent.class);
|
||||
```
|
||||
|
||||
## Composants Cerveau
|
||||
|
||||
### NPCBrainComponent
|
||||
|
||||
Le composant principal de traitement IA :
|
||||
|
||||
```java
|
||||
public class NPCBrainComponent {
|
||||
private DecisionMaker decisionMaker;
|
||||
private float thinkInterval;
|
||||
private float lastThinkTime;
|
||||
|
||||
public void setDecisionMaker(DecisionMaker maker);
|
||||
public DecisionMaker getDecisionMaker();
|
||||
public boolean shouldThink(float currentTime);
|
||||
}
|
||||
```
|
||||
|
||||
### NPCMemoryComponent
|
||||
|
||||
Stocke les mémoires et connaissances du NPC :
|
||||
|
||||
```java
|
||||
public class NPCMemoryComponent {
|
||||
private Map<String, Memory> memories;
|
||||
private float memoryDuration;
|
||||
|
||||
public void remember(String key, Object value, float duration);
|
||||
public <T> T recall(String key, Class<T> type);
|
||||
public boolean hasMemory(String key);
|
||||
public void forget(String key);
|
||||
}
|
||||
```
|
||||
|
||||
## Composants d'État
|
||||
|
||||
### NPCStateComponent
|
||||
|
||||
État comportemental actuel :
|
||||
|
||||
```java
|
||||
public class NPCStateComponent {
|
||||
private NPCState currentState;
|
||||
private NPCState previousState;
|
||||
private float stateEnterTime;
|
||||
|
||||
public enum NPCState {
|
||||
IDLE,
|
||||
WALKING,
|
||||
RUNNING,
|
||||
ATTACKING,
|
||||
FLEEING,
|
||||
INTERACTING,
|
||||
SLEEPING,
|
||||
DEAD
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### NPCAlertComponent
|
||||
|
||||
Niveau de vigilance et de conscience :
|
||||
|
||||
```java
|
||||
public class NPCAlertComponent {
|
||||
private AlertLevel alertLevel;
|
||||
private float alertDecayRate;
|
||||
private Entity alertSource;
|
||||
|
||||
public enum AlertLevel {
|
||||
RELAXED, // État normal
|
||||
CURIOUS, // Quelque chose a attiré l'attention
|
||||
ALERT, // Investigation active
|
||||
ALARMED, // Menace détectée
|
||||
COMBAT // En combat
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Composants de Cible
|
||||
|
||||
### NPCTargetComponent
|
||||
|
||||
Suivi de cible actuel :
|
||||
|
||||
```java
|
||||
public class NPCTargetComponent {
|
||||
private Ref<EntityStore> currentTarget;
|
||||
private TargetType targetType;
|
||||
private float targetAcquiredTime;
|
||||
private Vector3d lastKnownPosition;
|
||||
|
||||
public enum TargetType {
|
||||
HOSTILE,
|
||||
FRIENDLY,
|
||||
NEUTRAL,
|
||||
OBJECT
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### NPCFocusComponent
|
||||
|
||||
Point de focus visuel :
|
||||
|
||||
```java
|
||||
public class NPCFocusComponent {
|
||||
private Vector3d focusPoint;
|
||||
private Ref<EntityStore> focusEntity;
|
||||
private float focusStrength;
|
||||
private boolean shouldLookAt;
|
||||
}
|
||||
```
|
||||
|
||||
## Composants de Mouvement
|
||||
|
||||
### NPCMovementComponent
|
||||
|
||||
Configuration de mouvement :
|
||||
|
||||
```java
|
||||
public class NPCMovementComponent {
|
||||
private float walkSpeed;
|
||||
private float runSpeed;
|
||||
private float turnSpeed;
|
||||
private boolean canJump;
|
||||
private boolean canSwim;
|
||||
private boolean canClimb;
|
||||
}
|
||||
```
|
||||
|
||||
### NPCPathComponent
|
||||
|
||||
Données de suivi de chemin :
|
||||
|
||||
```java
|
||||
public class NPCPathComponent {
|
||||
private List<Vector3d> currentPath;
|
||||
private int currentWaypointIndex;
|
||||
private float pathRecalculateInterval;
|
||||
private float lastPathTime;
|
||||
|
||||
public Vector3d getCurrentWaypoint();
|
||||
public Vector3d getNextWaypoint();
|
||||
public boolean hasReachedWaypoint(Vector3d position, float threshold);
|
||||
}
|
||||
```
|
||||
|
||||
### NPCNavigationComponent
|
||||
|
||||
Paramètres de navigation :
|
||||
|
||||
```java
|
||||
public class NPCNavigationComponent {
|
||||
private float avoidanceRadius;
|
||||
private float pathfindingRange;
|
||||
private int maxPathLength;
|
||||
private NavigationFlags flags;
|
||||
|
||||
public static class NavigationFlags {
|
||||
public boolean avoidWater;
|
||||
public boolean avoidFire;
|
||||
public boolean canUseDoors;
|
||||
public boolean canBreakBlocks;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Composants de Combat
|
||||
|
||||
### NPCCombatComponent
|
||||
|
||||
Capacités de combat :
|
||||
|
||||
```java
|
||||
public class NPCCombatComponent {
|
||||
private float attackRange;
|
||||
private float attackCooldown;
|
||||
private float lastAttackTime;
|
||||
private DamageType preferredDamageType;
|
||||
private List<String> availableAttacks;
|
||||
}
|
||||
```
|
||||
|
||||
### NPCAggroComponent
|
||||
|
||||
Gestion de l'aggro :
|
||||
|
||||
```java
|
||||
public class NPCAggroComponent {
|
||||
private Map<Ref<EntityStore>, Float> aggroTable;
|
||||
private float aggroDecayRate;
|
||||
private float aggroRange;
|
||||
|
||||
public void addAggro(Ref<EntityStore> entity, float amount);
|
||||
public void removeAggro(Ref<EntityStore> entity);
|
||||
public Ref<EntityStore> getHighestAggroTarget();
|
||||
}
|
||||
```
|
||||
|
||||
## Composants Sociaux
|
||||
|
||||
### NPCFactionComponent
|
||||
|
||||
Affiliation de faction :
|
||||
|
||||
```java
|
||||
public class NPCFactionComponent {
|
||||
private String factionId;
|
||||
private Map<String, FactionRelation> relations;
|
||||
|
||||
public enum FactionRelation {
|
||||
ALLIED,
|
||||
FRIENDLY,
|
||||
NEUTRAL,
|
||||
UNFRIENDLY,
|
||||
HOSTILE
|
||||
}
|
||||
|
||||
public FactionRelation getRelation(String otherFaction);
|
||||
}
|
||||
```
|
||||
|
||||
### NPCDialogueComponent
|
||||
|
||||
Capacités de dialogue :
|
||||
|
||||
```java
|
||||
public class NPCDialogueComponent {
|
||||
private String dialogueTreeId;
|
||||
private Map<String, Boolean> dialogueFlags;
|
||||
private Ref<EntityStore> currentSpeaker;
|
||||
|
||||
public boolean hasDialogue();
|
||||
public void startDialogue(Player player);
|
||||
}
|
||||
```
|
||||
|
||||
## Composants Utilitaires
|
||||
|
||||
### NPCScheduleComponent
|
||||
|
||||
Programme journalier :
|
||||
|
||||
```java
|
||||
public class NPCScheduleComponent {
|
||||
private Map<Integer, ScheduleEntry> schedule;
|
||||
|
||||
public static class ScheduleEntry {
|
||||
public int startHour;
|
||||
public int endHour;
|
||||
public String activity;
|
||||
public Vector3d location;
|
||||
}
|
||||
|
||||
public ScheduleEntry getCurrentActivity(int worldHour);
|
||||
}
|
||||
```
|
||||
|
||||
### NPCInventoryComponent
|
||||
|
||||
Inventaire NPC :
|
||||
|
||||
```java
|
||||
public class NPCInventoryComponent {
|
||||
private ItemContainer inventory;
|
||||
private ItemStack equippedWeapon;
|
||||
private ItemStack equippedArmor;
|
||||
|
||||
public ItemStack getEquippedWeapon();
|
||||
public void equipItem(ItemStack item);
|
||||
}
|
||||
```
|
||||
|
||||
## Enregistrer des Composants Personnalisés
|
||||
|
||||
```java
|
||||
public class MyPlugin extends JavaPlugin {
|
||||
@Override
|
||||
public void start() {
|
||||
// Enregistrer un composant NPC personnalisé
|
||||
getEntityStoreRegistry().registerComponent(
|
||||
"custom_npc_data",
|
||||
CustomNPCComponent.class,
|
||||
CustomNPCComponent::new
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public class CustomNPCComponent {
|
||||
private String customData;
|
||||
private int customValue;
|
||||
|
||||
// Champs de données du composant
|
||||
}
|
||||
```
|
||||
|
||||
## Patterns d'Accès aux Composants
|
||||
|
||||
```java
|
||||
// Accès sécurisé aux composants
|
||||
public void processNPC(NPCEntity npc) {
|
||||
EntityStore store = npc.getEntityStore();
|
||||
|
||||
// Vérifier si le composant existe
|
||||
if (store.hasComponent(NPCCombatComponent.class)) {
|
||||
NPCCombatComponent combat = store.getComponent(NPCCombatComponent.class);
|
||||
// Traiter la logique de combat
|
||||
}
|
||||
|
||||
// Obtenir ou créer un composant
|
||||
NPCStateComponent state = store.getOrCreateComponent(
|
||||
NPCStateComponent.class,
|
||||
NPCStateComponent::new
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Bonnes Pratiques
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Directives des Composants :**
|
||||
- Les composants doivent être des données pures - pas de logique complexe
|
||||
- Utilisez les composants pour l'état qui doit persister
|
||||
- Accédez aux composants via EntityStore, pas directement
|
||||
- Vérifiez l'existence du composant avant l'accès
|
||||
- Utilisez le composant approprié pour chaque type de données
|
||||
{{< /callout >}}
|
||||
365
content/world/entities/npc/npc-movement.en.md
Normal file
365
content/world/entities/npc/npc-movement.en.md
Normal file
@@ -0,0 +1,365 @@
|
||||
---
|
||||
title: NPC Movement
|
||||
type: docs
|
||||
weight: 4
|
||||
---
|
||||
|
||||
The NPC movement system handles navigation, pathfinding, and motion control for NPCs.
|
||||
|
||||
**Packages:**
|
||||
- `com.hypixel.hytale.server.npc.movement`
|
||||
- `com.hypixel.hytale.server.npc.navigation`
|
||||
|
||||
## Motion Controller
|
||||
|
||||
The `MotionController` executes movement commands and manages NPC locomotion.
|
||||
|
||||
### MotionController Class
|
||||
|
||||
```java
|
||||
public class MotionController {
|
||||
private NPCEntity npc;
|
||||
private MovementState state;
|
||||
private float currentSpeed;
|
||||
private Vector3d targetVelocity;
|
||||
|
||||
// Movement commands
|
||||
public void moveTo(Vector3d target);
|
||||
public void moveInDirection(Vector3d direction);
|
||||
public void stop();
|
||||
|
||||
// Speed control
|
||||
public void setSpeed(float speed);
|
||||
public void walk();
|
||||
public void run();
|
||||
public void sprint();
|
||||
|
||||
// State queries
|
||||
public boolean isMoving();
|
||||
public boolean hasReachedTarget();
|
||||
public MovementState getState();
|
||||
}
|
||||
```
|
||||
|
||||
### Movement States
|
||||
|
||||
```java
|
||||
public enum MovementState {
|
||||
IDLE, // Not moving
|
||||
WALKING, // Normal movement
|
||||
RUNNING, // Fast movement
|
||||
SPRINTING, // Maximum speed
|
||||
JUMPING, // In air (jump)
|
||||
FALLING, // In air (fall)
|
||||
SWIMMING, // In water
|
||||
CLIMBING, // On ladder/vine
|
||||
SLIDING // On slope
|
||||
}
|
||||
```
|
||||
|
||||
### Using MotionController
|
||||
|
||||
```java
|
||||
NPCEntity npc = // get NPC
|
||||
MotionController motion = npc.getMotionController();
|
||||
|
||||
// Move to position
|
||||
motion.moveTo(targetPosition);
|
||||
|
||||
// Set movement speed
|
||||
motion.run(); // or motion.setSpeed(5.0f);
|
||||
|
||||
// Check if arrived
|
||||
if (motion.hasReachedTarget()) {
|
||||
// Destination reached
|
||||
}
|
||||
|
||||
// Stop movement
|
||||
motion.stop();
|
||||
```
|
||||
|
||||
## Path Follower
|
||||
|
||||
The `PathFollower` tracks and follows calculated paths.
|
||||
|
||||
### PathFollower Class
|
||||
|
||||
```java
|
||||
public class PathFollower {
|
||||
private List<Vector3d> path;
|
||||
private int currentIndex;
|
||||
private float waypointRadius;
|
||||
private boolean smoothPath;
|
||||
|
||||
// Path management
|
||||
public void setPath(List<Vector3d> path);
|
||||
public void clearPath();
|
||||
public boolean hasPath();
|
||||
|
||||
// Following
|
||||
public Vector3d getNextWaypoint();
|
||||
public void advanceToNextWaypoint();
|
||||
public boolean hasReachedWaypoint(Vector3d position);
|
||||
|
||||
// Progress
|
||||
public float getPathProgress(); // 0.0 to 1.0
|
||||
public int getRemainingWaypoints();
|
||||
}
|
||||
```
|
||||
|
||||
### Path Following Example
|
||||
|
||||
```java
|
||||
PathFollower pathFollower = npc.getPathFollower();
|
||||
MotionController motion = npc.getMotionController();
|
||||
|
||||
// Set a path
|
||||
pathFollower.setPath(calculatedPath);
|
||||
|
||||
// In update loop
|
||||
if (pathFollower.hasPath()) {
|
||||
Vector3d nextWaypoint = pathFollower.getNextWaypoint();
|
||||
|
||||
// Move towards waypoint
|
||||
motion.moveTo(nextWaypoint);
|
||||
|
||||
// Check if reached
|
||||
if (pathFollower.hasReachedWaypoint(npc.getPosition())) {
|
||||
pathFollower.advanceToNextWaypoint();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Navigation Graph
|
||||
|
||||
The navigation system uses A* pathfinding on a navigation graph.
|
||||
|
||||
### NavigationGraph Class
|
||||
|
||||
```java
|
||||
public class NavigationGraph {
|
||||
// Find path between points
|
||||
public List<Vector3d> findPath(
|
||||
Vector3d start,
|
||||
Vector3d end,
|
||||
NavigationConfig config
|
||||
);
|
||||
|
||||
// Check if point is navigable
|
||||
public boolean isNavigable(Vector3d position);
|
||||
|
||||
// Get nearest navigable point
|
||||
public Vector3d getNearestNavigablePoint(Vector3d position);
|
||||
}
|
||||
```
|
||||
|
||||
### NavigationConfig
|
||||
|
||||
```java
|
||||
public class NavigationConfig {
|
||||
private float maxDistance; // Maximum path length
|
||||
private float stepHeight; // Max step up height
|
||||
private float entityWidth; // Entity collision width
|
||||
private float entityHeight; // Entity collision height
|
||||
private boolean canSwim; // Allow water paths
|
||||
private boolean canClimb; // Allow ladder/vine paths
|
||||
private boolean canOpenDoors; // Allow door traversal
|
||||
private Set<String> avoidBlocks; // Blocks to avoid
|
||||
|
||||
// Builder pattern
|
||||
public static NavigationConfig builder()
|
||||
.maxDistance(100.0f)
|
||||
.stepHeight(1.0f)
|
||||
.entityWidth(0.6f)
|
||||
.entityHeight(1.8f)
|
||||
.canSwim(false)
|
||||
.build();
|
||||
}
|
||||
```
|
||||
|
||||
### Pathfinding Example
|
||||
|
||||
```java
|
||||
NavigationGraph navGraph = world.getNavigationGraph();
|
||||
|
||||
NavigationConfig config = NavigationConfig.builder()
|
||||
.maxDistance(50.0f)
|
||||
.canSwim(true)
|
||||
.build();
|
||||
|
||||
List<Vector3d> path = navGraph.findPath(
|
||||
npc.getPosition(),
|
||||
targetPosition,
|
||||
config
|
||||
);
|
||||
|
||||
if (path != null && !path.isEmpty()) {
|
||||
npc.getPathFollower().setPath(path);
|
||||
}
|
||||
```
|
||||
|
||||
## Movement Behaviors
|
||||
|
||||
Pre-built movement behaviors for common patterns.
|
||||
|
||||
### WanderBehavior
|
||||
|
||||
```java
|
||||
public class WanderBehavior {
|
||||
private float wanderRadius;
|
||||
private float minPauseDuration;
|
||||
private float maxPauseDuration;
|
||||
|
||||
public WanderBehavior(float radius) {
|
||||
this.wanderRadius = radius;
|
||||
}
|
||||
|
||||
public void update(NPCEntity npc, float deltaTime) {
|
||||
if (!npc.getMotionController().isMoving()) {
|
||||
Vector3d wanderTarget = calculateWanderTarget(npc);
|
||||
npc.getMotionController().moveTo(wanderTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### FollowBehavior
|
||||
|
||||
```java
|
||||
public class FollowBehavior {
|
||||
private Entity target;
|
||||
private float followDistance;
|
||||
private float catchUpDistance;
|
||||
|
||||
public void update(NPCEntity npc, float deltaTime) {
|
||||
float distance = npc.getPosition().distance(target.getPosition());
|
||||
|
||||
if (distance > catchUpDistance) {
|
||||
npc.getMotionController().run();
|
||||
} else if (distance > followDistance) {
|
||||
npc.getMotionController().walk();
|
||||
npc.getMotionController().moveTo(target.getPosition());
|
||||
} else {
|
||||
npc.getMotionController().stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PatrolBehavior
|
||||
|
||||
```java
|
||||
public class PatrolBehavior {
|
||||
private List<Vector3d> patrolPoints;
|
||||
private int currentPointIndex;
|
||||
private boolean loop;
|
||||
private float waitTimeAtPoint;
|
||||
|
||||
public void update(NPCEntity npc, float deltaTime) {
|
||||
Vector3d currentTarget = patrolPoints.get(currentPointIndex);
|
||||
MotionController motion = npc.getMotionController();
|
||||
|
||||
if (motion.hasReachedTarget()) {
|
||||
// Wait at point
|
||||
currentPointIndex = (currentPointIndex + 1) % patrolPoints.size();
|
||||
} else {
|
||||
motion.moveTo(currentTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### FleeBehavior
|
||||
|
||||
```java
|
||||
public class FleeBehavior {
|
||||
private float fleeDistance;
|
||||
private Entity threat;
|
||||
|
||||
public void update(NPCEntity npc, float deltaTime) {
|
||||
Vector3d awayFromThreat = npc.getPosition()
|
||||
.subtract(threat.getPosition())
|
||||
.normalize()
|
||||
.multiply(fleeDistance);
|
||||
|
||||
Vector3d fleeTarget = npc.getPosition().add(awayFromThreat);
|
||||
|
||||
npc.getMotionController().sprint();
|
||||
npc.getMotionController().moveTo(fleeTarget);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Obstacle Avoidance
|
||||
|
||||
```java
|
||||
public class ObstacleAvoidance {
|
||||
private float avoidanceRadius;
|
||||
private float lookAheadDistance;
|
||||
|
||||
public Vector3d calculateAvoidanceVector(
|
||||
NPCEntity npc,
|
||||
Vector3d desiredDirection
|
||||
) {
|
||||
// Cast rays to detect obstacles
|
||||
List<RaycastHit> obstacles = castAvoidanceRays(npc, desiredDirection);
|
||||
|
||||
if (obstacles.isEmpty()) {
|
||||
return desiredDirection;
|
||||
}
|
||||
|
||||
// Calculate avoidance steering
|
||||
Vector3d avoidance = Vector3d.ZERO;
|
||||
for (RaycastHit hit : obstacles) {
|
||||
Vector3d away = npc.getPosition().subtract(hit.position).normalize();
|
||||
avoidance = avoidance.add(away);
|
||||
}
|
||||
|
||||
return desiredDirection.add(avoidance.normalize()).normalize();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Movement Systems
|
||||
|
||||
ECS systems that process NPC movement:
|
||||
|
||||
```java
|
||||
// Movement update system
|
||||
public class NPCMovementSystem implements System {
|
||||
@Override
|
||||
public void update(float deltaTime) {
|
||||
for (NPCEntity npc : npcsWithMovement) {
|
||||
MotionController motion = npc.getMotionController();
|
||||
PathFollower path = npc.getPathFollower();
|
||||
|
||||
// Update path following
|
||||
if (path.hasPath()) {
|
||||
updatePathFollowing(npc, motion, path, deltaTime);
|
||||
}
|
||||
|
||||
// Apply movement
|
||||
motion.update(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Movement Guidelines:**
|
||||
- Use NavigationConfig appropriate for the NPC type
|
||||
- Cache paths when possible to avoid frequent recalculation
|
||||
- Use path smoothing for more natural movement
|
||||
- Consider entity size when pathfinding
|
||||
- Implement obstacle avoidance for dynamic environments
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Pathfinding Performance:**
|
||||
- Limit pathfinding requests per frame
|
||||
- Use shorter max distances when possible
|
||||
- Cache frequently used paths
|
||||
- Consider hierarchical pathfinding for large worlds
|
||||
{{< /callout >}}
|
||||
365
content/world/entities/npc/npc-movement.fr.md
Normal file
365
content/world/entities/npc/npc-movement.fr.md
Normal file
@@ -0,0 +1,365 @@
|
||||
---
|
||||
title: Mouvement NPC
|
||||
type: docs
|
||||
weight: 4
|
||||
---
|
||||
|
||||
Le système de mouvement NPC gère la navigation, le pathfinding et le contrôle de mouvement pour les NPCs.
|
||||
|
||||
**Packages:**
|
||||
- `com.hypixel.hytale.server.npc.movement`
|
||||
- `com.hypixel.hytale.server.npc.navigation`
|
||||
|
||||
## Motion Controller
|
||||
|
||||
Le `MotionController` exécute les commandes de mouvement et gère la locomotion des NPCs.
|
||||
|
||||
### Classe MotionController
|
||||
|
||||
```java
|
||||
public class MotionController {
|
||||
private NPCEntity npc;
|
||||
private MovementState state;
|
||||
private float currentSpeed;
|
||||
private Vector3d targetVelocity;
|
||||
|
||||
// Commandes de mouvement
|
||||
public void moveTo(Vector3d target);
|
||||
public void moveInDirection(Vector3d direction);
|
||||
public void stop();
|
||||
|
||||
// Contrôle de vitesse
|
||||
public void setSpeed(float speed);
|
||||
public void walk();
|
||||
public void run();
|
||||
public void sprint();
|
||||
|
||||
// Requêtes d'état
|
||||
public boolean isMoving();
|
||||
public boolean hasReachedTarget();
|
||||
public MovementState getState();
|
||||
}
|
||||
```
|
||||
|
||||
### États de Mouvement
|
||||
|
||||
```java
|
||||
public enum MovementState {
|
||||
IDLE, // Immobile
|
||||
WALKING, // Mouvement normal
|
||||
RUNNING, // Mouvement rapide
|
||||
SPRINTING, // Vitesse maximum
|
||||
JUMPING, // En l'air (saut)
|
||||
FALLING, // En l'air (chute)
|
||||
SWIMMING, // Dans l'eau
|
||||
CLIMBING, // Sur échelle/liane
|
||||
SLIDING // Sur pente
|
||||
}
|
||||
```
|
||||
|
||||
### Utiliser MotionController
|
||||
|
||||
```java
|
||||
NPCEntity npc = // obtenir le NPC
|
||||
MotionController motion = npc.getMotionController();
|
||||
|
||||
// Se déplacer vers une position
|
||||
motion.moveTo(targetPosition);
|
||||
|
||||
// Définir la vitesse de mouvement
|
||||
motion.run(); // ou motion.setSpeed(5.0f);
|
||||
|
||||
// Vérifier si arrivé
|
||||
if (motion.hasReachedTarget()) {
|
||||
// Destination atteinte
|
||||
}
|
||||
|
||||
// Arrêter le mouvement
|
||||
motion.stop();
|
||||
```
|
||||
|
||||
## Path Follower
|
||||
|
||||
Le `PathFollower` suit et parcourt les chemins calculés.
|
||||
|
||||
### Classe PathFollower
|
||||
|
||||
```java
|
||||
public class PathFollower {
|
||||
private List<Vector3d> path;
|
||||
private int currentIndex;
|
||||
private float waypointRadius;
|
||||
private boolean smoothPath;
|
||||
|
||||
// Gestion de chemin
|
||||
public void setPath(List<Vector3d> path);
|
||||
public void clearPath();
|
||||
public boolean hasPath();
|
||||
|
||||
// Suivi
|
||||
public Vector3d getNextWaypoint();
|
||||
public void advanceToNextWaypoint();
|
||||
public boolean hasReachedWaypoint(Vector3d position);
|
||||
|
||||
// Progression
|
||||
public float getPathProgress(); // 0.0 à 1.0
|
||||
public int getRemainingWaypoints();
|
||||
}
|
||||
```
|
||||
|
||||
### Exemple de Suivi de Chemin
|
||||
|
||||
```java
|
||||
PathFollower pathFollower = npc.getPathFollower();
|
||||
MotionController motion = npc.getMotionController();
|
||||
|
||||
// Définir un chemin
|
||||
pathFollower.setPath(calculatedPath);
|
||||
|
||||
// Dans la boucle de mise à jour
|
||||
if (pathFollower.hasPath()) {
|
||||
Vector3d nextWaypoint = pathFollower.getNextWaypoint();
|
||||
|
||||
// Se déplacer vers le waypoint
|
||||
motion.moveTo(nextWaypoint);
|
||||
|
||||
// Vérifier si atteint
|
||||
if (pathFollower.hasReachedWaypoint(npc.getPosition())) {
|
||||
pathFollower.advanceToNextWaypoint();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Navigation Graph
|
||||
|
||||
Le système de navigation utilise le pathfinding A* sur un graphe de navigation.
|
||||
|
||||
### Classe NavigationGraph
|
||||
|
||||
```java
|
||||
public class NavigationGraph {
|
||||
// Trouver un chemin entre deux points
|
||||
public List<Vector3d> findPath(
|
||||
Vector3d start,
|
||||
Vector3d end,
|
||||
NavigationConfig config
|
||||
);
|
||||
|
||||
// Vérifier si un point est navigable
|
||||
public boolean isNavigable(Vector3d position);
|
||||
|
||||
// Obtenir le point navigable le plus proche
|
||||
public Vector3d getNearestNavigablePoint(Vector3d position);
|
||||
}
|
||||
```
|
||||
|
||||
### NavigationConfig
|
||||
|
||||
```java
|
||||
public class NavigationConfig {
|
||||
private float maxDistance; // Longueur max du chemin
|
||||
private float stepHeight; // Hauteur max de marche
|
||||
private float entityWidth; // Largeur de collision entité
|
||||
private float entityHeight; // Hauteur de collision entité
|
||||
private boolean canSwim; // Autoriser chemins aquatiques
|
||||
private boolean canClimb; // Autoriser échelles/lianes
|
||||
private boolean canOpenDoors; // Autoriser traversée de portes
|
||||
private Set<String> avoidBlocks; // Blocs à éviter
|
||||
|
||||
// Pattern builder
|
||||
public static NavigationConfig builder()
|
||||
.maxDistance(100.0f)
|
||||
.stepHeight(1.0f)
|
||||
.entityWidth(0.6f)
|
||||
.entityHeight(1.8f)
|
||||
.canSwim(false)
|
||||
.build();
|
||||
}
|
||||
```
|
||||
|
||||
### Exemple de Pathfinding
|
||||
|
||||
```java
|
||||
NavigationGraph navGraph = world.getNavigationGraph();
|
||||
|
||||
NavigationConfig config = NavigationConfig.builder()
|
||||
.maxDistance(50.0f)
|
||||
.canSwim(true)
|
||||
.build();
|
||||
|
||||
List<Vector3d> path = navGraph.findPath(
|
||||
npc.getPosition(),
|
||||
targetPosition,
|
||||
config
|
||||
);
|
||||
|
||||
if (path != null && !path.isEmpty()) {
|
||||
npc.getPathFollower().setPath(path);
|
||||
}
|
||||
```
|
||||
|
||||
## Comportements de Mouvement
|
||||
|
||||
Comportements de mouvement pré-construits pour les patterns courants.
|
||||
|
||||
### WanderBehavior
|
||||
|
||||
```java
|
||||
public class WanderBehavior {
|
||||
private float wanderRadius;
|
||||
private float minPauseDuration;
|
||||
private float maxPauseDuration;
|
||||
|
||||
public WanderBehavior(float radius) {
|
||||
this.wanderRadius = radius;
|
||||
}
|
||||
|
||||
public void update(NPCEntity npc, float deltaTime) {
|
||||
if (!npc.getMotionController().isMoving()) {
|
||||
Vector3d wanderTarget = calculateWanderTarget(npc);
|
||||
npc.getMotionController().moveTo(wanderTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### FollowBehavior
|
||||
|
||||
```java
|
||||
public class FollowBehavior {
|
||||
private Entity target;
|
||||
private float followDistance;
|
||||
private float catchUpDistance;
|
||||
|
||||
public void update(NPCEntity npc, float deltaTime) {
|
||||
float distance = npc.getPosition().distance(target.getPosition());
|
||||
|
||||
if (distance > catchUpDistance) {
|
||||
npc.getMotionController().run();
|
||||
} else if (distance > followDistance) {
|
||||
npc.getMotionController().walk();
|
||||
npc.getMotionController().moveTo(target.getPosition());
|
||||
} else {
|
||||
npc.getMotionController().stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PatrolBehavior
|
||||
|
||||
```java
|
||||
public class PatrolBehavior {
|
||||
private List<Vector3d> patrolPoints;
|
||||
private int currentPointIndex;
|
||||
private boolean loop;
|
||||
private float waitTimeAtPoint;
|
||||
|
||||
public void update(NPCEntity npc, float deltaTime) {
|
||||
Vector3d currentTarget = patrolPoints.get(currentPointIndex);
|
||||
MotionController motion = npc.getMotionController();
|
||||
|
||||
if (motion.hasReachedTarget()) {
|
||||
// Attendre au point
|
||||
currentPointIndex = (currentPointIndex + 1) % patrolPoints.size();
|
||||
} else {
|
||||
motion.moveTo(currentTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### FleeBehavior
|
||||
|
||||
```java
|
||||
public class FleeBehavior {
|
||||
private float fleeDistance;
|
||||
private Entity threat;
|
||||
|
||||
public void update(NPCEntity npc, float deltaTime) {
|
||||
Vector3d awayFromThreat = npc.getPosition()
|
||||
.subtract(threat.getPosition())
|
||||
.normalize()
|
||||
.multiply(fleeDistance);
|
||||
|
||||
Vector3d fleeTarget = npc.getPosition().add(awayFromThreat);
|
||||
|
||||
npc.getMotionController().sprint();
|
||||
npc.getMotionController().moveTo(fleeTarget);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Évitement d'Obstacles
|
||||
|
||||
```java
|
||||
public class ObstacleAvoidance {
|
||||
private float avoidanceRadius;
|
||||
private float lookAheadDistance;
|
||||
|
||||
public Vector3d calculateAvoidanceVector(
|
||||
NPCEntity npc,
|
||||
Vector3d desiredDirection
|
||||
) {
|
||||
// Lancer des rayons pour détecter les obstacles
|
||||
List<RaycastHit> obstacles = castAvoidanceRays(npc, desiredDirection);
|
||||
|
||||
if (obstacles.isEmpty()) {
|
||||
return desiredDirection;
|
||||
}
|
||||
|
||||
// Calculer la direction d'évitement
|
||||
Vector3d avoidance = Vector3d.ZERO;
|
||||
for (RaycastHit hit : obstacles) {
|
||||
Vector3d away = npc.getPosition().subtract(hit.position).normalize();
|
||||
avoidance = avoidance.add(away);
|
||||
}
|
||||
|
||||
return desiredDirection.add(avoidance.normalize()).normalize();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Systèmes de Mouvement
|
||||
|
||||
Systèmes ECS qui traitent le mouvement des NPCs :
|
||||
|
||||
```java
|
||||
// Système de mise à jour de mouvement
|
||||
public class NPCMovementSystem implements System {
|
||||
@Override
|
||||
public void update(float deltaTime) {
|
||||
for (NPCEntity npc : npcsWithMovement) {
|
||||
MotionController motion = npc.getMotionController();
|
||||
PathFollower path = npc.getPathFollower();
|
||||
|
||||
// Mettre à jour le suivi de chemin
|
||||
if (path.hasPath()) {
|
||||
updatePathFollowing(npc, motion, path, deltaTime);
|
||||
}
|
||||
|
||||
// Appliquer le mouvement
|
||||
motion.update(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Bonnes Pratiques
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Directives de Mouvement :**
|
||||
- Utilisez un NavigationConfig approprié au type de NPC
|
||||
- Mettez en cache les chemins quand possible pour éviter les recalculs fréquents
|
||||
- Utilisez le lissage de chemin pour un mouvement plus naturel
|
||||
- Considérez la taille de l'entité lors du pathfinding
|
||||
- Implémentez l'évitement d'obstacles pour les environnements dynamiques
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Performance du Pathfinding :**
|
||||
- Limitez les requêtes de pathfinding par frame
|
||||
- Utilisez des distances max plus courtes quand possible
|
||||
- Mettez en cache les chemins fréquemment utilisés
|
||||
- Considérez le pathfinding hiérarchique pour les grands mondes
|
||||
{{< /callout >}}
|
||||
Reference in New Issue
Block a user