2 votes

Lancer la commande quand le mouvement est une certaine valeur près du joueur

Mon cerveau refuse d'expliquer un problème sans contexte, alors soyez indulgent avec moi.

J'essaie de faire une carte PVP, mais je veux qu'il y ait un "message de mort" spécifique et personnalisé pour les flèches qui sont "touchées" parce qu'il y a plusieurs flèches différentes que j'ai l'intention d'avoir (flèches à pointe personnalisée) ; par exemple, j'ai une flèche qui devrait être une mort instantanée que je veux annoncer. *target* was sniped by *source* . Parce que j'ai showDeathMessages invalides pour cette façon de mourir et d'autres, et Je veux aussi qu'il y ait un ensemble spécifique de commandes à exécuter après la mort, je ne peux pas simplement tuer la cible avec la flèche et laisser les messages de mort principaux de Minecraft s'en occuper.

Voici le problème réel. Pour faire cela tout en restant précis sur la santé de la cible, je veux calculer la vitesse d'une flèche et, à condition que les dégâts de la flèche soient égaux ou supérieurs à ladite santé, exécuter une commande ; dans ce cas, je veux téléporter la cible au spawn.

A partir de ce moment là. J'ai déjà mis en place les éléments suivants ;

  • Un tableau d'affichage (uuid) mis en place pour trouver et faire correspondre les UUID d'une flèche. Owner[0] d'un joueur UUID[0] -- cela a été fait en supposant que le premier objet dans le IntArray sera toujours unique (en partie à cause de la signification de UUID) ;
  • Un tag pour cela a été trouvé, nommé "ping" ;
  • Une chaîne de commande s'exécutant tous les tics pour trouver, comparer et faire correspondre ces UUID ;
  • Les tableaux d'affichage (vx, vy et vz) sont configurés pour trouver et stocker les trois points d'une flèche. Motion tags ;
  • Chaînes de commande fonctionnant chaque tick pour faire ce qui précède, à condition que la Flèche ne soit pas dans le sol.

Le problème principal est que la commande (ci-dessous) que j'essaie d'utiliser pour déterminer un "hit" ne fait rien. Pour cela, je suppose que l'arc est complètement chargé et qu'une flèche doit être à moins d'un demi-bloc de la cible avant que Minecraft la reconnaisse comme un hit ;

execute as @e[tag=ping,scores={vx=2..}] at @s if entity @p[distance=..0.5,scores={health=..6}] unless score @p uuid = @s uuid run tp @p 127 179 8

Ce que je comprends de la commande devrait être ;

  • Comme toute entité avec le tag ping dont vx est égal ou supérieur à 2,
    • ...si le joueur le plus proche est à moins de 0,5 bloc et a <=6 de santé,
    • ...sauf si ce joueur a le même UUID que l'étiquette du propriétaire de l'entité,
  • téléporter le joueur aux coordonnées.

Au lieu de cela, la flèche touche et endommage le joueur, quelle que soit sa santé, et le tue donc avant qu'il ne se téléporte. Comme je veux que d'autres commandes et messages de mort s'exécutent et s'affichent après la téléportation, je ne peux pas laisser le joueur se faire tuer.

La syntaxe de la commande est-elle incorrecte ? Je pensais que c'était un problème avec le distance sélecteur (à if entity @p [distance=..0.5]... ), mais même après avoir fixé cette valeur à ..1 au lieu de ..0.5 mais cela n'a toujours rien donné.

2voto

ginkgo Points 2439

Problèmes avec votre commande

Dans votre question, vous essayez de détecter quand un joueur est sur le point d'être touché par une flèche. Je suppose que vous faites cela parce que vous voulez conserver le propriétaire de la flèche, c'est-à-dire qui l'a tirée. Ceci sera ensuite utilisé dans votre message de mort.

Pour ce faire, vous calculez sa vitesse et détectez ensuite quand il se trouve à une distance d'un demi-pâté de maisons. Mais comme vous l'avez dit, cela n'a pas fonctionné. Voici quelques raisons possibles pour lesquelles votre commande a échoué :

Problème 1 : dommages aléatoires

La vitesse d'une flèche détermine les dégâts qu'elle inflige. Lorsqu'elles sont tirées par un arc non enchanté entièrement chargé, les flèches infligent 6() points de dégâts, avec une chance plus faible d'infliger jusqu'à 11( × 5,5) points de dégâts en cas de coup critique. Elles infligent jusqu'à 5() de dégâts avec un arc moyennement chargé, et 1() avec un arc non chargé. Les flèches tirées depuis un distributeur infligent toujours 3() de dégâts, sauf si leur vitesse est modifiée par une source externe. Les flèches tirées par une arbalète font de 6() à 11( × 5,5) points de dégâts.

