Skip to content

Commit

Permalink
Added chunk-based xp limiting
Browse files Browse the repository at this point in the history
+Implemented chunk-based xp limiting: mob farms have been a real issue for PlayerEx. However, limiting xp from mob farms whilst allowing xp from dungeons was complicated to implement. This is a new feature that aims to solve this problem. It works by attaching a factor to each chunk, which sits at 1.0. This factor is the chance for xp to spawn in the chunk (so 1.0 means guaranteed). Every time xp is created in the chunk, the chunk's factor decreases, therefore decreasing the chance for more xp to spawn. Meanwhile, the chunk has a restorative force, acting to bring the factor back to 1.0 over time. All of these values are configurable and this whole system can be disabled. More documentation to come.
  • Loading branch information
CleverNucleus committed Dec 18, 2022
1 parent 0b58c49 commit d13c190
Show file tree
Hide file tree
Showing 13 changed files with 192 additions and 3 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ dependencies {
include "dev.onyxstudios.cardinal-components-api:cardinal-components-base:${project.cardinal_components_version}"
modImplementation "dev.onyxstudios.cardinal-components-api:cardinal-components-entity:${project.cardinal_components_version}"
include "dev.onyxstudios.cardinal-components-api:cardinal-components-entity:${project.cardinal_components_version}"
modImplementation "dev.onyxstudios.cardinal-components-api:cardinal-components-chunk:${project.cardinal_components_version}"
include "dev.onyxstudios.cardinal-components-api:cardinal-components-chunk:${project.cardinal_components_version}"

modApi("me.shedaniel.cloth:cloth-config-fabric:${project.cloth_config_version}") {
exclude(group: "net.fabricmc.fabric-api")
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ minecraft_version=1.19.2
yarn_mappings=1.19.2+build.28
loader_version=0.14.10

mod_version = 3.3.8
mod_version = 3.3.9
maven_group = com.github.clevernucleus
archives_base_name = playerex

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public final class ExAPI {
public static final CacheableValue<Integer> LEVEL_VALUE = OfflinePlayerCache.register(new com.github.clevernucleus.playerex.impl.LevelValue());
/** The Cardinal Components Key for PlayerEx player data. */
public static final ComponentKey<PlayerData> PLAYER_DATA = ComponentRegistry.getOrCreate(new Identifier(MODID, "player_data"), PlayerData.class);
/** The Cardinal Components Key for PlayerEx experience data. */
public static final ComponentKey<ExperienceData> EXPERIENCE_DATA = ComponentRegistry.getOrCreate(new Identifier(MODID, "experience_data"), ExperienceData.class);

public static final EntityAttributeSupplier LEVEL = define("level");
public static final EntityAttributeSupplier CONSTITUTION = define("constitution");
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/github/clevernucleus/playerex/api/ExConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,21 @@ public interface ExConfig {
*/
int requiredXp(final PlayerEntity player);

/**
* @return The number of ticks taken for a chunk to restore the experience negation factor.
*/
int restorativeForceTicks();

/**
* @return The restorative force multiplier.
*/
float restorativeForceMultiplier();

/**
* @return The multiplier for experience negation.
*/
float expNegationFactor();

/**
* Client option.
* @return 0 - 1.5. Volume multiplier for level up event.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.clevernucleus.playerex.api;

import dev.onyxstudios.cca.api.v3.component.tick.ServerTickingComponent;

public interface ExperienceData extends ServerTickingComponent {
boolean updateExperienceNegationFactor(final int amount);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ public static enum Tooltip { DEFAULT, VANILLA, PLAYEREX; }
@ConfigEntry.Gui.Tooltip(count = 2)
protected String levelFormula = "stairs(x,0.2,2.4,17,10,25)";

@ConfigEntry.Category(value = "server")
@ConfigEntry.Gui.Tooltip(count = 2)
private int restorativeForceTicks = 600;

@ConfigEntry.Category(value = "server")
@ConfigEntry.Gui.Tooltip(count = 2)
private int restorativeForceMultiplier = 110;

@ConfigEntry.Category(value = "server")
@ConfigEntry.BoundedDiscrete(min = 1, max = 100)
@ConfigEntry.Gui.Tooltip(count = 2)
private int expNegationFactor = 95;

@ConfigEntry.Category(value = "client")
@ConfigEntry.BoundedDiscrete(min = 0, max = 150)
@ConfigEntry.Gui.Tooltip
Expand Down Expand Up @@ -95,6 +108,21 @@ public int requiredXp(final PlayerEntity player) {
return DataAttributesAPI.ifPresent(player, ExAPI.LEVEL, 1, ConfigServer.INSTANCE::level);
}

@Override
public int restorativeForceTicks() {
return this.restorativeForceTicks;
}

@Override
public float restorativeForceMultiplier() {
return (float)this.restorativeForceMultiplier * 0.01F;
}

@Override
public float expNegationFactor() {
return (float)this.expNegationFactor * 0.01F;
}

@Override
public float levelUpVolume() {
return this.levelUpVolume * 0.01F;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.github.clevernucleus.playerex.impl;

import com.github.clevernucleus.playerex.api.ExAPI;

import dev.onyxstudios.cca.api.v3.chunk.ChunkComponentFactoryRegistry;
import dev.onyxstudios.cca.api.v3.chunk.ChunkComponentInitializer;

public final class ExperienceDataContainer implements ChunkComponentInitializer {

@Override
public void registerChunkComponentFactories(ChunkComponentFactoryRegistry registry) {
registry.register(ExAPI.EXPERIENCE_DATA, ExperienceDataManager.class, ExperienceDataManager::new);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.github.clevernucleus.playerex.impl;

import java.util.Random;

import com.github.clevernucleus.playerex.api.ExAPI;
import com.github.clevernucleus.playerex.api.ExConfig;
import com.github.clevernucleus.playerex.api.ExperienceData;

import net.minecraft.nbt.NbtCompound;
import net.minecraft.world.chunk.Chunk;

public final class ExperienceDataManager implements ExperienceData {
private static final String KEY_EXP_NEGATION_CHANCE = "ExpNegationFactor";
private static final Random RANDOM = new Random();
private final Chunk chunk;
private float expNegationFactor;
private int ticks;
private final int restorativeForceTicks;
private final float restorativeForce;
private final float expNegationMultiplier;

public ExperienceDataManager(final Chunk chunk) {
this.chunk = chunk;
this.expNegationFactor = 1.0F;
this.ticks = 0;

ExConfig config = ExAPI.getConfig();
this.restorativeForceTicks = config.restorativeForceTicks();
this.restorativeForce = config.restorativeForceMultiplier();
this.expNegationMultiplier = config.expNegationFactor();
}

@Override
public boolean updateExperienceNegationFactor(final int amount) {
if(RANDOM.nextFloat() > this.expNegationFactor) return true;
float dynamicMultiplier = this.expNegationMultiplier + ((1.0F - this.expNegationMultiplier) * (1.0F - (0.1F * (float)amount)));
this.expNegationFactor = Math.max(this.expNegationFactor * dynamicMultiplier, 0.0F);
this.chunk.setNeedsSaving(true);
return false;
}

@Override
public void serverTick() {
if(this.expNegationFactor == 1.0F) return;
if(this.ticks < this.restorativeForceTicks) {
this.ticks++;
} else {
this.ticks = 0;
this.expNegationFactor = Math.min(this.expNegationFactor * this.restorativeForce, 1.0F);
this.chunk.setNeedsSaving(true);
}
}

@Override
public void readFromNbt(NbtCompound tag) {
this.expNegationFactor = tag.getFloat(KEY_EXP_NEGATION_CHANCE);
}

@Override
public void writeToNbt(NbtCompound tag) {
tag.putFloat(KEY_EXP_NEGATION_CHANCE, this.expNegationFactor);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.github.clevernucleus.playerex.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 com.github.clevernucleus.playerex.api.ExAPI;

import net.minecraft.entity.Entity.RemovalReason;
import net.minecraft.entity.ExperienceOrbEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;

@Mixin(ExperienceOrbEntity.class)
abstract class ExperienceOrbEntityMixin {

@Inject(method = "<init>", at = @At("TAIL"))
public void playerex_init(World world, double x, double y, double z, int amount, CallbackInfo ci) {
BlockPos pos = new BlockPos(x, y, z);
Chunk chunk = world.getChunk(pos);

ExAPI.EXPERIENCE_DATA.maybeGet(chunk).ifPresent(data -> {
if(data.updateExperienceNegationFactor(amount)) {
((ExperienceOrbEntity)(Object)this).remove(RemovalReason.DISCARDED);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.github.clevernucleus.playerex.mixin;

import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;

import net.minecraft.server.world.ServerWorld;

@Mixin(ServerWorld.class)
abstract class ServerWorldMixin {

@Redirect(method = "addEntity", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V"))
private void playerex_addEntity(Logger logger, String arg0, Object arg1) {}
}
9 changes: 9 additions & 0 deletions src/main/resources/assets/playerex/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@
"text.autoconfig.playerex.option.levelFormula": "Level Up Formula",
"text.autoconfig.playerex.option.levelFormula.@Tooltip[0]": "The number of experience points required to level up. The 'x' \nvariable refers to the player's current level; 'x' is required.",
"text.autoconfig.playerex.option.levelFormula.@Tooltip[1]": "(Requires restart)",
"text.autoconfig.playerex.option.restorativeForceTicks": "Restorative Force Ticks",
"text.autoconfig.playerex.option.restorativeForceTicks.@Tooltip[0]": "The number of ticks between every restorative event. \nNote that 20 ticks is 1 second.",
"text.autoconfig.playerex.option.restorativeForceTicks.@Tooltip[1]": "(Requires restart)",
"text.autoconfig.playerex.option.restorativeForceMultiplier": "Restorative Force",
"text.autoconfig.playerex.option.restorativeForceMultiplier.@Tooltip[0]": "The restorative force multiplier.",
"text.autoconfig.playerex.option.restorativeForceMultiplier.@Tooltip[1]": "(Requires restart)",
"text.autoconfig.playerex.option.expNegationFactor": "XP Negation Factor",
"text.autoconfig.playerex.option.expNegationFactor.@Tooltip[0]": "The chance for xp orbs to drop in a given chunk. \nSet to 100 for vanilla behaviour.",
"text.autoconfig.playerex.option.expNegationFactor.@Tooltip[1]": "(Requires restart)",
"text.autoconfig.playerex.option.levelUpVolume": "Level Up Volume",
"text.autoconfig.playerex.option.levelUpVolume.@Tooltip": "Volume multiplier as a percentage.",
"text.autoconfig.playerex.option.skillUpVolume": "Skill Up Volume",
Expand Down
6 changes: 4 additions & 2 deletions src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@
"com.github.clevernucleus.playerex.client.PlayerExClient"
],
"cardinal-components": [
"com.github.clevernucleus.playerex.impl.PlayerDataContainer"
"com.github.clevernucleus.playerex.impl.PlayerDataContainer",
"com.github.clevernucleus.playerex.impl.ExperienceDataContainer"
],
"modmenu": [
"com.github.clevernucleus.playerex.config.ModMenuCompat"
]
},
"custom": {
"cardinal-components": [
"playerex:player_data"
"playerex:player_data",
"playerex:experience_data"
]
},
"mixins": [
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/playerex.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"LivingEntityMixin",
"PlayerEntityMixin",
"ServerPlayerEntityMixin",
"ExperienceOrbEntityMixin",
"ServerWorldMixin",
"PlayerInventoryMixin",
"PersistentProjectileEntityMixin"
],
Expand Down

0 comments on commit d13c190

Please # to comment.