- 选择界面:弃用renderBackground模糊着色器,改为纯色覆盖层,文字清晰 - 跨维度传送:初级/中级默认禁止,高级/永久允许(config可配) - 传送魔镜:默认仅限同team玩家(teleportTeamOnly可配) - debuff完全可配置:格式 effect_id,seconds,amplifier;... 每镜独立 - 饱食度减半独立开关(halveFood.xxx) - 合成配方可通过config覆盖(格式 row1;row2;row3|key=item;...) - 蓄力满自动触发(onUseTick托管)
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
package com.le.teleportmirror;
|
package com.le.teleportmirror;
|
||||||
|
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.neoforged.neoforge.common.ModConfigSpec;
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
|
|
||||||
public class Config {
|
public class Config {
|
||||||
@@ -13,6 +15,26 @@ public class Config {
|
|||||||
.comment("Number of ticks required to charge the mirror (20 ticks = 1 second)")
|
.comment("Number of ticks required to charge the mirror (20 ticks = 1 second)")
|
||||||
.defineInRange("chargeTicks", 40, 1, Integer.MAX_VALUE);
|
.defineInRange("chargeTicks", 40, 1, Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
public static final ModConfigSpec.BooleanValue ALLOW_CROSS_DIMENSION_BASIC = BUILDER
|
||||||
|
.comment("Allow Basic tier mirrors to teleport across dimensions")
|
||||||
|
.define("allowCrossDimension.basic", false);
|
||||||
|
|
||||||
|
public static final ModConfigSpec.BooleanValue ALLOW_CROSS_DIMENSION_INTERMEDIATE = BUILDER
|
||||||
|
.comment("Allow Intermediate tier mirrors to teleport across dimensions")
|
||||||
|
.define("allowCrossDimension.intermediate", false);
|
||||||
|
|
||||||
|
public static final ModConfigSpec.BooleanValue ALLOW_CROSS_DIMENSION_ADVANCED = BUILDER
|
||||||
|
.comment("Allow Advanced tier mirrors to teleport across dimensions")
|
||||||
|
.define("allowCrossDimension.advanced", true);
|
||||||
|
|
||||||
|
public static final ModConfigSpec.BooleanValue ALLOW_CROSS_DIMENSION_PERMANENT = BUILDER
|
||||||
|
.comment("Allow Permanent tier mirrors to teleport across dimensions")
|
||||||
|
.define("allowCrossDimension.permanent", true);
|
||||||
|
|
||||||
|
public static final ModConfigSpec.BooleanValue TELEPORT_TEAM_ONLY = BUILDER
|
||||||
|
.comment("Teleport Mirror can only target players on the same team")
|
||||||
|
.define("teleportTeamOnly", true);
|
||||||
|
|
||||||
public static final ModConfigSpec.IntValue BASIC_DURABILITY = BUILDER
|
public static final ModConfigSpec.IntValue BASIC_DURABILITY = BUILDER
|
||||||
.comment("Durability for Basic tier mirrors")
|
.comment("Durability for Basic tier mirrors")
|
||||||
.defineInRange("basicDurability", 10, 0, Integer.MAX_VALUE);
|
.defineInRange("basicDurability", 10, 0, Integer.MAX_VALUE);
|
||||||
@@ -25,41 +47,101 @@ public class Config {
|
|||||||
.comment("Durability for Advanced tier mirrors")
|
.comment("Durability for Advanced tier mirrors")
|
||||||
.defineInRange("advancedDurability", 100, 0, Integer.MAX_VALUE);
|
.defineInRange("advancedDurability", 100, 0, Integer.MAX_VALUE);
|
||||||
|
|
||||||
public static final ModConfigSpec.IntValue BASIC_NAUSEA_SECONDS = BUILDER
|
public static final ModConfigSpec.BooleanValue HALVE_FOOD_BASIC = BUILDER
|
||||||
.comment("Nausea effect duration in seconds for Basic tier")
|
.comment("Halve food when using Basic tier mirrors")
|
||||||
.defineInRange("basicNauseaSeconds", 10, 0, Integer.MAX_VALUE);
|
.define("halveFood.basic", true);
|
||||||
|
|
||||||
public static final ModConfigSpec.IntValue BASIC_WITHER_SECONDS = BUILDER
|
public static final ModConfigSpec.BooleanValue HALVE_FOOD_INTERMEDIATE = BUILDER
|
||||||
.comment("Wither effect duration in seconds for Basic tier")
|
.comment("Halve food when using Intermediate tier mirrors")
|
||||||
.defineInRange("basicWitherSeconds", 5, 0, Integer.MAX_VALUE);
|
.define("halveFood.intermediate", true);
|
||||||
|
|
||||||
public static final ModConfigSpec.IntValue INTERMEDIATE_NAUSEA_SECONDS = BUILDER
|
public static final ModConfigSpec.BooleanValue HALVE_FOOD_ADVANCED = BUILDER
|
||||||
.comment("Nausea effect duration in seconds for Intermediate tier")
|
.comment("Halve food when using Advanced tier mirrors")
|
||||||
.defineInRange("intermediateNauseaSeconds", 5, 0, Integer.MAX_VALUE);
|
.define("halveFood.advanced", true);
|
||||||
|
|
||||||
public static final ModConfigSpec.IntValue INTERMEDIATE_WITHER_SECONDS = BUILDER
|
public static final ModConfigSpec.BooleanValue HALVE_FOOD_PERMANENT = BUILDER
|
||||||
.comment("Wither effect duration in seconds for Intermediate tier")
|
.comment("Halve food when using Permanent tier mirrors")
|
||||||
.defineInRange("intermediateWitherSeconds", 3, 0, Integer.MAX_VALUE);
|
.define("halveFood.permanent", false);
|
||||||
|
|
||||||
public static final ModConfigSpec.IntValue ADVANCED_NAUSEA_SECONDS = BUILDER
|
public static final ModConfigSpec.ConfigValue<String> EFFECTS_RETURN_BASIC = BUILDER
|
||||||
.comment("Nausea effect duration in seconds for Advanced tier")
|
.comment("Effects for Basic Return Mirror. Format: \"effect_id,dur_sec,amplifier;...\"")
|
||||||
.defineInRange("advancedNauseaSeconds", 3, 0, Integer.MAX_VALUE);
|
.define("effects.return.basic", "minecraft:nausea,10,0;minecraft:wither,5,0");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> EFFECTS_RETURN_INTERMEDIATE = BUILDER
|
||||||
|
.comment("Effects for Intermediate Return Mirror. Format: \"effect_id,dur_sec,amplifier;...\"")
|
||||||
|
.define("effects.return.intermediate", "minecraft:nausea,5,0;minecraft:wither,3,0");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> EFFECTS_RETURN_ADVANCED = BUILDER
|
||||||
|
.comment("Effects for Advanced Return Mirror. Format: \"effect_id,dur_sec,amplifier;...\"")
|
||||||
|
.define("effects.return.advanced", "minecraft:nausea,3,0");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> EFFECTS_RETURN_PERMANENT = BUILDER
|
||||||
|
.comment("Effects for Permanent Return Mirror. Format: \"effect_id,dur_sec,amplifier;...\"")
|
||||||
|
.define("effects.return.permanent", "");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> EFFECTS_TELEPORT_BASIC = BUILDER
|
||||||
|
.comment("Effects for Basic Teleport Mirror. Format: \"effect_id,dur_sec,amplifier;...\"")
|
||||||
|
.define("effects.teleport.basic", "minecraft:nausea,10,0;minecraft:wither,5,0");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> EFFECTS_TELEPORT_INTERMEDIATE = BUILDER
|
||||||
|
.comment("Effects for Intermediate Teleport Mirror. Format: \"effect_id,dur_sec,amplifier;...\"")
|
||||||
|
.define("effects.teleport.intermediate", "minecraft:nausea,5,0;minecraft:wither,3,0");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> EFFECTS_TELEPORT_ADVANCED = BUILDER
|
||||||
|
.comment("Effects for Advanced Teleport Mirror. Format: \"effect_id,dur_sec,amplifier;...\"")
|
||||||
|
.define("effects.teleport.advanced", "minecraft:nausea,3,0");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> EFFECTS_TELEPORT_PERMANENT = BUILDER
|
||||||
|
.comment("Effects for Permanent Teleport Mirror. Format: \"effect_id,dur_sec,amplifier;...\"")
|
||||||
|
.define("effects.teleport.permanent", "");
|
||||||
|
|
||||||
public static final ModConfigSpec.BooleanValue ENABLE_BASIC_RECIPE = BUILDER
|
public static final ModConfigSpec.BooleanValue ENABLE_BASIC_RECIPE = BUILDER
|
||||||
.comment("Enable crafting recipe for Basic tier mirrors")
|
.comment("Enable crafting recipe for Basic tier mirrors")
|
||||||
.define("enableBasicRecipe", true);
|
.define("enableRecipe.basic", true);
|
||||||
|
|
||||||
public static final ModConfigSpec.BooleanValue ENABLE_INTERMEDIATE_RECIPE = BUILDER
|
public static final ModConfigSpec.BooleanValue ENABLE_INTERMEDIATE_RECIPE = BUILDER
|
||||||
.comment("Enable crafting recipe for Intermediate tier mirrors")
|
.comment("Enable crafting recipe for Intermediate tier mirrors")
|
||||||
.define("enableIntermediateRecipe", true);
|
.define("enableRecipe.intermediate", true);
|
||||||
|
|
||||||
public static final ModConfigSpec.BooleanValue ENABLE_ADVANCED_RECIPE = BUILDER
|
public static final ModConfigSpec.BooleanValue ENABLE_ADVANCED_RECIPE = BUILDER
|
||||||
.comment("Enable crafting recipe for Advanced tier mirrors")
|
.comment("Enable crafting recipe for Advanced tier mirrors")
|
||||||
.define("enableAdvancedRecipe", true);
|
.define("enableRecipe.advanced", true);
|
||||||
|
|
||||||
public static final ModConfigSpec.BooleanValue ENABLE_PERMANENT_RECIPE = BUILDER
|
public static final ModConfigSpec.BooleanValue ENABLE_PERMANENT_RECIPE = BUILDER
|
||||||
.comment("Enable crafting recipe for Permanent tier mirrors")
|
.comment("Enable crafting recipe for Permanent tier mirrors")
|
||||||
.define("enablePermanentRecipe", true);
|
.define("enableRecipe.permanent", true);
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> RECIPE_OVERRIDE_RETURN_BASIC = BUILDER
|
||||||
|
.comment("Override recipe for Basic Return Mirror. Format: \"row1;row2;row3|key=item_id;...\". Empty=use default.")
|
||||||
|
.define("recipeOverride.return.basic", "");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> RECIPE_OVERRIDE_RETURN_INTERMEDIATE = BUILDER
|
||||||
|
.comment("Override recipe for Intermediate Return Mirror.")
|
||||||
|
.define("recipeOverride.return.intermediate", "");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> RECIPE_OVERRIDE_RETURN_ADVANCED = BUILDER
|
||||||
|
.comment("Override recipe for Advanced Return Mirror.")
|
||||||
|
.define("recipeOverride.return.advanced", "");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> RECIPE_OVERRIDE_RETURN_PERMANENT = BUILDER
|
||||||
|
.comment("Override recipe for Permanent Return Mirror.")
|
||||||
|
.define("recipeOverride.return.permanent", "");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> RECIPE_OVERRIDE_TELEPORT_BASIC = BUILDER
|
||||||
|
.comment("Override recipe for Basic Teleport Mirror.")
|
||||||
|
.define("recipeOverride.teleport.basic", "");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> RECIPE_OVERRIDE_TELEPORT_INTERMEDIATE = BUILDER
|
||||||
|
.comment("Override recipe for Intermediate Teleport Mirror.")
|
||||||
|
.define("recipeOverride.teleport.intermediate", "");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> RECIPE_OVERRIDE_TELEPORT_ADVANCED = BUILDER
|
||||||
|
.comment("Override recipe for Advanced Teleport Mirror.")
|
||||||
|
.define("recipeOverride.teleport.advanced", "");
|
||||||
|
|
||||||
|
public static final ModConfigSpec.ConfigValue<String> RECIPE_OVERRIDE_TELEPORT_PERMANENT = BUILDER
|
||||||
|
.comment("Override recipe for Permanent Teleport Mirror.")
|
||||||
|
.define("recipeOverride.teleport.permanent", "");
|
||||||
|
|
||||||
static final ModConfigSpec SPEC = BUILDER.build();
|
static final ModConfigSpec SPEC = BUILDER.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
package com.le.teleportmirror;
|
package com.le.teleportmirror;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
@@ -7,16 +12,13 @@ import net.minecraft.sounds.SoundSource;
|
|||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResultHolder;
|
import net.minecraft.world.InteractionResultHolder;
|
||||||
import net.minecraft.world.effect.MobEffectInstance;
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
import net.minecraft.world.effect.MobEffects;
|
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.food.FoodData;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.UseAnim;
|
import net.minecraft.world.item.UseAnim;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.world.food.FoodData;
|
|
||||||
|
|
||||||
public class MirrorItem extends Item {
|
public class MirrorItem extends Item {
|
||||||
private final MirrorTier tier;
|
private final MirrorTier tier;
|
||||||
@@ -84,6 +86,15 @@ public class MirrorItem extends Item {
|
|||||||
public void releaseUsing(ItemStack stack, Level level, LivingEntity entity, int timeCharged) {
|
public void releaseUsing(ItemStack stack, Level level, LivingEntity entity, int timeCharged) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean canCrossDimension() {
|
||||||
|
return switch (tier) {
|
||||||
|
case BASIC -> Config.ALLOW_CROSS_DIMENSION_BASIC.get();
|
||||||
|
case INTERMEDIATE -> Config.ALLOW_CROSS_DIMENSION_INTERMEDIATE.get();
|
||||||
|
case ADVANCED -> Config.ALLOW_CROSS_DIMENSION_ADVANCED.get();
|
||||||
|
case PERMANENT -> Config.ALLOW_CROSS_DIMENSION_PERMANENT.get();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void performReturnTeleport(ServerPlayer player, ItemStack stack) {
|
private void performReturnTeleport(ServerPlayer player, ItemStack stack) {
|
||||||
ServerLevel serverLevel = player.serverLevel();
|
ServerLevel serverLevel = player.serverLevel();
|
||||||
BlockPos targetPos;
|
BlockPos targetPos;
|
||||||
@@ -105,6 +116,10 @@ public class MirrorItem extends Item {
|
|||||||
targetPos = targetLevel.getSharedSpawnPos();
|
targetPos = targetLevel.getSharedSpawnPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!canCrossDimension() && targetLevel.dimension() != serverLevel.dimension()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
consumeMirrorUse(player, stack);
|
consumeMirrorUse(player, stack);
|
||||||
|
|
||||||
player.teleportTo(targetLevel, targetPos.getCenter().x, targetPos.getCenter().y, targetPos.getCenter().z,
|
player.teleportTo(targetLevel, targetPos.getCenter().x, targetPos.getCenter().y, targetPos.getCenter().z,
|
||||||
@@ -117,6 +132,10 @@ public class MirrorItem extends Item {
|
|||||||
ServerLevel targetLevel = target.serverLevel();
|
ServerLevel targetLevel = target.serverLevel();
|
||||||
BlockPos targetPos = target.blockPosition();
|
BlockPos targetPos = target.blockPosition();
|
||||||
|
|
||||||
|
if (!canCrossDimension() && targetLevel.dimension() != player.serverLevel().dimension()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
consumeMirrorUse(player, stack);
|
consumeMirrorUse(player, stack);
|
||||||
|
|
||||||
player.teleportTo(targetLevel, targetPos.getCenter().x, targetPos.getCenter().y, targetPos.getCenter().z,
|
player.teleportTo(targetLevel, targetPos.getCenter().x, targetPos.getCenter().y, targetPos.getCenter().z,
|
||||||
@@ -155,42 +174,67 @@ public class MirrorItem extends Item {
|
|||||||
player.getCooldowns().addCooldown(this, cooldownTicks);
|
player.getCooldowns().addCooldown(this, cooldownTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applySideEffects(Player player) {
|
private String getEffectsConfig() {
|
||||||
int nauseaDuration;
|
return switch (type) {
|
||||||
int witherDuration;
|
case RETURN -> switch (tier) {
|
||||||
|
case BASIC -> Config.EFFECTS_RETURN_BASIC.get();
|
||||||
|
case INTERMEDIATE -> Config.EFFECTS_RETURN_INTERMEDIATE.get();
|
||||||
|
case ADVANCED -> Config.EFFECTS_RETURN_ADVANCED.get();
|
||||||
|
case PERMANENT -> Config.EFFECTS_RETURN_PERMANENT.get();
|
||||||
|
};
|
||||||
|
case TELEPORT -> switch (tier) {
|
||||||
|
case BASIC -> Config.EFFECTS_TELEPORT_BASIC.get();
|
||||||
|
case INTERMEDIATE -> Config.EFFECTS_TELEPORT_INTERMEDIATE.get();
|
||||||
|
case ADVANCED -> Config.EFFECTS_TELEPORT_ADVANCED.get();
|
||||||
|
case PERMANENT -> Config.EFFECTS_TELEPORT_PERMANENT.get();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
switch (tier) {
|
private boolean shouldHalveFood() {
|
||||||
case BASIC:
|
return switch (tier) {
|
||||||
nauseaDuration = Config.BASIC_NAUSEA_SECONDS.get() * 20;
|
case BASIC -> Config.HALVE_FOOD_BASIC.get();
|
||||||
witherDuration = Config.BASIC_WITHER_SECONDS.get() * 20;
|
case INTERMEDIATE -> Config.HALVE_FOOD_INTERMEDIATE.get();
|
||||||
if (nauseaDuration > 0) {
|
case ADVANCED -> Config.HALVE_FOOD_ADVANCED.get();
|
||||||
player.addEffect(new MobEffectInstance(MobEffects.CONFUSION, nauseaDuration, 0));
|
case PERMANENT -> Config.HALVE_FOOD_PERMANENT.get();
|
||||||
}
|
};
|
||||||
if (witherDuration > 0) {
|
}
|
||||||
player.addEffect(new MobEffectInstance(MobEffects.WITHER, witherDuration, 0));
|
|
||||||
}
|
private void applySideEffects(Player player) {
|
||||||
halveFood(player);
|
String effectsConfig = getEffectsConfig();
|
||||||
break;
|
if (effectsConfig == null || effectsConfig.isBlank()) {
|
||||||
case INTERMEDIATE:
|
return;
|
||||||
nauseaDuration = Config.INTERMEDIATE_NAUSEA_SECONDS.get() * 20;
|
}
|
||||||
witherDuration = Config.INTERMEDIATE_WITHER_SECONDS.get() * 20;
|
|
||||||
if (nauseaDuration > 0) {
|
String[] effectEntries = effectsConfig.split(";");
|
||||||
player.addEffect(new MobEffectInstance(MobEffects.CONFUSION, nauseaDuration, 0));
|
for (String entry : effectEntries) {
|
||||||
}
|
entry = entry.trim();
|
||||||
if (witherDuration > 0) {
|
if (entry.isEmpty()) continue;
|
||||||
player.addEffect(new MobEffectInstance(MobEffects.WITHER, witherDuration, 0));
|
|
||||||
}
|
String[] parts = entry.split(",");
|
||||||
halveFood(player);
|
if (parts.length < 3) continue;
|
||||||
break;
|
|
||||||
case ADVANCED:
|
String effectId = parts[0].trim();
|
||||||
nauseaDuration = Config.ADVANCED_NAUSEA_SECONDS.get() * 20;
|
int durationSeconds;
|
||||||
if (nauseaDuration > 0) {
|
int amplifier;
|
||||||
player.addEffect(new MobEffectInstance(MobEffects.CONFUSION, nauseaDuration, 0));
|
try {
|
||||||
}
|
durationSeconds = Integer.parseInt(parts[1].trim());
|
||||||
halveFood(player);
|
amplifier = Integer.parseInt(parts[2].trim());
|
||||||
break;
|
} catch (NumberFormatException e) {
|
||||||
case PERMANENT:
|
continue;
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
if (durationSeconds <= 0) continue;
|
||||||
|
|
||||||
|
var effectKey = ResourceKey.create(Registries.MOB_EFFECT,
|
||||||
|
ResourceLocation.parse(effectId));
|
||||||
|
var effectHolder = BuiltInRegistries.MOB_EFFECT.getHolder(effectKey);
|
||||||
|
effectHolder.ifPresent(holder ->
|
||||||
|
player.addEffect(new MobEffectInstance(holder, durationSeconds * 20, amplifier)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldHalveFood()) {
|
||||||
|
halveFood(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,12 +38,19 @@ public class MirrorNetwork {
|
|||||||
public static void sendOpenSelectionToClient(ServerPlayer player, MirrorTier tier) {
|
public static void sendOpenSelectionToClient(ServerPlayer player, MirrorTier tier) {
|
||||||
List<String> names = new ArrayList<>();
|
List<String> names = new ArrayList<>();
|
||||||
List<UUID> uuids = new ArrayList<>();
|
List<UUID> uuids = new ArrayList<>();
|
||||||
|
boolean teamOnly = Config.TELEPORT_TEAM_ONLY.get();
|
||||||
|
|
||||||
for (ServerPlayer onlinePlayer : player.server.getPlayerList().getPlayers()) {
|
for (ServerPlayer onlinePlayer : player.server.getPlayerList().getPlayers()) {
|
||||||
if (!onlinePlayer.getUUID().equals(player.getUUID())) {
|
if (onlinePlayer.getUUID().equals(player.getUUID())) {
|
||||||
names.add(onlinePlayer.getName().getString());
|
continue;
|
||||||
uuids.add(onlinePlayer.getUUID());
|
|
||||||
}
|
}
|
||||||
|
if (teamOnly && player.getTeam() != null) {
|
||||||
|
if (onlinePlayer.getTeam() != player.getTeam()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
names.add(onlinePlayer.getName().getString());
|
||||||
|
uuids.add(onlinePlayer.getUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketDistributor.sendToPlayer(player, new OpenPlayerSelectionPayload(names, uuids, tier.getName()));
|
PacketDistributor.sendToPlayer(player, new OpenPlayerSelectionPayload(names, uuids, tier.getName()));
|
||||||
|
|||||||
@@ -1,19 +1,34 @@
|
|||||||
package com.le.teleportmirror;
|
package com.le.teleportmirror;
|
||||||
|
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.CreativeModeTab;
|
import net.minecraft.world.item.CreativeModeTab;
|
||||||
import net.minecraft.world.item.CreativeModeTabs;
|
import net.minecraft.world.item.CreativeModeTabs;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||||
|
import net.minecraft.world.item.crafting.RecipeType;
|
||||||
|
import net.minecraft.world.item.crafting.ShapedRecipe;
|
||||||
|
import net.minecraft.world.item.crafting.ShapedRecipePattern;
|
||||||
|
import net.minecraft.world.item.crafting.Ingredient;
|
||||||
|
import net.minecraft.world.item.crafting.CraftingBookCategory;
|
||||||
import net.neoforged.bus.api.IEventBus;
|
import net.neoforged.bus.api.IEventBus;
|
||||||
import net.neoforged.bus.api.SubscribeEvent;
|
|
||||||
import net.neoforged.fml.ModContainer;
|
import net.neoforged.fml.ModContainer;
|
||||||
import net.neoforged.fml.common.Mod;
|
import net.neoforged.fml.common.Mod;
|
||||||
import net.neoforged.fml.config.ModConfig;
|
import net.neoforged.fml.config.ModConfig;
|
||||||
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||||
import net.neoforged.neoforge.registries.DeferredItem;
|
import net.neoforged.neoforge.registries.DeferredItem;
|
||||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||||
|
import net.neoforged.neoforge.event.server.ServerStartedEvent;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Mod(TeleportMirrorMod.MODID)
|
@Mod(TeleportMirrorMod.MODID)
|
||||||
public class TeleportMirrorMod {
|
public class TeleportMirrorMod {
|
||||||
@@ -77,9 +92,95 @@ public class TeleportMirrorMod {
|
|||||||
|
|
||||||
modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC);
|
modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC);
|
||||||
modEventBus.addListener(this::onRegisterPayloads);
|
modEventBus.addListener(this::onRegisterPayloads);
|
||||||
|
|
||||||
|
NeoForge.EVENT_BUS.addListener(this::onServerStarted);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onRegisterPayloads(final RegisterPayloadHandlersEvent event) {
|
private void onRegisterPayloads(final RegisterPayloadHandlersEvent event) {
|
||||||
MirrorNetwork.registerPayloads(event);
|
MirrorNetwork.registerPayloads(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onServerStarted(final ServerStartedEvent event) {
|
||||||
|
registerConfigRecipes(event.getServer().getRecipeManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerConfigRecipes(net.minecraft.world.item.crafting.RecipeManager manager) {
|
||||||
|
tryRegisterRecipe(manager, Config.ENABLE_BASIC_RECIPE.get(),
|
||||||
|
Config.RECIPE_OVERRIDE_RETURN_BASIC.get(), BASIC_RETURN_MIRROR.get(), "basic_return_mirror");
|
||||||
|
tryRegisterRecipe(manager, Config.ENABLE_INTERMEDIATE_RECIPE.get(),
|
||||||
|
Config.RECIPE_OVERRIDE_RETURN_INTERMEDIATE.get(), INTERMEDIATE_RETURN_MIRROR.get(), "intermediate_return_mirror");
|
||||||
|
tryRegisterRecipe(manager, Config.ENABLE_ADVANCED_RECIPE.get(),
|
||||||
|
Config.RECIPE_OVERRIDE_RETURN_ADVANCED.get(), ADVANCED_RETURN_MIRROR.get(), "advanced_return_mirror");
|
||||||
|
tryRegisterRecipe(manager, Config.ENABLE_PERMANENT_RECIPE.get(),
|
||||||
|
Config.RECIPE_OVERRIDE_RETURN_PERMANENT.get(), PERMANENT_RETURN_MIRROR.get(), "permanent_return_mirror");
|
||||||
|
tryRegisterRecipe(manager, Config.ENABLE_BASIC_RECIPE.get(),
|
||||||
|
Config.RECIPE_OVERRIDE_TELEPORT_BASIC.get(), BASIC_TELEPORT_MIRROR.get(), "basic_teleport_mirror");
|
||||||
|
tryRegisterRecipe(manager, Config.ENABLE_INTERMEDIATE_RECIPE.get(),
|
||||||
|
Config.RECIPE_OVERRIDE_TELEPORT_INTERMEDIATE.get(), INTERMEDIATE_TELEPORT_MIRROR.get(), "intermediate_teleport_mirror");
|
||||||
|
tryRegisterRecipe(manager, Config.ENABLE_ADVANCED_RECIPE.get(),
|
||||||
|
Config.RECIPE_OVERRIDE_TELEPORT_ADVANCED.get(), ADVANCED_TELEPORT_MIRROR.get(), "advanced_teleport_mirror");
|
||||||
|
tryRegisterRecipe(manager, Config.ENABLE_PERMANENT_RECIPE.get(),
|
||||||
|
Config.RECIPE_OVERRIDE_TELEPORT_PERMANENT.get(), PERMANENT_TELEPORT_MIRROR.get(), "permanent_teleport_mirror");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void tryRegisterRecipe(net.minecraft.world.item.crafting.RecipeManager manager,
|
||||||
|
boolean enabled, String override, Item result, String name) {
|
||||||
|
if (!enabled) return;
|
||||||
|
if (override.isBlank()) return;
|
||||||
|
|
||||||
|
RecipeHolder<?> recipe = parseRecipeOverride(override, result, name);
|
||||||
|
if (recipe == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Field recipesField = manager.getClass().getDeclaredField("recipes");
|
||||||
|
recipesField.setAccessible(true);
|
||||||
|
Object recipeMap = recipesField.get(manager);
|
||||||
|
|
||||||
|
Field byTypeField = recipeMap.getClass().getDeclaredField("byType");
|
||||||
|
byTypeField.setAccessible(true);
|
||||||
|
Map<RecipeType<?>, Map<ResourceLocation, RecipeHolder<?>>> byType =
|
||||||
|
(Map<RecipeType<?>, Map<ResourceLocation, RecipeHolder<?>>>) byTypeField.get(recipeMap);
|
||||||
|
|
||||||
|
Map<ResourceLocation, RecipeHolder<?>> crafting = byType
|
||||||
|
.computeIfAbsent(RecipeType.CRAFTING, k -> new HashMap<>());
|
||||||
|
crafting.put(recipe.id(), recipe);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Silently ignore - default JSON recipe will be used
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RecipeHolder<?> parseRecipeOverride(String override, Item result, String name) {
|
||||||
|
String[] parts = override.split("\\|");
|
||||||
|
if (parts.length < 2) return null;
|
||||||
|
|
||||||
|
String[] rows = parts[0].split(";");
|
||||||
|
if (rows.length != 3) return null;
|
||||||
|
|
||||||
|
Map<Character, Ingredient> key = new HashMap<>();
|
||||||
|
String[] keyEntries = parts[1].split(";");
|
||||||
|
for (String entry : keyEntries) {
|
||||||
|
String[] kv = entry.split("=");
|
||||||
|
if (kv.length != 2) continue;
|
||||||
|
char k = kv[0].trim().charAt(0);
|
||||||
|
String itemId = kv[1].trim();
|
||||||
|
var item = BuiltInRegistries.ITEM.get(ResourceLocation.parse(itemId));
|
||||||
|
key.put(k, Ingredient.of(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> pattern = List.of(rows[0].trim(), rows[1].trim(), rows[2].trim());
|
||||||
|
|
||||||
|
ShapedRecipePattern shapedPattern;
|
||||||
|
try {
|
||||||
|
shapedPattern = ShapedRecipePattern.of(key, pattern);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapedRecipe recipe = new ShapedRecipe("", CraftingBookCategory.MISC, shapedPattern, new ItemStack(result));
|
||||||
|
|
||||||
|
return new RecipeHolder<>(
|
||||||
|
ResourceLocation.fromNamespaceAndPath(MODID, name + "_config"),
|
||||||
|
recipe);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,9 +88,8 @@ public class PlayerSelectionScreen extends Screen {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
|
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
|
||||||
this.renderBackground(guiGraphics, mouseX, mouseY, partialTick);
|
guiGraphics.fill(0, 0, this.width, this.height, 0xC0101010);
|
||||||
guiGraphics.fill(0, 0, this.width, 32, 0x88000000);
|
guiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 12, 0xFFFFFF);
|
||||||
guiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 10, 0xFFFFFF);
|
|
||||||
super.render(guiGraphics, mouseX, mouseY, partialTick);
|
super.render(guiGraphics, mouseX, mouseY, partialTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user