~From the Wiki officiel de Minecraft .

  • Vous ne pourrez pas imiter avec précision les mécanismes de la vanille, car un joueur peut mourir même s'il a plus de 6 points de vie. J'ai envisagé la possibilité d'utiliser des flèches à dégâts nuls (peut-être des flèches à santé instantanée ?) et d'infliger artificiellement des dégâts, mais cela commence à devenir beaucoup trop complexe. Il existe des solutions plus simples.

Numéro 2 : mouvement des projectiles

  • Les projectiles de Minecraft semblent se déplacer en douceur dans l'air, mais ils se téléportent en fait par petits incréments. Si la flèche se déplace assez rapidement, il est possible qu'elle se "téléporte" sur plus d'un demi-pâté de maisons et qu'elle échoue au test de distance.

Numéro 3 : distance sélecteur

  • Vous utilisez le distance=..0.5 mais ce n'est pas ce dont vous avez besoin. Intuitivement, il semble que cela permettrait de détecter si la flèche se trouve à l'intérieur de 0.5 de la hitbox du joueur, mais le sélecteur de distance sélectionne d'autres entités dont les pieds/origine sont dans un rayon d'une 0.5 rayon sphérique. Cela signifie que si la flèche frappe la tête d'un joueur, à environ 2 pâtés de maisons au-dessus de ses pieds ou de son origine, le test de distance échouera.

  • Cela peut être corrigé en utilisant une sélection cuboïde volumétrique, dx , dy y dz comme ça : @p[dx=0] . Cela sélectionne le joueur le plus proche dont la hitbox se trouve dans le même bloc que la flèche. Mais ce n'est pas parfait non plus.

Numéro 4 : stockage de la motion

  • Vous avez enregistré le mouvement x, y et z de la flèche sur un tableau d'affichage. Dans votre commande, vous ne testez que le mouvement x, mais vous ne testez également que le mouvement positif de 2 ou plus. Cela signifie que si la flèche se déplace dans la direction z, votre sélecteur échouera. Ou, si la flèche se déplace dans la direction x négative, le mouvement x sera en fait négatif de 2. De même, si la flèche se déplace dans une direction diagonale, ses composantes x, y et z peuvent toutes être inférieures à 2, mais la vitesse totale de la flèche peut être suffisamment élevée pour infliger des dégâts complets.

Problème 5 : utilisation d'une seule partie de l'UUID

  • Dans votre question, vous dites que le "premier objet du tableau IntArray sera toujours unique". Je ne suis pas sûr que ce soit vrai, je crois qu'il est possible pour 2 entités d'avoir le même UUID[0] mais de différer dans les 3 autres parties de l'UUID. Je ne soulève pas ce point parce que c'est ce qui a fait échouer votre commande, mais c'est une source d'échec possible, bien qu'improbable.

La situation

Je suis heureux que vous ayez donné le contexte, car votre situation est assez complexe. Vous devez détecter les impacts de flèches, quel type de flèche c'était, si le joueur est mort, le joueur qui l'a tué, etc.

Je ne voyais pas vraiment comment ce que vous avez essayé parviendrait à s'intégrer dans tous ces facteurs, alors j'ai proposé une approche différente.

Pour résoudre votre problème, nous avons besoin de quelques éléments clés.

Pour identifier la flèche personnalisée, nous utiliserons une balise système d'identification basé sur un amplificateur . Vous pourrez ainsi créer tous les effets spéciaux de flèches et les messages de décès que vous souhaitez.

Pour détecter l'endroit où la flèche atterrit, nous utiliserons un système de passagers . Ceci est principalement utilisé pour sauvegarder l'effet personnalisé de la flèche, même après que la flèche ait touché un joueur et cessé d'exister. Il sera également utile si nous voulons exécuter un effet spécial à l'endroit où la flèche a été touchée.

Pour détecter la mort d'un joueur et son assassin, nous utiliserons les bons vieux tableaux d'affichage.

Tous ces éléments seront expliqués dans la section suivante.


L'explication du Datapack

Ma réponse ici utilise un datapack, car pour de grands projets comme ceux-ci, les blocs de commande n'ont pas la puissance nécessaire. Voici le fichier . Assurez-vous de le dézipper, puis placez-le dans le dossier .minecraft/saves/YOUR_WORLD_NAME/datapacks .

Je vous recommande de télécharger le datapack afin de pouvoir suivre l'explication.

L'explication commencera par le main.mcfunction situé dans data/custom_arrows/functions/dont_edit . Cette fonction sera exécutée à chaque tic, comme spécifié dans data/minecraft/tags/functions/tick.json .

execute as @e[type=arrow,tag=!checked] run function custom_arrows:dont_edit/new
...

Première ligne du fichier - à l'instar de votre approche, j'utilise une balise appelée checked pour initialiser toutes les flèches qui sont tirées. Ces nouvelles flèches exécutent la fonction data/custom_arrows/functions/dont_edit/new :

execute at @s run summon arrow ~ ~ ~ {Tags:["checked","new"],Passengers:[{id:"minecraft:marker",Tags:["arrow_rider"]}]}
data modify entity @e[type=arrow,tag=new,limit=1] Motion set from entity @s Motion
data modify entity @e[type=arrow,tag=new,limit=1] Fire set from entity @s Fire
data modify entity @e[type=arrow,tag=new,limit=1] pickup set from entity @s pickup
data modify entity @e[type=arrow,tag=new,limit=1] player set from entity @s player
data modify entity @e[type=arrow,tag=new,limit=1] Owner set from entity @s Owner
data modify entity @e[type=arrow,tag=new,limit=1] damage set from entity @s damage
data modify entity @e[type=arrow,tag=new,limit=1] crit set from entity @s crit
data modify entity @e[type=arrow,tag=new,limit=1] ShotFromCrossbow set from entity @s ShotFromCrossbow
data modify entity @e[type=arrow,tag=new,limit=1] PierceLevel set from entity @s PierceLevel
data modify entity @e[type=arrow,tag=new,limit=1] SoundEvent set from entity @s SoundEvent
data modify entity @e[type=arrow,tag=new,limit=1] Color set from entity @s Color
data modify entity @e[type=arrow,tag=new,limit=1] Potion set from entity @s Potion
data modify entity @e[type=arrow,tag=new,limit=1] CustomPotionEffects set from entity @s CustomPotionEffects
data modify entity @e[type=marker,tag=arrow_rider,limit=1] data set from entity @s CustomPotionEffects[]

kill @s
tag @e[type=arrow,tag=new,limit=1] remove new

Cela peut sembler beaucoup, mais tout ce qu'il fait est d'invoquer une nouvelle flèche identique, puis de tuer l'original. Il le fait en utilisant beaucoup de data modify pour copier toutes les données importantes. La seule différence est qu'il y a un passager à bord ; un marker entité. Comme expliqué dans le vidéo du système de transport de passagers Cette entité marqueur restera derrière même si le projectile touche une entité et disparaît. C'est important, car nous voulons savoir quelle flèche a touché le joueur, même s'il est mort. Pour ce faire, nous copions également le marqueur de flèche original CustomPotionEffects sur le marker de l'entité data étiquette.

En revenant à la main.mcfunction nous arrivons à la deuxième ligne :

...
#If there is an arrow that has hit an entity (i.e. it disappeared and the marker is no longer riding anything) and there is a player who just died, run a function that identifies the amplifier and runs the corresponding custom arrow kill function.
execute as @e[type=marker,tag=arrow_rider,predicate=!custom_arrows:is_riding_arrow] if entity @a[scores={deaths=1..,killed_by_player=1..}] at @s run function custom_arrows:arrow_kill
...

Ici, plusieurs nouveaux acteurs entrent en scène. Le site custom_arrows:is_riding_arrow prédicat, un deaths et un killed_by_player score. Avant que cela ne soit expliqué, il est probablement préférable de passer d'abord à un autre fichier mcfunction, init.mcfunction . ( data/custom_arrows/functions/dont_edit/init.mcfunction .)

Ce fichier sera exécuté à chaque fois que le serveur sera rechargé ( /reload ) ou à chaque fois que le monde est chargé, comme spécifié par data/minecraft/tags/functions/load.json . C'est un endroit idéal pour placer les commandes d'initialisation. Dans ce cas, init.mcfunction ne contient que 3 commandes :

scoreboard objectives add killed_by_player minecraft.killed_by:minecraft.player
scoreboard objectives add player_kills playerKillCount
scoreboard objectives add deaths deathCount

2 de ces commandes que nous avons vues dans main.mcfunction , deaths y killed_by_player . Il y en a un troisième, player_kills . Ensemble, ces 3 tableaux de bord nous permettent d'identifier un tueur et une victime, mais pas avec une précision de 100%. Si 2 joueurs sont tués dans le même tick, il y aura 2 joueurs avec un score de deaths=1.. y player_kills=1.. . Ainsi, le mauvais joueur pourrait être identifié comme le tueur/la victime. S'il existe une meilleure façon de procéder, je ne la connais pas.

