Aller au contenu principal

API FreeMinecraftModels et guide du développeur

FreeMinecraftModels est à la fois un plugin autonome et une surface d'API pour d'autres plugins.

Dépôt Maven

<repository>
<id>magmaguy-repo-releases</id>
<name>MagmaGuy's Repository</name>
<url>https://repo.magmaguy.com/releases</url>
</repository>
<repository>
<id>magmaguy-repo-snapshots</id>
<name>MagmaGuy's Snapshot Repository</name>
<url>https://repo.magmaguy.com/snapshots</url>
</repository>

Dépendance

<dependency>
<groupId>com.magmaguy</groupId>
<artifactId>FreeMinecraftModels</artifactId>
<version>LATEST.VERSION.HERE</version>
<scope>provided</scope>
</dependency>

Utilisez-le en compileOnly/provided. Ne shadez pas le plugin dans votre propre jar.

Points d'entrée principaux

  • ModeledEntityManager.modelExists(String)
  • ModeledEntityManager.reload()
  • ModeledEntityManager.getAllEntities()
  • ModeledEntityManager.getDynamicEntities()
  • ModeledEntityManager.propEntities()
  • DisguiseAPI — déguise / dé-déguise les joueurs en modèles chargés
  • LocationAPI — enregistre des détecteurs de donjons et fournisseurs de protection (alimente les prédicats Lua em.location.*)
  • ScriptedItemAPI — marque des ItemStacks tiers avec les métadonnées d'objets scriptés FMM

ModeledEntityManager.getAllEntities(), getDynamicEntities() et propEntities() retournent des copies à un instant donné. Modifier l'ensemble ou la map retournés ne modifie pas les registres vivants de FMM. Utilisez modelExists(String) pour un test d'existence plutôt que de conserver et recopier sans cesse un registre complet.

Types runtime principaux

  • ModeledEntity
  • StaticEntity
  • DynamicEntity
  • PropEntity

Création d'entités

StaticEntity preview = StaticEntity.create("example_model", location);
DynamicEntity mobModel = DynamicEntity.create("example_model", livingEntity);
DynamicEntity mount = DynamicEntity.createWithInvisibility("example_model", livingEntity);
PropEntity prop = PropEntity.spawnPropEntity("example_model", location);

Tous les chemins de création retournent null si l'ID de modèle demandé n'est pas chargé.

PropEntity.spawnPropEntity retourne également null lorsqu'un prop de ce même modèle est déjà chargé sur le bloc cible — le doublon est refusé plutôt qu'empilé, et un avertissement [FMM Props] Prevented duplicate prop spawn ... est journalisé. Vérifiez toujours que sa valeur de retour n'est pas nulle ; un retour non nul est la seule confirmation que le prop a réellement été créé.

createWithInvisibility est une variante qui applique une potion d'invisibilité au lieu de masquer l'entité aux clients. Cela maintient l'entité suivie côté client, ce qui est nécessaire pour le contrôle de véhicule (utilisé en interne par /fmm mount).

