diff --git a/README.md b/README.md index 26dd9f7..c91e7df 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,12 @@ The aim of this mod is to fix (major) annoyances or backport useful features tha - Axes are also effective against: crafting tables, wooden slabs (experimental), wooden stairs, fences, wooden doors, ladders, signs, pumpkins, wooden pressure plates, jukeboxes, and noteblocks - Fences are placeable like normal and bounding box was minimized when appropriate - Stairs drop themselves -- Boats drop themselves -- Pigs drop their saddles if they have a saddle equipped - Bookshelves drop three books -- Boats don't break due to high velocity +- Pigs drop their saddles if they have a saddle equipped +- Boats drop themselves +- Boats don't break due to high velocity (or drop boat, or vanilla, toggle with config) - Never fall through boats anymore when getting out +- Logout/login with vehicle (no longer exit vehicle upon logout) - Pick block (middle mouse button click) works for blocks that are in the player's inventory, but not in their hotbar - Pick block also works on: paintings, minecarts (all three types), wooden doors, iron doors, signs, crops, redstone repeaters, redstone wire, beds, piston heads and cake - Add missing wooden items as fuel sources in furnace: wooden tools, wooden doors, boats, bowls, signs, and ladders diff --git a/gradle.properties b/gradle.properties index e08ce47..ea5ffc4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ yarn_mappings=b1.7.3-build.2 loader_version=0.14.24-babric.1 # Mod Properties -mod_version=2.3.0 +mod_version=2.4.0 maven_group=com.github.telvarost archives_base_name=AnnoyanceFix diff --git a/src/main/java/com/github/telvarost/annoyancefix/Config.java b/src/main/java/com/github/telvarost/annoyancefix/Config.java index d48f092..535061c 100644 --- a/src/main/java/com/github/telvarost/annoyancefix/Config.java +++ b/src/main/java/com/github/telvarost/annoyancefix/Config.java @@ -177,15 +177,20 @@ public static class ConfigFields { @Comment("Options here require restart to take effect") public final RecipesConfig RECIPES_CONFIG = new RecipesConfig(); + @ConfigName("Boat Collision Behavior") + @MultiplayerSynced + @ValueOnVanillaServer(integerValue = 0) + public BoatCollisionEnum boatCollisionBehavior = BoatCollisionEnum.INVINCIBLE; + @ConfigName("Boat Drop Fixes Enabled") @MultiplayerSynced @ValueOnVanillaServer(booleanValue = TriBoolean.FALSE) public Boolean boatDropFixesEnabled = true; - @ConfigName("Boat Speed Collision Behavior") + @ConfigName("Boat Logout/Login Fixes Enabled") @MultiplayerSynced - @ValueOnVanillaServer(integerValue = 0) - public BoatCollisionEnum boatCollisionBehavior = BoatCollisionEnum.INVINCIBLE; + @ValueOnVanillaServer(booleanValue = TriBoolean.FALSE) + public Boolean boatLogoutLoginFixesEnabled = true; @ConfigName("Bookshelf Fixes Enabled") @MultiplayerSynced diff --git a/src/main/java/com/github/telvarost/annoyancefix/ModHelper.java b/src/main/java/com/github/telvarost/annoyancefix/ModHelper.java index 9d5ff85..ea76870 100644 --- a/src/main/java/com/github/telvarost/annoyancefix/ModHelper.java +++ b/src/main/java/com/github/telvarost/annoyancefix/ModHelper.java @@ -7,6 +7,14 @@ public enum BlockTypeEnum { SLAB_BLOCK_IS_WOODEN } + public static byte toByte(boolean value) { + return (byte) (value ? 1 : 0); + } + + public static boolean toBool(byte value) { + return value > 0; + } + public static class ModHelperFields { /** @brief - Special data for remembering block type */ diff --git a/src/main/java/com/github/telvarost/annoyancefix/interfaces/VehicleInterface.java b/src/main/java/com/github/telvarost/annoyancefix/interfaces/VehicleInterface.java new file mode 100644 index 0000000..9bc49b3 --- /dev/null +++ b/src/main/java/com/github/telvarost/annoyancefix/interfaces/VehicleInterface.java @@ -0,0 +1,22 @@ +package com.github.telvarost.annoyancefix.interfaces; + +import net.minecraft.util.io.CompoundTag; +import net.modificationstation.stationapi.api.util.Util; + +public interface VehicleInterface { + default String vehicle_getVehicleName() { + return Util.assertImpl(); + } + + default void vehicle_setVehicleName(String vehicleName) { + Util.assertImpl(); + } + + default CompoundTag vehicle_getVehicleTag() { + return Util.assertImpl(); + } + + default void vehicle_setVehicleTag(CompoundTag vehicleTag) { + Util.assertImpl(); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/telvarost/annoyancefix/mixin/PlayerBaseMixin.java b/src/main/java/com/github/telvarost/annoyancefix/mixin/PlayerBaseMixin.java index 5188d34..1e721be 100644 --- a/src/main/java/com/github/telvarost/annoyancefix/mixin/PlayerBaseMixin.java +++ b/src/main/java/com/github/telvarost/annoyancefix/mixin/PlayerBaseMixin.java @@ -1,88 +1,138 @@ -//package com.github.telvarost.annoyancefix.mixin; -// -//import net.minecraft.entity.EntityBase; -//import net.minecraft.entity.Living; -//import net.minecraft.entity.player.PlayerBase; -//import net.minecraft.entity.player.PlayerContainer; -//import net.minecraft.item.ItemInstance; -//import net.minecraft.util.io.CompoundTag; -//import org.objectweb.asm.Opcodes; -//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.Redirect; -//import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -// -//@Mixin(PlayerBase.class) -//public class PlayerBaseMixin { -// -// @Unique -// private String _vehicleName = null; -// @Unique -// private boolean _playerInVehicle = false; -// @Unique -// private double _vehicleX = 0; -// @Unique -// private double _vehicleY = 70; -// @Unique -// private double _vehicleZ = 0; -// -// @Redirect( -// method = "interactWith", -// at = @At( -// value = "INVOKE", -// target = "Lnet/minecraft/entity/EntityBase;interact(Lnet/minecraft/entity/player/PlayerBase;)Z" -// ) -// ) -// public boolean interactWith(EntityBase instance, PlayerBase playerBase) { -// boolean canInteract = instance.interact(playerBase); -// -// if (canInteract) { -// _playerInVehicle = (instance.passenger != null); -// -// if (instance.passenger != null) { -// _vehicleName = instance.getClass().toString(); -// _vehicleX = Math.floor(instance.x); -// _vehicleY = Math.floor(instance.y); -// _vehicleZ = Math.floor(instance.z); -// } -// } -// -// return canInteract; -// } -// -// -// -// @Inject(method = "writeCustomDataToTag", at = @At("HEAD")) -// private void betaTweaks_writeCustomDataToTag(CompoundTag tag, CallbackInfo info) { -// if (!true) { -// return; -// } -// -// tag.put("PlayerInVehicle", _playerInVehicle); -// -// if (_playerInVehicle) { -// tag.put("VehicleName", _vehicleName); -// tag.put("VehicleX", _vehicleX); -// tag.put("VehicleY", _vehicleY); -// tag.put("VehicleZ", _vehicleZ); -// } -// } -// -// @Inject(method = "readCustomDataFromTag", at = @At("HEAD")) -// private void betaTweaks_readCustomDataFromTag(CompoundTag tag, CallbackInfo info) { -// if (!true) { -// return; -// } -// -// _playerInVehicle = tag.getBoolean("PlayerInVehicle"); -// -// if (_playerInVehicle) { -// _vehicleName = tag.getString("VehicleName"); -// _vehicleX = tag.getDouble("VehicleX"); -// _vehicleY = tag.getDouble("VehicleY"); -// _vehicleZ = tag.getDouble("VehicleZ"); -// } -// } -//} +package com.github.telvarost.annoyancefix.mixin; + +import com.github.telvarost.annoyancefix.Config; +import com.github.telvarost.annoyancefix.interfaces.VehicleInterface; +import net.minecraft.entity.EntityBase; +import net.minecraft.entity.EntityRegistry; +import net.minecraft.entity.Living; +import net.minecraft.entity.player.PlayerBase; +import net.minecraft.level.Level; +import net.minecraft.util.io.CompoundTag; +import net.modificationstation.stationapi.api.entity.player.PlayerHelper; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(PlayerBase.class) +public abstract class PlayerBaseMixin extends Living implements VehicleInterface { + + @Unique + private static String NULL_AS_STRING = "null"; + + @Unique + public String _vehicleName = NULL_AS_STRING; + + @Unique + public CompoundTag _vehicleTag = new CompoundTag(); + + public PlayerBaseMixin(Level arg) { + super(arg); + } + + @Override + public String vehicle_getVehicleName() { + return _vehicleName; + } + + @Override + public void vehicle_setVehicleName(String vehicleName) { + _vehicleName = vehicleName; + } + + @Override + public CompoundTag vehicle_getVehicleTag() { + return _vehicleTag; + } + + @Override + public void vehicle_setVehicleTag(CompoundTag vehicleTag) { + _vehicleTag = vehicleTag; + } + + @Redirect( + method = "interactWith", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/entity/EntityBase;interact(Lnet/minecraft/entity/player/PlayerBase;)Z" + ) + ) + public boolean interactWith(EntityBase instance, PlayerBase playerBase) { + boolean canInteract = instance.interact(playerBase); + + if (Config.config.boatLogoutLoginFixesEnabled && canInteract) { + /** - Set vehicle data */ + _vehicleName = (instance.passenger != null) ? EntityRegistry.getStringId(instance) : NULL_AS_STRING; + if (!_vehicleName.equals(NULL_AS_STRING)) { + instance.toTag(_vehicleTag); + } + } + + return canInteract; + } + + + + @Inject(method = "writeCustomDataToTag", at = @At("HEAD")) + private void betaTweaks_writeCustomDataToTag(CompoundTag tag, CallbackInfo info) { + if (!Config.config.boatLogoutLoginFixesEnabled) { + return; + } + + /** - Save vehicle data */ + _vehicleName = (this.vehicle != null) ? EntityRegistry.getStringId(this.vehicle) : NULL_AS_STRING; + tag.put("VehicleName", _vehicleName); + if (!_vehicleName.equals(NULL_AS_STRING)) { + this.vehicle.toTag(_vehicleTag); + tag.put("VehicleTag", _vehicleTag); + } + } + + @Inject(method = "readCustomDataFromTag", at = @At("HEAD")) + private void betaTweaks_readCustomDataFromTag(CompoundTag tag, CallbackInfo info) { + if (!Config.config.boatLogoutLoginFixesEnabled) { + return; + } + + /** - Get vehicle data */ + _vehicleName = tag.getString("VehicleName"); + if (!_vehicleName.equals(NULL_AS_STRING)) { + _vehicleTag = tag.getCompoundTag("VehicleTag"); + } + + /** - Spawn saved vehicle if on single player (and remove old vehicle) */ + if (level.isServerSide) return; + PlayerBase singlePlayer = PlayerHelper.getPlayerFromGame(); + if (null == singlePlayer) return; + if (null == _vehicleTag) return; + if (_vehicleName.equals(NULL_AS_STRING)) return; + EntityBase vehicle = EntityRegistry.create(_vehicleName, level); + if (null != vehicle) { + + try { + vehicle.fromTag(_vehicleTag); + } catch(Exception ex) { + vehicle.setPositionAndAngles(x, y, z, yaw, pitch); + System.out.println("Failed to read vehicle data"); + } + + /** - Remove old entity if there is one */ + for (int entityIndex = 0; entityIndex < level.entities.size(); entityIndex++) { + EntityBase entityToCheck = (EntityBase)level.entities.get(entityIndex); + + if ( (entityToCheck.getClass().equals(vehicle.getClass())) + && (entityToCheck.x == vehicle.x) + && (entityToCheck.y == vehicle.y) + && (entityToCheck.z == vehicle.z) + ) { + level.removeEntity(entityToCheck); + } + } + + level.spawnEntity(vehicle); + startRiding(vehicle); + } + } +} diff --git a/src/main/java/com/github/telvarost/annoyancefix/mixin/ServerPacketHandlerMixin.java b/src/main/java/com/github/telvarost/annoyancefix/mixin/ServerPacketHandlerMixin.java new file mode 100644 index 0000000..e95f1da --- /dev/null +++ b/src/main/java/com/github/telvarost/annoyancefix/mixin/ServerPacketHandlerMixin.java @@ -0,0 +1,51 @@ +package com.github.telvarost.annoyancefix.mixin; + +import com.github.telvarost.annoyancefix.Config; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.entity.EntityBase; +import net.minecraft.entity.EntityRegistry; +import net.minecraft.entity.player.ServerPlayer; +import net.minecraft.server.network.ServerPacketHandler; +import net.minecraft.util.io.CompoundTag; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Environment(EnvType.SERVER) +@Mixin(ServerPacketHandler.class) +public abstract class ServerPacketHandlerMixin { + + @Redirect( + method = "complete", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/entity/player/ServerPlayer;method_317()V" + ) + ) + public void annoyanceFix_completeLoadVehicle(ServerPlayer instance) { + instance.method_317(); + + if (Config.config.boatLogoutLoginFixesEnabled) { + /** - Spawn saved vehicle if on multiplayer */ + String vehicleName = instance.vehicle_getVehicleName(); + if (!vehicleName.equals("null")) { + CompoundTag vehicleTag = instance.vehicle_getVehicleTag(); + if (vehicleTag != null) { + EntityBase vehicle = EntityRegistry.create(vehicleName, instance.level); + if (null != vehicle) { + try { + vehicle.fromTag(vehicleTag); + } catch(Exception ex) { + vehicle.setPositionAndAngles(instance.x, instance.y, instance.z, instance.yaw, instance.pitch); + System.out.println("Failed to read vehicle data"); + } + instance.level.spawnEntity(vehicle); + instance.startRiding(vehicle); + } + } + } + } + } + +} diff --git a/src/main/java/com/github/telvarost/annoyancefix/mixin/ServerPlayerConnectionManagerMixin.java b/src/main/java/com/github/telvarost/annoyancefix/mixin/ServerPlayerConnectionManagerMixin.java new file mode 100644 index 0000000..cf8301e --- /dev/null +++ b/src/main/java/com/github/telvarost/annoyancefix/mixin/ServerPlayerConnectionManagerMixin.java @@ -0,0 +1,31 @@ +package com.github.telvarost.annoyancefix.mixin; + +import com.github.telvarost.annoyancefix.Config; +import net.minecraft.entity.player.PlayerBase; +import net.minecraft.server.PlayerHandler; +import net.minecraft.server.ServerPlayerConnectionManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ServerPlayerConnectionManager.class) +public abstract class ServerPlayerConnectionManagerMixin { + + @Redirect( + method = "updateDimension", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/server/PlayerHandler;savePlayer(Lnet/minecraft/entity/player/PlayerBase;)V" + ) + ) + public void updateDimension(PlayerHandler instance, PlayerBase playerBase) { + instance.savePlayer(playerBase); + + if (Config.config.boatLogoutLoginFixesEnabled) { + /** - Remove vehicle on logout */ + if (null != playerBase.vehicle) { + playerBase.level.removeEntity(playerBase.vehicle); + } + } + } +} diff --git a/src/main/resources/annoyancefix.mixins.json b/src/main/resources/annoyancefix.mixins.json index b035f16..02806ef 100644 --- a/src/main/resources/annoyancefix.mixins.json +++ b/src/main/resources/annoyancefix.mixins.json @@ -16,10 +16,13 @@ "MinecraftMixin", "PickaxeMixin", "PigMixin", + "PlayerBaseMixin", "StairsMixin", "ToolBaseMixin" ], "server": [ + "ServerPacketHandlerMixin", + "ServerPlayerConnectionManagerMixin" ], "client": [ "PlayerInventoryMixin", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index dabd51d..4579d98 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -41,5 +41,13 @@ "depends": { "minecraft": "1.0.0-beta.7.3" + }, + + "custom": { + "loom:injected_interfaces": { + "net/minecraft/class_54": [ + "com/github/telvarost/annoyancefix/interfaces/VehicleInterface" + ] + } } }