-
-
Notifications
You must be signed in to change notification settings - Fork 103
/
AttachCommand.java
121 lines (115 loc) · 6.59 KB
/
AttachCommand.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package com.denizenscript.denizen.scripts.commands.entity;
import com.denizenscript.denizen.objects.EntityTag;
import com.denizenscript.denizen.objects.LocationTag;
import com.denizenscript.denizen.objects.PlayerTag;
import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException;
import com.denizenscript.denizencore.scripts.commands.generator.*;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import com.denizenscript.denizen.utilities.entity.EntityAttachmentHelper;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.scripts.ScriptEntry;
import com.denizenscript.denizencore.scripts.commands.AbstractCommand;
import java.util.List;
import java.util.UUID;
import java.util.function.BiConsumer;
public class AttachCommand extends AbstractCommand {
public AttachCommand() {
setName("attach");
setSyntax("attach [<entity>|...] [to:<entity>/cancel] (offset:<offset>) (relative) (yaw_offset:<#.#>) (pitch_offset:<#.#>) (sync_server) (no_rotate/no_pitch) (for:<player>|...)");
setRequiredArguments(2, 9);
isProcedural = false;
autoCompile();
}
// <--[command]
// @Name attach
// @Syntax attach [<entity>|...] [to:<entity>/cancel] (offset:<offset>) (relative) (yaw_offset:<#.#>) (pitch_offset:<#.#>) (sync_server) (no_rotate/no_pitch) (for:<player>|...)
// @Required 2
// @Maximum 9
// @Short Attaches a list of entities to another entity, for client-visible motion sync.
// @Group entity
//
// @Description
// Attaches a list of entities to another entity, for client-visible motion sync.
//
// You must specify the entity or list of entities to be attached.
// You must specify the entity that they will be attached to, or 'cancel' to end attachment.
//
// Optionally, specify an offset location vector to be a positional offset. This can include a yaw/pitch to offset those as well.
// Note that setting an offset of 0,0,0 will produce slightly different visual results from not setting any offset.
//
// Optionally, specify 'relative' to indicate that the offset vector should rotate with the target entity.
// If relative is used, optionally specify yaw_offset and/or pitch_offset to add an offset to rotation of the target entity when calculating the attachment offset.
//
// Optionally, specify 'for' with a player or list of players to only sync motion for those players.
// If unspecified, will sync for everyone.
//
// Optionally, specify 'sync_server' to keep the serverside position of the attached entities near the target entity.
// This can reduce some visual artifacts (such as entity unloading at distance), but may produce unintended functional artifacts.
// Note that you should generally only use 'sync_server' when you exclude the 'for' argument.
//
// Optionally specify 'no_rotate' to retain the attached entity's own rotation and ignore the target rotation.
// Optionally instead specify 'no_pitch' to retain the attached entity's own pitch, but use the target yaw.
//
// Note that attaches involving a player will not be properly visible to that player, but will still be visible to *other* players.
//
// It may be ideal to change setting "Packets.Auto init" in the Denizen config to "true" to guarantee this command functions as expected.
//
// @Tags
// <EntityTag.attached_entities[(<player>)]>
// <EntityTag.attached_to[(<player>)]>
// <EntityTag.attached_offset[(<player>)]>
//
// @Usage
// Use to attach random NPC to the air 3 blocks above a linked NPC.
// - attach <server.list_npcs.random> to:<npc> offset:0,3,0
// -->
public static void autoExecute(ScriptEntry scriptEntry,
@ArgName("entities") @ArgLinear @ArgSubType(EntityTag.class) List<EntityTag> entities,
@ArgName("to") @ArgPrefixed @ArgDefaultNull EntityTag target,
@ArgName("cancel") boolean cancel,
@ArgName("offset") @ArgPrefixed @ArgDefaultNull LocationTag offset,
@ArgName("relative") boolean relative,
@ArgName("yaw_offset") @ArgPrefixed @ArgDefaultNull ElementTag yawOffset,
@ArgName("pitch_offset") @ArgPrefixed @ArgDefaultNull ElementTag pitchOffset,
@ArgName("sync_server") boolean syncServer,
@ArgName("no_rotate") boolean noRotate,
@ArgName("no_pitch") boolean noPitch,
@ArgName("for") @ArgPrefixed @ArgDefaultNull @ArgSubType(PlayerTag.class) List<PlayerTag> forPlayers) {
if (target == null && !cancel) {
throw new InvalidArgumentsRuntimeException("Must specify a target entity, or 'cancel'!");
}
BiConsumer<EntityTag, UUID> procPlayer = (entity, player) -> {
if (cancel) {
EntityAttachmentHelper.removeAttachment(entity.getUUID(), player);
}
else {
EntityAttachmentHelper.AttachmentData attachment = new EntityAttachmentHelper.AttachmentData();
attachment.attached = entity;
attachment.to = target;
attachment.positionalOffset = offset == null ? null : offset.clone();
attachment.offsetRelative = relative;
attachment.yawAngleOffset = yawOffset == null ? 0 : yawOffset.asFloat();
attachment.pitchAngleOffset = pitchOffset == null ? 0 : pitchOffset.asFloat();
attachment.syncServer = syncServer;
attachment.forPlayer = player;
attachment.noRotate = noRotate;
attachment.noPitch = noPitch;
EntityAttachmentHelper.registerAttachment(attachment);
}
};
for (EntityTag entity : entities) {
if (!entity.isSpawned() && !entity.isFake && !cancel) {
Debug.echoError("Cannot attach entity '" + entity + "': entity is not spawned.");
continue;
}
if (forPlayers == null || (forPlayers.isEmpty() && syncServer)) {
procPlayer.accept(entity, null);
}
else {
for (PlayerTag player : forPlayers) {
procPlayer.accept(entity, player.getUUID());
}
}
}
}
}