Skip to content

Commit

Permalink
misc: 不再对本体有效,修正ByRangeExecutor的模拟链构建
Browse files Browse the repository at this point in the history
  • Loading branch information
MATRIX-feather committed Jan 29, 2025
1 parent e7d8b6b commit b151880
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 92 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package xyz.nifeather.morph.events.mirror.impl;

import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.world.level.GameType;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
Expand All @@ -9,7 +11,6 @@
import xyz.nifeather.morph.storage.mirrorlogging.OperationType;

import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class ByRangeExecutor extends ChainedExecutor
{
Expand All @@ -20,38 +21,44 @@ public ByRangeExecutor(ExecutorHub executorHub)

@Override
protected @Nullable Player findNextControllablePlayerFrom(Player source, List<Player> pendingChain)
{
var index = pendingChain.indexOf(source);

if (index == -1 || index >= pendingChain.size())
return null;

return pendingChain.get(index + 1);
}

@Override
protected List<Player> buildSimulateChain(Player source)
{
var targetName = getTargetControlFor(source);
if (targetName == null)
targetName = source.getName();

var range = executorHub.getControlDistance();
return List.of(source);

String finalTargetName = targetName;
var nmsPlayer = NmsRecord.ofPlayer(source).level()
.getNearestPlayer(source.getX(), source.getY(), source.getZ(),
range, entity ->
{
var bukkitInstance = entity.getBukkitEntity();
var matchedPlayers = source.getWorld().getNearbyPlayers(source.getLocation(), executorHub.getControlDistance(), p ->
{
if (p == source)
return false;

if (bukkitInstance == source)
return false;
if (NmsRecord.ofPlayer(p).gameMode.getGameModeForPlayer() ==GameType.SPECTATOR)
return false;

if (!(bukkitInstance instanceof Player player))
return false;
var theirState = morphManager().getDisguiseStateFor(p);

if (pendingChain.contains(player))
return false;
if (theirState != null && theirState.getDisguiseIdentifier().equals("player:" + targetName))
return true;
else
return p.getName().equals(targetName) && theirState == null;
});

var theirState = morphManager().getDisguiseStateFor(bukkitInstance);
var list = new ObjectArrayList<Player>();

if (theirState != null && theirState.getDisguiseIdentifier().equals("player:" + finalTargetName))
return true;
else
return bukkitInstance.getName().equals(finalTargetName) && theirState == null;
});
list.add(source);
list.addAll(matchedPlayers);

return nmsPlayer == null ? null : (Player) nmsPlayer.getBukkitEntity();
return list;
}

@Override
Expand Down Expand Up @@ -94,6 +101,12 @@ public boolean onSwing(Player source)
return false;
}

@Override
public boolean onHurtEntity(Player damager, Player hurted)
{
return !isInChain(damager) || !isInChain(hurted);
}

@Override
public void reset()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package xyz.nifeather.morph.events.mirror.impl;

import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import xyz.nifeather.morph.events.InteractionMirrorProcessor;
import xyz.nifeather.morph.events.PlayerTracker;
import xyz.nifeather.morph.events.mirror.ExecutorHub;
import xyz.nifeather.morph.storage.mirrorlogging.OperationType;
import xyz.nifeather.morph.utilities.NmsUtils;

import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class BySightExecutor extends ChainedExecutor
{
Expand Down Expand Up @@ -52,4 +56,73 @@ else if (targetPlayer.getName().equals(targetName) && state == null)
else
return null;
}

@Override
public boolean onHurtEntity(Player damager, Player hurted)
{
var simulateTarget = findNextControllablePlayerFrom(damager, currentSimulateChain.get());

if (simulateTarget == null)
return false;

// 因为HurtEntity之后一定有次ArmSwing,所以不需要在这里进行模拟操作

var damagerLookingAt = damager.getTargetEntity(5);
var playerLookingAt = simulateTarget.getTargetEntity(5);

//如果伪装的玩家想攻击的实体和被伪装的玩家一样,模拟左键并取消事件
if (damagerLookingAt != null && damagerLookingAt.equals(playerLookingAt))
return true;

return hurted.equals(simulateTarget);
}