Avant de revenir à main.mcfunction nous devons également savoir ce qu'est un prédicat. Les prédicats sont un outil puissant que nous pouvons utiliser pour vérifier de nombreuses propriétés différentes. Ils sont stockés au format JSON, j'utilise donc ce générateur pour les créer.

Dans ce datapack, un prédicat personnalisé, is_riding_arrow a été fait ( data/custom_arrows/predicates/is_riding_arrow.json ) :

{
  "condition": "minecraft:entity_properties",
  "entity": "this",
  "predicate": {
    "nbt": "{Tags:[\"arrow_rider\"]}",
    "vehicle": {
      "type": "minecraft:arrow"
    }
  }
}

Comme son nom l'indique, il vérifie si l'entité qui exécute la commande chevauche une flèche. Il vérifie également si l'entité possède la balise, arrow_rider (qui a été donné à notre entité de marquage). C'est assez simple.

RETOUR À NOTRE main.mcfunction nous pouvons commencer à donner un sens à la deuxième ligne, recollée ici :

...
#If there is an arrow that has hit an entity (i.e. it disappeared and the marker is no longer riding anything) and there is a player who just died, run a function that identifies the amplifier and runs the corresponding custom arrow kill function.
execute as @e[type=marker,tag=arrow_rider,predicate=!custom_arrows:is_riding_arrow] if entity @a[scores={deaths=1..,killed_by_player=1..}] at @s run function custom_arrows:arrow_kill
...

Comme le décrit le commentaire, cette commande s'exécutera comme toutes les entités marqueurs qui ne sont PAS sur une flèche. En effet, lorsque la flèche touche une entité, celle-ci disparaît et l'entité marqueur ne porte plus de flèche. Ceci sert à la détection des coups. L'entité marqueur vérifie ensuite si un joueur a été tué par un autre joueur. Si c'est le cas, l'entité marqueur exécute la fonction arrow_kill fonction :

### This function runs as the marker rider, at the location where the arrow hit.
### Edit this stuff
### Make a new function file for each arrow

#If a player is killed by a tipped arrow of Luck I:
execute if entity @s[nbt={data:{Id:26b,Amplifier:0b}}] run function custom_arrows:killed_by_sniper_arrow

#If a player is killed by a tipped arrow of Luck II:
execute if entity @s[nbt={data:{Id:26b,Amplifier:1b}}] run function custom_arrows:killed_by_silverfish_arrow

### Do not delete
kill @s

