Compare commits
	
		
			10 Commits
		
	
	
		
			15901d9e79
			...
			b4e64f7f33
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						b4e64f7f33
	
				 | 
					
					
						|||
| 
						 | 
					ea1d87e16d | ||
| 
						 | 
					adfadd5eb7 | ||
| 
						 | 
					a56299bf56 | ||
| 
						 | 
					d7af5ef4bb | ||
| 
						 | 
					21bff77a28 | ||
| 
						 | 
					294fadb7b5 | ||
| 
						 | 
					b60e4492cf | ||
| 
						 | 
					af889f4808 | ||
| 
						 | 
					ca438aac32 | 
							
								
								
									
										95
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								build.gradle
									
									
									
									
									
								
							@@ -1,13 +1,17 @@
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
    id 'java-library'
 | 
			
		||||
    id 'eclipse'
 | 
			
		||||
    id 'idea'
 | 
			
		||||
    id 'maven-publish'
 | 
			
		||||
    id 'net.neoforged.gradle.userdev' version '7.0.145'
 | 
			
		||||
    id 'net.neoforged.moddev' version '2.0.80'
 | 
			
		||||
    id 'net.darkhax.curseforgegradle' version '[1.1.24,)'
 | 
			
		||||
    id "at.stnwtr.gradle-secrets-plugin" version "1.0.1"
 | 
			
		||||
    id "com.modrinth.minotaur" version "2.+"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
version = mod_version
 | 
			
		||||
group = 'dev.kxmc'
 | 
			
		||||
group = 'dev.xkmc'
 | 
			
		||||
 | 
			
		||||