Méthodes runtime utiles

  • ModeledEntity#setDisplayName(String) -- ne fait silencieusement rien à moins que le modèle ne contienne un os tag_ (voir l'avertissement ci-dessous)
  • ModeledEntity#setDisplayNameVisible(boolean) -- même exigence
  • ModeledEntity#setLeftClickCallback(...)
  • ModeledEntity#setRightClickCallback(...)
  • ModeledEntity#setHitboxContactCallback(...)
  • ModeledEntity#setModeledEntityHitByProjectileCallback(...)
  • ModeledEntity#playAnimation(String, boolean blend, boolean loop) -- retourne false lorsque le nom ne correspond ni à un état intégré ni à une animation du modèle. blend met en file d'attente au lieu de faire un fondu enchaîné ; loop ne s'applique qu'aux animations personnalisées. Voir Animations
  • ModeledEntity#stopCurrentAnimations()
  • ModeledEntity#hasAnimation(String)
  • ModeledEntity#damage(double) / damage(Entity damager, double) / damage(Entity damager) / damage(Projectile) -- acheminé via le DamageableComponent de l'entité
  • ModeledEntity#attack(LivingEntity) / attack(LivingEntity, double damage)
  • ModeledEntity#teleport(Location, boolean teleportUnderlyingEntity)
  • ModeledEntity#setUnderlyingEntity(Entity) / ModeledEntity.getModeledEntity(Entity) -- recherche inverse statique depuis une entité Bukkit vers le modèle qui lui est attaché, ou null
  • ModeledEntity#showUnderlyingEntity(Player) / hideUnderlyingEntity(Player) -- visibilité par joueur de l'entité vanilla sous-jacente
  • ModeledEntity#getEntityID() -- retourne la chaîne d'ID de modèle
  • ModeledEntity#getModelInstanceId() -- UUID par instance, stable pendant toute la vie du modèle
  • ModeledEntity#isRemoved() / isDying() -- drapeaux de cycle de vie
  • ModeledEntity#getLocation() -- retourne la Location actuelle
  • ModeledEntity#getSpawnLocation() -- retourne la Location où le modèle a été créé
  • ModeledEntity#getWorld() -- retourne le World
  • ModeledEntity#getSkeleton() / getSkeletonBlueprint() / getMountPointManager() -- accès à la structure d'exécution
  • ModeledEntity#getInteractionComponent() / getHitboxComponent() / getDamageableComponent() / getAnimationComponent() -- les objets composants derrière les méthodes de commodité ci-dessus
  • ModeledEntity.getLoadedModeledEntities() -- ensemble statique et vivant de toutes les entités modélisées chargées
  • ModeledEntity#getViewers() -- retourne le HashSet<UUID> des joueurs qui peuvent voir l'entité
  • ModeledEntity#getNametagBones() -- retourne List<Bone> des os de nametag (utile pour placer du texte supplémentaire)
  • ModeledEntity#getScaleModifier() / setScaleModifier(double)
  • ModeledEntity#removeWithDeathAnimation() -- supprime avec l'animation de mort (s'il en existe une)
  • ModeledEntity#removeWithMinimizedAnimation() -- supprime avec une animation de réduction d'échelle
  • ModeledEntity#remove() -- supprime immédiatement l'entité et tous les os
  • ModeledEntity#setTintColor(Color) / getTintColor() -- applique une teinte persistante via le canal de teinte de l'armure de cuir. Les flashs de dégâts remplacent brièvement la teinte puis s'estompent vers elle. Passez null pour effacer.
  • ModeledEntity#setViewDistanceOverride(int) / getEffectiveViewDistance() -- surcharge DefaultConfig.maxModelViewDistance pour une seule entité. Passez -1 pour revenir à la valeur par défaut du plugin.
  • DynamicEntity#setSyncMovement(boolean)
  • DynamicEntity#isDamagesOnContact() / setDamagesOnContact(boolean) -- contrôle si l'entité inflige des dégâts aux joueurs via le contact de la hitbox
  • DynamicEntity.isDynamicEntity(Entity) / DynamicEntity.getDynamicEntity(Entity) -- recherches statiques depuis une entité Bukkit
  • DynamicEntity#getBodyLocation() -- position orientée sur le corps, distincte de getLocation()
  • Bone#getBoneLocation()

