aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Hergès <william@herges.fr>2025-10-12 17:02:48 +0200
committerWilliam Hergès <william@herges.fr>2025-10-12 17:02:48 +0200
commitcb9b24a15cbcd3e534dcc7939b3c566ab0204436 (patch)
tree0bcae2e6ca5ebde32e895624c761a3b76bf7b4c7
parent3307cef52177c882bdc9f956b2dd72fbb9e9753f (diff)
feat(player): represents custom data
-rwxr-xr-x[-rw-r--r--]LICENSE (renamed from LICENSE.txt)55
-rw-r--r--README.md3
-rw-r--r--src/main/java/world/anhgelus/lifesteal/LifeStealer.java98
3 files changed, 143 insertions, 13 deletions
diff --git a/LICENSE.txt b/LICENSE
index 313e689..9718cb2 100644..100755
--- a/LICENSE.txt
+++ b/LICENSE
@@ -1,19 +1,7 @@
-Copyright (c) 2025
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -629,3 +617,44 @@ Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ LifeSteal Copyright (C) <no value> William Hergès
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<https://www.gnu.org/licenses/>.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e2f233a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# LifeSteal
+
+LifeSteal is a server-side mod recreating the LifeSteal SMP experience.
diff --git a/src/main/java/world/anhgelus/lifesteal/LifeStealer.java b/src/main/java/world/anhgelus/lifesteal/LifeStealer.java
new file mode 100644
index 0000000..86410de
--- /dev/null
+++ b/src/main/java/world/anhgelus/lifesteal/LifeStealer.java
@@ -0,0 +1,98 @@
+package world.anhgelus.lifesteal;
+
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.component.DataComponentTypes;
+import net.minecraft.component.type.NbtComponent;
+import net.minecraft.entity.attribute.EntityAttributeModifier;
+import net.minecraft.entity.attribute.EntityAttributes;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.nbt.NbtCompound;
+import net.minecraft.server.network.ServerPlayerEntity;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.math.MathHelper;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class LifeStealer {
+ public static final Identifier HEALTH_MODIFIER = Identifier.of(LifeSteal.MOD_ID, "health_modifier");
+ public static final String PLAYER_KEY = "player";
+
+ private ServerPlayerEntity player;
+ private final UUID uuid;
+ private float healthModifier;
+
+ public LifeStealer(ServerPlayerEntity player, Data data) {
+ this.player = player;
+ this.uuid = player.getUuid();
+ this.healthModifier = data.healthModifier();
+ }
+
+ private void updateHealth() {
+ healthModifier = MathHelper.clamp(healthModifier, -20, 20);
+ final var attr = player.getAttributeInstance(EntityAttributes.MAX_HEALTH);
+ if (attr == null) throw new IllegalStateException("No health attribute assigned to LifeStealer");
+ if (attr.hasModifier(HEALTH_MODIFIER)) attr.removeModifier(HEALTH_MODIFIER);
+ final var modifier = new EntityAttributeModifier(HEALTH_MODIFIER, healthModifier, EntityAttributeModifier.Operation.ADD_VALUE);
+ attr.addTemporaryModifier(modifier);
+ }
+
+ public ItemStack getHeart() {
+ final var nbt = new NbtCompound();
+ nbt.putString(PLAYER_KEY, player.getUuid().toString());
+ final var is = new ItemStack(Items.NETHER_STAR);
+ is.set(DataComponentTypes.CUSTOM_NAME, player.getName());
+ is.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(nbt));
+ return is;
+ }
+
+ public void respawn(ServerPlayerEntity newPlayer) {
+ if (!newPlayer.getUuid().equals(uuid)) throw new IllegalArgumentException("Player does not have the same UUID");
+ this.player = newPlayer;
+ updateHealth();
+ }
+
+ public void kill() {
+ healthModifier = MathHelper.clamp(healthModifier + 2, -20, 20);
+ updateHealth();
+ }
+
+ public void killed() {
+ healthModifier = MathHelper.clamp(healthModifier - 2, -20, 20);
+ if (healthModifier <= 0) {
+ //TODO: ban player
+ return;
+ }
+ updateHealth();
+ }
+
+ public float getHealthModifier() {
+ return healthModifier;
+ }
+
+ public record Data(float healthModifier) {
+ public final static String HEALTH_MODIFIER_KEY = "health_modifier";
+ public static final Codec<Data> CODEC = RecordCodecBuilder.create(i -> i.group(
+ Codec.FLOAT.fieldOf(HEALTH_MODIFIER_KEY).forGetter(Data::healthModifier)
+ ).apply(i, Data::new));
+
+ public static Data DEFAULT = new Data(0.0F);
+ }
+
+ public static class Manager {
+ private static final Map<UUID, LifeStealer> players = new HashMap<>();
+
+ public static LifeStealer getLifeStealer(ServerPlayerEntity player) {
+ return players.computeIfAbsent(player.getUuid(), k -> new LifeStealer(player, Data.DEFAULT));
+ }
+
+ @Nullable
+ public static LifeStealer getLifeStealer(UUID uuid) {
+ return players.get(uuid);
+ }
+ }
+}