Compare commits

..

3 Commits

9 changed files with 324 additions and 36 deletions

View File

@ -54,8 +54,20 @@ After:
![white text showingcasing the number of days spent in game](https://i.imgur.com/clje0xb.png)
**Format: ingame days (real life days)**
Both are calculated using the play time stat the player has, which means if the stats file gets corrupted or deleted these numbers will reset as well!
**Format**: ingame days (real life days)
The ingame time is calculated using the world's time, this means that other mods that poorly reset the time of day might influence it, sleeping also passes 1 ingame game as expected.<br>
Real life days are calculated differently from the world time but are stored in the world's data (level.dat) if this file gets corrupted or deleted both ingame time and real life time will be lost.
**Note**: Unfortunately due to how the time is tracked real life days will start being counted since this mod gets installed, any prior time not being tracked. Ingame days will however be tracked correctly.
</details>
<details><summary>Two different config options to handle how boats break</summary>
- Default config (value of 2) allows boats to break only when they crash with almost maximum speed. Making them less likely to break randomly.
- A value of 1 disables boat breaking logic entirely.
</details>
@ -212,12 +224,44 @@ After:
Before:<br>
<video controls src="https://i.imgur.com/BY0t3iG.mp4"/>
After:
After:<br>
<video controls src="https://i.imgur.com/4O7Fo8V.mp4" />
</details>
<details><summary>Fixes bookshelves not dropping anything when mined</summary>
Before:<br>
<video controls src="https://i.imgur.com/9dt46cf.mp4"/>
After:<br>
<video controls src="https://i.imgur.com/v9nEcfp.mp4" />
</details>
<details><summary>Fixes double doors not working with pressure plates</summary>
Before:<br>
<video controls src="https://i.imgur.com/WWcOZA0.mp4"/>
After:<br>
<video controls src="https://i.imgur.com/8Dj19lR.mp4" />
**Note**: This is not the prettiest of fixes and edge cases might still exist as I didn't test it in normal gameplay for long periods of time. If you experience any issues with already placed doors break them and then place them again, this should fix them.
</details>
<br>
As well as a bunch of other minor issues not worth having before/after images such as grass block items being rendered incorrectly or the useless 10mb array wasting resources.
As well as a bunch of other minor issues not worth having before/after images such as:
- fixes grass block items being rendered incorrectly
- made the chicken hitbox slightly taller
- allows the use of `shift` key to drop the entire held stack and to exit vehicles
- adds a config option that disables nightmares (mosters spawning at your bed while sleeping), disabled by default
- adds a config option that disables bed functionality (so no more spawn point setting or night skipping), disabled by default
- replaces the fence's bulky hitbox with a more slim version
- removing the useless 10mb array wasting resources
## Install

View File

@ -30,6 +30,8 @@ public class ModConfig {
"0 - Vanilla behavior\n1 - Boats will never break regardless of their speed\n2 - Boats will only break when crashing with almost max speed");
public static final Option<Boolean> STACK_DROP = make("Drop Held Stack", true,
"Allows the player to drop the entire stack they're holding using Shift + Q (or whatever drop key they have set)");
public static final Option<Boolean> ENABLE_TIME_TRACKING = make("Enable Time Tracking", true,
"Adds a Days Played entry in the F3 overlay displaying number of ingame days and real life days played in that world");
public static final Option<Boolean> FIX_BOW_MODEL = make("Fix bow model", true,
"Makes the box model held by players and skeletons bigger and facing forward");
@ -51,6 +53,8 @@ public class ModConfig {
"Fixes furnaces consuming the bucket when using lava buckets as fuel");
public static final Option<Boolean> FIX_BOOKSHELVES_DROP = make("Fix Bookshelves Drops", true,
"Drops 3 books when breaking a bookshelf");
public static final Option<Boolean> FIX_DOUBLE_DOORS = make("Fix Double Doors", true,
"Fixes double doors not being in their correct state when pressure plates are used to open them");
private static ModConfig instance = new ModConfig();
public static final ModConfig instance() {

View File

@ -3,42 +3,51 @@ package xyz.pixelatedw.finalbeta;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.time.Duration;
import java.util.HashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.Player;
import net.minecraft.item.ItemInstance;
import net.minecraft.item.ItemType;
import net.minecraft.stat.Stats;
public class WyHelper {
public static Minecraft getInstance() {
try {
Field f = Minecraft.class.getDeclaredField("instance");
f.setAccessible(true);
return (Minecraft) f.get(null);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
private static final Minecraft INSTANCE;
public static final String SPAWN_TIME_TAG = "SpawnTime";
public static final String PLAY_TIME_TAG = "PlayTime";
public static long playTime;
// Look if they're allowed to hold all block and item data in fucking arrays
// I am also allowed to abuse maps to extend the shitty metadata excuse
// doors have ok ? I don't even care about the overhead at this point.
public static final HashMap<Integer, Long> DOOR_UPDATES = new HashMap<>();
public static final HashMap<Integer, Boolean> DOOR_STATES = new HashMap<>();
static {
INSTANCE = getInstance();
}
public static Minecraft getInstance() {
if (INSTANCE != null) {
return INSTANCE;
} else {
try {
Field f = Minecraft.class.getDeclaredField("instance");
f.setAccessible(true);
return (Minecraft) f.get(null);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
return null;
}
public static boolean isTimeBehind() {
// int currentPlayTime = WyHelper.getInstance().statManager.getStatAmount(Stats.playOneMinute)
return false;
}
public static long getTicksPlayed() {
return WyHelper.getInstance().statManager.getStatAmount(Stats.playOneMinute);
}
public static long getRealDaysPlayed() {
int seconds = WyHelper.getInstance().statManager.getStatAmount(Stats.playOneMinute) / 20;
long seconds = WyHelper.playTime / 20;
return Duration.ofSeconds(seconds).toDays();
}
public static long getGameDaysPlayed() {
int seconds = WyHelper.getInstance().statManager.getStatAmount(Stats.playOneMinute) / 20;
long seconds = WyHelper.getInstance().level.getLevelTime() / 20;
return Duration.ofSeconds(seconds).toMinutes() / 20;
}
@ -56,7 +65,7 @@ public class WyHelper {
public static void cheatCommand(Player player) {
player.dropItem(new ItemInstance(ItemType.boat, 1));
// player.dropItem(new ItemInstance(Tile.LEVER, 1));
// int x = MathsHelper.floor(player.x);
// int y = MathsHelper.floor(player.boundingBox.minY);
@ -69,7 +78,7 @@ public class WyHelper {
// player.dropItem(new ItemInstance(Tile.BED, 64));
// player.dropItem(new ItemInstance(Tile.FENCE, 64));
// player.dropItem(new ItemInstance(Tile.STONE_PRESSURE_PLATE, 64));
// player.dropItem(new ItemInstance(Tile.BUTTON, 64));
// player.dropItem(new ItemInstance(Tile.BOOKSHELF, 64));
@ -97,7 +106,7 @@ public class WyHelper {
// Pig animal = new Pig(player.level);
// animal.setPositionAndAngles(player.x + 2, player.y, player.z, 0.0f, 0.0f);
// player.level.spawnEntity(animal);
player.level.setLevelTime(0);
player.level.getProperties().setRaining(false);
player.level.getProperties().setRainTime(0);

View File

@ -27,12 +27,12 @@ public class ClientPlayerMixin {
Minecraft mc = WyHelper.getInstance();
Player player = (Player) (Object) this;
if (player.vehicle != null && key == Keyboard.KEY_LSHIFT) {
if (player.vehicle != null && key == Keyboard.KEY_LSHIFT && state) {
player.startRiding(null);
return;
}
if (ModConfig.STACK_DROP.get() && key == mc.options.dropKey.key && Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
if (ModConfig.STACK_DROP.get() && key == mc.options.dropKey.key && state && Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
ItemInstance heldItem = player.inventory.getHeldItem();
if (heldItem != null && heldItem.count > 0) {
player.dropItem(player.inventory.takeInvItem(player.inventory.selectedHotbarSlot, heldItem.count), false);

View File

@ -0,0 +1,147 @@
package xyz.pixelatedw.finalbeta.mixin;
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;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.Player;
import net.minecraft.level.Level;
import net.minecraft.tile.DoorTile;
import net.minecraft.tile.Tile;
import net.minecraft.tile.material.Material;
import xyz.pixelatedw.finalbeta.ModConfig;
import xyz.pixelatedw.finalbeta.WyHelper;
@Mixin(DoorTile.class)
public class DoorTileMixin extends Tile {
protected DoorTileMixin(int i, int j, Material arg) {
super(i, j, arg);
}
/*
* This is horrible and with edge cases, not the best of fixes, needs more
* work preferably changing the metadata of doors to allow for more states.
*
* When times get hard always remember:
* "If it's stupid but it works, it's still stupid but it works so fuck it."
*/
@Inject(method = "activate", at = @At("HEAD"), cancellable = true)
public void activate(Level level, int x, int y, int z, Player player, CallbackInfoReturnable<Boolean> cir) {
if (!ModConfig.FIX_DOUBLE_DOORS.get()) {
return;
}
DoorTile tile = ((DoorTile) (Object) this);
if (tile.material != Material.METAL) {
int tileMeta = level.getTileMeta(x, y, z);
int yOffset = 0;
if ((tileMeta & 8) != 0) {
setDoorTileMeta(level, x, y - 1, z, (tileMeta ^ 4) - 8);
yOffset = 1;
} else {
setDoorTileMeta(level, x, y, z, tileMeta ^ 4);
}
boolean state = false;
int hash = generatePosHash(x, y - yOffset, z);
if (WyHelper.DOOR_STATES.containsKey(hash)) {
state = WyHelper.DOOR_STATES.get(hash);
}
WyHelper.DOOR_STATES.put(hash, !state);
cir.setReturnValue(true);
}
}
@Inject(method = "method_837", at = @At("HEAD"), cancellable = true)
public void updateRedstoneSignal(Level level, int x, int y, int z, boolean openSignal, CallbackInfo ci) {
if (!ModConfig.FIX_DOUBLE_DOORS.get()) {
return;
}
// Top Tile Meta
// Open: 12 11 - 13 8 - 14 9 - 15 10
// Close: 8 15 - 9 12 - 10 13 - 11 14
// Bottom Tile Meta
// Open: 4 3 - 5 0 - 6 1 - 7 2
// Close: 0 7 - 1 4 - 2 5 - 3 6
int hash = generatePosHash(x, y, z);
if (WyHelper.DOOR_UPDATES.containsKey(hash)) {
long lastUpdate = System.currentTimeMillis() - WyHelper.DOOR_UPDATES.get(hash);
if (lastUpdate < 200) {
ci.cancel();
return;
}
}
int tileMeta = level.getTileMeta(x, y, z);
if (openSignal) {
if (WyHelper.DOOR_STATES.containsKey(hash) && WyHelper.DOOR_STATES.get(hash)) {
ci.cancel();
return;
}
setDoorTileMeta(level, x, y, z, Math.floorMod((tileMeta + 4), 8));
WyHelper.DOOR_STATES.put(hash, true);
} else {
if (WyHelper.DOOR_STATES.containsKey(hash) && !WyHelper.DOOR_STATES.get(hash)) {
ci.cancel();
return;
}
setDoorTileMeta(level, x, y, z, Math.floorMod((tileMeta - 4), 8));
WyHelper.DOOR_STATES.put(hash, false);
}
ci.cancel();
}
@Override
public void beforeDestroyedByExplosion(Level level, int x, int y, int z, int i1, float f) {
int tileMeta = level.getTileMeta(x, y, z);
int yOffset = 0;
if ((tileMeta & 8) != 0) {
yOffset = 1;
}
int hash = generatePosHash(x, y - yOffset, z);
WyHelper.DOOR_UPDATES.remove(hash);
WyHelper.DOOR_STATES.remove(hash);
super.beforeDestroyedByExplosion(level, x, y, z, i1, f);
}
@Override
public void afterPlaced(Level level, int x, int y, int z, LivingEntity entity) {
int hash = generatePosHash(x, y, z);
WyHelper.DOOR_STATES.put(hash, false);
}
private void setDoorTileMeta(Level level, int x, int y, int z, int meta) {
int tileId = level.getTileId(x, y, z);
level.setTileMeta(x, y, z, meta);
generateAndSaveHash(x, y, z);
if (level.getTileId(x, y + 1, z) == tileId) {
level.setTileMeta(x, y + 1, z, meta + 8);
generateAndSaveHash(x, y, z);
}
level.updateRedstone(x, y - 1, z, x, y, z);
level.playLevelEvent((Player) null, 1003, x, y, z, 0);
}
public int generatePosHash(int x, int y, int z) {
return (y * 31) + (z * 15) + x;
}
private void generateAndSaveHash(int x, int y, int z) {
WyHelper.DOOR_UPDATES.put(generatePosHash(x, y, z), System.currentTimeMillis());
}
}

View File

@ -0,0 +1,19 @@
package xyz.pixelatedw.finalbeta.mixin;
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;
import net.minecraft.level.Level;
import xyz.pixelatedw.finalbeta.WyHelper;
@Mixin(Level.class)
public class LevelMixin {
@Inject(method = "method_242", at = @At(value = "INVOKE", target = "Lnet/minecraft/level/LevelMonsterSpawner;method_1870"))
public void tick(CallbackInfo ci) {
WyHelper.playTime++;
}
}

View File

@ -0,0 +1,59 @@
package xyz.pixelatedw.finalbeta.mixin;
import java.util.Map.Entry;
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;
import net.minecraft.level.LevelProperties;
import net.minecraft.util.io.CompoundTag;
import net.minecraft.util.io.ListTag;
import xyz.pixelatedw.finalbeta.ModConfig;
import xyz.pixelatedw.finalbeta.WyHelper;
@Mixin(LevelProperties.class)
public class LevelPropertiesMixin {
private long spawnTime;
@Inject(method = "<init>", at = @At("TAIL"))
public void settingSpawnTime(CompoundTag nbt, CallbackInfo ci) {
if (!nbt.containsKey(WyHelper.SPAWN_TIME_TAG)) {
this.spawnTime = System.currentTimeMillis();
} else {
this.spawnTime = nbt.getLong(WyHelper.SPAWN_TIME_TAG);
}
WyHelper.playTime = nbt.getLong(WyHelper.PLAY_TIME_TAG);
if (ModConfig.FIX_DOUBLE_DOORS.get()) {
WyHelper.DOOR_STATES.clear();
ListTag doorStates = nbt.getListTag("DoorStates");
for (int i = 0; i < doorStates.size(); i++) {
CompoundTag doorTag = (CompoundTag) doorStates.get(i);
int hash = doorTag.getInt("hash");
boolean state = doorTag.getBoolean("state");
WyHelper.DOOR_STATES.put(hash, state);
}
}
}
@Inject(method = "updateProperties", at = @At("TAIL"))
public void updateSpawnTime(CompoundTag worldNbt, CompoundTag playerNbt, CallbackInfo ci) {
worldNbt.put(WyHelper.SPAWN_TIME_TAG, this.spawnTime);
worldNbt.put(WyHelper.PLAY_TIME_TAG, WyHelper.playTime);
if (ModConfig.FIX_DOUBLE_DOORS.get()) {
ListTag doorStates = new ListTag();
for (Entry<Integer, Boolean> entry : WyHelper.DOOR_STATES.entrySet()) {
CompoundTag doorTag = new CompoundTag();
doorTag.put("hash", entry.getKey());
doorTag.put("state", entry.getValue());
doorStates.add(doorTag);
}
worldNbt.put("DoorStates", doorStates);
}
}
}

View File

@ -12,6 +12,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.Overlay;
import net.minecraft.client.render.TextRenderer;
import xyz.pixelatedw.finalbeta.ModConfig;
import xyz.pixelatedw.finalbeta.WyHelper;
@Mixin(Overlay.class)
@ -39,7 +40,9 @@ public class OverlayMixin extends DrawableHelper {
)
)
public void render(float f, boolean flag, int i, int j, CallbackInfo ci) {
TextRenderer textRenderer = this.minecraft.textRenderer;
this.drawTextWithShadow(textRenderer, "Days Played: " + WyHelper.getGameDaysPlayed() + " (" + WyHelper.getRealDaysPlayed() + ")", 2, 96, 14737632);
if (ModConfig.ENABLE_TIME_TRACKING.get()) {
TextRenderer textRenderer = this.minecraft.textRenderer;
this.drawTextWithShadow(textRenderer, "Days Played: " + WyHelper.getGameDaysPlayed() + " (" + WyHelper.getRealDaysPlayed() + ")", 2, 96, 14737632);
}
}
}

View File

@ -33,7 +33,10 @@
"FenceTileMixin",
"LevelMonsterSpawnerMixin",
"BedTileMixin",
"BoatMixin"
"BoatMixin",
"LevelPropertiesMixin",
"LevelMixin",
"DoorTileMixin"
],
"injectors": {
"defaultRequire": -1