Spécificités de PropEntity

  • PropEntity.isPropEntity(ArmorStand) / PropEntity.getPropEntityID(ArmorStand) -- identifie un prop depuis son porte-armure de support
  • PropEntity.hasLoadedPropOnSameBlock(String entityID, Location) -- la vérification de doublon que spawnPropEntity exécute en interne ; appelez-la d'abord si vous préférez brancher plutôt que tester un null
  • PropEntity.respawnPropEntityFromArmorStand(String entityID, ArmorStand) -- reconstruit un prop autour d'un porte-armure ayant survécu à un rechargement de chunk
  • PropEntity.getPropEntities() -- map vivante des props chargés, indexée par UUID de porte-armure
  • PropEntity#setPersistent(boolean) -- bascule la persistance du porte-armure de support
  • PropEntity#setCustomDataString(NamespacedKey, String) / getCustomDataString(NamespacedKey) -- lit/écrit vos propres valeurs PDC sur le prop. C'est le même magasin qu'utilisent les aides Lua set_persistent_data / get_persistent_data, sous l'espace de noms fmm_lua_<key>
  • PropEntity#remove() / remove(boolean showRealBlocks) -- supprime le modèle mais laisse l'entrée persistante
  • PropEntity#permanentlyRemove() -- supprime le modèle et son entrée persistante
  • PropEntity#setVoxelizeConfig(boolean voxelize, boolean solidify) / applySolidify() -- les équivalents à l'exécution des champs YML voxelize: / solidify:
  • PropEntity#showFakePropBlocksToPlayer(Player) / showRealBlocksToPlayer(Player) et les variantes ...ToAllPlayers() -- contrôlent les blocs barrière envoyés uniquement par paquets qui donnent une collision côté client à un prop solidifié
Les plaques de nom nécessitent un os tag_ dans le modèle

setDisplayName et setDisplayNameVisible parcourent les os de plaque de nom du modèle, qui n'existent que pour les os dont le nom commence par tag_. Sur un modèle dépourvu d'un tel os, cette liste est vide : les deux appels réussissent et ne font rien — aucune exception, aucune ligne de journal.

Il n'y a aucun repli. Une DynamicEntity masque son entité vivante sous-jacente aux clients, la plaque de nom vanilla du mob ne s'affiche donc pas non plus. Le résultat net est un mob totalement anonyme alors même que votre plugin a défini le nom sans erreur.