@Override
public boolean onSwing(Player source)
{
var isInChain = isInChain(source);

// 如果玩家在链条中,并且不是链条中的最后一个,则取消挥手的事件
if (isInChain)
{
if (isLastInChain(source))
return false;

return true;
}

var tracker = tracker();

//若源玩家正在丢出物品,不要处理
if (tracker.droppingItemThisTick(source))
return false;

var lastAction = tracker.getLastInteractAction(source);

//如果此时玩家没有触发Interaction, 那么默认设置为左键空气
if (!tracker.interactingThisTick(source))
lastAction = PlayerTracker.InteractType.LEFT_CLICK_AIR;

if (lastAction == null) return false;

//旁观者模式下左键方块不会产生Interact事件,我们得猜这个玩家现在是左键还是右键
if (source.getGameMode() == GameMode.SPECTATOR)
{
if (lastAction.isRightClick())
lastAction = PlayerTracker.InteractType.LEFT_CLICK_BLOCK;
}

PlayerTracker.InteractType finalLastAction = lastAction;
AtomicBoolean simulateSuccess = new AtomicBoolean(false);

runIfChainable(source, targetPlayer ->
{
simulateSuccess.set(true);

simulateOperation(finalLastAction.toBukkitAction(), targetPlayer, source);
logOperation(source, targetPlayer, finalLastAction.isLeftClick() ? OperationType.LeftClick : OperationType.RightClick);
});

return simulateSuccess.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,20 @@ protected void runIfChainable(Player source, Consumer<Player> chainConsumer)
currentSimulateChain.remove();
}

/**
* 寻找给定玩家的下一个可控制目标
* @param pendingChain 可以用来参考的模拟链,该链可能未完成
*/
@Nullable
protected abstract Player findNextControllablePlayerFrom(Player source, List<Player> pendingChain);

/**
* 构建包含发起玩家在内的模拟链
* @implNote 发起的玩家必须是第一个元素
*
* @param source
* @return
*/
protected List<Player> buildSimulateChain(Player source)
{
List<Player> chain = new ObjectArrayList<>();
Expand Down Expand Up @@ -165,75 +176,6 @@ public void onStopUsingItem(Player player, ItemStack itemStack)
});
}

@Override
public boolean onHurtEntity(Player damager, Player hurted)
{
var targetPlayer = findNextControllablePlayerFrom(damager, List.of());

if (targetPlayer == null)
return false;

// 因为HurtEntity之后一定有次ArmSwing,所以不需要在这里进行模拟操作

var damagerLookingAt = damager.getTargetEntity(5);
var playerLookingAt = targetPlayer.getTargetEntity(5);

//如果伪装的玩家想攻击的实体和被伪装的玩家一样,模拟左键并取消事件
if (damagerLookingAt != null && damagerLookingAt.equals(playerLookingAt))
return true;

return hurted.equals(targetPlayer);
}

@Override
public boolean onSwing(Player source)
{
var isInChain = isInChain(source);

// 如果玩家在链条中,并且不是链条中的最后一个,则取消挥手的事件
if (isInChain)
{
if (isLastInChain(source))
return false;

return true;
}

var tracker = tracker();

//若源玩家正在丢出物品,不要处理
if (tracker.droppingItemThisTick(source))
return false;

var lastAction = tracker.getLastInteractAction(source);

//如果此时玩家没有触发Interaction, 那么默认设置为左键空气
if (!tracker.interactingThisTick(source))
lastAction = PlayerTracker.InteractType.LEFT_CLICK_AIR;

if (lastAction == null) return false;

//旁观者模式下左键方块不会产生Interact事件,我们得猜这个玩家现在是左键还是右键
if (source.getGameMode() == GameMode.SPECTATOR)
{
if (lastAction.isRightClick())
lastAction = PlayerTracker.InteractType.LEFT_CLICK_BLOCK;
}

PlayerTracker.InteractType finalLastAction = lastAction;
AtomicBoolean simulateSuccess = new AtomicBoolean(false);

runIfChainable(source, targetPlayer ->
{
simulateSuccess.set(true);

simulateOperation(finalLastAction.toBukkitAction(), targetPlayer, source);
logOperation(source, targetPlayer, finalLastAction.isLeftClick() ? OperationType.LeftClick : OperationType.RightClick);
});

return simulateSuccess.get();
}

@Override
public void onInteract(Player source, Action action)
{
Expand Down

0 comments on commit b151880

Please sign in to comment.