package com.disklexar.mmorpg.combat; import com.disklexar.mmorpg.MmorpgPlugin; import com.disklexar.mmorpg.core.service.Service; import com.disklexar.mmorpg.player.OnlinePlayer; import com.disklexar.mmorpg.player.OnlinePlayerRegistry; import com.disklexar.mmorpg.player.PlayerSessionService; import com.disklexar.mmorpg.player.model.PlayerProfile; import com.disklexar.mmorpg.rpg.power.PowerCatalog; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.protocol.MovementSettings; import com.hypixel.hytale.server.core.entity.entities.player.movement.MovementManager; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; import java.util.concurrent.ScheduledFuture; /** * Reconciles passive movement effects every couple of seconds. *

* The "Sprinter" power grants {@code +10%} base movement speed while the player is out of combat; * the bonus is removed while in combat and restored afterwards. */ public final class PassiveEffectService implements Service { private static final long RECONCILE_PERIOD = 2_000L; private final MmorpgScheduler scheduler; private final OnlinePlayerRegistry online; private final PlayerSessionService sessions; private final CombatStateService combatState; private ScheduledFuture task; public PassiveEffectService( @Nonnull MmorpgPlugin plugin, @Nonnull MmorpgScheduler scheduler, @Nonnull OnlinePlayerRegistry online, @Nonnull PlayerSessionService sessions, @Nonnull CombatStateService combatState) { this.scheduler = scheduler; this.online = online; this.sessions = sessions; this.combatState = combatState; } @Override public void start() { task = scheduler.runRepeating(this::reconcileAll, RECONCILE_PERIOD, RECONCILE_PERIOD); } @Override public void shutdown() { if (task != null) { task.cancel(false); task = null; } } private void reconcileAll() { for (OnlinePlayer player : online.all()) { PlayerProfile profile = sessions.getSession(player.uuid()); if (profile == null) { continue; } boolean sprinter = profile.getPowers().contains(PowerCatalog.SPRINTER.id()); boolean active = sprinter && !combatState.isInCombat(player.uuid()); player.world().execute(() -> applySpeed(player, active)); } } private void applySpeed(@Nonnull OnlinePlayer player, boolean buffed) { Store store = player.world().getEntityStore().getStore(); Ref ref = player.entityRef(); MovementManager movement = store.getComponent(ref, MovementManager.getComponentType()); if (movement == null) { return; } MovementSettings defaults = movement.getDefaultSettings(); MovementSettings current = movement.getSettings(); if (defaults == null || current == null) { return; } float baseline = defaults.baseSpeed; float target = buffed ? baseline * (float) (1.0 + PowerCatalog.SPRINTER_SPEED_BONUS) : baseline; if (Math.abs(current.baseSpeed - target) > 0.0001f) { current.baseSpeed = target; movement.update(player.playerRef().getPacketHandler()); } } }