Si votre plugin nomme des modèles (boss, PNJ, tout ce qui est visible par l'utilisateur), exigez un os tag_ dans les modèles que vous livrez, ou vérifiez getNametagBones().isEmpty() au moment de l'attachement et avertissez l'auteur du contenu. Voir Notes sur la création de modèles.

Surface d'événements

Événements d'interaction génériques :

  • ModeledEntityLeftClickEvent
  • ModeledEntityRightClickEvent
  • ModeledEntityHitboxContactEvent
  • ModeledEntityHitByProjectileEvent

Les quatre sont des événements Bukkit annulables ; les chemins de détection intégrés de FMM les émettent sur le thread principal du serveur. Annuler l'un d'eux empêche le callback ou le comportement par défaut correspondant de FMM. Les scans de contact de hitbox s'exécutent tous les deux ticks serveur ; les événements de clic conservent une courte fenêtre de déduplication par joueur afin que le chemin d'interaction par paquets et le raytrace OBB ne puissent pas déclencher deux fois la même action.

Événements de cycle de vie :

  • FmmReloadedEvent -- se déclenche après que FMM termine sa séquence d'initialisation au démarrage et après chaque /fmm reload. Se déclenche toujours sur le thread principal du serveur.

La surface d'interaction publique est volontairement neutre vis-à-vis du type de modèle. Les anciennes variantes StaticEntity*Event, DynamicEntity*Event et PropEntity*Event, ainsi que ResourcePackGenerationEvent, ne font plus partie de l'API actuelle. Utilisez plutôt les quatre événements génériques d'entité modélisée ci-dessus et FmmReloadedEvent.

Les plugins consommateurs qui détiennent des références DynamicEntity ou PropEntity à long terme (EliteMobs, BetterStructures, etc.) doivent gérer cet événement en recréant leurs attachements de modèle sur les entités sous-jacentes survivantes. Sans cela, ces entités deviennent invisibles après un reload car FMM a démonté les display entities durant onDisable tandis que la référence du consommateur est maintenant obsolète.

@EventHandler
public void onFmmReloaded(FmmReloadedEvent event) {
for (MyTrackedEntity tracked : myEntities) {
if (tracked.bukkitEntity != null && tracked.bukkitEntity.isValid()) {
tracked.fmmModel = DynamicEntity.create("my_model", tracked.bukkitEntity);
}
}
}

ModeledEntityHitByProjectileEvent et détection de projectiles OBB

FMM utilise la détection de coup OBB (oriented bounding box) pour les projectiles contre les entités modélisées. Lorsqu'un projectile intersecte la hitbox OBB d'une entité modélisée, FMM déclenche un ModeledEntityHitByProjectileEvent. Il s'agit d'un événement Bukkit standard annulable.

Détails clés :

  • La détection balaie tout le segment de déplacement du projectile depuis le tick précédent, si bien que des flèches rapides ne peuvent pas traverser un modèle fin entre deux échantillons
  • Les candidats sur ce segment sont résolus du plus proche au plus lointain, indépendamment de l'ordre d'itération du registre des modèles
  • Un projectile non perforant est acheminé vers une seule cible modélisée. Une flèche avec Perforation peut toucher pierce level + 1 cibles modélisées distinctes, dans l'ordre du trajet, sans double déclenchement lorsque l'OBB et la hitbox vanilla sous-jacente l'observent tous deux
  • Le gestionnaire par défaut des entités dynamiques transmet l'impact à l'entité vivante sous-jacente sous forme de véritable événement de dégâts de projectile, en utilisant la vélocité du projectile au moment de l'impact. Cela préserve la cause du projectile, la gestion par les plugins de combat et l'attribution au tireur
  • Annuler l'événement empêche le callback et le comportement de dégâts par défaut de FMM, mais la collision consomme tout de même le budget de cibles modélisées du projectile. Un coup non perforant annulé consomme donc quand même le projectile
@EventHandler
public void onProjectileHitModel(ModeledEntityHitByProjectileEvent event) {
ModeledEntity target = event.getModeledEntity();
Projectile projectile = event.getProjectile();
// Cancel to prevent damage
event.setCancelled(true);
}

Utilitaires d'objets et de modèles

ModelItemFactory

Classe factory pour créer programmatiquement des ItemStacks liés aux modèles.

// Create a prop placement item (uses "model_id" PDC key)
ItemStack placementItem = ModelItemFactory.createModelItem("lamp_post", Material.STICK);

// Create a custom item from config (uses "fmm_item_id" PDC key)
PropScriptConfigFields config = ItemScriptManager.getItemDefinitions().get("magic_sword");
ItemStack customItem = ModelItemFactory.createCustomItem("magic_sword", config);
  • createModelItem(String modelId, Material material) -- crée un objet de placement pour les props. Sur 1.21.4+, applique automatiquement le rendu de modèle d'affichage si un JSON d'affichage existe.
  • createCustomItem(String itemId, PropScriptConfigFields config) -- crée un objet personnalisé avec nom, lore, enchantements et modèle d'affichage depuis la config unifiée.
  • formatModelName(String modelId) -- utilitaire qui convertit un ID de modèle comme 01_em_flame_sword en Flame Sword.

DisplayModelRegistry

Registre simple qui suit quels modèles ont un JSON d'affichage disponible.

// Check if a model has a display model JSON registered
boolean has3D = DisplayModelRegistry.hasDisplayModel("magic_sword");
  • register(String modelId) -- enregistre un ID de modèle (appelé en interne pendant le reload)
  • hasDisplayModel(String modelId) -- retourne true si un .json de modèle d'affichage existe pour ce modèle
  • getRegisteredModels() -- retourne un Set<String> immuable de tous les IDs de modèle qui ont des modèles d'affichage enregistrés
  • shutdown() -- efface tous les enregistrements

ItemScriptManager

Gère le cycle de vie des scripts Lua par joueur pour les objets personnalisés (modèles avec material: défini dans leur config YML).

// Get all registered custom item definitions
Map<String, PropScriptConfigFields> items = ItemScriptManager.getItemDefinitions();

// Get the active Lua script instance for a player + item
ScriptInstance instance = ItemScriptManager.getActiveScript(playerUUID, "magic_sword");

// Get all active scripts for a player
Map<String, ScriptInstance> scripts = ItemScriptManager.getActiveScripts(playerUUID);
  • scanForCustomItems(File modelsFolder) -- scanne les configs YML de modèles pour les objets personnalisés
  • updateEquippedScripts(Player player) -- compare les objets équipés aux scripts en cours d'exécution, déclenchant les hooks equip/unequip
  • removePlayer(Player player) -- arrête tous les scripts pour un joueur (appeler à la déconnexion)
  • getItemDefinitions() -- retourne la map d'ID d'objet vers PropScriptConfigFields

ScriptedItemAPI

API publique pour les plugins externes pour s'intégrer au système d'objets scriptés de FMM. Cela permet à d'autres plugins de marquer leurs propres ItemStacks avec les données d'objet scripté FMM (tag PDC + item model) afin que les hooks de script Lua de FMM se déclenchent pour ces objets, sans que FMM ne remplace le nom, le lore ou les enchantements de l'objet.

// Check if a scripted item definition exists
boolean exists = ScriptedItemAPI.isValidItemId("flame_blade");

// Apply FMM scripted item data to an existing ItemStack
// This sets:
// - The fmm_item_id PDC tag (so FMM's script system recognizes the item)
// - The item model (1.21.4+) from FMM's display model registry
// Does NOT modify name, lore, enchantments, or any other item properties.
boolean success = ScriptedItemAPI.applyScriptedItemData(itemStack, "flame_blade");

// Get the config for a scripted item
PropScriptConfigFields config = ScriptedItemAPI.getItemConfig("flame_blade");
  • isValidItemId(String itemId) -- retourne true si l'ID d'objet est enregistré dans les définitions d'objet de FMM
  • applyScriptedItemData(ItemStack itemStack, String itemId) -- estampe le tag PDC et l'item model sur un ItemStack existant. Retourne true en cas de succès, false si l'ID d'objet est invalide ou si l'ItemStack n'a pas de meta. Note arc/arbalète : si l'itemId donné n'a pas de modèle d'affichage mais que itemId + "_idle" en a un (c'est-à-dire que l'objet a des modèles d'état d'arc/arbalète), la méthode utilise automatiquement le modèle _idle comme modèle d'affichage
  • getItemConfig(String itemId) -- retourne le PropScriptConfigFields pour l'ID d'objet donné, ou null si non trouvé
Intégration EliteMobs

EliteMobs utilise cette API en interne via le champ de config scriptedItem. Lorsqu'un objet personnalisé EliteMobs définit scriptedItem: flame_blade, EliteMobs construit son objet normalement (nom, lore, enchantements, niveau) puis appelle ScriptedItemAPI.applyScriptedItemData() pour ajouter le modèle et le comportement de script de FMM par-dessus.

DisguiseAPI

Point d'entrée public pour la fonctionnalité de déguisement des joueurs. Les plugins tiers devraient appeler cette classe plutôt que le DisguiseManager interne afin que les refactorisations internes restent sûres.

import com.magmaguy.freeminecraftmodels.api.DisguiseAPI;

// Disguise a player as a loaded model. Replaces any existing disguise cleanly.
boolean ok = DisguiseAPI.disguise(player, "dragon");

// Undisguise (returns true if a disguise was removed).
DisguiseAPI.undisguise(player);

// Query state.
boolean disguised = DisguiseAPI.isDisguised(player);
String modelID = DisguiseAPI.getDisguiseModelID(player); // null if not disguised

// Snapshot of all currently disguised players.
Collection<Player> all = DisguiseAPI.getDisguisedPlayers();
  • disguise(Player, String modelID) -- retourne false si l'ID de modèle n'est pas chargé
  • undisguise(Player) -- retourne true si un déguisement a été retiré
  • isDisguised(Player) -- vérification booléenne rapide
  • getDisguiseModelID(Player) -- retourne l'ID de modèle actif ou null
  • getDisguisedPlayers() -- snapshot non modifiable des joueurs déguisés

Les joueurs déguisés sont rendus invisibles aux autres et le restent jusqu'au dé-déguisement — les seaux de lait, les effets de balise et les interactions similaires ne brisent pas l'invisibilité.

LocationAPI

API publique pour les plugins afin de contribuer à la détection de donjons et aux vérifications de protection de région. Les prédicats enregistrés alimentent les vérifications Lua em.location.is_in_dungeon et em.location.is_protected de FMM (utilisés par les scripts préfaits comme pickupable.lua et storage_double.lua).

Les plugins passent un Predicate<Location> simple afin qu'aucun type FMM shadé ne traverse les classloaders de plugin.

import com.magmaguy.freeminecraftmodels.api.LocationAPI;

// On your plugin's enable, after WorldGuard/EliteMobs/etc. are available.
LocationAPI.registerDungeonLocator("EliteMobs",
location -> EliteMobs.isInsideDungeon(location));

LocationAPI.registerProtectionProvider("WorldGuard",
location -> WorldGuardBridge.isProtected(location));
  • registerDungeonLocator(String providerName, Predicate<Location> predicate) — tout prédicat enregistré retournant true marque l'emplacement comme « in dungeon »
  • registerProtectionProvider(String providerName, Predicate<Location> predicate) — tout prédicat enregistré retournant true marque l'emplacement comme protégé

Les opérateurs peuvent vérifier l'enregistrement avec /fmm location, qui rapporte le nombre de fournisseurs en direct et teste les deux prédicats sur leur position actuelle.

Fournisseurs de protection et placement de props

Ces mêmes fournisseurs de protection pilotent également la vérification de placement de props preventPropPlacementInProtectedRegions, mais cette vérification appelle canBuild(player, location) plutôt que le isProtected(location) basé uniquement sur l'emplacement. La distinction a son importance :

FournisseurComportement de canBuild
Adaptateur WorldGuard intégréRespecte le contournement propre à WorldGuard, puis délègue à testBuild de WorldGuard — les membres et propriétaires de région peuvent donc construire normalement
Adaptateur GriefPrevention intégréL'absence de claim à cet emplacement signifie autorisé ; à l'intérieur d'un claim, il délègue à la permission de construction propre à GriefPrevention pour ce joueur
Fournisseur enregistré via LocationAPI.registerProtectionProviderRetombe sur !isProtected(location)uniquement basé sur l'emplacement, bloque tout le monde dans un emplacement que votre prédicat déclare protégé

Ce repli est intentionnel et prudent : un Predicate<Location> ne peut pas exprimer une permission propre à un joueur, et FMM n'en inventera pas une. Si vous voulez un comportement réellement conscient du joueur pour votre propre système de régions, implémentez directement le RegionProtectionProvider de MagmaCore en surchargeant canBuild, puis enregistrez-le avec LocationQueryRegistry.registerProtectionProvider au lieu de passer par l'enveloppe de commodité par prédicat.

Deux autres comportements à connaître :

  • Les échecs d'adaptateur échouent en mode fermé. Si un fournisseur lève une erreur pendant une requête de construction, le placement est refusé et un avertissement nommant le fournisseur est journalisé. Il ne retombe jamais silencieusement sur « autorisé ».
  • Tous les fournisseurs enregistrés doivent être d'accord. Le premier fournisseur qui dit non l'emporte ; les fournisseurs de propriété enregistrés via LocationOwnership restent basés uniquement sur l'emplacement et bloquent tout le monde.

PropScriptConfigFields

Classe de configuration unifiée pour les fichiers de config YML de modèle. Utilisée à la fois par les scripts de prop et les objets personnalisés.

# Example: torch_01.yml
isEnabled: true
scripts:
- torch_glow.lua
material: STICK # If set, model becomes a custom item
name: "&eMagic Torch" # Custom display name (optional)
lore: # Custom lore lines (optional)
- "&7Glows in the dark"
enchantments: # Enchantments (optional, format: NAME,LEVEL)
- "FIRE_ASPECT,1"

Méthodes clés : isCustomItem(), getParsedMaterial(), getParsedEnchantments(), getScripts().

Scripting Lua

FreeMinecraftModels supporte les scripts Lua à la fois pour les props et les objets personnalisés via le moteur de scripting MagmaCore 2.0. Les fichiers de scripts sont placés dans plugins/FreeMinecraftModels/scripts/ et sont liés aux modèles via une config YML voisine à côté du fichier de modèle. Le fichier de script sur le disque doit se terminer par .lua ; les entrées de config peuvent inclure l'extension ou l'omettre.

Les props lient chaque script listé dans scripts: comme des instances indépendantes. Les objets personnalisés ne lient actuellement que le premier script valide de la liste, pour chaque paire joueur/objet.

Hooks de script de prop

HookDéclencheur
on_spawnLe prop apparaît dans le monde
on_game_tickÀ chaque tick tant que le prop est vivant
on_zone_enterUn joueur entre dans une zone surveillée créée par le script
on_zone_leaveUn joueur quitte une zone surveillée créée par le script
on_destroyLe prop est retiré
on_left_clickLe joueur clique gauche sur le prop
on_right_clickLe joueur clique droit sur le prop
on_projectile_hitRéservé : accepté par la validation, mais non distribué aux scripts de prop dans le runtime actuel

Hooks de script d'objet

Les objets personnalisés (modèles avec material: défini) supportent 22 hooks Lua :

HookDéclencheur
on_equipL'objet entre dans un slot d'équipement suivi
on_unequipL'objet quitte un slot d'équipement suivi
on_game_tickÀ chaque tick tant que l'objet est équipé
on_attack_entityLe joueur attaque une entité en tenant l'objet
on_kill_entityLe joueur tue une entité en tenant l'objet
on_take_damageLe joueur subit des dégâts pendant que l'objet est équipé
on_shield_blockLe joueur bloque avec un bouclier
on_shoot_bowLe joueur tire à l'arc
on_projectile_hitUn projectile tiré par le joueur touche quelque chose
on_projectile_launchLe joueur lance un projectile
on_right_clickLe joueur clique droit avec l'objet
on_left_clickLe joueur clique gauche avec l'objet
on_shift_right_clickLe joueur fait shift+clic droit avec l'objet
on_shift_left_clickLe joueur fait shift+clic gauche avec l'objet
on_interact_entityLe joueur clique droit sur une entité avec l'objet
on_swap_handsLe joueur échange l'objet entre les mains
on_dropLe joueur jette l'objet
on_break_blockLe joueur casse un bloc en tenant l'objet
on_consumeLe joueur consomme l'objet
on_item_damageL'objet subit des dégâts de durabilité
on_fishLe joueur utilise une canne à pêche
on_deathLe joueur meurt pendant que l'objet est équipé

Les scripts d'objet reçoivent context.item (avec l'ID d'objet et les infos joueur) au lieu de context.prop.

Table de contexte des scripts de prop

Les scripts de prop reçoivent une table context. Voici un résumé des APIs clés -- voir API Prop Lua pour tous les détails.

context.prop :

  • model_id -- le nom de modèle blueprint
  • current_location -- la position actuelle du prop
  • play_animation(name, blend, loop) -- joue l'animation nommée (blend et loop sont à true par défaut)
  • stop_animation() -- arrête toutes les animations en cours
  • hurt_visual() -- joue le visuel de blessure (flash rouge) sur le prop
  • pickup() -- met en file d'attente la suppression du prop et le drop de son objet de placement
  • mount(player) -- met en file d'attente une tentative de montage ; un retour true signifie que le joueur et le gestionnaire de montures étaient valides, pas qu'un siège a finalement été attribué
  • dismount(player) -- met en file d'attente une vérification de démontage ; un retour true signifie que le joueur et le gestionnaire de montures étaient valides
  • get_passengers() -- retourne une liste des joueurs chevauchant actuellement le prop
  • spawn_elitemobs_boss(filename, x, y, z) -- fait apparaître un boss EliteMobs à des coordonnées absolues dans le monde actuel du prop

context.event :

  • Disponible dans les hooks de prop on_left_click, on_right_click, on_zone_enter et on_zone_leave, ainsi que dans les hooks d'objet provoqués par un joueur
  • cancel(), uncancel(), is_cancelled lorsque le hook sous-jacent est annulable
  • player -- le joueur qui a déclenché l'événement

context.world :

  • spawn_entity(entity_type, x, y, z) -- fait apparaître une entité vanilla, ou retourne nil si le type d'entité est invalide
  • set_block_at(x, y, z, material) -- met en file d'attente un changement de bloc si le matériau est valide ; les chunks non chargés sont ignorés
  • Plus particules, sons, requêtes de blocs, foudre et recherches d'entités proches

context.cooldowns :

  • check_local(key, ticks) -- vérifie et démarre un temps de recharge propre au script
  • global_ready() / set_global(ticks) -- temps de recharge partagé pour le prop ou le joueur propriétaire

Objets joueur (depuis context.player ou context.event.player) :

  • get_held_item() -- retourne l'objet que tient le joueur ; type est le nom de matériau Bukkit en majuscules
  • consume_held_item() -- retire un de l'objet tenu
  • has_item(material) -- vérifie si le joueur a un objet
  • send_message(text) -- envoie un message de chat au joueur
  • game_mode -- le mode de jeu actuel du joueur

Exemple de script de prop

return {
api_version = 1,

on_spawn = function(context)
context.prop:play_animation("idle", true, true)
end,

on_right_click = function(context)
if context.cooldowns:check_local("activate", 40) then
context.prop:play_animation("activate", false, false)
end
end
}

Exemple de script d'objet

return {
api_version = 1,

on_equip = function(context)
context.player:send_message("&6You equipped the Flame Blade!")
end,

on_attack_entity = function(context)
-- Fire effect on hit
context.player:send_message("&cBurn!")
end,

on_unequip = function(context)
context.player:send_message("&7Flame Blade sheathed.")
end
}

Notes

  • FreeMinecraftModels est une dépendance plugin installée, pas une bibliothèque embarquable.
  • Si votre plugin a besoin de modèles fraîchement importés, appelez ModeledEntityManager.reload() au lieu d'essayer de reconstruire l'état de FreeMinecraftModels vous-même.
  • Tous les plugins de l'écosystème Nightbreak dépendent désormais de MagmaCore 2.2.0-SNAPSHOT, qui inclut le moteur de scripting Lua partagé utilisé par les scripts de prop FreeMinecraftModels et les pouvoirs Lua d'EliteMobs, plus les LocationQueryRegistry et WorldFolderResolver partagés.
  • FreeMinecraftModels déclare WorldGuard, WorldEdit, GriefPrevention, Vault, floodgate et Geyser-Spigot en tant que softdepend. Aucun n'est requis pour démarrer le plugin, mais ils débloquent des fonctionnalités spécifiques : WorldGuard/WorldEdit/GriefPrevention alimentent LocationAPI et la vérification de placement de props tenant compte du joueur, Vault active la boutique de mobilier, et floodgate/Geyser-Spigot activent le backend Bedrock par modèle.
  • ModeledEntityManager.reload() effectue un cycle de rechargement complet du plugin (onDisable / onLoad / onEnable). Appelez-le sur le thread principal du serveur.