Added first version.
This commit is contained in:
parent
693fb2c717
commit
c00b2444bd
10
README.md
10
README.md
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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.");
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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": [
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue