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ésLocationAPI— enregistre des détecteurs de donjons et fournisseurs de protection (alimente les prédicats Luaem.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
ModeledEntityStaticEntityDynamicEntityPropEntity
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 ostag_(voir l'avertissement ci-dessous)ModeledEntity#setDisplayNameVisible(boolean)-- même exigenceModeledEntity#setLeftClickCallback(...)ModeledEntity#setRightClickCallback(...)ModeledEntity#setHitboxContactCallback(...)ModeledEntity#setModeledEntityHitByProjectileCallback(...)ModeledEntity#playAnimation(String, boolean blend, boolean loop)-- retournefalselorsque le nom ne correspond ni à un état intégré ni à une animation du modèle.blendmet en file d'attente au lieu de faire un fondu enchaîné ;loopne s'applique qu'aux animations personnalisées. Voir AnimationsModeledEntity#stopCurrentAnimations()ModeledEntity#hasAnimation(String)ModeledEntity#damage(double)/damage(Entity damager, double)/damage(Entity damager)/damage(Projectile)-- acheminé via leDamageableComponentde 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é, ounullModeledEntity#showUnderlyingEntity(Player)/hideUnderlyingEntity(Player)-- visibilité par joueur de l'entité vanilla sous-jacenteModeledEntity#getEntityID()-- retourne la chaîne d'ID de modèleModeledEntity#getModelInstanceId()--UUIDpar instance, stable pendant toute la vie du modèleModeledEntity#isRemoved()/isDying()-- drapeaux de cycle de vieModeledEntity#getLocation()-- retourne laLocationactuelleModeledEntity#getSpawnLocation()-- retourne laLocationoù le modèle a été crééModeledEntity#getWorld()-- retourne leWorldModeledEntity#getSkeleton()/getSkeletonBlueprint()/getMountPointManager()-- accès à la structure d'exécutionModeledEntity#getInteractionComponent()/getHitboxComponent()/getDamageableComponent()/getAnimationComponent()-- les objets composants derrière les méthodes de commodité ci-dessusModeledEntity.getLoadedModeledEntities()-- ensemble statique et vivant de toutes les entités modélisées chargéesModeledEntity#getViewers()-- retourne leHashSet<UUID>des joueurs qui peuvent voir l'entitéModeledEntity#getNametagBones()-- retourneList<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'échelleModeledEntity#remove()-- supprime immédiatement l'entité et tous les osModeledEntity#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. Passeznullpour effacer.ModeledEntity#setViewDistanceOverride(int)/getEffectiveViewDistance()-- surchargeDefaultConfig.maxModelViewDistancepour une seule entité. Passez-1pour 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 hitboxDynamicEntity.isDynamicEntity(Entity)/DynamicEntity.getDynamicEntity(Entity)-- recherches statiques depuis une entité BukkitDynamicEntity#getBodyLocation()-- position orientée sur le corps, distincte degetLocation()Bone#getBoneLocation()
Spécificités de PropEntity
PropEntity.isPropEntity(ArmorStand)/PropEntity.getPropEntityID(ArmorStand)-- identifie un prop depuis son porte-armure de supportPropEntity.hasLoadedPropOnSameBlock(String entityID, Location)-- la vérification de doublon quespawnPropEntityexécute en interne ; appelez-la d'abord si vous préférez brancher plutôt que tester unnullPropEntity.respawnPropEntityFromArmorStand(String entityID, ArmorStand)-- reconstruit un prop autour d'un porte-armure ayant survécu à un rechargement de chunkPropEntity.getPropEntities()-- map vivante des props chargés, indexée par UUID de porte-armurePropEntity#setPersistent(boolean)-- bascule la persistance du porte-armure de supportPropEntity#setCustomDataString(NamespacedKey, String)/getCustomDataString(NamespacedKey)-- lit/écrit vos propres valeurs PDC sur le prop. C'est le même magasin qu'utilisent les aides Luaset_persistent_data/get_persistent_data, sous l'espace de nomsfmm_lua_<key>PropEntity#remove()/remove(boolean showRealBlocks)-- supprime le modèle mais laisse l'entrée persistantePropEntity#permanentlyRemove()-- supprime le modèle et son entrée persistantePropEntity#setVoxelizeConfig(boolean voxelize, boolean solidify)/applySolidify()-- les équivalents à l'exécution des champs YMLvoxelize:/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é
tag_ dans le modèlesetDisplayName 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 :
ModeledEntityLeftClickEventModeledEntityRightClickEventModeledEntityHitboxContactEventModeledEntityHitByProjectileEvent
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 + 1cibles 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 comme01_em_flame_swordenFlame 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)-- retournetruesi un.jsonde modèle d'affichage existe pour ce modèlegetRegisteredModels()-- retourne unSet<String>immuable de tous les IDs de modèle qui ont des modèles d'affichage enregistrésshutdown()-- 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ésupdateEquippedScripts(Player player)-- compare les objets équipés aux scripts en cours d'exécution, déclenchant les hooks equip/unequipremovePlayer(Player player)-- arrête tous les scripts pour un joueur (appeler à la déconnexion)getItemDefinitions()-- retourne la map d'ID d'objet versPropScriptConfigFields
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)-- retournetruesi l'ID d'objet est enregistré dans les définitions d'objet de FMMapplyScriptedItemData(ItemStack itemStack, String itemId)-- estampe le tag PDC et l'item model sur un ItemStack existant. Retournetrueen cas de succès,falsesi l'ID d'objet est invalide ou si l'ItemStack n'a pas de meta. Note arc/arbalète : si l'itemIddonné n'a pas de modèle d'affichage mais queitemId + "_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_idlecomme modèle d'affichagegetItemConfig(String itemId)-- retourne lePropScriptConfigFieldspour l'ID d'objet donné, ounullsi non trouvé
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)-- retournefalsesi l'ID de modèle n'est pas chargéundisguise(Player)-- retournetruesi un déguisement a été retiréisDisguised(Player)-- vérification booléenne rapidegetDisguiseModelID(Player)-- retourne l'ID de modèle actif ounullgetDisguisedPlayers()-- 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é retournanttruemarque l'emplacement comme « in dungeon »registerProtectionProvider(String providerName, Predicate<Location> predicate)— tout prédicat enregistré retournanttruemarque 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 :
| Fournisseur | Comportement 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.registerProtectionProvider | Retombe 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
LocationOwnershiprestent 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
| Hook | Déclencheur |
|---|---|
on_spawn | Le prop apparaît dans le monde |
on_game_tick | À chaque tick tant que le prop est vivant |
on_zone_enter | Un joueur entre dans une zone surveillée créée par le script |
on_zone_leave | Un joueur quitte une zone surveillée créée par le script |
on_destroy | Le prop est retiré |
on_left_click | Le joueur clique gauche sur le prop |
on_right_click | Le joueur clique droit sur le prop |
on_projectile_hit | Ré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 :
| Hook | Déclencheur |
|---|---|
on_equip | L'objet entre dans un slot d'équipement suivi |
on_unequip | L'objet quitte un slot d'équipement suivi |
on_game_tick | À chaque tick tant que l'objet est équipé |
on_attack_entity | Le joueur attaque une entité en tenant l'objet |
on_kill_entity | Le joueur tue une entité en tenant l'objet |
on_take_damage | Le joueur subit des dégâts pendant que l'objet est équipé |
on_shield_block | Le joueur bloque avec un bouclier |
on_shoot_bow | Le joueur tire à l'arc |
on_projectile_hit | Un projectile tiré par le joueur touche quelque chose |
on_projectile_launch | Le joueur lance un projectile |
on_right_click | Le joueur clique droit avec l'objet |
on_left_click | Le joueur clique gauche avec l'objet |
on_shift_right_click | Le joueur fait shift+clic droit avec l'objet |
on_shift_left_click | Le joueur fait shift+clic gauche avec l'objet |
on_interact_entity | Le joueur clique droit sur une entité avec l'objet |
on_swap_hands | Le joueur échange l'objet entre les mains |
on_drop | Le joueur jette l'objet |
on_break_block | Le joueur casse un bloc en tenant l'objet |
on_consume | Le joueur consomme l'objet |
on_item_damage | L'objet subit des dégâts de durabilité |
on_fish | Le joueur utilise une canne à pêche |
on_death | Le 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 blueprintcurrent_location-- la position actuelle du propplay_animation(name, blend, loop)-- joue l'animation nommée (blend et loop sont àtruepar défaut)stop_animation()-- arrête toutes les animations en courshurt_visual()-- joue le visuel de blessure (flash rouge) sur le proppickup()-- met en file d'attente la suppression du prop et le drop de son objet de placementmount(player)-- met en file d'attente une tentative de montage ; un retourtruesignifie 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 retourtruesignifie que le joueur et le gestionnaire de montures étaient validesget_passengers()-- retourne une liste des joueurs chevauchant actuellement le propspawn_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_entereton_zone_leave, ainsi que dans les hooks d'objet provoqués par un joueur cancel(),uncancel(),is_cancelledlorsque le hook sous-jacent est annulableplayer-- 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 retournenilsi le type d'entité est invalideset_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 scriptglobal_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 ;typeest le nom de matériau Bukkit en majusculesconsume_held_item()-- retire un de l'objet tenuhas_item(material)-- vérifie si le joueur a un objetsend_message(text)-- envoie un message de chat au joueurgame_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
LocationQueryRegistryetWorldFolderResolverpartagé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 alimententLocationAPIet 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.