Modules implementation
This commit is contained in:
@@ -0,0 +1,80 @@
|
|||||||
|
package org.saturnclient.impl.modules;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.util.hit.EntityHitResult;
|
||||||
|
import net.minecraft.util.hit.HitResult;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
|
||||||
|
import org.saturnclient.common.module.EntityModule;
|
||||||
|
import org.saturnclient.modules.HealthRenderState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fabric implementation of {@link EntityModule}.
|
||||||
|
*
|
||||||
|
* Crosshair targeting is resolved via {@link MinecraftClient#crosshairTarget}.
|
||||||
|
* Entity state for nametag rendering is supplied at render time by
|
||||||
|
* {@link org.saturnclient.modules.mixins.LivingEntityRendererMixin} which
|
||||||
|
* writes into the render state; {@link NametagsMixin} then constructs
|
||||||
|
* a {@link RenderStateEntityState} from the already-extracted snapshot.
|
||||||
|
*/
|
||||||
|
public class EntityModuleFabric implements EntityModule {
|
||||||
|
|
||||||
|
private final MinecraftClient mc;
|
||||||
|
|
||||||
|
public EntityModuleFabric(MinecraftClient mc) {
|
||||||
|
this.mc = mc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetingLivingEntity() {
|
||||||
|
HitResult target = mc.crosshairTarget;
|
||||||
|
if (target == null || target.getType() != HitResult.Type.ENTITY)
|
||||||
|
return false;
|
||||||
|
Entity hit = ((EntityHitResult) target).getEntity();
|
||||||
|
return hit instanceof LivingEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Render-state adapter
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a {@link HealthRenderState} (already injected into the
|
||||||
|
* Minecraft render-state object) as a platform-neutral
|
||||||
|
* {@link EntityState} for use by {@link NametagsFeature}.
|
||||||
|
*
|
||||||
|
* This is constructed inside {@link NametagsMixin} where both the
|
||||||
|
* render-state mixin interface and the entity name are available.
|
||||||
|
*/
|
||||||
|
public static final class RenderStateEntityState implements EntityState {
|
||||||
|
|
||||||
|
private final String customName;
|
||||||
|
private final HealthRenderState hrs;
|
||||||
|
|
||||||
|
public RenderStateEntityState(String customName, HealthRenderState hrs) {
|
||||||
|
this.customName = customName;
|
||||||
|
this.hrs = hrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCustomName() {
|
||||||
|
return customName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getHealth() {
|
||||||
|
return hrs.saturn$getHealth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getMaxHealth() {
|
||||||
|
return hrs.saturn$getMaxHealth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityType getEntityType() {
|
||||||
|
return hrs.saturn$getEntityType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package org.saturnclient.impl.modules;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
|
||||||
|
import org.saturnclient.common.provider.ModuleProvider;
|
||||||
|
import org.saturnclient.common.module.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fabric implementation of {@link ModuleProvider}.
|
||||||
|
*
|
||||||
|
* Instantiated once during client startup (e.g. in the mod initialiser)
|
||||||
|
* and passed to every feature constructor. All five sub-modules share
|
||||||
|
* the same {@link MinecraftClient} reference so there is no
|
||||||
|
* inconsistency between modules reading state within the same tick.
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* ModuleProvider provider = new ModuleProviderFabric(MinecraftClient.getInstance());
|
||||||
|
* FeatureManager.register(new AutoSprintFeature(provider));
|
||||||
|
* FeatureManager.register(new CoordinatesFeature(provider));
|
||||||
|
* // …
|
||||||
|
* }</pre>
|
||||||
|
*/
|
||||||
|
public class ModuleProviderFabric implements ModuleProvider {
|
||||||
|
|
||||||
|
private final PlayerModule player;
|
||||||
|
private final WorldModule world;
|
||||||
|
private final EntityModule entity;
|
||||||
|
private final RenderModule render;
|
||||||
|
private final NetworkModule network;
|
||||||
|
|
||||||
|
public ModuleProviderFabric(MinecraftClient mc) {
|
||||||
|
this.player = new PlayerModuleFabric(mc);
|
||||||
|
this.world = new WorldModuleFabric(mc);
|
||||||
|
this.entity = new EntityModuleFabric(mc);
|
||||||
|
this.render = new RenderModuleFabric(mc);
|
||||||
|
this.network = new NetworkModuleFabric(mc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlayerModule player() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WorldModule world() {
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityModule entity() {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RenderModule render() {
|
||||||
|
return render;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkModule network() {
|
||||||
|
return network;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package org.saturnclient.impl.modules;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.network.PlayerListEntry;
|
||||||
|
|
||||||
|
import org.saturnclient.common.module.NetworkModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fabric implementation of {@link NetworkModule}.
|
||||||
|
*
|
||||||
|
* Connection presence is checked via the network handler.
|
||||||
|
* Ping is read from the player's {@link PlayerListEntry} which the
|
||||||
|
* server populates; returns {@code -1} when unavailable.
|
||||||
|
*/
|
||||||
|
public class NetworkModuleFabric implements NetworkModule {
|
||||||
|
|
||||||
|
private final MinecraftClient mc;
|
||||||
|
|
||||||
|
public NetworkModuleFabric(MinecraftClient mc) {
|
||||||
|
this.mc = mc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNetwork() {
|
||||||
|
return mc.getNetworkHandler() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPing() {
|
||||||
|
if (mc.player == null || mc.getNetworkHandler() == null)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
PlayerListEntry entry = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
|
||||||
|
|
||||||
|
return entry != null ? entry.getLatency() : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,301 @@
|
|||||||
|
package org.saturnclient.impl.modules;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.network.ClientPlayerEntity;
|
||||||
|
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
|
||||||
|
import org.saturnclient.common.module.PlayerModule;
|
||||||
|
import org.saturnclient.common.ref.asset.SpriteRef;
|
||||||
|
import org.saturnclient.common.ref.game.ItemStackRef;
|
||||||
|
import org.saturnclient.feature.features.StatusEffectsFeature;
|
||||||
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fabric implementation of {@link PlayerModule}.
|
||||||
|
*
|
||||||
|
* All access to {@link MinecraftClient} and {@link ClientPlayerEntity}
|
||||||
|
* is encapsulated here. Features only ever see the {@link PlayerModule}
|
||||||
|
* interface; they never import Minecraft classes directly.
|
||||||
|
*
|
||||||
|
* Every method guards against a missing player and returns a safe
|
||||||
|
* default so features are free of null checks.
|
||||||
|
*/
|
||||||
|
public class PlayerModuleFabric implements PlayerModule {
|
||||||
|
|
||||||
|
private final MinecraftClient mc;
|
||||||
|
|
||||||
|
public PlayerModuleFabric(MinecraftClient mc) {
|
||||||
|
this.mc = mc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Internal helper — never returns null
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Returns the local player, or {@code null} if one is not loaded. */
|
||||||
|
private ClientPlayerEntity player() {
|
||||||
|
return mc.player;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Presence
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPlayer() {
|
||||||
|
return mc.player != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Position
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return hasPlayer() ? (int) player().getX() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getY() {
|
||||||
|
return hasPlayer() ? (int) player().getY() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZ() {
|
||||||
|
return hasPlayer() ? (int) player().getZ() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Input / movement
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isForwardPressed() {
|
||||||
|
return mc.options.forwardKey.isPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBackPressed() {
|
||||||
|
return mc.options.backKey.isPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeftPressed() {
|
||||||
|
return mc.options.leftKey.isPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRightPressed() {
|
||||||
|
return mc.options.rightKey.isPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isJumpPressed() {
|
||||||
|
return mc.options.jumpKey.isPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAttackPressed() {
|
||||||
|
return mc.options.attackKey.isPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUsePressed() {
|
||||||
|
return mc.options.useKey.isPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSneaking() {
|
||||||
|
return hasPlayer() && player().isSneaking();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUsingItem() {
|
||||||
|
return hasPlayer() && player().isUsingItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasHorizontalCollision() {
|
||||||
|
return hasPlayer() && player().horizontalCollision;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOnGround() {
|
||||||
|
return hasPlayer() && player().isOnGround();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSprinting(boolean sprinting) {
|
||||||
|
if (hasPlayer())
|
||||||
|
player().setSprinting(sprinting);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Velocity
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Velocity getVelocity() {
|
||||||
|
if (!hasPlayer())
|
||||||
|
return Velocity.ZERO;
|
||||||
|
var v = player().getVelocity();
|
||||||
|
return new Velocity(v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Stats
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getHealth() {
|
||||||
|
return hasPlayer() ? player().getHealth() : 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Equipment
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStackRef getMainHand() {
|
||||||
|
return wrap(hasPlayer() ? player().getMainHandStack() : ItemStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStackRef getHelmet() {
|
||||||
|
return wrap(hasPlayer() ? player().getInventory().armor.get(3) : ItemStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStackRef getChestplate() {
|
||||||
|
return wrap(hasPlayer() ? player().getInventory().armor.get(2) : ItemStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStackRef getLeggings() {
|
||||||
|
return wrap(hasPlayer() ? player().getInventory().armor.get(1) : ItemStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStackRef getBoots() {
|
||||||
|
return wrap(hasPlayer() ? player().getInventory().armor.get(0) : ItemStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Dummy equipment
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStackRef getDummyMainHand() {
|
||||||
|
return wrap(hasPlayer() ? player().getInventory().armor.get(3) : ItemStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStackRef getDummyHelmet() {
|
||||||
|
return wrap(hasPlayer() ? player().getInventory().armor.get(3) : ItemStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStackRef getDummyChestplate() {
|
||||||
|
return wrap(hasPlayer() ? player().getInventory().armor.get(2) : ItemStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStackRef getDummyLeggings() {
|
||||||
|
return wrap(hasPlayer() ? player().getInventory().armor.get(1) : ItemStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStackRef getDummyBoots() {
|
||||||
|
return wrap(hasPlayer() ? player().getInventory().armor.get(0) : ItemStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Status effects
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends StatusEffectsFeature.EffectView> getActiveEffects() {
|
||||||
|
if (!hasPlayer())
|
||||||
|
return Collections.emptyList();
|
||||||
|
|
||||||
|
var effects = player().getActiveStatusEffects().values();
|
||||||
|
List<FabricEffectView> result = new ArrayList<>(effects.size());
|
||||||
|
for (StatusEffectInstance instance : effects) {
|
||||||
|
result.add(new FabricEffectView(instance));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends StatusEffectsFeature.EffectView> getDummyEffects() {
|
||||||
|
if (!hasPlayer())
|
||||||
|
return Collections.emptyList();
|
||||||
|
|
||||||
|
var effects = player().getActiveStatusEffects().values();
|
||||||
|
List<FabricEffectView> result = new ArrayList<>(effects.size());
|
||||||
|
for (StatusEffectInstance instance : effects) {
|
||||||
|
result.add(new FabricEffectView(instance));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Helpers
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
private static ItemStackRef wrap(ItemStack stack) {
|
||||||
|
return (ItemStackRef) (Object) stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Inner — EffectView adapter
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bridges a Fabric {@link StatusEffectInstance} to the
|
||||||
|
* platform-neutral {@link StatusEffectsFeature.EffectView}.
|
||||||
|
*/
|
||||||
|
public static final class FabricEffectView implements StatusEffectsFeature.EffectView {
|
||||||
|
|
||||||
|
private final StatusEffectInstance instance;
|
||||||
|
|
||||||
|
public FabricEffectView(StatusEffectInstance instance) {
|
||||||
|
this.instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldShowIcon() {
|
||||||
|
return instance.shouldShowIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Minecraft sprite identifier for this effect's icon.
|
||||||
|
* The platform-specific renderer knows how to draw a
|
||||||
|
* {@link net.minecraft.util.Identifier}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public SpriteRef getIcon() {
|
||||||
|
return (SpriteRef) SaturnClient.client.getStatusEffectSpriteManager().getSprite(instance.getEffectType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInfinite() {
|
||||||
|
return instance.isInfinite();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getInfiniteText() {
|
||||||
|
return "∞";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDurationSeconds() {
|
||||||
|
return instance.getDuration() / 20; // ticks → seconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package org.saturnclient.impl.modules;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.option.Perspective;
|
||||||
|
|
||||||
|
import org.saturnclient.common.module.RenderModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fabric implementation of {@link RenderModule}.
|
||||||
|
*
|
||||||
|
* Window dimensions and FPS are read directly from
|
||||||
|
* {@link MinecraftClient}. Camera perspective control delegates to
|
||||||
|
* {@link net.minecraft.client.option.GameOptions}.
|
||||||
|
*/
|
||||||
|
public class RenderModuleFabric implements RenderModule {
|
||||||
|
|
||||||
|
private final MinecraftClient mc;
|
||||||
|
|
||||||
|
public RenderModuleFabric(MinecraftClient mc) {
|
||||||
|
this.mc = mc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Window
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getScaledWindowWidth() {
|
||||||
|
return mc.getWindow().getScaledWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getScaledWindowHeight() {
|
||||||
|
return mc.getWindow().getScaledHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Performance
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFps() {
|
||||||
|
return mc.getCurrentFps();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Camera perspective
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFirstPerson() {
|
||||||
|
return mc.options.getPerspective() == Perspective.FIRST_PERSON;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFirstPerson() {
|
||||||
|
mc.options.setPerspective(Perspective.FIRST_PERSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setThirdPersonBack() {
|
||||||
|
mc.options.setPerspective(Perspective.THIRD_PERSON_BACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.saturnclient.impl.modules;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
|
||||||
|
import org.saturnclient.common.module.WorldModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fabric implementation of {@link WorldModule}.
|
||||||
|
*
|
||||||
|
* Reads the client world's time directly from {@link MinecraftClient}.
|
||||||
|
* Returns safe defaults when no world is loaded.
|
||||||
|
*/
|
||||||
|
public class WorldModuleFabric implements WorldModule {
|
||||||
|
|
||||||
|
private final MinecraftClient mc;
|
||||||
|
|
||||||
|
public WorldModuleFabric(MinecraftClient mc) {
|
||||||
|
this.mc = mc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasWorld() {
|
||||||
|
return mc.world != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total world age in ticks, or {@code 0} when no world
|
||||||
|
* is loaded. Used by {@link TpsFeature#onTimePacket} (which is
|
||||||
|
* called from the mixin and stores its own copy) and by
|
||||||
|
* {@link DayCounterFeature} for the day count.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long getWorldAge() {
|
||||||
|
return hasWorld() ? mc.world.getTime() : 0L;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user