Player spawn in Overworld fix
This commit is contained in:
parent
e09d1d2235
commit
56591633ec
12 changed files with 370 additions and 41 deletions
|
@ -15,9 +15,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.resource.ServerResourceManager;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.PlayerManager;
|
||||
import net.minecraft.server.WorldGenerationProgressListener;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.SaveProperties;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.level.ServerWorldProperties;
|
||||
import ru.betterend.recipe.EndRecipeManager;
|
||||
import ru.betterend.registry.EndBiomes;
|
||||
import ru.betterend.world.generator.GeneratorOptions;
|
||||
|
@ -30,6 +34,10 @@ public class MinecraftServerMixin {
|
|||
@Final
|
||||
@Shadow
|
||||
private Map<RegistryKey<World>, ServerWorld> worlds;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
protected SaveProperties saveProperties;
|
||||
|
||||
@Inject(method = "reloadResources", at = @At(value = "RETURN"), cancellable = true)
|
||||
private void beOnReload(Collection<String> collection, CallbackInfoReturnable<CompletableFuture<Void>> info) {
|
||||
|
@ -53,6 +61,36 @@ public class MinecraftServerMixin {
|
|||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "createWorlds", at = @At(value = "TAIL"))
|
||||
private final void be_CreateWorlds(WorldGenerationProgressListener worldGenerationProgressListener, CallbackInfo info) {
|
||||
if (GeneratorOptions.swapOverworldToEnd()) {
|
||||
ServerWorld world = worlds.get(World.END);
|
||||
if (world == null) {
|
||||
world = worlds.get(World.OVERWORLD);
|
||||
}
|
||||
this.getPlayerManager().setMainWorld(world);
|
||||
ServerWorldProperties serverWorldProperties = saveProperties.getMainWorldProperties();
|
||||
net.minecraft.world.gen.GeneratorOptions generatorOptions = saveProperties.getGeneratorOptions();
|
||||
boolean bl = generatorOptions.isDebugWorld();
|
||||
setupSpawn(world, serverWorldProperties, generatorOptions.hasBonusChest(), bl, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "setupSpawn", at = @At(value = "HEAD"), cancellable = true)
|
||||
private static void be_SetupSpawn(ServerWorld world, ServerWorldProperties serverWorldProperties, boolean bonusChest, boolean debugWorld, boolean bl, CallbackInfo info) {
|
||||
if (GeneratorOptions.swapOverworldToEnd() && world.getRegistryKey() == World.OVERWORLD) {
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private static void setupSpawn(ServerWorld world, ServerWorldProperties serverWorldProperties, boolean bonusChest, boolean debugWorld, boolean bl) {}
|
||||
|
||||
@Shadow
|
||||
public PlayerManager getPlayerManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void beInjectRecipes() {
|
||||
if (FabricLoader.getInstance().isModLoaded("kubejs")) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
import net.minecraft.world.biome.source.BiomeSource;
|
||||
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
|
||||
import net.minecraft.world.gen.chunk.NoiseChunkGenerator;
|
||||
import ru.betterend.world.generator.GeneratorOptions;
|
||||
import ru.betterend.world.generator.TerrainGenerator;
|
||||
|
||||
@Mixin(NoiseChunkGenerator.class)
|
||||
|
@ -27,7 +28,7 @@ public abstract class NoiseChunkGeneratorMixin {
|
|||
|
||||
@Inject(method = "sampleNoiseColumn([DII)V", at = @At("HEAD"), cancellable = true, allow = 2)
|
||||
private void beSampleNoiseColumn(double[] buffer, int x, int z, CallbackInfo info) {
|
||||
if (TerrainGenerator.useNewGenerator() && settings.get().equals(ChunkGeneratorSettings.END)) {
|
||||
if (GeneratorOptions.useNewGenerator() && settings.get().equals(ChunkGeneratorSettings.END)) {
|
||||
if (TerrainGenerator.canGenerate(x, z)) {
|
||||
TerrainGenerator.fillTerrainDensity(buffer, x, z);
|
||||
info.cancel();
|
||||
|
|
260
src/main/java/ru/betterend/mixin/common/PlayerManagerMixin.java
Normal file
260
src/main/java/ru/betterend/mixin/common/PlayerManagerMixin.java
Normal file
|
@ -0,0 +1,260 @@
|
|||
package ru.betterend.mixin.common;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.MessageType;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.DifficultyS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.EntityStatusEffectS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.HeldItemChangeS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.PlayerAbilitiesS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.SynchronizeTagsS2CPacket;
|
||||
import net.minecraft.scoreboard.ServerScoreboard;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.PlayerManager;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.UserCache;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.registry.DynamicRegistryManager;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.GameRules;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldProperties;
|
||||
import net.minecraft.world.biome.source.BiomeAccess;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import ru.betterend.world.generator.GeneratorOptions;
|
||||
|
||||
@Mixin(PlayerManager.class)
|
||||
public class PlayerManagerMixin {
|
||||
@Final
|
||||
@Shadow
|
||||
private static Logger LOGGER;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private MinecraftServer server;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private DynamicRegistryManager.Impl registryManager;
|
||||
|
||||
@Shadow
|
||||
private int viewDistance;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private List<ServerPlayerEntity> players;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private Map<UUID, ServerPlayerEntity> playerMap;
|
||||
|
||||
@Inject(method = "onPlayerConnect", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void be_onPlayerConnect(ClientConnection connection, ServerPlayerEntity player, CallbackInfo info) {
|
||||
if (GeneratorOptions.swapOverworldToEnd()) {
|
||||
GameProfile gameProfile = player.getGameProfile();
|
||||
UserCache userCache = this.server.getUserCache();
|
||||
GameProfile gameProfile2 = userCache.getByUuid(gameProfile.getId());
|
||||
String string = gameProfile2 == null ? gameProfile.getName() : gameProfile2.getName();
|
||||
userCache.add(gameProfile);
|
||||
CompoundTag compoundTag = this.loadPlayerData(player);
|
||||
RegistryKey<World> var23;
|
||||
if (compoundTag != null) {
|
||||
DataResult<RegistryKey<World>> var10000 = DimensionType.method_28521(new Dynamic<Tag>(NbtOps.INSTANCE, compoundTag.get("Dimension")));
|
||||
Logger var10001 = LOGGER;
|
||||
var10001.getClass();
|
||||
var23 = (RegistryKey<World>) var10000.resultOrPartial(var10001::error).orElse(World.END);
|
||||
}
|
||||
else {
|
||||
var23 = World.END;
|
||||
}
|
||||
|
||||
System.out.println("World " + this.server.getWorld(World.END));
|
||||
|
||||
RegistryKey<World> registryKey = var23;
|
||||
ServerWorld serverWorld = this.server.getWorld(registryKey);
|
||||
ServerWorld serverWorld3;
|
||||
if (serverWorld == null) {
|
||||
LOGGER.warn("Unknown respawn dimension {}, defaulting to overworld", registryKey);
|
||||
serverWorld3 = this.server.getOverworld();
|
||||
}
|
||||
else {
|
||||
serverWorld3 = serverWorld;
|
||||
}
|
||||
|
||||
player.setWorld(serverWorld3);
|
||||
player.interactionManager.setWorld((ServerWorld) player.world);
|
||||
String string2 = "local";
|
||||
if (connection.getAddress() != null) {
|
||||
string2 = connection.getAddress().toString();
|
||||
}
|
||||
|
||||
LOGGER.info("{}[{}] logged in with entity id {} at ({}, {}, {})", player.getName().getString(), string2, player.getEntityId(), player.getX(), player.getY(), player.getZ());
|
||||
WorldProperties worldProperties = serverWorld3.getLevelProperties();
|
||||
this.setGameMode(player, (ServerPlayerEntity) null, serverWorld3);
|
||||
ServerPlayNetworkHandler serverPlayNetworkHandler = new ServerPlayNetworkHandler(this.server, connection, player);
|
||||
GameRules gameRules = serverWorld3.getGameRules();
|
||||
boolean bl = gameRules.getBoolean(GameRules.DO_IMMEDIATE_RESPAWN);
|
||||
boolean bl2 = gameRules.getBoolean(GameRules.REDUCED_DEBUG_INFO);
|
||||
serverPlayNetworkHandler.sendPacket(new GameJoinS2CPacket(player.getEntityId(), player.interactionManager.getGameMode(), player.interactionManager.getPreviousGameMode(), BiomeAccess.hashSeed(serverWorld3.getSeed()),
|
||||
worldProperties.isHardcore(), this.server.getWorldRegistryKeys(), this.registryManager, serverWorld3.getDimension(), serverWorld3.getRegistryKey(), this.getMaxPlayerCount(), this.viewDistance, bl2, !bl,
|
||||
serverWorld3.isDebugWorld(), serverWorld3.isFlat()));
|
||||
serverPlayNetworkHandler.sendPacket(new CustomPayloadS2CPacket(CustomPayloadS2CPacket.BRAND, (new PacketByteBuf(Unpooled.buffer())).writeString(this.getServer().getServerModName())));
|
||||
serverPlayNetworkHandler.sendPacket(new DifficultyS2CPacket(worldProperties.getDifficulty(), worldProperties.isDifficultyLocked()));
|
||||
serverPlayNetworkHandler.sendPacket(new PlayerAbilitiesS2CPacket(player.abilities));
|
||||
serverPlayNetworkHandler.sendPacket(new HeldItemChangeS2CPacket(player.inventory.selectedSlot));
|
||||
serverPlayNetworkHandler.sendPacket(new SynchronizeRecipesS2CPacket(this.server.getRecipeManager().values()));
|
||||
serverPlayNetworkHandler.sendPacket(new SynchronizeTagsS2CPacket(this.server.getTagManager()));
|
||||
this.sendCommandTree(player);
|
||||
player.getStatHandler().updateStatSet();
|
||||
player.getRecipeBook().sendInitRecipesPacket(player);
|
||||
this.sendScoreboard(serverWorld3.getScoreboard(), player);
|
||||
this.server.forcePlayerSampleUpdate();
|
||||
TranslatableText mutableText2;
|
||||
if (player.getGameProfile().getName().equalsIgnoreCase(string)) {
|
||||
mutableText2 = new TranslatableText("multiplayer.player.joined", new Object[] { player.getDisplayName() });
|
||||
}
|
||||
else {
|
||||
mutableText2 = new TranslatableText("multiplayer.player.joined.renamed", new Object[] { player.getDisplayName(), string });
|
||||
}
|
||||
|
||||
this.broadcastChatMessage(mutableText2.formatted(Formatting.YELLOW), MessageType.SYSTEM, Util.NIL_UUID);
|
||||
serverPlayNetworkHandler.requestTeleport(player.getX(), player.getY(), player.getZ(), player.yaw, player.pitch);
|
||||
this.players.add(player);
|
||||
this.playerMap.put(player.getUuid(), player);
|
||||
this.sendToAll(new PlayerListS2CPacket(PlayerListS2CPacket.Action.ADD_PLAYER, new ServerPlayerEntity[] { player }));
|
||||
|
||||
for (int i = 0; i < this.players.size(); ++i) {
|
||||
player.networkHandler.sendPacket(new PlayerListS2CPacket(PlayerListS2CPacket.Action.ADD_PLAYER, new ServerPlayerEntity[] { (ServerPlayerEntity) this.players.get(i) }));
|
||||
}
|
||||
|
||||
serverWorld3.onPlayerConnected(player);
|
||||
this.server.getBossBarManager().onPlayerConnect(player);
|
||||
this.sendWorldInfo(player, serverWorld3);
|
||||
if (!this.server.getResourcePackUrl().isEmpty()) {
|
||||
player.sendResourcePackUrl(this.server.getResourcePackUrl(), this.server.getResourcePackHash());
|
||||
}
|
||||
|
||||
Iterator<?> var24 = player.getStatusEffects().iterator();
|
||||
|
||||
while (var24.hasNext()) {
|
||||
StatusEffectInstance statusEffectInstance = (StatusEffectInstance) var24.next();
|
||||
serverPlayNetworkHandler.sendPacket(new EntityStatusEffectS2CPacket(player.getEntityId(), statusEffectInstance));
|
||||
}
|
||||
|
||||
if (compoundTag != null && compoundTag.contains("RootVehicle", 10)) {
|
||||
CompoundTag compoundTag2 = compoundTag.getCompound("RootVehicle");
|
||||
Entity entity = EntityType.loadEntityWithPassengers(compoundTag2.getCompound("Entity"), serverWorld3, (vehicle) -> {
|
||||
return !serverWorld3.tryLoadEntity(vehicle) ? null : vehicle;
|
||||
});
|
||||
if (entity != null) {
|
||||
UUID uUID2;
|
||||
if (compoundTag2.containsUuid("Attach")) {
|
||||
uUID2 = compoundTag2.getUuid("Attach");
|
||||
}
|
||||
else {
|
||||
uUID2 = null;
|
||||
}
|
||||
|
||||
Iterator<?> var21;
|
||||
Entity entity3;
|
||||
if (entity.getUuid().equals(uUID2)) {
|
||||
player.startRiding(entity, true);
|
||||
}
|
||||
else {
|
||||
var21 = entity.getPassengersDeep().iterator();
|
||||
|
||||
while (var21.hasNext()) {
|
||||
entity3 = (Entity) var21.next();
|
||||
if (entity3.getUuid().equals(uUID2)) {
|
||||
player.startRiding(entity3, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!player.hasVehicle()) {
|
||||
LOGGER.warn("Couldn't reattach entity to player");
|
||||
serverWorld3.removeEntity(entity);
|
||||
var21 = entity.getPassengersDeep().iterator();
|
||||
|
||||
while (var21.hasNext()) {
|
||||
entity3 = (Entity) var21.next();
|
||||
serverWorld3.removeEntity(entity3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player.onSpawn();
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public CompoundTag loadPlayerData(ServerPlayerEntity player) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private void setGameMode(ServerPlayerEntity player, @Nullable ServerPlayerEntity oldPlayer, ServerWorld world) {}
|
||||
|
||||
@Shadow
|
||||
public void sendCommandTree(ServerPlayerEntity player) {}
|
||||
|
||||
@Shadow
|
||||
public int getMaxPlayerCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public MinecraftServer getServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
protected void sendScoreboard(ServerScoreboard scoreboard, ServerPlayerEntity player) {}
|
||||
|
||||
@Shadow
|
||||
public void broadcastChatMessage(Text message, MessageType type, UUID senderUuid) {}
|
||||
|
||||
@Shadow
|
||||
public void sendToAll(Packet<?> packet) {}
|
||||
|
||||
@Shadow
|
||||
public void sendWorldInfo(ServerPlayerEntity player, ServerWorld world) {}
|
||||
}
|
|
@ -1,34 +1,57 @@
|
|||
package ru.betterend.mixin.common;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.World;
|
||||
import ru.betterend.interfaces.TeleportingEntity;
|
||||
|
||||
@Mixin(ServerPlayerEntity.class)
|
||||
public abstract class ServerPlayerEntityMixin implements TeleportingEntity {
|
||||
public abstract class ServerPlayerEntityMixin extends PlayerEntity implements TeleportingEntity {
|
||||
private static final Map<ServerPlayerEntity, Long> COOLDOWN = Maps.newHashMap();
|
||||
|
||||
private long beCooldown;
|
||||
public ServerPlayerEntityMixin(World world, BlockPos pos, float yaw, GameProfile profile) {
|
||||
super(world, pos, yaw, profile);
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private RegistryKey<World> spawnPointDimension;
|
||||
|
||||
@Inject(method = "tick", at = @At("TAIL"))
|
||||
public void be_baseTick(CallbackInfo info) {
|
||||
if (hasCooldown()) {
|
||||
this.beCooldown--;
|
||||
ServerPlayerEntity key = (ServerPlayerEntity) (Object) this;
|
||||
long value = COOLDOWN.getOrDefault(key, 0L) - 1;
|
||||
COOLDOWN.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private void moveToSpawn(ServerWorld world) {}
|
||||
|
||||
@Override
|
||||
public long beGetCooldown() {
|
||||
return this.beCooldown;
|
||||
ServerPlayerEntity key = (ServerPlayerEntity) (Object) this;
|
||||
return COOLDOWN.getOrDefault(key, 0L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beSetCooldown(long time) {
|
||||
this.beCooldown = time;
|
||||
ServerPlayerEntity key = (ServerPlayerEntity) (Object) this;
|
||||
COOLDOWN.put(key, time);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue