Added first version.

This commit is contained in:
Andrew Lalis 2021-07-18 22:35:27 +02:00
parent 693fb2c717
commit c00b2444bd
8 changed files with 208 additions and 48 deletions

View File

@ -1,9 +1,3 @@
# Fabric Example Mod
# Speed Carts
## Setup
For setup instructions please see the [fabric wiki page](https://fabricmc.net/wiki/tutorial:setup) that relates to the IDE that you are using.
## License
This template is available under the CC0 license. Feel free to learn from it and incorporate it in your own projects.
This mod adds the ability to control minecarts with signs.

View File

@ -9,8 +9,8 @@ org.gradle.jvmargs=-Xmx1G
# Mod Properties
mod_version = 1.0.0
maven_group = com.example
archives_base_name = fabric-example-mod
maven_group = nl.andrewlalis
archives_base_name = speed-carts
# Dependencies
fabric_version=0.37.0+1.17

View File

@ -1,14 +0,0 @@
package net.fabricmc.example;
import net.fabricmc.api.ModInitializer;
public class ExampleMod implements ModInitializer {
@Override
public void onInitialize() {
// This code runs as soon as Minecraft is in a mod-load-ready state.
// However, some things (like resources) may still be uninitialized.
// Proceed with mild caution.
System.out.println("Hello Fabric world!");
}
}

View File

@ -1,15 +0,0 @@
package net.fabricmc.example.mixin;
import net.minecraft.client.gui.screen.TitleScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(TitleScreen.class)
public class ExampleMixin {
@Inject(at = @At("HEAD"), method = "init()V")
private void init(CallbackInfo info) {
System.out.println("This line is printed by an example mod mixin!");
}
}

View File

@ -0,0 +1,10 @@
package nl.andrewlalis.speed_carts;
import net.fabricmc.api.ModInitializer;
public class SpeedCarts implements ModInitializer {
@Override
public void onInitialize() {
System.out.println("Speed Carts initialized.");
}
}

View File

@ -0,0 +1,181 @@
package nl.andrewlalis.speed_carts.mixin;
import com.mojang.datafixers.util.Pair;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.SignBlockEntity;
import net.minecraft.block.enums.RailShape;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent;
import net.minecraft.state.property.Properties;
import net.minecraft.text.Text;
import net.minecraft.util.DyeColor;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Mixin which overrides the default minecart behavior so that we can define a
* changeable speed, and check for updates.
*/
@Mixin(AbstractMinecartEntity.class)
public abstract class AbstractMinecartMixin extends Entity {
private static final double DEFAULT_SPEED = 8.0;
private static final double MIN_SPEED = 1.0;
private static final double MAX_SPEED = 128.0;
private static final long SPEED_UPDATE_COOLDOWN = 20 * 3;
/**
* The currently-set maximum speed, in blocks per second.
*/
private double maxSpeedBps = DEFAULT_SPEED;
/**
* The last time (in game ticks) that the speed was updated.
*/
private long lastSpeedUpdate = 0;
/**
* The position of the block which was last responsible for updating the
* cart's speed.
*/
private BlockPos lastUpdatedFrom = null;
@Shadow
public abstract Vec3d snapPositionToRail(double x, double y, double z);
@Shadow
private static Pair<Vec3i, Vec3i> getAdjacentRailPositionsByShape(RailShape shape) {
return null;
}
@Shadow
protected abstract double getMaxOffRailSpeed();
@Inject(at = @At("HEAD"), method = "getMaxOffRailSpeed", cancellable = true)
public void getMaxOffRailSpeedOverwrite(CallbackInfoReturnable<Double> cir) {
cir.setReturnValue(this.maxSpeedBps / 20.0);
}
@Shadow
protected abstract void applySlowdown();
@Shadow
protected abstract boolean willHitBlockAt(BlockPos pos);
public AbstractMinecartMixin(EntityType<?> type, World world) {
super(type, world);
}
@Shadow
protected abstract void moveOnRail(BlockPos pos, BlockState state);
@Shadow public abstract Direction getMovementDirection();
@Inject(at = @At("HEAD"), method = "moveOnRail", cancellable = true)
public void moveOnRailOverwrite(BlockPos pos, BlockState state, CallbackInfo ci) {
this.updateForSpeedModifiers(pos);
}
/**
* Checks for any speed modifiers (signs, blocks, etc.) and attempts to
* apply their effects to the cart. It does this by iterating over a list of
* possible positions for blocks which are considered speed modifiers, and
* then if a valid speed modifier is found, the cart's speed is updated.
* @param pos The cart's current position.
*/
private void updateForSpeedModifiers(BlockPos pos) {
// Quit if the cart is not moving, and set its speed to default.
if (this.getVelocity().length() == 0) {
this.maxSpeedBps = DEFAULT_SPEED;
return;
}
for (var position : this.getPositionsToCheck(pos)) {
if (
this.world.getBlockEntity(position) instanceof SignBlockEntity sign &&
(!sign.getPos().equals(this.lastUpdatedFrom) || this.world.getTime() > this.lastSpeedUpdate + SPEED_UPDATE_COOLDOWN)
) {
var state = this.world.getBlockState(position);
var dir = (Direction) state.getEntries().get(Properties.HORIZONTAL_FACING);
// Only allow free-standing signs or those facing the cart.
if (dir == null || dir.equals(this.getMovementDirection().getOpposite())) {
if (this.updateSpeedForSign(sign)) return;
}
}
}
}
/**
* Attempts to update the cart's speed according to a sign.
* @param sign The sign that contains speed information.
* @return True if the cart's speed was updated, or false otherwise.
*/
private boolean updateSpeedForSign(SignBlockEntity sign) {
Text text = sign.getTextOnRow(0, false);
String s = text.asString();
try {
double speed = Double.parseDouble(s);
if (speed >= MIN_SPEED && speed <= MAX_SPEED) {
this.maxSpeedBps = speed;
this.lastSpeedUpdate = this.world.getTime();
this.lastUpdatedFrom = sign.getPos();
if (this.hasPlayerRider()) {
PlayerEntity player = (PlayerEntity) this.getFirstPassenger();
if (player != null) {
player.playSound(new SoundEvent(new Identifier("block.note_block.bell")), SoundCategory.PLAYERS, 1.0f, 1.0f);
}
}
return true;
} else {
sign.setTextOnRow(0, Text.of("Invalid speed!"));
sign.setTextOnRow(1, Text.of("Min: " + MIN_SPEED));
sign.setTextOnRow(2, Text.of("Max: " + MAX_SPEED));
sign.setGlowingText(true);
sign.setTextColor(DyeColor.RED);
}
} catch (NumberFormatException e) {
// Do nothing if no value could be parsed.
}
return false;
}
/**
* Gathers a list of all block positions to check for signs that may affect
* the cart's speed.
* @param pos The cart's block position.
* @return A collection of positions to check.
*/
private Collection<BlockPos> getPositionsToCheck(BlockPos pos) {
// Compute the number of blocks we have to check ahead.
// This accounts for speeds greater than 1 block per tick.
int blockRange = Math.max(1, (int) Math.ceil(this.maxSpeedBps / 20));
List<BlockPos> positionsToCheck = new ArrayList<>(6 * blockRange);
for (int i = 0; i < blockRange; i++) {
positionsToCheck.add(pos.north());
positionsToCheck.add(pos.south());
positionsToCheck.add(pos.east());
positionsToCheck.add(pos.west());
positionsToCheck.add(pos.up());
positionsToCheck.add(pos.down());
pos = pos.add(this.getMovementDirection().getVector());
}
return positionsToCheck;
}
}

View File

@ -1,16 +1,16 @@
{
"schemaVersion": 1,
"id": "modid",
"id": "speed-carts",
"version": "${version}",
"name": "Example Mod",
"description": "This is an example description! Tell everyone what your mod is about!",
"name": "Speed Carts",
"description": "Increases the speed of minecarts.",
"authors": [
"Me!"
"Andrew Lalis"
],
"contact": {
"homepage": "https://fabricmc.net/",
"sources": "https://github.com/FabricMC/fabric-example-mod"
"homepage": "https://andrewl.nl/",
"sources": "https://github.com/andrewlalis/SpeedCarts"
},
"license": "CC0-1.0",
@ -19,7 +19,7 @@
"environment": "*",
"entrypoints": {
"main": [
"net.fabricmc.example.ExampleMod"
"nl.andrewlalis.speed_carts.SpeedCarts"
]
},
"mixins": [

View File

@ -1,12 +1,16 @@
{
"required": true,
"minVersion": "0.8",
"package": "net.fabricmc.example.mixin",
"package": "nl.andrewlalis.speed_carts.mixin",
"compatibilityLevel": "JAVA_16",
"mixins": [
"AbstractMinecartMixin"
],
"client": [
"ExampleMixin"
"AbstractMinecartMixin"
],
"server": [
"AbstractMinecartMixin"
],
"injectors": {
"defaultRequire": 1