(Comme vous l'avez peut-être remarqué, certains des fichiers sont situés dans un dossier nommé dont_edit et celui-ci comporte même les commentaires "### Editer ce truc" et "### Ne pas supprimer" en haut et en bas, respectivement. Oui, pour ajouter vos propres flèches personnalisées, vous devrez modifier ces fichiers).

Sur arrow_kill.mcfunction l'entité de marquage est vérifiée pour voir quelles données elle contient. Rappelez-vous que dans new.mcfunction quand nous avons copié la flèche CustomPotionEffects sur elle ? Ici, il voit son but ! Même si la flèche a disparu après avoir tué une entité, nous pouvons toujours identifier de quelle flèche personnalisée il s'agissait. Pour ce faire, nous vérifions la propriété CustomPotionEffects de l'amplificateur, qui est notre système d'identification de flèches personnalisé . Cela signifie que vos flèches personnalisées ne peuvent pas être les flèches à pointe par défaut de la vanille ! Les flèches de vanille ne contiennent pas de CustomPotionEffects seulement Potion .

Une fois que nous avons identifié la flèche qui a tué le joueur, nous pouvons exécuter une autre fonction, killed_by_sniper_arrow.mcfunction :

#Send a custom death message. "<Victim> was sniped by <Killer>"
execute as @a[scores={deaths=1..,killed_by_player=1..}] run tellraw @a [{"selector":"@s"},{"text":" was sniped by "},{"selector":"@p[scores={player_kills=1..}]"}]

#Teleport any dead players to spawn. This would require the gamerule doImmediateRespawn to be true (since you can't teleport players that are on the Respawn screen)
tp @p[scores={deaths=1..,killed_by_player=1..}] 127 179 8

C'est la partie amusante. Dans cet exemple de fichier de flèches personnalisées, plusieurs événements se produisent lorsqu'un joueur est tué par une flèche de Luck I. Cet exemple est également le plus pertinent pour votre question, puisqu'il prévoit l'utilisation d'un message de mort personnalisé et la téléportation du joueur au spawn, comme vous le souhaitiez. Alternativement, avec ce système, vous pourriez simplement définir leur point de spawn là.

J'ai également inclus un autre exemple, la flèche du poisson d'argent, qui s'exécute lorsqu'un joueur est tué par une flèche de Luck II :

#Send a custom death message. "<Killer> gave <Victim> a fatal dose of Entomophobia"
execute as @a[scores={deaths=1..,killed_by_player=1..}] run tellraw @a [{"selector":"@p[scores={player_kills=1..}]"},{"text":" gave "},{"selector":"@s"},{"text":" a fatal dose of Entomophobia"}]

#Summon 1 silverfish
summon silverfish ~ ~ ~

#Play silverfish ambient sound
playsound minecraft:entity.silverfish.ambient neutral @a ~ ~ ~

#Teleport any dead players to spawn. This would require the gamerule doImmediateRespawn to be true (since you can't teleport players that are on the Respawn screen)
tp @p[scores={deaths=1..,killed_by_player=1..}] 127 179 8

Des choses amusantes.

Si vous avez suivi l'évolution du fichier datapack, vous avez peut-être remarqué deux fichiers au nom similaire : hit_by_sniper_arrow.mcfunction y hit_by_silverfish_arrow.mcfunction . Les fichiers que nous venons d'examiner sont les fonctions de l'événement de mort, mais nous aurons également besoin de fonctions pour l'événement de coup. La fonction de l'évènement du coup requiert plusieurs conditions pour être exécutée, en commençant par notre bon vieux main.mcfunction de la troisième ligne :

...
#If a player has the Luck effect (meaning they didn't die but got hit by the tipped arrow), run a function that identifies the amplifier and runs the corresponding custom arrow hit function.
execute as @a[nbt={ActiveEffects:[{Id:26b}]}] at @s run function custom_arrows:arrow_hit
...

Si le joueur a survécu au coup de flèche, la flèche disparaîtra quand même, et l'entité de marquage descendra quand même. Pour différencier un coup de flèche d'une mort, nous pouvons utiliser le fait que les joueurs perdent leurs effets à la mort.

Donc, nous détectons cela en exécutant simplement tous les joueurs qui ont l'effet de chance, et en leur faisant exécuter la fonction, arrow_hit :

### This function runs as the player who was hit, at their origin/feet.
### Edit this stuff
### Make a new function file for each arrow

execute if entity @s[nbt={ActiveEffects:[{Id:26b,Amplifier:0b}]}] run function custom_arrows:hit_by_sniper_arrow
execute if entity @s[nbt={ActiveEffects:[{Id:26b,Amplifier:1b}]}] run function custom_arrows:hit_by_silverfish_arrow

De même que arrow_kill cette fonction est un répertoire permettant d'identifier l'amplificateur spécifique dont ils ont été affectés. Cela leur fera exécuter le fichier flèche personnalisé correspondant. Regardons dans le hit_by_sniper_arrow fonction :

#Give the player who was hit slowness for 10 seconds. Keep in mind that the slowness gets reapplied if the player has the Luck I effect! So if the luck lasts 2 seconds, the total slowness will be 12 seconds.
effect give @s slowness 10 4 true

#Play an explosion particle where the arrow hit. (Not 100% reliable)
execute as @e[type=marker,predicate=!is_riding_arrow,sort=nearest,limit=1] at @s run particle explosion ~ ~ ~

Comme avant, tout ce qui se passe ici dépend de vous.

Nous avons presque terminé tout le datapack ! Voici les dernières lignes de main.mcfunction :

...
#If the marker somehow loses it's arrow (hit a block and despawned), and hasn't ran a hit/kill function, kill it
execute as @e[type=marker,tag=arrow_rider,predicate=!custom_arrows:is_riding_arrow] run kill @s

scoreboard players reset @a deaths
scoreboard players reset @a killed_by_player
scoreboard players reset @a player_kills

C'est assez explicite. Si l'entité de marquage n'est plus sur une flèche, (mais n'a pas exécuté la commande hit o kill qui tue le marqueur après), nous tuons simplement l'entité marqueur afin qu'elle ne cause aucun problème.

ENFIN, nous avons réinitialisé les scores utilisés pour la détection des tueurs/victimes.


Le mot de la fin

Cela a représenté beaucoup de temps passé à écrire le datapack, à déboguer et à écrire cette réponse ! Malheureusement, je n'ai pas pu le tester dans un environnement multijoueur avec des amis, parce que... eh bien oui, je n'ai tout simplement pas pu. Si vous rencontrez des bogues, je mettrai cette réponse sur une Page Planète Minecraft où je peux partager ce paquet de données avec d'autres et où vous pouvez laisser un commentaire.

AlleGamers.com

AlleGamers est une communauté de gamers qui cherche à élargir la connaissance des jeux vidéo.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X