This commit is contained in:
Cilly Leang 2025-03-08 15:13:29 +11:00
parent 6c61b330d1
commit bc920a5d1e
Signed by: cilly
GPG key ID: 6500251E087653C9
15 changed files with 217 additions and 197 deletions

View file

@ -1,6 +1,7 @@
plugins { plugins {
id 'fabric-loom' version '1.10-SNAPSHOT' id 'fabric-loom' version '1.10-SNAPSHOT'
id 'maven-publish' id 'maven-publish'
id 'org.jetbrains.kotlin.jvm'
} }
version = project.mod_version version = project.mod_version
@ -27,6 +28,7 @@ repositories {
includeGroup "maven.modrinth" includeGroup "maven.modrinth"
} }
} }
mavenCentral()
} }
loom { loom {
@ -38,6 +40,7 @@ dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}" minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation "net.fabricmc:fabric-language-kotlin:${project.kotlin_version}"
//modImplementation "maven.modrinth:linkart:5.4.5-1.20.6-build.29" //modImplementation "maven.modrinth:linkart:5.4.5-1.20.6-build.29"
@ -63,8 +66,6 @@ java {
// If you remove this line, sources will not be generated. // If you remove this line, sources will not be generated.
withSourcesJar() withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
} }
jar { jar {
@ -92,3 +93,6 @@ publishing {
// retrieving dependencies. // retrieving dependencies.
} }
} }
kotlin {
jvmToolchain(21)
}

View file

@ -7,6 +7,7 @@ org.gradle.parallel=true
minecraft_version=1.21.4 minecraft_version=1.21.4
yarn_mappings=1.21.4+build.8 yarn_mappings=1.21.4+build.8
loader_version=0.16.10 loader_version=0.16.10
kotlin_version=1.13.1+kotlin.2.1.10
# Mod Properties # Mod Properties
mod_version=1.0.0 mod_version=1.0.0

View file

@ -7,4 +7,10 @@ pluginManagement {
mavenCentral() mavenCentral()
gradlePluginPortal() gradlePluginPortal()
} }
plugins {
id 'org.jetbrains.kotlin.jvm' version '2.1.10'
}
}
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
} }

View file

@ -1,10 +1,9 @@
package moe.lava.cartloader.accessor package moe.lava.cartloader.accessor
import net.minecraft.entity.vehicle.MinecartController import moe.lava.cartloader.impl.MixinAbstractMinecartEntityImpl
import net.minecraft.util.math.ChunkPos import net.minecraft.entity.vehicle.AbstractMinecartEntity
import net.minecraft.world.World
@Suppress("FunctionName") @Suppress("FunctionName")
interface AbstractMinecartEntityAccessor { interface AccessorAbstractMinecartEntity {
fun `cartloader$linkedTick`() fun `cartloader$getImpl`(): MixinAbstractMinecartEntityImpl
} }

View file

@ -1,12 +1,7 @@
package moe.lava.cartloader.accessor package moe.lava.cartloader.accessor
import net.minecraft.entity.vehicle.AbstractMinecartEntity
import net.minecraft.entity.vehicle.ExperimentalMinecartController
import net.minecraft.entity.vehicle.MinecartEntity
import net.minecraft.world.World
@Suppress("FunctionName") @Suppress("FunctionName")
interface ExperimentalMinecartControllerAccessor { interface AccessorExperimentalMinecartController {
fun `cartloader$getSpeedMultiplers`(): Pair<Double, Double> fun `cartloader$getSpeedMultiplers`(): Pair<Double, Double>
fun `cartloader$finishSlowdown`() fun `cartloader$finishSlowdown`()
} }

View file

