Skip to content

Commit

Permalink
I think i'm finally storing/retrieving exp correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
Direwolf20-MC committed Sep 12, 2024
1 parent 8ca3661 commit 95d2c4c
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// 1.21.1 2024-09-12T11:15:53.905581 Languages: en_us for mod: justdirethings
80317086157715c924dcacf357e72efab49d8580 assets/justdirethings/lang/en_us.json
// 1.21.1 2024-09-12T13:18:00.5916321 Languages: en_us for mod: justdirethings
370a2cb7525636b760559d6e7176176093558760 assets/justdirethings/lang/en_us.json
2 changes: 2 additions & 0 deletions src/generated/resources/assets/justdirethings/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@
"justdirethings.screen.renderarea": "Render Area",
"justdirethings.screen.renderparadox": "Render Paradox",
"justdirethings.screen.requireequipped": "Activate if Equipped",
"justdirethings.screen.retrieveexp": "Retrieve Exp",
"justdirethings.screen.rightclicksettings": "Right Click for Settings",
"justdirethings.screen.save_close": "Save and Close",
"justdirethings.screen.senditems": "Push Items",
Expand All @@ -419,6 +420,7 @@
"justdirethings.screen.snapshotarea": "Snapshot Area",
"justdirethings.screen.sneak-click": "Sneak Click",
"justdirethings.screen.stay_open": "Stay Open",
"justdirethings.screen.storeexp": "Store Exp",
"justdirethings.screen.swapitems": "Swap Items",
"justdirethings.screen.target-adult": "Target Adult",
"justdirethings.screen.target-air": "Target Air",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,44 @@
package com.direwolf20.justdirethings.client.screens;

import com.direwolf20.justdirethings.client.screens.basescreens.BaseMachineScreen;
import com.direwolf20.justdirethings.client.screens.standardbuttons.ToggleButtonFactory;
import com.direwolf20.justdirethings.common.blockentities.ExperienceHolderBE;
import com.direwolf20.justdirethings.common.containers.ExperienceHolderContainer;
import com.direwolf20.justdirethings.common.network.data.ExperienceHolderPayload;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import net.neoforged.neoforge.network.PacketDistributor;

