Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.19.2] Persistently save XP saves for entities #20

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Disable autocrlf on generated files, they always generate with LF
# Add any extra files or paths here to make git stop saying they
# are changed when only line endings change.
src/generated/**/.cache/cache text eol=lf
src/generated/**/*.json text eol=lf

src/generated/** linguist-generated
188 changes: 188 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
## Java

# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# Libraries
!libs/*


## Gradle

.gradle
**/build/
!src/**/build/

# Ignore Gradle GUI config
gradle-app.setting

# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar

# Cache of project
.gradletasknamecache


## Minecraft Forge

# ForgeGradle
run/
eclipse/

# MixinGradle Eclipse logs
/logs/

# TestMaven repo folder
mcmodsrepo/


## IntelliJ IDEA

# Basic project files
.idea
*.iml
*.ipr

# File-based project format
*.iws

# Compiler output
out/


## Eclipse

.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.classpath

# External tool builders
.externalToolBuilders/

# Locally stored "Eclipse launch configurations"
*.launch

# Java annotation processor (APT)
.factorypath

# Code Recommenders
.recommenders/

# Annotation Processing
.apt_generated/
.apt_generated_test/

# Project description file
.project


## Other

# Java Keystores
*.jks


## Windows

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk


## macOS

# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon


# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk


## Linux

*~

# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*

# KDE directory preferences
.directory

# Linux trash folder which might appear on any partition or disk
.Trash-*

# .nfs files are created when an open file is removed but is still being accessed
.nfs*
/.apt_generated_tests/
10 changes: 9 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ buildscript {

apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'maven-publish'
apply plugin: 'org.spongepowered.mixin'

Expand Down Expand Up @@ -103,4 +104,11 @@ jar.finalizedBy('reobfJar')
task sourcesJar(type: Jar) {
archiveClassifier.set('sources')
from sourceSets.main.allJava
}
}

idea {
module {
downloadJavadoc = true
downloadSources = true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package net.lyof.sortilege.capabilities;

import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.Lazy;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.common.util.NonNullSupplier;

public class CapabilityProvider<C extends IPersistentCapability<C>> implements ICapabilitySerializable<CompoundTag> {
private static final NonNullSupplier<IllegalStateException> EXCEPTION =
() -> new IllegalStateException("Capability handler was holding a null or empty capability!");

private final LazyOptional<C> capabilityHandler;
private final Lazy<Capability<C>> instance;

public CapabilityProvider(C capability) {
this.capabilityHandler = LazyOptional.of(() -> capability);
this.instance = Lazy.of(capability::getDefaultInstance);
}

@Override
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
return cap == this.instance.get() ? this.capabilityHandler.cast() : LazyOptional.empty();
}

@Override
public void deserializeNBT(CompoundTag compound) {
this.get().load(compound);
}

@Override
public CompoundTag serializeNBT() {
return this.get().save(new CompoundTag());
}

private C get() {
return this.capabilityHandler.orElseThrow(EXCEPTION);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package net.lyof.sortilege.capabilities;

import net.minecraft.nbt.CompoundTag;
import net.minecraftforge.common.capabilities.Capability;

public interface IPersistentCapability<C> {
Capability<C> getDefaultInstance();

CompoundTag save(CompoundTag tag);

void load(CompoundTag tag);
}
44 changes: 44 additions & 0 deletions src/main/java/net/lyof/sortilege/capabilities/ModCapabilities.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package net.lyof.sortilege.capabilities;

import net.lyof.sortilege.capabilities.entity.EntityXpStorage;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

@Mod.EventBusSubscriber
public class ModCapabilities {
@SubscribeEvent
public static void onAttachEntityCapabilities(AttachCapabilitiesEvent<Entity> event) {
EntityXpStorage.attach(event);
}

/**
* Clones player capabilities along with the new player.
*
* @param event The player clone event.
* @see <a
* href="https://github.com/MinecraftForge/MinecraftForge/issues/9311">MinecraftForge/MinecraftForge#9311</a>
*
* @implNote Sortilege only adds one capability to store XP data, so we are unconditionally transferring all data.
* If you want to add more capabilities, you should add a check for {@link PlayerEvent.Clone#isWasDeath()} so
* that the data persists if the player is cloned due to leaving The End through the dragon portal.
*/
@SubscribeEvent
public static void onPlayerClone(PlayerEvent.Clone event) {
if (event.getEntity() instanceof ServerPlayer serverPlayerNew && event.getOriginal() instanceof ServerPlayer serverPlayerOld) {
// since we want the new player to have the same XP number as the old one, we are unconditionally transferring all data
serverPlayerOld.reviveCaps();
EntityXpStorage.ifPresent(serverPlayerNew, capabilityNew -> EntityXpStorage.ifPresent(serverPlayerOld, capabilityOld -> capabilityNew.load(capabilityOld.save(new CompoundTag()))));
serverPlayerOld.invalidateCaps();

// uncomment the below line and add other capabilites after it if you want to add more
// see the @implNote above for why
//if (!event.isWasDeath()) return
}
}

}
Loading