@ -1,16 +1,17 @@
package moe.lava.cartloader.mixin.impl package moe.lava.cartloader.impl
import moe.lava.cartloader.accessor.AbstractMinecartEntityAccessor import moe.lava.cartloader.accessor.AccessorAbstractMinecartEntity
import moe.lava.cartloader.accessor.ExperimentalMinecartControllerAccessor import moe.lava.cartloader.accessor.AccessorExperimentalMinecartController
import moe.lava.cartloader.mixin.MixinAbstractMinecartEntity import net.minecraft.entity.Entity
import net.minecraft.entity.vehicle.AbstractMinecartEntity
import net.minecraft.entity.vehicle.MinecartController
import net.minecraft.server.world.ChunkTicketType import net.minecraft.server.world.ChunkTicketType
import net.minecraft.server.world.ServerWorld import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.ChunkPos import net.minecraft.util.math.ChunkPos
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import net.minecraft.world.World
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.spongepowered.asm.mixin.injection.At
import org.spongepowered.asm.mixin.injection.Inject
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo import org.spongepowered.asm.mixin.injection.callback.CallbackInfo
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
import java.util.* import java.util.*
@ -18,24 +19,54 @@ import java.util.*
private val TICKET: ChunkTicketType<ChunkPos> = private val TICKET: ChunkTicketType<ChunkPos> =
ChunkTicketType.create("minecart", Comparator.comparingLong { obj: ChunkPos -> obj.toLong() }, 50) ChunkTicketType.create("minecart", Comparator.comparingLong { obj: ChunkPos -> obj.toLong() }, 50)
class MixinAbstractMinecartEntityImpl(private val parent: AbstractMinecartEntityAccessor) { class MixinAbstractMinecartEntityImpl(private val self: AbstractMinecartEntity) {
private val log: Logger = LoggerFactory.getLogger("cartloader@mixin.ame") private val log: Logger = LoggerFactory.getLogger("cartloader@mixin.ame")
private var lastChunk: ChunkPos? = null private var lastChunk: ChunkPos? = null
fun onTick() { // private var parent: UUID? = null;
val world = parent.world; // private var child: UUID? = null;
private var parent: AbstractMinecartEntity? = null;
private var child: AbstractMinecartEntity? = null;
var linked = false
private set
private var allowTicking = false;
private fun linkedTick() {
allowTicking = true;
self.tick();
}
fun linkTo(target: AbstractMinecartEntity) {
parent = target
linked = true
val impl = (target as AccessorAbstractMinecartEntity).`cartloader$getImpl`()
impl.child = self;
impl.linked = true;
}
fun onPreTick(world: World, chunkPos: ChunkPos, callbackInfo: CallbackInfo) {
if (linked && !allowTicking && parent != null) {
callbackInfo.cancel();
return;
}
allowTicking = false;
if (world !is ServerWorld) return if (world !is ServerWorld) return
if (lastChunk == parent.chunkPos) return if (lastChunk == chunkPos) return
lastChunk = parent.chunkPos lastChunk = chunkPos
world.chunkManager.addTicket(TICKET, lastChunk, 3, lastChunk) world.chunkManager.addTicket(TICKET, lastChunk, 3, lastChunk)
} }
fun slowdown(cir: CallbackInfoReturnable<Vec3d>) { fun onPostTick() {
val world = parent.world if (child != null)
val controller = parent.`cartloader$getController`() (child as AccessorAbstractMinecartEntity).`cartloader$getImpl`().linkedTick()
}
fun slowdown(world: World, controller: MinecartController, cir: CallbackInfoReturnable<Vec3d>) {
if (world !is ServerWorld) return if (world !is ServerWorld) return
if (controller !is ExperimentalMinecartControllerAccessor) { if (controller !is AccessorExperimentalMinecartController) {
return return
} }

View file

@ -1,13 +1,13 @@
package moe.lava.cartloader.mixin.impl package moe.lava.cartloader.impl
import jdk.jfr.Experimental import moe.lava.cartloader.accessor.AccessorExperimentalMinecartController
import moe.lava.cartloader.accessor.ExperimentalMinecartControllerAccessor
import moe.lava.cartloader.mixin.MixinExperimentalMinecartController
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.block.Blocks import net.minecraft.block.Blocks
import net.minecraft.block.PoweredRailBlock import net.minecraft.block.PoweredRailBlock
import net.minecraft.entity.vehicle.AbstractMinecartEntity
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import net.minecraft.world.World
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
@ -17,19 +17,19 @@ private const val MAX_ACCELERATION = TOTAL_ACCELERATION * (1 - ACCELERATION_DECA
private const val FINAL_ACCELERATION = TOTAL_ACCELERATION * private const val FINAL_ACCELERATION = TOTAL_ACCELERATION *
ACCELERATION_DECAY * ACCELERATION_DECAY * ACCELERATION_DECAY * ACCELERATION_DECAY * ACCELERATION_DECAY ACCELERATION_DECAY * ACCELERATION_DECAY * ACCELERATION_DECAY * ACCELERATION_DECAY * ACCELERATION_DECAY
class MixinExperimentalMinecartControllerImpl(private val parent: ExperimentalMinecartControllerAccessor) { class MixinExperimentalMinecartControllerImpl(private val parent: AccessorExperimentalMinecartController) {
private val log = LoggerFactory.getLogger("cartloader@mixin.emc") private val log = LoggerFactory.getLogger("cartloader@mixin.emc")
var currentMultiplier = 0.5 var currentMultiplier = 0.5
var targetMultiplier = 0.5 var targetMultiplier = 0.5
private var specialAcceleration = false private var specialAcceleration = false
fun checkRail(pos: BlockPos, railState: BlockState) { fun checkRail(world: World, pos: BlockPos, railState: BlockState) {
val unpoweredRail = railState.isOf(Blocks.POWERED_RAIL) && !railState.get(PoweredRailBlock.POWERED) val unpoweredRail = railState.isOf(Blocks.POWERED_RAIL) && !railState.get(PoweredRailBlock.POWERED)
if (!railState.isOf(Blocks.DETECTOR_RAIL) && !unpoweredRail) if (!railState.isOf(Blocks.DETECTOR_RAIL) && !unpoweredRail)
return return
val under: BlockState = parent.world.getBlockState(pos.down()) val under: BlockState = world.getBlockState(pos.down())
var newMultiplier = 0.0 var newMultiplier = 0.0
if (under.isOf(Blocks.IRON_BLOCK)) newMultiplier = 0.25 if (under.isOf(Blocks.IRON_BLOCK)) newMultiplier = 0.25
else if (under.isOf(Blocks.GOLD_BLOCK)) newMultiplier = 0.5 else if (under.isOf(Blocks.GOLD_BLOCK)) newMultiplier = 0.5
@ -51,6 +51,7 @@ class MixinExperimentalMinecartControllerImpl(private val parent: ExperimentalMi
private var currentAcceleration = 0.0 private var currentAcceleration = 0.0
fun accelerateFromPoweredRail( fun accelerateFromPoweredRail(
minecart: AbstractMinecartEntity,
velocity: Vec3d, velocity: Vec3d,
railPos: BlockPos, railPos: BlockPos,
railState: BlockState, railState: BlockState,
@ -70,7 +71,7 @@ class MixinExperimentalMinecartControllerImpl(private val parent: ExperimentalMi
if (velocity.length() > 0.01) if (velocity.length() > 0.01)
cir.returnValue = velocity.normalize().multiply(velocity.length() * (1 + currentAcceleration)) cir.returnValue = velocity.normalize().multiply(velocity.length() * (1 + currentAcceleration))
else { else {
val vec3d: Vec3d = this.parent.minecart.getLaunchDirection(railPos) val vec3d: Vec3d = minecart.getLaunchDirection(railPos)
cir.returnValue = if (vec3d.lengthSquared() <= 0.0) cir.returnValue = if (vec3d.lengthSquared() <= 0.0)
velocity velocity
else else
@ -89,8 +90,4 @@ class MixinExperimentalMinecartControllerImpl(private val parent: ExperimentalMi
cir.returnValue = velocity cir.returnValue = velocity
} }
} }
var linked = true
private set;
} }

View file

@ -1,4 +1,42 @@
package moe.lava.cartloader.impl package moe.lava.cartloader.impl
import moe.lava.cartloader.accessor.AccessorAbstractMinecartEntity
import net.minecraft.entity.Entity
import net.minecraft.entity.ItemEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.vehicle.AbstractMinecartEntity
import net.minecraft.item.Items
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
class MixinPlayerEntityImpl { class MixinPlayerEntityImpl {
private var linking: AbstractMinecartEntity? = null
fun interact(minecart: Entity, player: PlayerEntity, hand: Hand): ActionResult? {
if (minecart !is AbstractMinecartEntity)
return null
if (minecart !is AccessorAbstractMinecartEntity)
return null;
if (!player.getStackInHand(hand).isOf(Items.CHAIN))
return null
val target = linking
if (target == null) {
linking = minecart
return ActionResult.SUCCESS
}
if (target !is AccessorAbstractMinecartEntity)
return null
linking = null
if (!target.isAlive)
return ActionResult.FAIL
if (!minecart.boundingBox.expand(0.1).intersects(target.boundingBox))
return ActionResult.FAIL
target.`cartloader$getImpl`().linkTo(minecart)
return ActionResult.SUCCESS
}
} }

View file

@ -1,82 +1,50 @@
package moe.lava.cartloader.mixin; package moe.lava.cartloader.mixin;
import moe.lava.cartloader.accessor.ExperimentalMinecartControllerAccessor; import moe.lava.cartloader.accessor.AccessorAbstractMinecartEntity;
import moe.lava.cartloader.impl.MixinAbstractMinecartEntityImpl;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity; import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.entity.vehicle.MinecartController; import net.minecraft.entity.vehicle.MinecartController;
import net.minecraft.entity.vehicle.VehicleEntity; import net.minecraft.entity.vehicle.VehicleEntity;
import net.minecraft.server.world.ChunkTicketType;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.Pair;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import org.slf4j.Logger; import org.jetbrains.annotations.NotNull;
import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Comparator;
import java.util.Objects;
@Mixin(AbstractMinecartEntity.class) @Mixin(AbstractMinecartEntity.class)
public abstract class AbstractMinecartEntityMixin extends VehicleEntity { public abstract class MixinAbstractMinecartEntity extends VehicleEntity implements AccessorAbstractMinecartEntity {
@Final @Final
@Shadow @Shadow
private MinecartController controller; private MinecartController controller;
public AbstractMinecartEntityMixin(EntityType<?> entityType, World world) { @Unique
private final MixinAbstractMinecartEntityImpl impl = new MixinAbstractMinecartEntityImpl((AbstractMinecartEntity) (Object) this);
@Unique
public @NotNull MixinAbstractMinecartEntityImpl cartloader$getImpl() {
return impl;
}
public MixinAbstractMinecartEntity(EntityType<?> entityType, World world) {
super(entityType, world); super(entityType, world);
} }
@Unique @Inject(at = @At("HEAD"), method = "tick", cancellable = true)
private ChunkPos lastChunk; private void onPreTick(CallbackInfo info) {
impl.onPreTick(this.getWorld(), this.getChunkPos(), info);
}
@Unique @Inject(at = @At("RETURN"), method = "tick")
private static final Logger log = LoggerFactory.getLogger("cartloader@ameMixin"); private void onPostTick(CallbackInfo info) {
impl.onPostTick();
@Unique
private static final ChunkTicketType<ChunkPos> TICKET = ChunkTicketType.create("minecart", Comparator.comparingLong(ChunkPos::toLong), 50);
@Inject(at = @At("HEAD"), method = "tick")
private void onTick(CallbackInfo info) {
if (!(getWorld() instanceof ServerWorld world))
return;
if (lastChunk == getChunkPos())
return;
lastChunk = getChunkPos();
world.getChunkManager().addTicket(TICKET, lastChunk, 3, lastChunk);
} }
@Inject(method = "applySlowdown", at = @At(value = "RETURN"), cancellable = true) @Inject(method = "applySlowdown", at = @At(value = "RETURN"), cancellable = true)
private void cartloader$slowDown(Vec3d velocity, CallbackInfoReturnable<Vec3d> cir) { private void cartloader$slowDown(Vec3d velocity, CallbackInfoReturnable<Vec3d> cir) {
if (!(this.getWorld() instanceof ServerWorld world)) impl.slowdown(this.getWorld(), this.controller, cir);
return;
if (!(controller instanceof ExperimentalMinecartControllerAccessor mixedController)) {
return;
}
Pair<Double, Double> multiplers = mixedController.cartloader$getSpeedMultiplers();
if (Objects.equals(multiplers.getLeft(), multiplers.getRight()))
return;
double base = controller.getMaxSpeed(world);
double mult = multiplers.getRight() / multiplers.getLeft();
double newMax = base * mult;
Vec3d ret = cir.getReturnValue();
double diff = ret.horizontalLength() - newMax;
if (diff > 0) {
if (diff < 0.15)
mixedController.cartloader$finishSlowdown();
else
cir.setReturnValue(ret.multiply(0.95f));
}
} }
} }

View file

@ -3,9 +3,7 @@ package moe.lava.cartloader.mixin;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.hud.DebugHud; import net.minecraft.client.gui.hud.DebugHud;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.math.Vec3d;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@ -13,7 +11,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List; import java.util.List;
@Mixin(DebugHud.class) @Mixin(DebugHud.class)
public class DebugHudMixin { public class MixinDebugHud {
@Inject(at = @At("RETURN"), method = "getLeftText") @Inject(at = @At("RETURN"), method = "getLeftText")
private void cartloader$addLeftText(CallbackInfoReturnable<List<String>> cir) { private void cartloader$addLeftText(CallbackInfoReturnable<List<String>> cir) {
Entity ent = MinecraftClient.getInstance().getCameraEntity(); Entity ent = MinecraftClient.getInstance().getCameraEntity();

View file

@ -1,4 +1,32 @@
package moe.lava.cartloader.mixin; package moe.lava.cartloader.mixin;
public class MixinEntity { import moe.lava.cartloader.accessor.AccessorAbstractMinecartEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.util.math.Vec3d;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Entity.class)
public abstract class MixinEntity {
@Unique
private boolean checkLink(Entity e) {
if (e instanceof AccessorAbstractMinecartEntity minecart)
return minecart.cartloader$getImpl().getLinked();
return false;
}
@Inject(method = "pushAwayFrom", at = @At("HEAD"), cancellable = true)
private void cartloader$cancelCollision(Entity entity, CallbackInfo ci) {
Entity self = (Entity) (Object) this;
if (checkLink(self) || checkLink(entity))
ci.cancel();
}
@Inject(method = "adjustMovementForCollisions(Lnet/minecraft/util/math/Vec3d;)Lnet/minecraft/util/math/Vec3d;", at = @At("HEAD"), cancellable = true)
private void cartloader$cancelCollision(Vec3d movement, CallbackInfoReturnable<Vec3d> cir) {
}
} }

View file

@ -1,52 +1,40 @@
package moe.lava.cartloader.mixin; package moe.lava.cartloader.mixin;
import moe.lava.cartloader.accessor.ExperimentalMinecartControllerAccessor; import kotlin.Pair;
import moe.lava.cartloader.accessor.AccessorAbstractMinecartEntity;
import moe.lava.cartloader.accessor.AccessorExperimentalMinecartController;
import moe.lava.cartloader.impl.MixinExperimentalMinecartControllerImpl;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.PoweredRailBlock;
import net.minecraft.block.enums.RailShape; import net.minecraft.block.enums.RailShape;
import net.minecraft.entity.vehicle.AbstractMinecartEntity; import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.entity.vehicle.ExperimentalMinecartController; import net.minecraft.entity.vehicle.ExperimentalMinecartController;
import net.minecraft.entity.vehicle.MinecartController; import net.minecraft.entity.vehicle.MinecartController;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Pair;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import org.slf4j.Logger; import org.jetbrains.annotations.NotNull;
import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ExperimentalMinecartController.class) @Mixin(ExperimentalMinecartController.class)
public abstract class ExperimentalMinecartControllerMixin extends MinecartController implements ExperimentalMinecartControllerAccessor { public abstract class MixinExperimentalMinecartController extends MinecartController implements AccessorExperimentalMinecartController {
@Unique @Unique
private static final Logger log = LoggerFactory.getLogger("cartloader@emcmixin"); private final MixinExperimentalMinecartControllerImpl impl = new MixinExperimentalMinecartControllerImpl(this);
@Unique protected MixinExperimentalMinecartController(AbstractMinecartEntity minecart) {
private double currentMultiplier = 0.5;
@Unique
private double targetMultiplier = 0.5;
@Unique
private boolean specialAcceleration = false;
protected ExperimentalMinecartControllerMixin(AbstractMinecartEntity minecart) {
super(minecart); super(minecart);
} }
@Unique @Unique
public Pair<Double, Double> cartloader$getSpeedMultiplers() { public @NotNull Pair<Double, Double> cartloader$getSpeedMultiplers() {
//return this.speedMultiplier; return new Pair<>(impl.getCurrentMultiplier(), impl.getTargetMultiplier());
return new Pair<>(this.currentMultiplier, this.targetMultiplier);
} }
@Unique @Unique
public void cartloader$finishSlowdown() { public void cartloader$finishSlowdown() {
this.currentMultiplier = this.targetMultiplier; impl.setCurrentMultiplier(impl.getTargetMultiplier());
} }
@Inject(method = "calcNewHorizontalVelocity", at = @At("HEAD")) @Inject(method = "calcNewHorizontalVelocity", at = @At("HEAD"))
@ -59,85 +47,30 @@ public abstract class ExperimentalMinecartControllerMixin extends MinecartContro
RailShape railShape, RailShape railShape,
CallbackInfoReturnable<Vec3d> cir CallbackInfoReturnable<Vec3d> cir
) { ) {
if (!(railState.isOf(Blocks.DETECTOR_RAIL) || (railState.isOf(Blocks.POWERED_RAIL) && !railState.get(PoweredRailBlock.POWERED)))) { impl.checkRail(world, pos, railState);
return;
}
BlockState under = this.getWorld().getBlockState(pos.down());
double newMultiplier = 0;
if (under.isOf(Blocks.IRON_BLOCK))
newMultiplier = 0.25;
else if (under.isOf(Blocks.GOLD_BLOCK))
newMultiplier = 0.5;
else if (under.isOf(Blocks.EMERALD_BLOCK))
newMultiplier = 0.75;
else if (under.isOf(Blocks.DIAMOND_BLOCK))
newMultiplier = 1.0;
if (newMultiplier != 0) {
specialAcceleration = true;
targetMultiplier = newMultiplier;
}
if (targetMultiplier > currentMultiplier)
currentMultiplier = targetMultiplier;
} }
@Inject(method = "getMaxSpeed", at = @At(value = "RETURN"), cancellable = true) @Inject(method = "getMaxSpeed", at = @At(value = "RETURN"), cancellable = true)
private void cartloader$applyMaxSpeedMultiplier(ServerWorld world, CallbackInfoReturnable<Double> cir) { private void cartloader$applyMaxSpeedMultiplier(ServerWorld world, CallbackInfoReturnable<Double> cir) {
double ret = cir.getReturnValue(); impl.applyMaxSpeedMultiplier(cir);
cir.setReturnValue(ret * currentMultiplier);
//cir.setReturnValue(ret * speedMultiplier);
} }
@Unique
private static final double TOTAL_ACCELERATION = 0.075;
@Unique
private static final double ACCELERATION_DECAY = 0.5;
@Unique
private static final double MAX_ACCELERATION = TOTAL_ACCELERATION * (1 - ACCELERATION_DECAY);
@Unique
private static final double FINAL_ACCELERATION = TOTAL_ACCELERATION * Math.pow(ACCELERATION_DECAY, 5);
@Unique
private double currentAcceleration = 0.0;
@Inject(method = "accelerateFromPoweredRail", at = @At("HEAD"), cancellable = true) @Inject(method = "accelerateFromPoweredRail", at = @At("HEAD"), cancellable = true)
private void accelerateFromPoweredRail(Vec3d velocity, BlockPos railPos, BlockState railState, CallbackInfoReturnable<Vec3d> cir) { private void cartloader$accelerateFromPoweredRail(Vec3d velocity, BlockPos railPos, BlockState railState, CallbackInfoReturnable<Vec3d> cir) {
if (!specialAcceleration) impl.accelerateFromPoweredRail(this.minecart, velocity, railPos, railState, cir);
return;
if (railState.isOf(Blocks.POWERED_RAIL) && railState.get(PoweredRailBlock.POWERED))
currentAcceleration = MAX_ACCELERATION;
if (!railState.isOf(Blocks.POWERED_RAIL)) {
currentAcceleration = currentAcceleration * ACCELERATION_DECAY;
if (currentAcceleration <= FINAL_ACCELERATION)
currentAcceleration = 0.0;
}
//log.info(String.valueOf(currentAcceleration));
if (velocity.length() > 0.01)
cir.setReturnValue(velocity.normalize().multiply(velocity.length() * (1 + currentAcceleration)));
else {
Vec3d vec3d = this.minecart.getLaunchDirection(railPos);
cir.setReturnValue(vec3d.lengthSquared() <= 0.0 ? velocity : vec3d.multiply(velocity.length() + MAX_ACCELERATION));
}
} }
@Inject(method = "decelerateFromPoweredRail", at = @At("HEAD"), cancellable = true) @Inject(method = "decelerateFromPoweredRail", at = @At("HEAD"), cancellable = true)
private void decelerateFromPoweredRail(Vec3d velocity, BlockState railState, CallbackInfoReturnable<Vec3d> cir) { private void cartloader$decelerateFromPoweredRail(Vec3d velocity, BlockState railState, CallbackInfoReturnable<Vec3d> cir) {
if (!specialAcceleration) impl.decelerateFromPoweredRail(velocity, railState, cir);
return;
if (railState.isOf(Blocks.POWERED_RAIL) && !(Boolean)railState.get(PoweredRailBlock.POWERED)) {
log.info("Decel");
log.info(String.valueOf(velocity.length()));
cir.setReturnValue(velocity.length() < 0.03 ? Vec3d.ZERO : velocity.multiply(0.915));
} else {
cir.setReturnValue(velocity);
} }
//@Inject(method = "pushAwayFromEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;pushAwayFrom(Lnet/minecraft/entity/Entity;)V"), cancellable = true)
@SuppressWarnings("InvalidInjectorMethodSignature")
@ModifyConstant(method = "pushAwayFromEntities", constant = @Constant(classValue = AbstractMinecartEntity.class))
private boolean cartloader$handleCollision(Object obj, Class<?> c) {
if (((AccessorAbstractMinecartEntity)minecart).cartloader$getImpl().getLinked())
return false;
return obj instanceof AbstractMinecartEntity;
} }
} }

View file

@ -1,18 +1,37 @@
package moe.lava.cartloader.mixin; package moe.lava.cartloader.mixin;
import moe.lava.cartloader.impl.MixinPlayerEntityImpl;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(PlayerEntity.class) @Mixin(PlayerEntity.class)
public class PlayerEntityMixin { public abstract class MixinPlayerEntity extends LivingEntity {
@Shadow public abstract void handleStatus(byte status);
protected MixinPlayerEntity(EntityType<? extends LivingEntity> entityType, World world) {
super(entityType, world);
}
@Unique
private final MixinPlayerEntityImpl impl = new MixinPlayerEntityImpl();
@Redirect(method = "interact", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;interact(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;")) @Redirect(method = "interact", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;interact(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;"))
private ActionResult meth(Entity entity, PlayerEntity player, Hand hand) { private ActionResult meth(Entity entity, PlayerEntity player, Hand hand) {
ActionResult res = impl.interact(entity, player, hand);
if (res != null)
return res;
return entity.interact(player, hand); return entity.interact(player, hand);
} }
} }

View file

@ -3,13 +3,15 @@
"package": "moe.lava.cartloader.mixin", "package": "moe.lava.cartloader.mixin",
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_21",
"mixins": [ "mixins": [
"AbstractMinecartEntityMixin", "MixinAbstractMinecartEntity",
"ExperimentalMinecartControllerMixin" "MixinEntity",
"MixinExperimentalMinecartController",
"MixinPlayerEntity"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1
}, },
"client": [ "client": [
"DebugHudMixin" "MixinDebugHud"
] ]
} }

View file

@ -19,6 +19,7 @@
], ],
"depends": { "depends": {
"fabricloader": ">=0.15", "fabricloader": ">=0.15",
"fabric-language-kotlin": ">=1.13.1+kotlin.2.1.10",
"minecraft": "~1.21.4", "minecraft": "~1.21.4",
"java": ">=21" "java": ">=21"
} }