repositories {
 | 
			
		||||
    mavenLocal()
 | 
			
		||||
@@ -17,38 +21,53 @@ base {
 | 
			
		||||
    archivesName = mod_id
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
java {
 | 
			
		||||
    withSourcesJar()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
java.toolchain.languageVersion = JavaLanguageVersion.of(21)
 | 
			
		||||
 | 
			
		||||
minecraft.accessTransformers.file rootProject.file('src/main/resources/META-INF/accesstransformer.cfg')
 | 
			
		||||
sourceSets {
 | 
			
		||||
    client {}
 | 
			
		||||
    server {}
 | 
			
		||||
    data {}
 | 
			
		||||
    common {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
runs {
 | 
			
		||||
    configureEach {
 | 
			
		||||
        systemProperty 'forge.logging.markers', 'REGISTRIES'
 | 
			
		||||
        systemProperty 'forge.logging.console.level', 'debug'
 | 
			
		||||
        modSource project.sourceSets.main
 | 
			
		||||
neoForge {
 | 
			
		||||
    // We currently only support NeoForge versions later than 21.0.x
 | 
			
		||||
    // See https://projects.neoforged.net/neoforged/neoforge for the latest updates
 | 
			
		||||
    version = "${neo_version}"
 | 
			
		||||
 | 
			
		||||
    // Validate AT files and raise errors when they have invalid targets
 | 
			
		||||
    // This option is false by default, but turning it on is recommended
 | 
			
		||||
    //validateAccessTransformers = true
 | 
			
		||||
    accessTransformers.from "./src/main/resources/META-INF/accesstransformer.cfg"
 | 
			
		||||
 | 
			
		||||
    runs {
 | 
			
		||||
        client {
 | 
			
		||||
            client()
 | 
			
		||||
        }
 | 
			
		||||
        data {
 | 
			
		||||
            data()
 | 
			
		||||
 | 
			
		||||
            programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath()
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        server {
 | 
			
		||||
            server()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    client {
 | 
			
		||||
        systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
 | 
			
		||||
    }
 | 
			
		||||
    server {
 | 
			
		||||
        systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
 | 
			
		||||
        programArgument '--nogui'
 | 
			
		||||
    }
 | 
			
		||||
    gameTestServer {
 | 
			
		||||
        systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
 | 
			
		||||
    }
 | 
			
		||||
    data {
 | 
			
		||||
        programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath()
 | 
			
		||||
 | 
			
		||||
    mods {
 | 
			
		||||
        "${mod_id}" {
 | 
			
		||||
            sourceSet sourceSets.main
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sourceSets.main.resources { srcDir 'src/generated/resources' }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    implementation "net.neoforged:neoforge:${neo_version}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks.withType(ProcessResources).configureEach {
 | 
			
		||||
    var replaceProperties = [
 | 
			
		||||
            minecraft_version   : minecraft_version, minecraft_version_range: minecraft_version_range,
 | 
			
		||||
@@ -84,10 +103,6 @@ tasks.withType(JavaCompile).configureEach {
 | 
			
		||||
 | 
			
		||||
if (lljij.toBoolean()) jarJar.enable()
 | 
			
		||||
 | 
			
		||||
java {
 | 
			
		||||
    withSourcesJar()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
jar {
 | 
			
		||||
    manifest {
 | 
			
		||||
        attributes([
 | 
			
		||||
@@ -148,14 +163,22 @@ dependencies {
 | 
			
		||||
    implementation "mezz.jei:jei-${jei_minecraft_version}:${jei_version}"
 | 
			
		||||
    implementation "com.tterrag.registrate:Registrate:${registrate_version}"
 | 
			
		||||
    implementation "dev.xkmc:l2serial:${l2serial_ver}"
 | 
			
		||||
    implementation "vazkii.patchouli:Patchouli:${patchouli_ver}"
 | 
			
		||||
    compileOnly "vazkii.patchouli:Patchouli:${patchouli_ver}"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    runtimeOnly "dev.xkmc:l2damagetracker:3.0.2"
 | 
			
		||||
    runtimeOnly "dev.xkmc:l2menustacker:3.0.9"
 | 
			
		||||
    runtimeOnly "dev.xkmc:l2itemselector:3.0.7"
 | 
			
		||||
    runtimeOnly "dev.xkmc:l2library:3.0.2"
 | 
			
		||||
    runtimeOnly "dev.xkmc:l2complements:3.0.2+3"
 | 
			
		||||
    //runtimeOnly "dev.xkmc:l2damagetracker:3.0.3+2"
 | 
			
		||||
    //runtimeOnly "dev.xkmc:l2menustacker:3.0.9"
 | 
			
		||||
    //runtimeOnly "dev.xkmc:l2itemselector:3.0.8"
 | 
			
		||||
    //runtimeOnly "dev.xkmc:l2library:3.0.2+4"
 | 
			
		||||
    //runtimeOnly "dev.xkmc:l2complements:3.0.2+7"
 | 
			
		||||
    //runtimeOnly "dev.xkmc:l2archery:3.0.0+8"
 | 
			
		||||
 | 
			
		||||
    //runtimeOnly "curse.maven:embeddium-908741:5630163"
 | 
			
		||||
    //runtimeOnly "curse.maven:farmers-delight-398521:5566383"
 | 
			
		||||
    //runtimeOnly "dev.xkmc:cuisinedelight:1.2.2"
 | 
			
		||||
 | 
			
		||||
    //implementation "curse.maven:enchantment-descriptions-250419:5760047"
 | 
			
		||||
    //implementation "curse.maven:bookshelf-228525:5757624"
 | 
			
		||||
    //implementation "curse.maven:prickle-1023259:5757615"
 | 
			
		||||
 | 
			
		||||
    runtimeOnly "curse.maven:embeddium-908741:5630163"
 | 
			
		||||
}
 | 
			
		||||
@@ -8,9 +8,11 @@ org.gradle.debug=false
 | 
			
		||||
neogradle.subsystems.parchment.minecraftVersion=1.20.6
 | 
			
		||||
neogradle.subsystems.parchment.mappingsVersion=2024.06.02
 | 
			
		||||
 | 
			
		||||
org.gradle.configuration-cache=false
 | 
			
		||||
 | 
			
		||||
minecraft_version=1.21.1
 | 
			
		||||
minecraft_version_range=[1.21.1,1.22)
 | 
			
		||||
neo_version=21.1.4
 | 
			
		||||
neo_version=21.1.143
 | 
			
		||||
neo_version_range=[21.1.4,)
 | 
			
		||||
loader_version_range=[2,)
 | 
			
		||||
 | 
			
		||||
@@ -18,18 +20,18 @@ loader_version_range=[2,)
 | 
			
		||||
mod_id=l2core
 | 
			
		||||
mod_name=L2Core
 | 
			
		||||
mod_license=LGPL-2.1
 | 
			
		||||
mod_version=3.0.7+31
 | 
			
		||||
mod_version=3.0.8+15
 | 
			
		||||
mod_group_id=dev.xkmc
 | 
			
		||||
mod_authors=lcy0x1
 | 
			
		||||
mod_description=Core Library mod for all L2 mods
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jei_minecraft_version = 1.21-neoforge
 | 
			
		||||
jei_version = 19.5.0.44
 | 
			
		||||
jei_minecraft_version = 1.21.1-neoforge
 | 
			
		||||
jei_version = 19.21.0.246
 | 
			
		||||
registrate_version = MC1.21-1.3.0+50
 | 
			
		||||
patchouli_ver = 1.21-87-NEOFORGE-SNAPSHOT
 | 
			
		||||
 | 
			
		||||
lljij = false
 | 
			
		||||
rootMod = false
 | 
			
		||||
 | 
			
		||||
l2serial_ver = 3.0.9
 | 
			
		||||
l2serial_ver = 3.0.9+4
 | 
			
		||||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
distributionBase=GRADLE_USER_HOME
 | 
			
		||||
distributionPath=wrapper/dists
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
 | 
			
		||||
networkTimeout=10000
 | 
			
		||||
zipStoreBase=GRADLE_USER_HOME
 | 
			
		||||
zipStorePath=wrapper/dists
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								libs/cuisinedelight-1.2.2.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/cuisinedelight-1.2.2.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								libs/l2archery-3.0.0+8-sources.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/l2archery-3.0.0+8-sources.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								libs/l2archery-3.0.0+8.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/l2archery-3.0.0+8.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								libs/l2damagetracker-3.0.3+2-sources.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/l2damagetracker-3.0.3+2-sources.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								libs/l2damagetracker-3.0.3+2.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/l2damagetracker-3.0.3+2.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								libs/l2modularblocks-3.0.0+4-sources.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/l2modularblocks-3.0.0+4-sources.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								libs/l2modularblocks-3.0.0+4.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/l2modularblocks-3.0.0+4.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -7,5 +7,5 @@ pluginManagement {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
    id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
 | 
			
		||||
    id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
// 1.21	2024-07-25T11:38:15.636395	Registrate Provider for l2core [Registries, Data Maps, Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), generic_server_provider, Blockstates, Item models, Lang (en_us/en_ud), generic_client_provider, Tags (mob_effect), Tags (attribute), Tags (enchantment)]
 | 
			
		||||
7fd8a37c6437c7cab27c53dbc0df73ececc1cd44 assets/l2core/lang/en_ud.json
 | 
			
		||||
18ae34417262501a3c00959390185e01ffb2ae7c assets/l2core/lang/en_us.json
 | 
			
		||||
// 1.21.1	2025-07-26T01:42:31.138209	Registrate Provider for l2core [Registries, Data Maps, Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), generic_server_provider, Blockstates, Item models, Lang (en_us/en_ud), generic_client_provider, Tags (mob_effect), Tags (attribute), Tags (enchantment)]
 | 
			
		||||
72a986cabe624a799bdb74cc1b5e67dd6f80baed assets/l2core/lang/en_ud.json
 | 
			
		||||
9eab006827655c8a83941f5d9c71681a1244378c assets/l2core/lang/en_us.json
 | 
			
		||||
35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/l2core/tags/mob_effect/tracked_effects.json
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,9 @@
 | 
			
		||||
  "l2core.configuration.addEnchantmentDescription": "suoıʇdıɹɔsǝᗡ ʇuǝɯʇuɐɥɔuƎ ppⱯ",
 | 
			
		||||
  "l2core.configuration.addEnchantmentDescription.tooltip": "SʎⱯMꞀⱯ 'ʎꞀNO‾⟘ℲIHS 'ƎꞀᗺⱯSIᗡ :sǝnןɐΛ pǝʍoןןⱯ",
 | 
			
		||||
  "l2core.configuration.overlayZVal": "ʎɐןɹǝʌo ɹǝʇɔɐɹɐɥɔ ɯǝʇı ɟo ʇɥbıǝɥ ǝɥ⟘",
 | 
			
		||||
  "l2core.configuration.overlayZVal.tooltip": "000000Ɩ ~ 000000Ɩ- :ǝbuɐᴚ",
 | 
			
		||||
  "l2core.configuration.overlayZVal.tooltip": "000000Ɩ ~ 000000Ɩ- :ǝbuɐᴚ \n0ϛᄅ :ʇןnɐɟǝᗡ ",
 | 
			
		||||
  "l2core.configuration.renderOverlayIcons": "sǝıʇıʇuǝ uo suoɔı ʎɐןɹǝʌo ɹǝpuǝᴚ",
 | 
			
		||||
  "l2core.configuration.renderOverlayIcons.tooltip": "",
 | 
			
		||||
  "l2core.configuration.section.l2configs.l2core.client.toml": "uoıʇɐɹnbıɟuoƆ ʇuǝıןƆ ǝɹoƆᄅꞀ",
 | 
			
		||||
  "l2core.configuration.section.l2configs.l2core.client.toml.title": "uoıʇɐɹnbıɟuoƆ ʇuǝıןƆ ǝɹoƆᄅꞀ",
 | 
			
		||||
  "l2core.configuration.title": "uoıʇɐɹnbıɟuoƆ ǝɹoƆᄅꞀ",
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,9 @@
 | 
			
		||||
  "l2core.configuration.addEnchantmentDescription": "Add Enchantment Descriptions",
 | 
			
		||||
  "l2core.configuration.addEnchantmentDescription.tooltip": "Allowed Values: DISABLE, SHIFT_ONLY, ALWAYS",
 | 
			
		||||
  "l2core.configuration.overlayZVal": "The height of item character overlay",
 | 
			
		||||
  "l2core.configuration.overlayZVal.tooltip": "Range: -1000000 ~ 1000000",
 | 
			
		||||
  "l2core.configuration.overlayZVal.tooltip": " Default: 250\n Range: -1000000 ~ 1000000",
 | 
			
		||||
  "l2core.configuration.renderOverlayIcons": "Render overlay icons on entities",
 | 
			
		||||
  "l2core.configuration.renderOverlayIcons.tooltip": "",
 | 
			
		||||
  "l2core.configuration.section.l2configs.l2core.client.toml": "L2Core Client Configuration",
 | 
			
		||||
  "l2core.configuration.section.l2configs.l2core.client.toml.title": "L2Core Client Configuration",
 | 
			
		||||
  "l2core.configuration.title": "L2Core Configuration",
 | 
			
		||||
 
 | 
			
		||||
@@ -3,22 +3,28 @@ package dev.xkmc.l2core.base.effects;
 | 
			
		||||
import dev.xkmc.l2core.base.effects.api.ForceEffect;
 | 
			
		||||
import net.minecraft.world.effect.MobEffectInstance;
 | 
			
		||||
import net.minecraft.world.entity.Entity;
 | 
			
		||||
import net.minecraft.world.entity.EntityType;
 | 
			
		||||
import net.minecraft.world.entity.LivingEntity;
 | 
			
		||||
import net.neoforged.neoforge.common.NeoForge;
 | 
			
		||||
import net.neoforged.neoforge.event.EventHooks;
 | 
			
		||||
import net.neoforged.neoforge.event.entity.living.MobEffectEvent;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Iterator;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.function.Predicate;
 | 
			
		||||
 | 
			
		||||
public class EffectUtil {
 | 
			
		||||
 | 
			
		||||
	private static final Set<EntityType<?>> INVALID = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * force add effect, make hard not override
 | 
			
		||||
	 * for icon use only, such as Arcane Mark on Wither and Ender Dragon
 | 
			
		||||
	 */
 | 
			
		||||
	private static void forceAddEffect(LivingEntity e, MobEffectInstance ins, @Nullable Entity source) {
 | 
			
		||||
	private synchronized static void forceAddEffect(LivingEntity e, MobEffectInstance ins, @Nullable Entity source) {
 | 
			
		||||
		if (INVALID.contains(e.getType())) return;
 | 
			
		||||
		MobEffectInstance old = e.activeEffects.get(ins.getEffect());
 | 
			
		||||
		var event = new ForceAddEffectEvent(e, ins);
 | 
			
		||||
		NeoForge.EVENT_BUS.post(event);
 | 
			
		||||
@@ -27,7 +33,12 @@ public class EffectUtil {
 | 
			
		||||
		}
 | 
			
		||||
		NeoForge.EVENT_BUS.post(new MobEffectEvent.Added(e, old, ins, source));
 | 
			
		||||
		if (old == null) {
 | 
			
		||||
			e.activeEffects.put(ins.getEffect(), ins);
 | 
			
		||||
			try {
 | 
			
		||||
				e.activeEffects.put(ins.getEffect(), ins);
 | 
			
		||||
			} catch (Exception ignored) {
 | 
			
		||||
				INVALID.add(e.getType());
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			e.onEffectAdded(ins, source);
 | 
			
		||||
			ins.onEffectAdded(e);
 | 
			
		||||
		} else if (old.update(ins)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,37 @@
 | 
			
		||||
 | 
			
		||||
package dev.xkmc.l2core.base.worldgen;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import dev.xkmc.l2core.serial.configval.DoubleConfigValue;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.util.RandomSource;
 | 
			
		||||
import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
 | 
			
		||||
import net.minecraft.world.level.levelgen.placement.RepeatingPlacement;
 | 
			
		||||
 | 
			
		||||
import java.util.function.DoubleSupplier;
 | 
			
		||||
 | 
			
		||||
public class ConfigChancePlacement extends RepeatingPlacement {
 | 
			
		||||
	public static final MapCodec<ConfigChancePlacement> CODEC = DoubleConfigValue.CODEC.fieldOf("chance").xmap(ConfigChancePlacement::new, e -> e.chance);
 | 
			
		||||
	private final DoubleSupplier chance;
 | 
			
		||||
 | 
			
		||||
	private ConfigChancePlacement(DoubleSupplier chance) {
 | 
			
		||||
		this.chance = chance;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static ConfigChancePlacement of(DoubleSupplier count) {
 | 
			
		||||
		return new ConfigChancePlacement(count);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	protected int count(RandomSource random, BlockPos pos) {
 | 
			
		||||
		double val = chance.getAsDouble();
 | 
			
		||||
		int ans = (int) val;
 | 
			
		||||
		return ans + (random.nextFloat() < val - ans ? 1 : 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public PlacementModifierType<?> type() {
 | 
			
		||||
		return L2LibReg.PM_CHANCE.get();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
 | 
			
		||||
package dev.xkmc.l2core.base.worldgen;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import dev.xkmc.l2core.serial.configval.DoubleConfigValue;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.util.RandomSource;
 | 
			
		||||
import net.minecraft.world.level.levelgen.placement.PlacementContext;
 | 
			
		||||
import net.minecraft.world.level.levelgen.placement.PlacementFilter;
 | 
			
		||||
import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
 | 
			
		||||
 | 
			
		||||
import java.util.function.DoubleSupplier;
 | 
			
		||||
 | 
			
		||||
public class ConfigRarityFilter extends PlacementFilter {
 | 
			
		||||
 | 
			
		||||
	public static final MapCodec<ConfigRarityFilter> CODEC =
 | 
			
		||||
			DoubleConfigValue.CODEC.fieldOf("chance").xmap(ConfigRarityFilter::new, e -> e.chance);
 | 
			
		||||
 | 
			
		||||
	private final DoubleSupplier chance;
 | 
			
		||||
 | 
			
		||||
	private ConfigRarityFilter(DoubleSupplier chance) {
 | 
			
		||||
		this.chance = chance;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static ConfigRarityFilter of(DoubleSupplier chance) {
 | 
			
		||||
		return new ConfigRarityFilter(chance);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	protected boolean shouldPlace(PlacementContext context, RandomSource random, BlockPos pos) {
 | 
			
		||||
		return random.nextFloat() < this.chance.getAsDouble();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public PlacementModifierType<?> type() {
 | 
			
		||||
		return L2LibReg.PM_RARITY.get();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
@MethodsReturnNonnullByDefault
 | 
			
		||||
@ParametersAreNonnullByDefault
 | 
			
		||||
 | 
			
		||||
package dev.xkmc.l2core.base.worldgen;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.ParametersAreNonnullByDefault;
 | 
			
		||||
@@ -2,14 +2,17 @@ package dev.xkmc.l2core.capability.conditionals;
 | 
			
		||||
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import dev.xkmc.l2core.util.Proxy;
 | 
			
		||||
import dev.xkmc.l2serial.serialization.codec.PacketCodec;
 | 
			
		||||
import dev.xkmc.l2serial.util.Wrappers;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
 | 
			
		||||
public class ClientDataHandler {
 | 
			
		||||
 | 
			
		||||
	public static <T extends ConditionalToken> void handle(TokenKey<T> key, T token) {
 | 
			
		||||
	public static <T extends ConditionalToken> void handle(TokenKey<T> key, byte[] data) {
 | 
			
		||||
		Player player = Proxy.getClientPlayer();
 | 
			
		||||
		if (player == null) return;
 | 
			
		||||
		var buf = PacketCodec.decode(player.registryAccess(), data);
 | 
			
		||||
		T token = Wrappers.cast(PacketCodec.from(buf, ConditionalToken.class, null));
 | 
			
		||||
		ConditionalToken old = L2LibReg.CONDITIONAL.type().getOrCreate(player).data.put(key, token);
 | 
			
		||||
		if (token instanceof NetworkSensitiveToken<?> t) {
 | 
			
		||||
			t.onSync(Wrappers.cast(old), player);
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ public interface NetworkSensitiveToken<T extends ConditionalToken> {
 | 
			
		||||
	void onSync(@Nullable T old, Player player);
 | 
			
		||||
 | 
			
		||||
	default void sync(TokenKey<T> key, T token, ServerPlayer sp) {
 | 
			
		||||
		L2Core.PACKET_HANDLER.toClientPlayer(TokenToClient.of(key, token), sp);
 | 
			
		||||
		L2Core.PACKET_HANDLER.toClientPlayer(TokenToClient.of(sp.registryAccess(), key, token), sp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,23 @@
 | 
			
		||||
package dev.xkmc.l2core.capability.conditionals;
 | 
			
		||||
 | 
			
		||||
import dev.xkmc.l2serial.network.SerialPacketBase;
 | 
			
		||||
import dev.xkmc.l2serial.serialization.codec.PacketCodec;
 | 
			
		||||
import net.minecraft.core.RegistryAccess;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
public record TokenToClient(ResourceLocation id, ConditionalToken token)
 | 
			
		||||
public record TokenToClient(ResourceLocation id, byte[] data)
 | 
			
		||||
		implements SerialPacketBase<TokenToClient> {
 | 
			
		||||
 | 
			
		||||
	public static <T extends ConditionalToken> TokenToClient of(TokenKey<T> key, T token) {
 | 
			
		||||
		return new TokenToClient(key.asLocation(), token);
 | 
			
		||||
	public static <T extends ConditionalToken> TokenToClient of(RegistryAccess access, TokenKey<T> key, T token) {
 | 
			
		||||
		var data = PacketCodec.toBytes(access, token, ConditionalToken.class, e -> true);
 | 
			
		||||
		return new TokenToClient(key.asLocation(), data);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void handle(@Nullable Player player) {
 | 
			
		||||
		ClientDataHandler.handle(TokenKey.of(id), token);
 | 
			
		||||
		ClientDataHandler.handle(TokenKey.of(id), data);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,14 @@ import mezz.jei.api.recipe.IFocusGroup;
 | 
			
		||||
import mezz.jei.api.recipe.RecipeType;
 | 
			
		||||
import mezz.jei.api.recipe.category.IRecipeCategory;
 | 
			
		||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
			
		||||
import net.minecraft.client.Minecraft;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.world.item.crafting.Recipe;
 | 
			
		||||
import net.minecraft.world.item.crafting.RecipeHolder;
 | 
			
		||||
import net.minecraft.world.item.crafting.RecipeInput;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.ParametersAreNonnullByDefault;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@ParametersAreNonnullByDefault
 | 
			
		||||
@MethodsReturnNonnullByDefault
 | 
			
		||||
@@ -27,6 +32,13 @@ public abstract class BaseRecipeCategory<T, C extends BaseRecipeCategory<T, C>>
 | 
			
		||||
		this.type = new RecipeType<>(name, cls);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public <R extends Recipe<I>, I extends RecipeInput> List<R> getAll(net.minecraft.world.item.crafting.RecipeType<R> type) {
 | 
			
		||||
		var level = Minecraft.getInstance().level;
 | 
			
		||||
		if (level == null) return List.of();
 | 
			
		||||
		return level.getRecipeManager().getAllRecipesFor(type)
 | 
			
		||||
				.stream().map(RecipeHolder::value).toList();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	public final C getThis() {
 | 
			
		||||
		return (C) this;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +1,24 @@
 | 
			
		||||
package dev.xkmc.l2core.events;
 | 
			
		||||
 | 
			
		||||
import dev.xkmc.l2core.capability.attachment.GeneralCapabilityHolder;
 | 
			
		||||
import dev.xkmc.l2core.capability.player.PlayerCapabilityHolder;
 | 
			
		||||
import dev.xkmc.l2core.init.L2Core;
 | 
			
		||||
import dev.xkmc.l2serial.util.Wrappers;
 | 
			
		||||
import net.minecraft.server.level.ServerPlayer;
 | 
			
		||||
import net.minecraft.world.entity.LivingEntity;
 | 
			
		||||
import net.neoforged.bus.api.EventPriority;
 | 
			
		||||
import net.neoforged.bus.api.SubscribeEvent;
 | 
			
		||||
import net.neoforged.fml.common.EventBusSubscriber;
 | 
			
		||||
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent;
 | 
			
		||||
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
 | 
			
		||||
import net.neoforged.neoforge.event.tick.EntityTickEvent;
 | 
			
		||||
import net.neoforged.neoforge.event.tick.PlayerTickEvent;
 | 
			
		||||
 | 
			
		||||
@EventBusSubscriber(modid = L2Core.MODID, bus = EventBusSubscriber.Bus.GAME)
 | 
			
		||||
public class BaseCapabilityEvents {
 | 
			
		||||
 | 
			
		||||
	@SubscribeEvent
 | 
			
		||||
	public static void onLivingTick(EntityTickEvent.Post event) {
 | 
			
		||||
		if (event.getEntity() instanceof LivingEntity le && le.isAlive()) {
 | 
			
		||||
			for (GeneralCapabilityHolder<?, ?> holder : GeneralCapabilityHolder.INTERNAL_MAP.values()) {
 | 
			
		||||
				if (holder.isFor(event.getEntity()))
 | 
			
		||||
					holder.getOrCreate(Wrappers.cast(event.getEntity())).tick(Wrappers.cast(event.getEntity()));
 | 
			
		||||
	public static void onPlayerTick(PlayerTickEvent.Post event) {
 | 
			
		||||
		if (event.getEntity().isAlive())
 | 
			
		||||
			for (PlayerCapabilityHolder<?> holder : PlayerCapabilityHolder.INTERNAL_MAP.values()) {
 | 
			
		||||
				holder.getOrCreate(event.getEntity()).tick(event.getEntity());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@SubscribeEvent(priority = EventPriority.LOW)
 | 
			
		||||
@@ -30,6 +26,13 @@ public class BaseCapabilityEvents {
 | 
			
		||||
		for (PlayerCapabilityHolder<?> holder : PlayerCapabilityHolder.INTERNAL_MAP.values()) {
 | 
			
		||||
			ServerPlayer e = (ServerPlayer) event.getEntity();
 | 
			
		||||
			holder.getOrCreate(e).onClone(e, event.isWasDeath());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@SubscribeEvent(priority = EventPriority.LOW)
 | 
			
		||||
	public static void onPlayerJoinLevel(EntityJoinLevelEvent event) {
 | 
			
		||||
		if (!(event.getEntity() instanceof ServerPlayer e)) return;
 | 
			
		||||
		for (PlayerCapabilityHolder<?> holder : PlayerCapabilityHolder.INTERNAL_MAP.values()) {
 | 
			
		||||
			holder.network.toClient(e);
 | 
			
		||||
			holder.network.toTracking(e);
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import dev.xkmc.l2core.base.effects.ClientEffectCap;
 | 
			
		||||
import dev.xkmc.l2core.base.effects.EffectToClient;
 | 
			
		||||
import dev.xkmc.l2core.base.effects.api.*;
 | 
			
		||||
import dev.xkmc.l2core.init.L2Core;
 | 
			
		||||
import dev.xkmc.l2core.init.L2CoreConfig;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import dev.xkmc.l2core.util.Proxy;
 | 
			
		||||
import net.minecraft.Util;
 | 
			
		||||
@@ -76,10 +77,18 @@ public class ClientEffectRenderEvents {
 | 
			
		||||
					.createCompositeState(false)
 | 
			
		||||
	));
 | 
			
		||||
 | 
			
		||||
	public static RenderType get2DIcon(ResourceLocation id) {
 | 
			
		||||
		return ICON_TYPE.apply(id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@SubscribeEvent
 | 
			
		||||
	public static void levelRenderLast(RenderLevelStageEvent event) {
 | 
			
		||||
		if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_WEATHER) return;
 | 
			
		||||
 | 
			
		||||
		if (ICONS.isEmpty()) return;
 | 
			
		||||
		if (!L2CoreConfig.CLIENT.renderOverlayIcons.get()) {
 | 
			
		||||
			ICONS.clear();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		DUMMY.setupRenderState();
 | 
			
		||||
		DUMMY.clearRenderState();
 | 
			
		||||
		MultiBufferSource.BufferSource buffers = Minecraft.getInstance().renderBuffers().bufferSource();
 | 
			
		||||
@@ -123,6 +132,10 @@ public class ClientEffectRenderEvents {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (entity == Minecraft.getInstance().getCameraEntity()) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int n = index;
 | 
			
		||||
		int w = (int) Math.ceil(Math.sqrt(n));
 | 
			
		||||
		int h = (int) Math.ceil(n * 1d / w);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
package dev.xkmc.l2core.events;
 | 
			
		||||
 | 
			
		||||
import com.mojang.datafixers.util.Either;
 | 
			
		||||
import dev.xkmc.l2core.init.L2Core;
 | 
			
		||||
import dev.xkmc.l2core.init.L2CoreConfig;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import dev.xkmc.l2core.init.reg.ench.CustomDescEnchantment;
 | 
			
		||||
@@ -19,9 +18,9 @@ import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.item.Items;
 | 
			
		||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
 | 
			
		||||
import net.neoforged.api.distmarker.Dist;
 | 
			
		||||
import net.neoforged.api.distmarker.OnlyIn;
 | 
			
		||||
import net.neoforged.bus.api.EventPriority;
 | 
			
		||||
import net.neoforged.bus.api.SubscribeEvent;
 | 
			
		||||
import net.neoforged.fml.common.EventBusSubscriber;
 | 
			
		||||
import net.neoforged.neoforge.event.entity.player.ItemTooltipEvent;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
@@ -29,13 +28,13 @@ import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Stream;
 | 
			
		||||
 | 
			
		||||
@EventBusSubscriber(value = Dist.CLIENT, modid = L2Core.MODID, bus = EventBusSubscriber.Bus.GAME)
 | 
			
		||||
public class ClientEventHandler {
 | 
			
		||||
 | 
			
		||||
	public enum EnchDesc {
 | 
			
		||||
		DISABLE, SHIFT_ONLY, ALWAYS
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@OnlyIn(Dist.CLIENT)
 | 
			
		||||
	@SubscribeEvent(priority = EventPriority.LOW)
 | 
			
		||||
	public static void modifyItemTooltip(ItemTooltipEvent event) {
 | 
			
		||||
		var config = L2CoreConfig.CLIENT.addEnchantmentDescription.get();
 | 
			
		||||
@@ -61,7 +60,7 @@ public class ClientEventHandler {
 | 
			
		||||
		for (int i = 0; i < n; i++) {
 | 
			
		||||
			Component comp = list.get(i);
 | 
			
		||||
			Component lit;
 | 
			
		||||
			if (comp.getContents() instanceof PlainTextContents.LiteralContents txt && comp.getSiblings().size() == 1) {
 | 
			
		||||
			if (comp.getContents() instanceof PlainTextContents txt && !comp.getSiblings().isEmpty()) {
 | 
			
		||||
				comp = comp.getSiblings().getFirst();
 | 
			
		||||
				lit = Component.literal(txt.text());
 | 
			
		||||
			} else lit = Component.empty();
 | 
			
		||||
 
 | 
			
		||||
@@ -3,13 +3,17 @@ package dev.xkmc.l2core.init;
 | 
			
		||||
import dev.xkmc.l2core.base.effects.EffectToClient;
 | 
			
		||||
import dev.xkmc.l2core.capability.conditionals.TokenToClient;
 | 
			
		||||
import dev.xkmc.l2core.capability.player.PlayerCapToClient;
 | 
			
		||||
import dev.xkmc.l2core.events.ClientEventHandler;
 | 
			
		||||
import dev.xkmc.l2core.init.reg.registrate.L2Registrate;
 | 
			
		||||
import dev.xkmc.l2core.serial.config.SyncPacket;
 | 
			
		||||
import dev.xkmc.l2serial.network.PacketHandler;
 | 
			
		||||
import dev.xkmc.l2serial.serialization.custom_handler.Handlers;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.neoforged.api.distmarker.Dist;
 | 
			
		||||
import net.neoforged.bus.api.IEventBus;
 | 
			
		||||
import net.neoforged.fml.ModList;
 | 
			
		||||
import net.neoforged.fml.common.Mod;
 | 
			
		||||
import net.neoforged.neoforge.common.NeoForge;
 | 
			
		||||
import org.apache.logging.log4j.LogManager;
 | 
			
		||||
import org.apache.logging.log4j.Logger;
 | 
			
		||||
 | 
			
		||||
@@ -31,11 +35,15 @@ public class L2Core {
 | 
			
		||||
			e -> e.create(SyncPacket.class, PLAY_TO_CLIENT)
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	public L2Core(IEventBus bus) {
 | 
			
		||||
	public L2Core(IEventBus bus, Dist currentDist) {
 | 
			
		||||
		L2LibReg.register();
 | 
			
		||||
		L2CoreConfig.init();
 | 
			
		||||
		Handlers.register();
 | 
			
		||||
		REGISTRATE.addDataGenerator(L2TagGen.EFF_TAGS, L2TagGen::onEffectTagGen);
 | 
			
		||||
 | 
			
		||||
		if (!ModList.get().isLoaded("enchdesc") && currentDist == Dist.CLIENT) {
 | 
			
		||||
			NeoForge.EVENT_BUS.register(ClientEventHandler.class);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static ResourceLocation loc(String id) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ public class L2CoreConfig {
 | 
			
		||||
 | 
			
		||||
		public final ModConfigSpec.IntValue overlayZVal;
 | 
			
		||||
		public final ModConfigSpec.EnumValue<ClientEventHandler.EnchDesc> addEnchantmentDescription;
 | 
			
		||||
		public final ModConfigSpec.BooleanValue renderOverlayIcons;
 | 
			
		||||
 | 
			
		||||
		Client(Builder builder) {
 | 
			
		||||
			markL2();
 | 
			
		||||
@@ -17,6 +18,8 @@ public class L2CoreConfig {
 | 
			
		||||
					.defineInRange("overlayZVal", 250, -1000000, 1000000);
 | 
			
		||||
			addEnchantmentDescription = builder.text("Add Enchantment Descriptions")
 | 
			
		||||
					.defineEnum("addEnchantmentDescription", ClientEventHandler.EnchDesc.ALWAYS);
 | 
			
		||||
			renderOverlayIcons = builder.text("Render overlay icons on entities")
 | 
			
		||||
					.define("renderOverlayIcons", true);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,8 @@ package dev.xkmc.l2core.init;
 | 
			
		||||
 | 
			
		||||
import dev.xkmc.l2core.base.effects.ClientEffectCap;
 | 
			
		||||
import dev.xkmc.l2core.base.menu.base.MenuLayoutConfig;
 | 
			
		||||
import dev.xkmc.l2core.base.worldgen.ConfigChancePlacement;
 | 
			
		||||
import dev.xkmc.l2core.base.worldgen.ConfigRarityFilter;
 | 
			
		||||
import dev.xkmc.l2core.capability.conditionals.ConditionalData;
 | 
			
		||||
import dev.xkmc.l2core.capability.conditionals.PlayerFlagData;
 | 
			
		||||
import dev.xkmc.l2core.capability.player.PlayerCapabilityNetworkHandler;
 | 
			
		||||
@@ -21,6 +23,7 @@ import dev.xkmc.l2core.serial.loot.PlayerFlagCondition;
 | 
			
		||||
import dev.xkmc.l2serial.serialization.codec.MapCodecAdaptor;
 | 
			
		||||
import net.minecraft.core.registries.BuiltInRegistries;
 | 
			
		||||
import net.minecraft.world.entity.LivingEntity;
 | 
			
		||||
import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
 | 
			
		||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
			
		||||
import net.neoforged.neoforge.common.loot.IGlobalLootModifier;
 | 
			
		||||
@@ -73,6 +76,10 @@ public class L2LibReg {
 | 
			
		||||
	public static final EECVal.Special<EnchColor> COLOR = ENCH_REG.special("color", EnchColor.CODEC);
 | 
			
		||||
	public static final EECVal.Special<LegacyEnchantment> LEGACY = ENCH_REG.special("legacy", ENCH.reg().byNameCodec());
 | 
			
		||||
 | 
			
		||||
	public static final SR<PlacementModifierType<?>> PM = SR.of(REG, BuiltInRegistries.PLACEMENT_MODIFIER_TYPE);
 | 
			
		||||
	public static final Val<PlacementModifierType<ConfigRarityFilter>> PM_RARITY = PM.reg("rarity", () -> () -> ConfigRarityFilter.CODEC);
 | 
			
		||||
	public static final Val<PlacementModifierType<ConfigChancePlacement>> PM_CHANCE = PM.reg("chance", () -> () -> ConfigChancePlacement.CODEC);
 | 
			
		||||
 | 
			
		||||
	public static void register() {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -33,25 +33,34 @@ public interface EnchVal {
 | 
			
		||||
	ResourceKey<Enchantment> id();
 | 
			
		||||
 | 
			
		||||
	@DataGenOnly
 | 
			
		||||
	Holder<Enchantment> datagenDirect(RegistrateProvider pvd);
 | 
			
		||||
	Holder<Enchantment> datagenDirect();
 | 
			
		||||
 | 
			
		||||
	@DataGenOnly
 | 
			
		||||
	default Holder<Enchantment> datagenDirect(RegistrateProvider pvd) {
 | 
			
		||||
		return datagenDirect();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	default Optional<Holder<Enchantment>> safeHolder() {
 | 
			
		||||
		return Optional.ofNullable(CommonHooks.resolveLookup(Registries.ENCHANTMENT)).flatMap(e -> e.get(id()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	default Holder<Enchantment> holder() {
 | 
			
		||||
		return Optional.ofNullable(CommonHooks.resolveLookup(Registries.ENCHANTMENT)).orElseThrow().getOrThrow(id());
 | 
			
		||||
		return safeHolder().orElseThrow();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	default int getLv(ItemStack stack) {
 | 
			
		||||
		return stack.getEnchantmentLevel(holder());
 | 
			
		||||
		return safeHolder().map(stack::getEnchantmentLevel).orElse(0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	default int getLvIntrinsic(ItemStack stack) {
 | 
			
		||||
		return stack.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY).getLevel(holder());
 | 
			
		||||
		return safeHolder().map(e -> stack.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY).getLevel(e)).orElse(0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	interface Impl extends EnchVal {
 | 
			
		||||
		Lazy<Builder> builder();
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		default Holder<Enchantment> datagenDirect(RegistrateProvider pvd) {
 | 
			
		||||
		default Holder<Enchantment> datagenDirect() {
 | 
			
		||||
			var val = builder().get().cache;
 | 
			
		||||
			if (val == null) throw new IllegalStateException("Enchantment is not built yet");
 | 
			
		||||
			return new DataGenHolder<>(id(), val);
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ import dev.xkmc.l2core.init.L2Core;
 | 
			
		||||
import dev.xkmc.l2core.init.reg.simple.Val;
 | 
			
		||||
import dev.xkmc.l2core.util.ConfigInit;
 | 
			
		||||
import dev.xkmc.l2serial.serialization.custom_handler.CodecHandler;
 | 
			
		||||
import dev.xkmc.l2serial.serialization.custom_handler.Handlers;
 | 
			
		||||
import dev.xkmc.l2serial.util.ModContainerHack;
 | 
			
		||||
import dev.xkmc.l2serial.util.Wrappers;
 | 
			
		||||
import net.minecraft.client.particle.ParticleEngine;
 | 
			
		||||
@@ -21,7 +22,6 @@ import net.minecraft.client.particle.ParticleProvider;
 | 
			
		||||
import net.minecraft.core.Registry;
 | 
			
		||||
import net.minecraft.core.particles.ParticleOptions;
 | 
			
		||||
import net.minecraft.core.particles.ParticleType;
 | 
			
		||||
import net.minecraft.core.registries.BuiltInRegistries;
 | 
			
		||||
import net.minecraft.core.registries.Registries;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.network.codec.ByteBufCodecs;
 | 
			
		||||
@@ -101,6 +101,10 @@ public class L2Registrate extends AbstractRegistrate<L2Registrate> {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public <T extends Potion> SimpleEntry<Potion> potion(String name, NonNullSupplier<T> sup) {
 | 
			
		||||
		return potion(name, RegistrateLangProvider.toEnglishName(name), sup);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public <T extends Potion> SimpleEntry<Potion> potion(String name, String desc, NonNullSupplier<T> sup) {
 | 
			
		||||
		RegistryEntry<Potion, T> ans = entry(name, (cb) -> new NoConfigBuilder<>(this, this, name, cb,
 | 
			
		||||
				Registries.POTION, sup)).register();
 | 
			
		||||
		if (doDataGen.get()) {
 | 
			
		||||
@@ -111,7 +115,7 @@ public class L2Registrate extends AbstractRegistrate<L2Registrate> {
 | 
			
		||||
				String str = item.getDescriptionId() + ".effect." + name;
 | 
			
		||||
				String pref_name = RegistrateLangProvider.toEnglishName(prefs[prefs.length - 1]);
 | 
			
		||||
				if (item == Items.TIPPED_ARROW) pref_name = "Arrow";
 | 
			
		||||
				addRawLang(str, pref_name + " of " + RegistrateLangProvider.toEnglishName(name));
 | 
			
		||||
				addRawLang(str, pref_name + " of " + desc);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return new SimpleEntry<>(ans);
 | 
			
		||||
@@ -142,6 +146,7 @@ public class L2Registrate extends AbstractRegistrate<L2Registrate> {
 | 
			
		||||
		cons.accept(ans);
 | 
			
		||||
		var reg = ans.create();
 | 
			
		||||
		new CodecHandler<>(Wrappers.cast(cls), reg.byNameCodec(), ByteBufCodecs.fromCodecWithRegistries(reg.byNameCodec()));
 | 
			
		||||
		Handlers.registerReg(Wrappers.cast(cls), key);
 | 
			
		||||
		OneTimeEventReceiver.addModListener(this, NewRegistryEvent.class, (e) -> e.register(reg));
 | 
			
		||||
		return new RegistryInstance<>(reg, key);
 | 
			
		||||
	}
 | 
			
		||||
@@ -242,13 +247,6 @@ public class L2Registrate extends AbstractRegistrate<L2Registrate> {
 | 
			
		||||
					before = e.id;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			for (var e : BuiltInRegistries.CREATIVE_MODE_TAB.entrySet()) {
 | 
			
		||||
				var id = e.getKey().location();
 | 
			
		||||
				if (known(id) || known(e.getValue())) {
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				b.withTabsAfter(id);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private static boolean known(ResourceLocation id) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package dev.xkmc.l2core.init.reg.registrate;
 | 
			
		||||
 | 
			
		||||
import dev.xkmc.l2serial.util.Wrappers;
 | 
			
		||||
import net.minecraft.core.Holder;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.network.chat.MutableComponent;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
@@ -46,4 +47,8 @@ public class NamedEntry<T extends NamedEntry<T>> {
 | 
			
		||||
		return Wrappers.cast(this);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Holder<T> holder() {
 | 
			
		||||
		return registry.get().wrapAsHolder(getThis());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,141 @@
 | 
			
		||||
package dev.xkmc.l2core.init.reg.registrate;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ListMultimap;
 | 
			
		||||
import com.google.common.collect.Multimaps;
 | 
			
		||||
import com.tterrag.registrate.providers.RegistrateLangProvider;
 | 
			
		||||
import net.minecraft.core.Holder;
 | 
			
		||||
import net.minecraft.resources.ResourceKey;
 | 
			
		||||
import net.minecraft.world.effect.MobEffect;
 | 
			
		||||
import net.minecraft.world.effect.MobEffectInstance;
 | 
			
		||||
import net.minecraft.world.item.CreativeModeTab;
 | 
			
		||||
import net.minecraft.world.item.Item;
 | 
			
		||||
import net.minecraft.world.item.Items;
 | 
			
		||||
import net.minecraft.world.item.alchemy.Potion;
 | 
			
		||||
import net.minecraft.world.item.alchemy.PotionBrewing;
 | 
			
		||||
import net.minecraft.world.item.alchemy.PotionContents;
 | 
			
		||||
import net.minecraft.world.item.alchemy.Potions;
 | 
			
		||||
import net.minecraft.world.level.ItemLike;
 | 
			
		||||
import net.neoforged.neoforge.common.NeoForge;
 | 
			
		||||
import net.neoforged.neoforge.event.brewing.RegisterBrewingRecipesEvent;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.LinkedHashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.TreeSet;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
import java.util.stream.Stream;
 | 
			
		||||
 | 
			
		||||
public class PotionBuilder {
 | 
			
		||||
 | 
			
		||||
	public static class TabHolder {
 | 
			
		||||
 | 
			
		||||
		private final ListMultimap<String, Holder<Potion>> potions;
 | 
			
		||||
		private final String modid;
 | 
			
		||||
 | 
			
		||||
		public TabHolder(String modid) {
 | 
			
		||||
			potions = Multimaps.newListMultimap(new LinkedHashMap<>(), ArrayList::new);
 | 
			
		||||
			this.modid = modid;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Stream<Holder<Potion>> stream() {
 | 
			
		||||
			List<String> ans = new ArrayList<>();
 | 
			
		||||
			ans.add(modid);
 | 
			
		||||
			var set = new TreeSet<>(potions.keySet());
 | 
			
		||||
			set.remove(modid);
 | 
			
		||||
			ans.addAll(set);
 | 
			
		||||
			return ans.stream().flatMap(e -> potions.get(e).stream());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public synchronized void add(String modid, SimpleEntry<Potion> ans) {
 | 
			
		||||
			potions.put(modid, ans);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private final List<Consumer<PotionBrewing.Builder>> recipes = new ArrayList<>();
 | 
			
		||||
	private final TabHolder tab;
 | 
			
		||||
 | 
			
		||||
	private final L2Registrate reg;
 | 
			
		||||
 | 
			
		||||
	private PotionBuilder(L2Registrate reg, TabHolder tab) {
 | 
			
		||||
		this.reg = reg;
 | 
			
		||||
		this.tab = tab;
 | 
			
		||||
		NeoForge.EVENT_BUS.addListener(this::registerBrewingRecipe);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public PotionBuilder(L2Registrate reg, PotionBuilder parent) {
 | 
			
		||||
		this(reg, parent.tab);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public PotionBuilder(L2Registrate reg) {
 | 
			
		||||
		this(reg, new TabHolder(reg.getModid()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void registerBrewingRecipe(RegisterBrewingRecipesEvent event) {
 | 
			
		||||
		var builder = event.getBuilder();
 | 
			
		||||
		recipes.forEach(e -> e.accept(builder));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void addMix(Holder<Potion> source, ItemLike item, Holder<Potion> potion) {
 | 
			
		||||
		recipes.add(e -> e.addMix(source, item.asItem(), potion));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public Holder<Potion> regPotion(String id, String name, Holder<MobEffect> sup, int dur, int amp) {
 | 
			
		||||
		var ans = reg.potion(id, RegistrateLangProvider.toEnglishName(name), () -> new Potion(new MobEffectInstance(sup, dur, amp)));
 | 
			
		||||
		tab.add(reg.getModid(), ans);
 | 
			
		||||
		return ans;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Holder<Potion> regPotion(String id, String nameId, Holder<MobEffect> sup, Holder<Potion> source, ItemLike item, int dur, int amp) {
 | 
			
		||||
		var potion = regPotion(id, nameId, sup, dur, amp);
 | 
			
		||||
		addMix(source, item, potion);
 | 
			
		||||
		return potion;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void regPotion2(String id, Holder<MobEffect> sup, ItemLike item, int dur, int durLong) {
 | 
			
		||||
		var potion = regPotion(id, id, sup, Potions.AWKWARD, item, dur, 0);
 | 
			
		||||
		regPotion("long_" + id, id, sup, potion, Items.REDSTONE, durLong, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void regPotion3(String id, Holder<MobEffect> sup, ItemLike item, int durStrong, int dur, int durLong, int amp, int ampStrong) {
 | 
			
		||||
		var potion = regPotion(id, id, sup, Potions.AWKWARD, item, dur, amp);
 | 
			
		||||
		regPotion("long_" + id, id, sup, potion, Items.REDSTONE, durLong, amp);
 | 
			
		||||
		regPotion("strong_" + id, id, sup, potion, Items.GLOWSTONE_DUST, durStrong, ampStrong);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void regPotion3(String id, Holder<MobEffect> sup, ItemLike item, int durStrong, int dur, int durLong, int amp, int ampStrong, ItemLike longItem, ItemLike strongItem) {
 | 
			
		||||
		var potion = regPotion(id, id, sup, Potions.AWKWARD, item, dur, amp);
 | 
			
		||||
		regPotion("long_" + id, id, sup, potion, longItem, durLong, amp);
 | 
			
		||||
		regPotion("strong_" + id, id, sup, potion, strongItem, durStrong, ampStrong);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void interleave(String id, Holder<MobEffect> sup, int durStrong, int dur, int durLong, int amp, int ampStrong,
 | 
			
		||||
						   ItemLike a, Holder<Potion> ap, @Nullable Holder<Potion> lap, @Nullable Holder<Potion> sap,
 | 
			
		||||
						   ItemLike b, Holder<Potion> bp, @Nullable Holder<Potion> lbp, @Nullable Holder<Potion> sbp) {
 | 
			
		||||
		var potion = regPotion(id, id, sup, dur, amp);
 | 
			
		||||
		var longPotion = regPotion("long_" + id, id, sup, potion, Items.REDSTONE, durLong, amp);
 | 
			
		||||
		var strongPotion = regPotion("strong_" + id, id, sup, potion, Items.GLOWSTONE_DUST, durStrong, ampStrong);
 | 
			
		||||
		addMix(ap, a, potion);
 | 
			
		||||
		addMix(bp, b, potion);
 | 
			
		||||
		if (lap != null) addMix(lap, a, longPotion);
 | 
			
		||||
		if (lbp != null) addMix(lbp, b, longPotion);
 | 
			
		||||
		if (sap != null) addMix(sap, a, strongPotion);
 | 
			
		||||
		if (sbp != null) addMix(sbp, b, strongPotion);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void regTab(ResourceKey<CreativeModeTab> key) {
 | 
			
		||||
		regTab(key, Items.POTION);
 | 
			
		||||
		regTab(key, Items.SPLASH_POTION);
 | 
			
		||||
		regTab(key, Items.LINGERING_POTION);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void regTab(ResourceKey<CreativeModeTab> key, Item potion) {
 | 
			
		||||
		reg.modifyCreativeModeTab(key, m -> tab.stream().forEach(e ->
 | 
			
		||||
				m.accept(PotionContents.createItemStack(potion, e),
 | 
			
		||||
						CreativeModeTab.TabVisibility.PARENT_TAB_ONLY)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -8,6 +8,7 @@ import dev.xkmc.l2core.capability.player.PlayerCapabilityTemplate;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.neoforged.neoforge.attachment.AttachmentHolder;
 | 
			
		||||
import net.neoforged.neoforge.attachment.AttachmentType;
 | 
			
		||||
import net.neoforged.neoforge.attachment.IAttachmentHolder;
 | 
			
		||||
import net.neoforged.neoforge.registries.DeferredHolder;
 | 
			
		||||
import net.neoforged.neoforge.registries.DeferredRegister;
 | 
			
		||||
import net.neoforged.neoforge.registries.NeoForgeRegistries;
 | 
			
		||||
@@ -32,7 +33,7 @@ public record AttReg(DeferredRegister<AttachmentType<?>> att) {
 | 
			
		||||
		return reg(id, type);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public <E extends GeneralCapabilityTemplate<H, E>, H extends AttachmentHolder> AttVal.CapVal<H, E>
 | 
			
		||||
	public <E extends GeneralCapabilityTemplate<H, E>, H extends IAttachmentHolder> AttVal.CapVal<H, E>
 | 
			
		||||
	entity(String id, Class<E> holder_class, Supplier<E> sup, Class<H> entity_class, Predicate<H> pred) {
 | 
			
		||||
		ResourceLocation rl = ResourceLocation.fromNamespaceAndPath(att.getNamespace(), id);
 | 
			
		||||
		var type = new GeneralCapabilityHolder<>(rl, holder_class, sup, entity_class, pred);
 | 
			
		||||
@@ -62,7 +63,7 @@ public record AttReg(DeferredRegister<AttachmentType<?>> att) {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private record CapValImpl<E extends AttachmentHolder, T extends GeneralCapabilityTemplate<E, T>>(
 | 
			
		||||
	private record CapValImpl<E extends IAttachmentHolder, T extends GeneralCapabilityTemplate<E, T>>(
 | 
			
		||||
			DeferredHolder<AttachmentType<?>, AttachmentType<T>> val, GeneralCapabilityHolder<E, T> type
 | 
			
		||||
	) implements AttVal.CapVal<E, T> {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,12 +7,13 @@ import dev.xkmc.l2core.capability.player.PlayerCapabilityHolder;
 | 
			
		||||
import dev.xkmc.l2core.capability.player.PlayerCapabilityTemplate;
 | 
			
		||||
import net.neoforged.neoforge.attachment.AttachmentHolder;
 | 
			
		||||
import net.neoforged.neoforge.attachment.AttachmentType;
 | 
			
		||||
import net.neoforged.neoforge.attachment.IAttachmentHolder;
 | 
			
		||||
 | 
			
		||||
public interface AttVal<T, H extends AttachmentDef<T>> extends Val<AttachmentType<T>> {
 | 
			
		||||
 | 
			
		||||
	H type();
 | 
			
		||||
 | 
			
		||||
	interface CapVal<E extends AttachmentHolder, T extends GeneralCapabilityTemplate<E, T>>
 | 
			
		||||
	interface CapVal<E extends IAttachmentHolder, T extends GeneralCapabilityTemplate<E, T>>
 | 
			
		||||
			extends AttVal<T, GeneralCapabilityHolder<E, T>> {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,10 @@ package dev.xkmc.l2core.init.reg.varitem;
 | 
			
		||||
import com.tterrag.registrate.util.entry.ItemEntry;
 | 
			
		||||
import net.minecraft.world.item.Item;
 | 
			
		||||
import net.minecraft.world.level.ItemLike;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
public class VarHolder<T extends Item> implements VarEntry<T>, ItemLike {
 | 
			
		||||
import java.util.function.Supplier;
 | 
			
		||||
 | 
			
		||||
public class VarHolder<T extends Item> implements VarEntry<T>, ItemLike, Supplier<T> {
 | 
			
		||||
 | 
			
		||||
	private final String str;
 | 
			
		||||
	private final VarBuilder<T> builder;
 | 
			
		||||
@@ -25,6 +26,11 @@ public class VarHolder<T extends Item> implements VarEntry<T>, ItemLike {
 | 
			
		||||
		return item.asItem();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public T get() {
 | 
			
		||||
		return item.get();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public String id() {
 | 
			
		||||
		return str;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@ package dev.xkmc.l2core.init.reg.varitem;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.*;
 | 
			
		||||
import com.mojang.datafixers.util.Pair;
 | 
			
		||||
import com.tterrag.registrate.util.OneTimeEventReceiver;
 | 
			
		||||
import com.tterrag.registrate.util.entry.ItemEntry;
 | 
			
		||||
import dev.xkmc.l2core.init.L2Core;
 | 
			
		||||
import dev.xkmc.l2core.init.reg.registrate.L2Registrate;
 | 
			
		||||
@@ -14,12 +13,10 @@ import net.neoforged.fml.loading.FMLPaths;
 | 
			
		||||
import net.neoforged.neoforge.registries.RegisterEvent;
 | 
			
		||||
import org.apache.logging.log4j.Level;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.io.FileReader;
 | 
			
		||||
import java.io.FileWriter;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.LinkedHashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.concurrent.ConcurrentHashMap;
 | 
			
		||||
import java.util.concurrent.ConcurrentMap;
 | 
			
		||||
import java.util.function.Function;
 | 
			
		||||
@@ -41,7 +38,7 @@ public class VarItemInit<T extends Item> {
 | 
			
		||||
	private final Function<ResourceLocation, T> func;
 | 
			
		||||
	private final VarBuilder<T> builder;
 | 
			
		||||
	private final Map<String, VarEntry<T>> defaults = new LinkedHashMap<>();
 | 
			
		||||
	private final List<String> registered = new ArrayList<>();
 | 
			
		||||
	private final Set<String> registered = new LinkedHashSet<>();
 | 
			
		||||
	private final Map<String, ItemEntry<T>> results = new ConcurrentHashMap<>();
 | 
			
		||||
 | 
			
		||||
	private VarItemInit(L2Registrate reg, ResourceLocation id, Function<ResourceLocation, T> func, VarBuilder<T> builder) {
 | 
			
		||||
@@ -49,7 +46,7 @@ public class VarItemInit<T extends Item> {
 | 
			
		||||
		this.id = id;
 | 
			
		||||
		this.func = func;
 | 
			
		||||
		this.builder = builder;
 | 
			
		||||
		reg.getModEventBus().addListener( EventPriority.HIGH, RegisterEvent.class, this::init);
 | 
			
		||||
		reg.getModEventBus().addListener(EventPriority.HIGH, RegisterEvent.class, this::init);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public synchronized void add(List<String> defaults) {
 | 
			
		||||
@@ -61,6 +58,11 @@ public class VarItemInit<T extends Item> {
 | 
			
		||||
		return e;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Nullable
 | 
			
		||||
	public ItemEntry<T> get(String str) {
 | 
			
		||||
		return results.get(str);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private synchronized void init(RegisterEvent event) {
 | 
			
		||||
		if (event.getRegistry() != BuiltInRegistries.ITEM) return;
 | 
			
		||||
		load();
 | 
			
		||||
@@ -119,17 +121,24 @@ public class VarItemInit<T extends Item> {
 | 
			
		||||
 | 
			
		||||
	private Pair<Boolean, List<String>> parseFile(JsonElement elem) {
 | 
			
		||||
		if (!elem.isJsonArray()) return Pair.of(true, List.of());
 | 
			
		||||
		List<String> ans = new ArrayList<>();
 | 
			
		||||
		Set<String> ans = new LinkedHashSet<>(defaults.keySet());
 | 
			
		||||
		Set<String> checker = new HashSet<>();
 | 
			
		||||
		boolean err = false;
 | 
			
		||||
		for (var e : elem.getAsJsonArray()) {
 | 
			
		||||
			var rl = e.getAsString();
 | 
			
		||||
			if (ResourceLocation.isValidPath(rl)) ans.add(rl);
 | 
			
		||||
			else {
 | 
			
		||||
			if (ResourceLocation.isValidPath(rl)) {
 | 
			
		||||
				ans.add(rl);
 | 
			
		||||
				checker.add(rl);
 | 
			
		||||
			} else {
 | 
			
		||||
				L2Core.LOGGER.error("Item ID {} for varitem type {} is invalid. Skipped", rl, id);
 | 
			
		||||
				err = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return Pair.of(err, ans);
 | 
			
		||||
		if (checker.size() != ans.size()) {
 | 
			
		||||
			L2Core.LOGGER.error("Found missing default items for varitem type {}. Filling", id);
 | 
			
		||||
			err = true;
 | 
			
		||||
		}
 | 
			
		||||
		return Pair.of(err, new ArrayList<>(ans));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private record SimpleVarEntry<T extends Item>(String id) implements VarEntry<T> {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
package dev.xkmc.l2core.mixin;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.core.registries.BuiltInRegistries;
 | 
			
		||||
import net.minecraft.world.item.CreativeModeTab;
 | 
			
		||||
import org.spongepowered.asm.mixin.Mixin;
 | 
			
		||||
 | 
			
		||||
@Mixin(CreativeModeTab.class)
 | 
			
		||||
public class CreativeModeTabMixin {
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toString() {
 | 
			
		||||
		CreativeModeTab tab = (CreativeModeTab) (Object) this;
 | 
			
		||||
		var key = BuiltInRegistries.CREATIVE_MODE_TAB.getKey(tab);
 | 
			
		||||
		return key == null ? "[Unregistered]" : key.toString();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -12,6 +12,7 @@ public class BaseConfigType<T extends BaseConfig> {
 | 
			
		||||
	public final PacketHandlerWithConfig parent;
 | 
			
		||||
 | 
			
		||||
	final Map<ResourceLocation, T> configs = new HashMap<>();
 | 
			
		||||
	final Map<ResourceLocation, T> clientConfigs = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
	protected BaseConfigType(PacketHandlerWithConfig parent, String id, Class<T> cls) {
 | 
			
		||||
		this.parent = parent;
 | 
			
		||||
@@ -26,4 +27,11 @@ public class BaseConfigType<T extends BaseConfig> {
 | 
			
		||||
	public void afterReload() {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void clientBeforeReload() {
 | 
			
		||||
		clientConfigs.clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void clientAfterReload() {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.config;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.JsonElement;
 | 
			
		||||
import com.tterrag.registrate.providers.ProviderType;
 | 
			
		||||
import dev.xkmc.l2serial.serialization.codec.JsonCodec;
 | 
			
		||||
import net.minecraft.core.HolderLookup;
 | 
			
		||||
import net.minecraft.data.CachedOutput;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,23 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.config;
 | 
			
		||||
 | 
			
		||||
import dev.xkmc.l2core.util.ServerProxy;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
 | 
			
		||||
public class MergedConfigType<T extends BaseConfig> extends BaseConfigType<T> {
 | 
			
		||||
 | 
			
		||||
	private T result;
 | 
			
		||||
	private T result, clientResult;
 | 
			
		||||
 | 
			
		||||
	MergedConfigType(PacketHandlerWithConfig parent, String id, Class<T> cls) {
 | 
			
		||||
		super(parent, id, cls);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	T load() {
 | 
			
		||||
		if (ServerProxy.isOnClient())
 | 
			
		||||
			return loadClient();
 | 
			
		||||
		return loadServer();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	T loadServer() {
 | 
			
		||||
		if (result != null) {
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
@@ -19,11 +26,28 @@ public class MergedConfigType<T extends BaseConfig> extends BaseConfigType<T> {
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	T loadClient() {
 | 
			
		||||
		if (clientResult != null) {
 | 
			
		||||
			return clientResult;
 | 
			
		||||
		}
 | 
			
		||||
		clientResult = new ConfigMerger<>(cls).apply(clientConfigs.values());
 | 
			
		||||
		clientResult.id = ResourceLocation.fromNamespaceAndPath(parent.modid, id);
 | 
			
		||||
		return clientResult;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void afterReload() {
 | 
			
		||||
		result = null;
 | 
			
		||||
		if (cls.isAnnotationPresent(ConfigLoadOnStart.class)) {
 | 
			
		||||
			load();
 | 
			
		||||
			loadServer();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void clientAfterReload() {
 | 
			
		||||
		clientResult = null;
 | 
			
		||||
		if (cls.isAnnotationPresent(ConfigLoadOnStart.class)) {
 | 
			
		||||
			loadClient();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -114,25 +114,30 @@ public class PacketHandlerWithConfig extends PacketHandler {
 | 
			
		||||
		private <T extends BaseConfig> void addJson(BaseConfigType<T> type, ResourceLocation k, JsonElement v) {
 | 
			
		||||
			T config = new JsonCodec(getRegistryLookup()).from(v, type.cls, null);
 | 
			
		||||
			if (config != null) {
 | 
			
		||||
				addConfig(type, k, config);
 | 
			
		||||
				addServerConfig(type, k, config);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private <T extends BaseConfig> void addConfig(BaseConfigType<T> type, ResourceLocation k, T config) {
 | 
			
		||||
		private <T extends BaseConfig> void addServerConfig(BaseConfigType<T> type, ResourceLocation k, T config) {
 | 
			
		||||
			config.id = k;
 | 
			
		||||
			type.configs.put(k, config);
 | 
			
		||||
			configs.add(new ConfigInstance(type.id, k, config));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private <T extends BaseConfig> void addClientConfig(BaseConfigType<T> type, ResourceLocation k, T config) {
 | 
			
		||||
			config.id = k;
 | 
			
		||||
			type.clientConfigs.put(k, config);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Called on client side only
 | 
			
		||||
		 */
 | 
			
		||||
		public void apply(ArrayList<ConfigInstance> list) {
 | 
			
		||||
			listener_before.forEach(Runnable::run);
 | 
			
		||||
			types.values().forEach(BaseConfigType::clientBeforeReload);
 | 
			
		||||
			for (var e : list) {
 | 
			
		||||
				addConfig(types.get(e.name), e.id(), Wrappers.cast(e.config));
 | 
			
		||||
				addClientConfig(types.get(e.name), e.id(), Wrappers.cast(e.config));
 | 
			
		||||
			}
 | 
			
		||||
			listener_after.forEach(Runnable::run);
 | 
			
		||||
			types.values().forEach(BaseConfigType::clientAfterReload);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,53 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.config;
 | 
			
		||||
 | 
			
		||||
import com.tterrag.registrate.AbstractRegistrate;
 | 
			
		||||
import com.tterrag.registrate.providers.ProviderType;
 | 
			
		||||
import com.tterrag.registrate.providers.RegistrateProvider;
 | 
			
		||||
import net.minecraft.core.HolderLookup;
 | 
			
		||||
import net.minecraft.data.CachedOutput;
 | 
			
		||||
import net.minecraft.data.DataGenerator;
 | 
			
		||||
import net.minecraft.data.DataProvider;
 | 
			
		||||
import net.neoforged.fml.LogicalSide;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.concurrent.CompletableFuture;
 | 
			
		||||
import java.util.function.BiFunction;
 | 
			
		||||
 | 
			
		||||
public class RegistrateNestedProvider implements RegistrateProvider {
 | 
			
		||||
 | 
			
		||||
	public static final ProviderType<RegistrateNestedProvider> TYPE = ProviderType.registerProvider("l2_custom", RegistrateNestedProvider::new);
 | 
			
		||||
 | 
			
		||||
	private final List<DataProvider> list = new ArrayList<>();
 | 
			
		||||
	private final AbstractRegistrate<?> reg;
 | 
			
		||||
	private final DataGenerator gen;
 | 
			
		||||
	private final CompletableFuture<HolderLookup.Provider> pvd;
 | 
			
		||||
 | 
			
		||||
	public RegistrateNestedProvider(ProviderType.Context<RegistrateNestedProvider> ctx) {
 | 
			
		||||
		this.reg = ctx.parent();
 | 
			
		||||
		this.gen = ctx.event().getGenerator();
 | 
			
		||||
		this.pvd = ctx.provider();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public LogicalSide getSide() {
 | 
			
		||||
		return LogicalSide.SERVER;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public RegistrateNestedProvider add(BiFunction<DataGenerator, CompletableFuture<HolderLookup.Provider>, DataProvider> factory) {
 | 
			
		||||
		list.add(factory.apply(gen, pvd));
 | 
			
		||||
		return this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public CompletableFuture<?> run(CachedOutput cachedOutput) {
 | 
			
		||||
		reg.genData(TYPE, this);
 | 
			
		||||
		return CompletableFuture.allOf(list.stream().map(e -> e.run(cachedOutput)).toArray(CompletableFuture[]::new));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public String getName() {
 | 
			
		||||
		return "Custom Registrate Provider";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@ import net.minecraft.MethodsReturnNonnullByDefault;
 | 
			
		||||
import net.minecraft.network.RegistryFriendlyByteBuf;
 | 
			
		||||
import net.minecraft.network.codec.StreamCodec;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.item.Items;
 | 
			
		||||
import net.minecraft.world.item.crafting.Ingredient;
 | 
			
		||||
import net.minecraft.world.item.crafting.SmithingTransformRecipe;
 | 
			
		||||
 | 
			
		||||
@@ -14,7 +15,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
 | 
			
		||||
@MethodsReturnNonnullByDefault
 | 
			
		||||
public abstract class AbstractSmithingRecipe<T extends AbstractSmithingRecipe<T>> extends SmithingTransformRecipe {
 | 
			
		||||
 | 
			
		||||
	public static final Ingredient TEMPLATE_PLACEHOLDER = Ingredient.EMPTY;
 | 
			
		||||
	public static final Ingredient TEMPLATE_PLACEHOLDER = Ingredient.of(Items.PAPER);
 | 
			
		||||
 | 
			
		||||
	public AbstractSmithingRecipe(Ingredient template, Ingredient base, Ingredient addition, ItemStack result) {
 | 
			
		||||
		super(template, base, addition, result);
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,7 @@ public class BaseRecipeBuilder<
 | 
			
		||||
				.rewards(AdvancementRewards.Builder.recipe(id))
 | 
			
		||||
				.requirements(AdvancementRequirements.Strategy.OR);
 | 
			
		||||
		this.criteria.forEach(builder::addCriterion);
 | 
			
		||||
		id = ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "recipes/" +
 | 
			
		||||
		id = ResourceLocation.fromNamespaceAndPath(id.getNamespace(),
 | 
			
		||||
				BuiltInRegistries.RECIPE_SERIALIZER.getKey(type).getPath() + "/" + id.getPath());
 | 
			
		||||
		pvd.accept(id, recipe, builder.build(id));
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,15 @@ import mezz.jei.api.gui.drawable.IDrawable;
 | 
			
		||||
import mezz.jei.api.recipe.IFocusGroup;
 | 
			
		||||
import mezz.jei.api.recipe.RecipeType;
 | 
			
		||||
import mezz.jei.api.recipe.category.IRecipeCategory;
 | 
			
		||||
import net.minecraft.client.Minecraft;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.world.item.crafting.Recipe;
 | 
			
		||||
import net.minecraft.world.item.crafting.RecipeHolder;
 | 
			
		||||
import net.minecraft.world.item.crafting.RecipeInput;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Deprecated(forRemoval = true)
 | 
			
		||||
public abstract class BaseRecipeCategory<T, C extends BaseRecipeCategory<T, C>> implements IRecipeCategory<T> {
 | 
			
		||||
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,10 @@
 | 
			
		||||
package dev.xkmc.l2core.util;
 | 
			
		||||
 | 
			
		||||
import com.mojang.blaze3d.systems.RenderSystem;
 | 
			
		||||
import net.minecraft.client.Minecraft;
 | 
			
		||||
import net.minecraft.client.player.LocalPlayer;
 | 
			
		||||
import net.minecraft.core.RegistryAccess;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import net.neoforged.api.distmarker.Dist;
 | 
			
		||||
import net.neoforged.fml.loading.FMLEnvironment;
 | 
			
		||||
@@ -11,16 +12,15 @@ import net.neoforged.neoforge.server.ServerLifecycleHooks;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.function.BiConsumer;
 | 
			
		||||
 | 
			
		||||
public class Proxy {
 | 
			
		||||
 | 
			
		||||
	@Deprecated
 | 
			
		||||
	public static RegistryAccess getRegistryAccess() {
 | 
			
		||||
	@Nullable
 | 
			
		||||
	public static Player getPlayer() {
 | 
			
		||||
		if (FMLEnvironment.dist == Dist.CLIENT) {
 | 
			
		||||
			return Minecraft.getInstance().level.registryAccess();
 | 
			
		||||
			return Minecraft.getInstance().player;
 | 
			
		||||
		}
 | 
			
		||||
		return ServerLifecycleHooks.getCurrentServer().registryAccess();
 | 
			
		||||
		return null;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Nullable
 | 
			
		||||
@@ -28,9 +28,14 @@ public class Proxy {
 | 
			
		||||
		if (FMLEnvironment.dist == Dist.CLIENT) {
 | 
			
		||||
			return Minecraft.getInstance().level;
 | 
			
		||||
		}
 | 
			
		||||
		return ServerLifecycleHooks.getCurrentServer().overworld();
 | 
			
		||||
		var server = ServerLifecycleHooks.getCurrentServer();
 | 
			
		||||
		if (server != null) {
 | 
			
		||||
			return server.overworld();
 | 
			
		||||
		}
 | 
			
		||||
		return null;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Deprecated
 | 
			
		||||
	public static Optional<MinecraftServer> getServer() {
 | 
			
		||||
		return Optional.ofNullable(ServerLifecycleHooks.getCurrentServer());
 | 
			
		||||
	}
 | 
			
		||||
@@ -40,4 +45,7 @@ public class Proxy {
 | 
			
		||||
		return Minecraft.getInstance().player;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static boolean isOnClient() {
 | 
			
		||||
		return getServer().isEmpty() || RenderSystem.isOnRenderThread();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								src/main/java/dev/xkmc/l2core/util/ServerProxy.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/main/java/dev/xkmc/l2core/util/ServerProxy.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
package dev.xkmc.l2core.util;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.core.RegistryAccess;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import net.neoforged.api.distmarker.Dist;
 | 
			
		||||
import net.neoforged.fml.loading.FMLEnvironment;
 | 
			
		||||
import net.neoforged.neoforge.server.ServerLifecycleHooks;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
public class ServerProxy {
 | 
			
		||||
 | 
			
		||||
	@Nullable
 | 
			
		||||
	public static RegistryAccess getRegistryAccess() {
 | 
			
		||||
		if (FMLEnvironment.dist == Dist.CLIENT) {
 | 
			
		||||
			Level level = Proxy.getLevel();
 | 
			
		||||
			if (level != null) {
 | 
			
		||||
				return level.registryAccess();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		var server = ServerLifecycleHooks.getCurrentServer();
 | 
			
		||||
		if (server != null) {
 | 
			
		||||
			return server.registryAccess();
 | 
			
		||||
		}
 | 
			
		||||
		return null;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static Optional<MinecraftServer> getServer() {
 | 
			
		||||
		return Optional.ofNullable(ServerLifecycleHooks.getCurrentServer());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static boolean isOnClient() {
 | 
			
		||||
		if (FMLEnvironment.dist == Dist.DEDICATED_SERVER) return false;
 | 
			
		||||
		return Proxy.isOnClient();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -6,5 +6,7 @@
 | 
			
		||||
  "l2core.configuration.overlayZVal.tooltip": "默认值:250",
 | 
			
		||||
  "l2core.configuration.section.l2configs.l2core.client.toml": "莱特兰核心 - 客户端配置",
 | 
			
		||||
  "l2core.configuration.section.l2configs.l2core.client.toml.title": "莱特兰核心 - 客户端配置",
 | 
			
		||||
  "l2core.configuration.title": "莱特兰核心 - 配置"
 | 
			
		||||
  "l2core.configuration.title": "莱特兰核心 - 配置",
 | 
			
		||||
  "l2core.configuration.renderOverlayIcons": "实体图标显示",
 | 
			
		||||
  "l2core.configuration.renderOverlayIcons.tooltip": ""
 | 
			
		||||
}
 | 
			
		||||
@@ -4,11 +4,12 @@
 | 
			
		||||
  "package": "dev.xkmc.l2core.mixin",
 | 
			
		||||
  "compatibilityLevel": "JAVA_21",
 | 
			
		||||
  "mixins": [
 | 
			
		||||
    "CreativeModeTabMixin"
 | 
			
		||||
  ],
 | 
			
		||||
  "client": [
 | 
			
		||||
  ],
 | 
			
		||||
  "injectors": {
 | 
			
		||||
	"defaultRequire": 1
 | 
			
		||||
    "defaultRequire": 1
 | 
			
		||||
  },
 | 
			
		||||
  "minVersion": "0.8"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user