public class ExperienceHolderScreen extends BaseMachineScreen<ExperienceHolderContainer> {
private ExperienceHolderBE experienceHolderBE;
private int exp;
public ExperienceHolderScreen(ExperienceHolderContainer container, Inventory inv, Component name) {
super(container, inv, name);
if (container.baseMachineBE instanceof ExperienceHolderBE experienceHolderBE) {
this.experienceHolderBE = experienceHolderBE;
this.exp = experienceHolderBE.exp;
}
}

@Override
public void init() {
super.init();
addRenderableWidget(ToggleButtonFactory.STOREEXPBUTTON(getGuiLeft() + 62, topSectionTop + 62, true, b -> {
int amt = 1;
if (Screen.hasControlDown())
amt = -1;
else if (Screen.hasShiftDown())
amt = amt * 10;
PacketDistributor.sendToServer(new ExperienceHolderPayload(true, amt));
}));
addRenderableWidget(ToggleButtonFactory.EXTRACTEXPBUTTON(getGuiLeft() + 102, topSectionTop + 62, true, b -> {
int amt = 1;
if (Screen.hasControlDown())
amt = -1;
else if (Screen.hasShiftDown())
amt = amt * 10;
PacketDistributor.sendToServer(new ExperienceHolderPayload(false, amt));
}));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ public static ToggleButton ALLOWLISTBUTTON(int x, int y, boolean startingValue,
return new ToggleButton(x, y, STANDARD_WIDTH, STANDARD_HEIGHT, ALLOW_LIST_TEXTURES, startingValue, onPress);
}

private static final ResourceLocation STORE_EXP_BUTTON = ResourceLocation.fromNamespaceAndPath(JustDireThings.MODID, "textures/gui/buttons/add.png");
private static final Component STORE_EXP_BUTTON_LOCALIZATION = Component.translatable("justdirethings.screen.storeexp");

public static GrayscaleButton STOREEXPBUTTON(int x, int y, boolean startingValue, Button.OnPress onPress) {
return new GrayscaleButton(x, y, STANDARD_WIDTH, STANDARD_HEIGHT, STORE_EXP_BUTTON, STORE_EXP_BUTTON_LOCALIZATION, startingValue, onPress);
}

private static final ResourceLocation EXTRACT_EXP_BUTTON = ResourceLocation.fromNamespaceAndPath(JustDireThings.MODID, "textures/gui/buttons/remove.png");
private static final Component EXTRACT_EXP_BUTTON_LOCALIZATION = Component.translatable("justdirethings.screen.retrieveexp");

public static GrayscaleButton EXTRACTEXPBUTTON(int x, int y, boolean startingValue, Button.OnPress onPress) {
return new GrayscaleButton(x, y, STANDARD_WIDTH, STANDARD_HEIGHT, EXTRACT_EXP_BUTTON, EXTRACT_EXP_BUTTON_LOCALIZATION, startingValue, onPress);
}

private static final ResourceLocation FILTER_ONLY = ResourceLocation.fromNamespaceAndPath(JustDireThings.MODID, "textures/gui/buttons/allowlisttrue.png");
private static final Component FILTER_ONLY_LOCALIZATION = Component.translatable("justdirethings.screen.filteronlytrue");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
import com.direwolf20.justdirethings.common.blockentities.basebe.BaseMachineBE;
import com.direwolf20.justdirethings.common.blockentities.basebe.RedstoneControlledBE;
import com.direwolf20.justdirethings.setup.Registration;
import com.direwolf20.justdirethings.util.ExperienceUtils;
import com.direwolf20.justdirethings.util.interfacehelpers.AreaAffectingData;
import com.direwolf20.justdirethings.util.interfacehelpers.FilterData;
import com.direwolf20.justdirethings.util.interfacehelpers.RedstoneControlData;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
Expand All @@ -25,6 +28,7 @@ public class ExperienceHolderBE extends BaseMachineBE implements AreaAffectingBE
public FilterData filterData = new FilterData();
public AreaAffectingData areaAffectingData = new AreaAffectingData();
public RedstoneControlData redstoneControlData = new RedstoneControlData();
public int exp;

public ExperienceHolderBE(BlockPos pPos, BlockState pBlockState) {
super(Registration.ExperienceHolderBE.get(), pPos, pBlockState);
Expand All @@ -45,6 +49,70 @@ public AreaAffectingData getAreaAffectingData() {
return areaAffectingData;
}

public void storeExp(Player player, int levelChange) {
if (levelChange == -1) {
// Move all experience from player
int totalExp = ExperienceUtils.getPlayerTotalExperience(player);
this.exp += totalExp;
player.giveExperiencePoints(-totalExp); // Removes all levels
} else if (levelChange > 0) {
// Handle fractional progress first, if the player is in the middle of a level
int expInCurrentLevel = (int) (player.experienceProgress * player.getXpNeededForNextLevel());

// If the player has partial progress within the current level, remove that first
if (expInCurrentLevel > 0) {
int expRemoved = ExperienceUtils.removePoints(player, expInCurrentLevel);
this.exp += expRemoved;
levelChange--; // We've already removed part of a level
}

if (levelChange > 0) {
// Now remove the specified number of full levels
int expRemoved = ExperienceUtils.removeLevels(player, levelChange);
this.exp += expRemoved;
}
}

markDirtyClient();
}

public void extractExp(Player player, int levelChange) {
if (exp == 0) return; // No experience in the block, exit early

if (levelChange == -1) {
// Move all experience from block to player
int expToGive = exp;
player.giveExperiencePoints(expToGive);
this.exp = 0; // Remove all experience from the block
} else if (levelChange > 0) {
// Handle fractional progress first, if the player is in the middle of a level
if (roundUpToNextLevel(player))
levelChange--;

if (levelChange > 0 && this.exp > 0) {
// Give full levels based on the remaining levels requested
int expForNextLevels = ExperienceUtils.getTotalExperienceForLevel(player.experienceLevel + levelChange) - ExperienceUtils.getPlayerTotalExperience(player);
int expToGive = Math.min(this.exp, expForNextLevels);
player.giveExperiencePoints(expToGive);
this.exp -= expToGive;
roundUpToNextLevel(player); //Thanks Floating point math!!
}
}

markDirtyClient();
}

public boolean roundUpToNextLevel(Player player) {
int expInCurrentLevel = (int) (player.experienceProgress * player.getXpNeededForNextLevel());
if (expInCurrentLevel > 0) {
int expToGive = Math.min(exp, ExperienceUtils.getExpNeededForNextLevel(player));
player.giveExperiencePoints(expToGive);
this.exp -= expToGive;
return true;
}
return false;
}

public void tickClient() {
}

Expand Down Expand Up @@ -77,4 +145,16 @@ private void handleExperience() {

}
}

@Override
public void saveAdditional(CompoundTag tag, HolderLookup.Provider provider) {
super.saveAdditional(tag, provider);
tag.putInt("exp", exp);
}

@Override
public void loadAdditional(CompoundTag tag, HolderLookup.Provider provider) {
super.loadAdditional(tag, provider);
exp = tag.getInt("exp");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public static void registerNetworking(final RegisterPayloadHandlersEvent event)
registrar.playToServer(InventoryHolderSaveSlotPayload.TYPE, InventoryHolderSaveSlotPayload.STREAM_CODEC, InventoryHolderSaveSlotPacket.get()::handle);
registrar.playToServer(InventoryHolderSettingsPayload.TYPE, InventoryHolderSettingsPayload.STREAM_CODEC, InventoryHolderSettingsPacket.get()::handle);
registrar.playToServer(InventoryHolderMoveItemsPayload.TYPE, InventoryHolderMoveItemsPayload.STREAM_CODEC, InventoryHolderMoveItemsPacket.get()::handle);
registrar.playToServer(ExperienceHolderPayload.TYPE, ExperienceHolderPayload.STREAM_CODEC, ExperienceHolderPacket.get()::handle);

//Going to Client
registrar.playToClient(ClientSoundPayload.TYPE, ClientSoundPayload.STREAM_CODEC, ClientSoundPacket.get()::handle);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.direwolf20.justdirethings.common.network.data;

import com.direwolf20.justdirethings.JustDireThings;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;

public record ExperienceHolderPayload(
boolean add,
int levels
) implements CustomPacketPayload {
public static final Type<ExperienceHolderPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(JustDireThings.MODID, "experience_holder"));

@Override
public Type<ExperienceHolderPayload> type() {
return TYPE;
}

public static final StreamCodec<FriendlyByteBuf, ExperienceHolderPayload> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.BOOL, ExperienceHolderPayload::add,
ByteBufCodecs.INT, ExperienceHolderPayload::levels,
ExperienceHolderPayload::new
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.direwolf20.justdirethings.common.network.handler;

import com.direwolf20.justdirethings.common.blockentities.ExperienceHolderBE;
import com.direwolf20.justdirethings.common.containers.ExperienceHolderContainer;
import com.direwolf20.justdirethings.common.network.data.ExperienceHolderPayload;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.neoforged.neoforge.network.handling.IPayloadContext;

public class ExperienceHolderPacket {
public static final ExperienceHolderPacket INSTANCE = new ExperienceHolderPacket();

public static ExperienceHolderPacket get() {
return INSTANCE;
}

public void handle(final ExperienceHolderPayload payload, final IPayloadContext context) {
context.enqueueWork(() -> {
Player sender = context.player();
AbstractContainerMenu container = sender.containerMenu;

if (container instanceof ExperienceHolderContainer experienceHolderContainer && experienceHolderContainer.baseMachineBE instanceof ExperienceHolderBE experienceHolderBE) {
if (payload.add())
experienceHolderBE.storeExp(sender, payload.levels());
else
experienceHolderBE.extractExp(sender, payload.levels());
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,8 @@ protected void addTranslations() {
add("justdirethings.screen.senditems", "Push Items");
add("justdirethings.screen.pullitems", "Pull Items");
add("justdirethings.screen.swapitems", "Swap Items");
add("justdirethings.screen.storeexp", "Store Exp");
add("justdirethings.screen.retrieveexp", "Retrieve Exp");

//Buttons
//add("justdirethings.buttons.save", "Save");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.direwolf20.justdirethings.util;

import net.minecraft.world.entity.player.Player;

public class ExperienceUtils {
// Calculate experience required to go from level 0 to target level
public static int getTotalExperienceForLevel(int level) {
if (level <= 16) {
return level * level + 6 * level;
} else if (level <= 31) {
return (int) (2.5 * level * level - 40.5 * level + 360);
} else {
return (int) (4.5 * level * level - 162.5 * level + 2220);
}
}

// Remove levels from a player, ensuring they don't lose more than available
public static int removeLevels(Player player, int levelsToRemove) {
int currentTotalExp = getPlayerTotalExperience(player);
int targetLevel = Math.max(0, player.experienceLevel - levelsToRemove);

// Calculate how much exp is required to be at the target level
int targetTotalExp = getTotalExperienceForLevel(targetLevel);
int expToRemove = currentTotalExp - targetTotalExp;

player.giveExperienceLevels(-levelsToRemove);
return expToRemove; // Amount of exp removed
}

// Calculate experience required to go from one level to the next
public static int getExperienceForNextLevel(int level) {
if (level >= 30) {
return 112 + (level - 30) * 9;
} else {
return level >= 15 ? 37 + (level - 15) * 5 : 7 + level * 2;
}
}

// Calculate total experience points player currently has (given level and progress)
public static int getPlayerTotalExperience(Player player) {
int exp = getTotalExperienceForLevel(player.experienceLevel);
exp += Math.round(player.experienceProgress * player.getXpNeededForNextLevel());
return exp;
}

public static int getExpNeededForNextLevel(Player player) {
return player.getXpNeededForNextLevel() - (int) (player.experienceProgress * player.getXpNeededForNextLevel());
}

// Remove points from a player, ensuring they don't lose more than available
public static int removePoints(Player player, int pointsToRemove) {
int currentTotalExp = getPlayerTotalExperience(player);
int expToRemove = Math.min(currentTotalExp, pointsToRemove);
player.giveExperiencePoints(-expToRemove);
return expToRemove; // Amount of exp removed
}
}

0 comments on commit 95d2c4c

Please sign in to comment.