Created
June 17, 2026 22:10
-
-
Save ZeroErrors/6d29be75d9969231caa532a8758e5bb4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package dev.zero.scaleeffect; | |
| import com.hypixel.hytale.component.Component; | |
| import com.hypixel.hytale.component.ComponentType; | |
| import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; | |
| import javax.annotation.Nonnull; | |
| public class ScaleAnimation implements Component<EntityStore> { | |
| private static ComponentType<EntityStore, ScaleAnimation> componentType; | |
| public static ComponentType<EntityStore, ScaleAnimation> getComponentType() { | |
| return componentType; | |
| } | |
| public static void setComponentType(@Nonnull ComponentType<EntityStore, ScaleAnimation> type) { | |
| componentType = type; | |
| } | |
| private float startScale = 1f; | |
| private float targetScale = 1f; | |
| private float duration = 1f; | |
| private float elapsed = 0f; | |
| public ScaleAnimation() { | |
| } | |
| public ScaleAnimation(float startScale, float targetScale, float duration) { | |
| this.startScale = startScale; | |
| this.targetScale = targetScale; | |
| this.duration = duration; | |
| } | |
| public float getStartScale() { | |
| return startScale; | |
| } | |
| public float getTargetScale() { | |
| return targetScale; | |
| } | |
| public float getDuration() { | |
| return duration; | |
| } | |
| public float getElapsed() { | |
| return elapsed; | |
| } | |
| public void advance(float dt) { | |
| elapsed += dt; | |
| } | |
| @Nonnull | |
| @Override | |
| public Component<EntityStore> clone() { | |
| var copy = new ScaleAnimation(startScale, targetScale, duration); | |
| copy.elapsed = elapsed; | |
| return copy; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package dev.zero.scaleeffect; | |
| import com.hypixel.hytale.component.ArchetypeChunk; | |
| import com.hypixel.hytale.component.CommandBuffer; | |
| import com.hypixel.hytale.component.Store; | |
| import com.hypixel.hytale.component.query.Query; | |
| import com.hypixel.hytale.component.system.tick.EntityTickingSystem; | |
| import com.hypixel.hytale.server.core.asset.type.model.config.Model; | |
| import com.hypixel.hytale.server.core.modules.entity.component.EntityScaleComponent; | |
| import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent; | |
| import com.hypixel.hytale.server.core.modules.entity.player.PlayerSkinComponent; | |
| import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; | |
| import javax.annotation.Nonnull; | |
| public class ScaleAnimationSystem extends EntityTickingSystem<EntityStore> { | |
| private static final float MIN_SCALE = 0.01f; | |
| private final Query<EntityStore> query = Query.and( | |
| ScaleAnimation.getComponentType(), | |
| ModelComponent.getComponentType() | |
| ); | |
| @Nonnull | |
| @Override | |
| public Query<EntityStore> getQuery() { | |
| return query; | |
| } | |
| @Override | |
| public void tick(float dt, int index, @Nonnull ArchetypeChunk<EntityStore> chunk, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer) { | |
| var animation = chunk.getComponent(index, ScaleAnimation.getComponentType()); | |
| var modelComponent = chunk.getComponent(index, ModelComponent.getComponentType()); | |
| if (animation == null || modelComponent == null) return; | |
| animation.advance(dt); | |
| float t = Math.min(animation.getElapsed() / animation.getDuration(), 1f); | |
| float eased = t * t * (3f - 2f * t); | |
| float scale = animation.getStartScale() + (animation.getTargetScale() - animation.getStartScale()) * eased; | |
| scale = Math.max(scale, MIN_SCALE); | |
| var ref = chunk.getReferenceTo(index); | |
| // Two scales drive a player: EntityScaleComponent is the rendered size, the model | |
| // scale is the camera, eye height, and hitbox. Set both so they shrink together. | |
| var scaleComponent = chunk.getComponent(index, EntityScaleComponent.getComponentType()); | |
| if (scaleComponent != null) { | |
| scaleComponent.setScale(scale); | |
| } else { | |
| commandBuffer.putComponent(ref, EntityScaleComponent.getComponentType(), new EntityScaleComponent(scale)); | |
| } | |
| var reference = modelComponent.getModel().toReference(); | |
| var scaledModel = new Model.ModelReference(reference.getModelAssetId(), scale, | |
| reference.getRandomAttachmentIds(), reference.isStaticModel()).toModel(); | |
| if (scaledModel != null) { | |
| commandBuffer.putComponent(ref, ModelComponent.getComponentType(), new ModelComponent(scaledModel)); | |
| // Rebuilding the model resends the default texture, so re-flag the skin to keep it applied. | |
| var skin = chunk.getComponent(index, PlayerSkinComponent.getComponentType()); | |
| if (skin != null) skin.setNetworkOutdated(); | |
| } | |
| if (t >= 1f) { | |
| commandBuffer.tryRemoveComponent(ref, ScaleAnimation.getComponentType()); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package dev.zero.scaleeffect; | |
| import com.hypixel.hytale.builtin.triggervolumes.effect.TriggerContext; | |
| import com.hypixel.hytale.builtin.triggervolumes.effect.TriggerEffect; | |
| import com.hypixel.hytale.codec.Codec; | |
| import com.hypixel.hytale.codec.KeyedCodec; | |
| import com.hypixel.hytale.codec.builder.BuilderCodec; | |
| import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent; | |
| import javax.annotation.Nonnull; | |
| public class ScaleEffect extends TriggerEffect { | |
| @Nonnull | |
| public static final BuilderCodec<ScaleEffect> CODEC = BuilderCodec.builder(ScaleEffect.class, ScaleEffect::new, BASE_CODEC) | |
| .append( | |
| new KeyedCodec<>("TargetScale", Codec.FLOAT, false), | |
| (e, v) -> e.targetScale = v, | |
| e -> e.targetScale | |
| ).add() | |
| .append( | |
| new KeyedCodec<>("Duration", Codec.FLOAT, false), | |
| (e, v) -> e.duration = v, | |
| e -> e.duration | |
| ).add() | |
| .build(); | |
| private float targetScale = 0.25f; | |
| private float duration = 3.0f; | |
| @Override | |
| public void execute(@Nonnull TriggerContext context) { | |
| var ref = context.getEntityRef(); | |
| var store = context.getStore(); | |
| var modelComponent = store.getComponent(ref, ModelComponent.getComponentType()); | |
| if (modelComponent == null) return; | |
| float startScale = modelComponent.getModel().getScale(); | |
| if (startScale <= 0f) startScale = 1f; | |
| float resolvedDuration = duration > 0f ? duration : 0.0001f; | |
| store.putComponent(ref, ScaleAnimation.getComponentType(), new ScaleAnimation(startScale, targetScale, resolvedDuration)); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package dev.zero.scaleeffect; | |
| import com.hypixel.hytale.builtin.triggervolumes.effect.TriggerEffect; | |
| import com.hypixel.hytale.protocol.ClientCameraView; | |
| import com.hypixel.hytale.protocol.packets.camera.SetServerCamera; | |
| import com.hypixel.hytale.server.core.event.events.BootEvent; | |
| import com.hypixel.hytale.server.core.event.events.player.PlayerReadyEvent; | |
| import com.hypixel.hytale.server.core.plugin.JavaPlugin; | |
| import com.hypixel.hytale.server.core.plugin.JavaPluginInit; | |
| import com.hypixel.hytale.server.core.universe.PlayerRef; | |
| import javax.annotation.Nonnull; | |
| import java.util.logging.Level; | |
| public class ScaleEffectPlugin extends JavaPlugin { | |
| public ScaleEffectPlugin(@Nonnull JavaPluginInit init) { | |
| super(init); | |
| } | |
| @Override | |
| protected void setup() { | |
| ScaleAnimation.setComponentType(getEntityStoreRegistry().registerComponent(ScaleAnimation.class, ScaleAnimation::new)); | |
| getEntityStoreRegistry().registerSystem(new ScaleAnimationSystem()); | |
| TriggerEffect.CODEC.register("Scale", ScaleEffect.class, ScaleEffect.CODEC); | |
| // Note: This is broken atm, prevents interactions and crashes if reset via `/player camera reset`. Fixed in 0.6.0-pre.4 | |
| // getEventRegistry().registerGlobal(PlayerReadyEvent.class, event -> { | |
| // var ref = event.getPlayerRef(); | |
| // var playerRef = ref.getStore().getComponent(ref, PlayerRef.getComponentType()); | |
| // | |
| // playerRef.getPacketHandler().writeNoCache(new SetServerCamera(ClientCameraView.ThirdPerson, false, null)); | |
| // }); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment