Skip to content

Commit 51b6bb1

Browse files
authored
Fixes vehicle register (#8092)
* Fix vehicle * Update src/main/java/ch/njol/skript/expressions/ExprVehicle.java Co-authored-by: sovdee <[email protected]> * Re-add delays * Fix suggestion commit * Avoid infinite mounting * Avoid infinite mounting * Better examples * Update src/main/java/ch/njol/skript/expressions/ExprVehicle.java Co-authored-by: Moderocky <[email protected]> * Use Java 17 * git conflicts * Update src/main/java/ch/njol/skript/expressions/ExprVehicle.java Co-authored-by: SirSmurfy2 <[email protected]> * Update src/main/java/ch/njol/skript/expressions/ExprVehicle.java * Requested changes * Update src/main/java/ch/njol/skript/expressions/ExprVehicle.java * Update src/main/java/ch/njol/skript/expressions/ExprVehicle.java * requested changes * Update src/main/java/ch/njol/skript/expressions/ExprVehicle.java Co-authored-by: SirSmurfy2 <[email protected]> * Update src/main/java/ch/njol/skript/expressions/ExprVehicle.java
1 parent 7d0d6f9 commit 51b6bb1

File tree

1 file changed

+104
-139
lines changed

1 file changed

+104
-139
lines changed
Lines changed: 104 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package ch.njol.skript.expressions;
22

3+
import java.util.function.Predicate;
4+
35
import org.bukkit.entity.Entity;
46
import org.bukkit.event.Event;
57
import org.bukkit.event.entity.EntityDismountEvent;
6-
import org.bukkit.event.entity.EntityEvent;
78
import org.bukkit.event.entity.EntityMountEvent;
89
import org.bukkit.event.vehicle.VehicleEnterEvent;
910
import org.bukkit.event.vehicle.VehicleExitEvent;
@@ -12,175 +13,139 @@
1213
import ch.njol.skript.Skript;
1314
import ch.njol.skript.classes.Changer.ChangeMode;
1415
import ch.njol.skript.doc.Description;
15-
import ch.njol.skript.doc.Examples;
16+
import ch.njol.skript.doc.Example;
1617
import ch.njol.skript.doc.Name;
1718
import ch.njol.skript.doc.Since;
18-
import ch.njol.skript.effects.Delay;
1919
import ch.njol.skript.entity.EntityData;
20-
import ch.njol.skript.expressions.base.SimplePropertyExpression;
21-
import ch.njol.util.coll.CollectionUtils;
20+
import ch.njol.skript.expressions.base.PropertyExpression;
21+
import ch.njol.skript.lang.Expression;
22+
import ch.njol.skript.lang.SkriptParser.ParseResult;
23+
import ch.njol.skript.registrations.EventValues;
24+
import ch.njol.util.Kleenean;
2225

23-
import java.lang.invoke.MethodHandle;
24-
import java.lang.invoke.MethodHandles;
25-
import java.lang.invoke.MethodType;
26+
import org.bukkit.entity.Player;
2627

27-
/**
28-
* @author Peter Güttinger
29-
*/
3028
@Name("Vehicle")
31-
@Description({"The vehicle an entity is in, if any. This can actually be any entity, e.g. spider jockeys are skeletons that ride on a spider, so the spider is the 'vehicle' of the skeleton.",
32-
"See also: <a href='#ExprPassenger'>passenger</a>"})
33-
@Examples({"vehicle of the player is a minecart"})
29+
@Description({
30+
"The vehicle an entity is in, if any.",
31+
"This can actually be any entity, e.g. spider jockeys are skeletons that ride on a spider, so the spider is the 'vehicle' of the skeleton.",
32+
"See also: <a href='#ExprPassenger'>passenger</a>"
33+
})
34+
@Example("""
35+
set the vehicle of {game::players::*} to a saddled pig
36+
give {game::players::*} a carrot on a stick
37+
""")
38+
@Example("""
39+
on vehicle enter:
40+
vehicle is a horse
41+
add 1 to {statistics::horseMounting::%uuid of player%}
42+
""")
3443
@Since("2.0")
35-
public class ExprVehicle extends SimplePropertyExpression<Entity, Entity> {
36-
37-
private static final boolean HAS_NEW_MOUNT_EVENTS = Skript.classExists("org.bukkit.event.entity.EntityMountEvent");
38-
39-
private static final boolean HAS_OLD_MOUNT_EVENTS;
40-
@Nullable
41-
private static final Class<?> OLD_MOUNT_EVENT_CLASS;
42-
@Nullable
43-
private static final MethodHandle OLD_GETMOUNT_HANDLE;
44-
@Nullable
45-
private static final Class<?> OLD_DISMOUNT_EVENT_CLASS;
46-
@Nullable
47-
private static final MethodHandle OLD_GETDISMOUNTED_HANDLE;
44+
public class ExprVehicle extends PropertyExpression<Entity, Entity> {
4845

4946
static {
50-
register(ExprVehicle.class, Entity.class, "vehicle[s]", "entities");
51-
52-
// legacy support
53-
boolean hasOldMountEvents = !HAS_NEW_MOUNT_EVENTS &&
54-
Skript.classExists("org.spigotmc.event.entity.EntityMountEvent");
55-
Class<?> oldMountEventClass = null;
56-
MethodHandle oldGetMountHandle = null;
57-
Class<?> oldDismountEventClass = null;
58-
MethodHandle oldGetDismountedHandle = null;
59-
if (hasOldMountEvents) {
60-
try {
61-
MethodHandles.Lookup lookup = MethodHandles.lookup();
62-
MethodType entityReturnType = MethodType.methodType(Entity.class);
63-
// mount event
64-
oldMountEventClass = Class.forName("org.spigotmc.event.entity.EntityMountEvent");
65-
oldGetMountHandle = lookup.findVirtual(oldMountEventClass, "getMount", entityReturnType);
66-
// dismount event
67-
oldDismountEventClass = Class.forName("org.spigotmc.event.entity.EntityDismountEvent");
68-
oldGetDismountedHandle = lookup.findVirtual(oldDismountEventClass, "getDismounted", entityReturnType);
69-
} catch (ClassNotFoundException | IllegalAccessException | NoSuchMethodException e) {
70-
hasOldMountEvents = false;
71-
oldMountEventClass = null;
72-
oldGetMountHandle = null;
73-
oldDismountEventClass = null;
74-
oldGetDismountedHandle = null;
75-
Skript.exception(e, "Failed to load old mount event support.");
76-
}
77-
}
78-
HAS_OLD_MOUNT_EVENTS = hasOldMountEvents;
79-
OLD_MOUNT_EVENT_CLASS = oldMountEventClass;
80-
OLD_GETMOUNT_HANDLE = oldGetMountHandle;
81-
OLD_DISMOUNT_EVENT_CLASS = oldDismountEventClass;
82-
OLD_GETDISMOUNTED_HANDLE = oldGetDismountedHandle;
83-
}
84-
85-
@Override
86-
protected Entity[] get(final Event e, final Entity[] source) {
87-
return get(source, entity -> {
88-
if (getTime() >= 0 && e instanceof VehicleEnterEvent && entity.equals(((VehicleEnterEvent) e).getEntered()) && !Delay.isDelayed(e)) {
89-
return ((VehicleEnterEvent) e).getVehicle();
90-
}
91-
if (getTime() >= 0 && e instanceof VehicleExitEvent && entity.equals(((VehicleExitEvent) e).getExited()) && !Delay.isDelayed(e)) {
92-
return ((VehicleExitEvent) e).getVehicle();
93-
}
94-
if (
95-
(HAS_OLD_MOUNT_EVENTS || HAS_NEW_MOUNT_EVENTS)
96-
&& getTime() >= 0 && !Delay.isDelayed(e)
97-
&& e instanceof EntityEvent && entity.equals(((EntityEvent) e).getEntity())
98-
) {
99-
if (HAS_NEW_MOUNT_EVENTS) {
100-
if (e instanceof EntityMountEvent)
101-
return ((EntityMountEvent) e).getMount();
102-
if (e instanceof EntityDismountEvent)
103-
return ((EntityDismountEvent) e).getDismounted();
104-
} else { // legacy mount event support
105-
try {
106-
assert OLD_MOUNT_EVENT_CLASS != null;
107-
if (OLD_MOUNT_EVENT_CLASS.isInstance(e)) {
108-
assert OLD_GETMOUNT_HANDLE != null;
109-
return (Entity) OLD_GETMOUNT_HANDLE.invoke(e);
110-
}
111-
assert OLD_DISMOUNT_EVENT_CLASS != null;
112-
if (OLD_DISMOUNT_EVENT_CLASS.isInstance(e)) {
113-
assert OLD_GETDISMOUNTED_HANDLE != null;
114-
return (Entity) OLD_GETDISMOUNTED_HANDLE.invoke(e);
115-
}
116-
} catch (Throwable ex) {
117-
Skript.exception(ex, "An error occurred while trying to invoke legacy mount event support.");
118-
}
119-
}
120-
}
121-
return entity.getVehicle();
122-
});
47+
if (Skript.classExists("org.bukkit.event.entity.EntityMountEvent"))
48+
registerDefault(ExprVehicle.class, Entity.class, "vehicle[s]", "entities");
12349
}
124-
125-
@Override
126-
@Nullable
127-
public Entity convert(final Entity e) {
128-
assert false;
129-
return e.getVehicle();
130-
}
131-
50+
13251
@Override
133-
public Class<? extends Entity> getReturnType() {
134-
return Entity.class;
52+
@SuppressWarnings("unchecked")
53+
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
54+
setExpr((Expression<Entity>) expressions[0]);
55+
return true;
13556
}
136-
57+
13758
@Override
138-
protected String getPropertyName() {
139-
return "vehicle";
59+
protected Entity[] get(Event event, Entity[] source) {
60+
if (event instanceof EntityDismountEvent entityDismountEvent && getTime() != EventValues.TIME_FUTURE) {
61+
return get(source, e -> e.equals(entityDismountEvent.getEntity()) ? entityDismountEvent.getDismounted() : e.getVehicle());
62+
} else if (event instanceof VehicleEnterEvent vehicleEnterEvent && getTime() != EventValues.TIME_PAST) {
63+
return get(source, e -> e.equals(vehicleEnterEvent.getEntered()) ? vehicleEnterEvent.getVehicle() : e.getVehicle());
64+
} else if (event instanceof VehicleExitEvent vehicleExitEvent && getTime() != EventValues.TIME_FUTURE) {
65+
return get(source, e -> e.equals(vehicleExitEvent.getExited()) ? vehicleExitEvent.getVehicle() : e.getVehicle());
66+
} else if (event instanceof EntityMountEvent entityMountEvent && getTime() != EventValues.TIME_PAST) {
67+
return get(source, e -> e.equals(entityMountEvent.getEntity()) ? entityMountEvent.getMount() : e.getVehicle());
68+
} else {
69+
return get(source, Entity::getVehicle);
70+
}
14071
}
141-
72+
14273
@Override
143-
@Nullable
144-
public Class<?>[] acceptChange(final ChangeMode mode) {
74+
public Class<?> @Nullable [] acceptChange(ChangeMode mode) {
14575
if (mode == ChangeMode.SET) {
76+
if (isDefault() && getParser().isCurrentEvent(VehicleExitEvent.class, EntityDismountEvent.class)) {
77+
Skript.error("Setting the vehicle during a dismount/exit vehicle event will create an infinite mounting loop.");
78+
return null;
79+
}
14680
return new Class[] {Entity.class, EntityData.class};
14781
}
14882
return super.acceptChange(mode);
14983
}
150-
84+
15185
@Override
152-
public void change(final Event e, final @Nullable Object[] delta, final ChangeMode mode) {
86+
public void change(Event event, @Nullable Object[] delta, ChangeMode mode) {
15387
if (mode == ChangeMode.SET) {
154-
assert delta != null;
155-
final Entity[] ps = getExpr().getArray(e);
156-
if (ps.length == 0)
88+
// The player can desync if setting an entity as it's currently mounting it.
89+
// Remember that there can be other entity types aside from players, so only cancel this for players.
90+
Predicate<Entity> predicate = Player.class::isInstance;
91+
if (event instanceof EntityMountEvent entityMountEvent && predicate.test(entityMountEvent.getEntity())) {
92+
return;
93+
}
94+
if (event instanceof VehicleEnterEvent vehicleEnterEvent && predicate.test(vehicleEnterEvent.getEntered())) {
95+
return;
96+
}
97+
Entity[] passengers = getExpr().getArray(event);
98+
if (passengers.length == 0)
15799
return;
158-
final Object o = delta[0];
159-
if (o instanceof Entity) {
160-
((Entity) o).eject();
161-
final Entity p = CollectionUtils.getRandom(ps);
162-
assert p != null;
163-
p.leaveVehicle();
164-
((Entity) o).setPassenger(p);
165-
} else if (o instanceof EntityData) {
166-
for (final Entity p : ps) {
167-
final Entity v = ((EntityData<?>) o).spawn(p.getLocation());
168-
if (v == null)
100+
assert delta != null;
101+
Object object = delta[0];
102+
if (object instanceof Entity entity) {
103+
entity.eject();
104+
for (Entity passenger : passengers) {
105+
// Avoid infinity mounting
106+
if (event instanceof VehicleExitEvent && predicate.test(passenger) && passenger.equals(((VehicleExitEvent) event).getExited()))
107+
continue;
108+
if (event instanceof EntityDismountEvent && predicate.test(passenger) && passenger.equals(((EntityDismountEvent) event).getEntity()))
109+
continue;
110+
assert passenger != null;
111+
passenger.leaveVehicle();
112+
entity.addPassenger(passenger);
113+
}
114+
} else if (object instanceof EntityData entityData) {
115+
VehicleExitEvent vehicleExitEvent = event instanceof VehicleExitEvent ? (VehicleExitEvent) event : null;
116+
EntityDismountEvent entityDismountEvent = event instanceof EntityDismountEvent ? (EntityDismountEvent) event : null;
117+
for (Entity passenger : passengers) {
118+
// Avoid infinity mounting
119+
if (vehicleExitEvent != null && predicate.test(passenger) && passenger.equals(vehicleExitEvent.getExited()))
120+
continue;
121+
if (entityDismountEvent != null && predicate.test(passenger) && passenger.equals(entityDismountEvent.getEntity()))
122+
continue;
123+
Entity vehicle = entityData.spawn(passenger.getLocation());
124+
if (vehicle == null)
169125
continue;
170-
v.setPassenger(p);
126+
vehicle.addPassenger(passenger);
171127
}
172128
} else {
173129
assert false;
174130
}
175131
} else {
176-
super.change(e, delta, mode);
132+
super.change(event, delta, mode);
177133
}
178134
}
179-
180-
@SuppressWarnings("unchecked")
135+
181136
@Override
182-
public boolean setTime(final int time) {
183-
return super.setTime(time, getExpr(), VehicleEnterEvent.class, VehicleExitEvent.class);
137+
public boolean setTime(int time) {
138+
return super.setTime(time, getExpr(), VehicleEnterEvent.class, VehicleExitEvent.class, EntityMountEvent.class, EntityDismountEvent.class);
184139
}
185-
140+
141+
@Override
142+
public Class<? extends Entity> getReturnType() {
143+
return Entity.class;
144+
}
145+
146+
@Override
147+
public String toString(@Nullable Event event, boolean debug) {
148+
return "vehicle of " + getExpr().toString(event, debug);
149+
}
150+
186151
}

0 commit comments

Comments
 (0)