Jump to content

[1.7.10+] Keeping player (or his clone) after he logs out.


Recommended Posts

Posted

Basically ani-logout system. I want that if ExtendedPlayer.get(player).canLogOut() is false, player will be locked for let's say 10sec after he disconnects.

I mean: client can disconnect in any way - exiting game or closing it, but server will spawn some fake player and keep it for 10sec.

 

Critical points: I have 3 ideas:

1.

- How to not-remove EntityPlayer from entity list?

- If i could do this, whole problem becomes very easy to resolve.

 

2. (If I can't keep real player, like in 1.)

- Should I spawn new EntityPlayer and clone() data from old one via PlayerLoggedOutEvent and operate on new entity.

- In this case - since they are clons, will this give me ability to edit "real" player's .dat file? (I mean, when I remove new clonned EntityPlayer, will it call saveNBT() like "real" one would - keeping the player/session UUID)?

- If I remove clonned EntityPlayer - will it call PlayerLoggedOutEvent and make finite loop (until player#canLogOut()), OR PlayerLoggedOutEvent is only called on disconnect?

 

3. Use some kind of Abstract/Fake Player, I heard Forge has some class with this name, I have no idea what's the use of it.

 

Okay so, please post you knowledge/ideas/critical-points. :)

 

Thanks all :P

1.7.10 is no longer supported by forge, you are on your own.

Posted

Dude, there is NO "better" way to do this. I need EntityPlayer to be IN WORLD and be treaten like you never logged out (killable, movable) after session is ended. That is literally what it means to have "ani-logout system", you can't run from combat, can't logout if threatened, can't logout with poison on you (to escape some player that want to loot you).

 

I'd like straight from-experience answers to this thread, or idea other than mine, or why mine wouldn't work. Thanks for help :P

1.7.10 is no longer supported by forge, you are on your own.

Posted

You are being fairly rude.

 

If you decide you want to change your attitude, there is a simple way to do it.

Long time Bukkit & Forge Programmer

Happy to try and help

Posted

Damn, I felt like I am kinda of charging here after re-reading, but that wasn't my intention. Sry to offended. Anyway, any further help still appreciated.

1.7.10 is no longer supported by forge, you are on your own.

Posted

Maybe you can try to catch the

GuiOpenEvent

, check if the

event.gui==GuiIngameMenu

and then use

event.gui.buttonList.set(0,button)

with the a button overriding the

onActionPerformed

method to first check if you can log out, and if so, proceed, else cancel.

Don't PM me with questions. They will be ignored! Make a thread on the appropriate board for support.

 

1.12 -> 1.13 primer by williewillus.

 

1.7.10 and older versions of Minecraft are no longer supported due to it's age! Update to the latest version for support.

 

http://www.howoldisminecraft1710.today/

Posted

That's Client-side, I need server-side solution.

 

You can close game without pressing "Quit Game" button. If you do that client will never send disconnect info, therefore player will still be logged on server and server will throw UnexpectedConnection error and kick player after short while. But that's not what I want. I need player to presist as long as I need him too (not too long ofc, few, maybe dozen of seconds).

 

To post above - he posed to right topic (i mean, hopefully), just from different point of view (client). :)

1.7.10 is no longer supported by forge, you are on your own.

Posted

Here is how to do it in 1.7.2, you will have to leverage changes from 1.7.10

 

Setup event for player logout and record the players name and inventory.

 

If you are having trouble getting the inventory before logout, something like this may help.

 

 

In the below example skin is the players name

 

        // Get NBT data

            NBTTagCompound nbt = instance.player_manager().player_nbt(skin);

           

            // Check for null

            if (nbt != null) {

           

            // Get Inventory tag

            NBTTagList nbttaglist = nbt.getTagList("Inventory", 10);

           

            // Read into it

            inventory.readFromNBT(nbttaglist);

           

            }

 

 

 

Spawn a Custom NPC with the skin (name) of the player.

- you need a datawatcher to move the skin name over to the client side

- Give the npc the inventory, weapons ect from what you saved above

- on the custom render for the npc look up the skin, you can look up skin with this

 

 

// Get the skin location

texture = new ResourceLocation("skins/" + StringUtils.stripControlCodes(name));

// Download the skin

ThreadDownloadImageData skin = getDownloadImageSkin(texture, name);

 

 

 

Put a timer in the NPC logic for how long you want it to exist.

 

Watch for if someone or something kills it.  If so, erase the players inventory on the server.  To find the players data you can adapt some code I had to move the player out of a deleted dimension.

 

 

public void offlinePlayerDimension_Check() {

   

        // Setup Variables

        String base = "[Player_Manager][offlinePlayerDimension_Check] : ";

        SaveHandler saveHandler = (SaveHandler) DimensionManager.getWorld(0).getSaveHandler();

       

        // Create high level Directory

        File player_directory = new File(saveHandler.getWorldDirectory(), "players");

       

        // Cycle through stored players

        String[] players = saveHandler.getAvailablePlayerDat();

 

        for (String item : players) {

       

            // Get the NBT Data

            NBTTagCompound tag = saveHandler.getPlayerData(item);

           

            // Grab the current dimension

            int current_dimension = tag.getInteger("Dimension");

           

            // Grab the home world

            World world = instance.functions_common().find_world(0);

 

            // If the Dimension does not exists, move the player

            if (!instance.functions_common().dimension_check(current_dimension)) {

           

                // Set to safe dimension

                tag.setInteger("Dimension", 0);

               

                // Set to spawn

                tag.setTag("Pos", this.newDoubleNBTList(new double[] {world.getWorldInfo().getSpawnX(), world.getWorldInfo().getSpawnY() + 1.0d, world.getWorldInfo().getSpawnZ()}));

 

                // Try and save the data

                try {

               

                    // Make a temporary file

                    File file1 = new File(player_directory, item + ".dat.tmp");

                   

                    // Grab the old file

                    File file2 = new File(player_directory, item + ".dat");

                   

                    // Write to the new file

                    CompressedStreamTools.writeCompressed(tag, new FileOutputStream(file1));

 

                    // See if the file exists and remove it

                    if (file2.exists()) {

                   

                        file2.delete();

                       

                    }

 

                    // Move the file name over

                    file1.renameTo(file2);

                   

                    // notify the system

                    instance.logger.warn(base + "Moved player " + item + " from non-Dimension " + current_dimension);

                   

                } catch (Exception e) {

               

                    // notify the system

                    instance.logger.warn(base + "Failed to mov player " + item + " from non-Dimension " + current_dimension);

                   

                }

               

            }

           

        }

       

    }

 

 

Long time Bukkit & Forge Programmer

Happy to try and help

Posted

@diesieben07

"You won't get around making a new entity most likely. In that entity..."

So either I missunderstood or you ment "will" not "won't", doesn't matter - I'll probably get around faking player anyway.

 

@delpi

Problem here is not with loading/saving even not copying data and keeping it. Main thing I am worried is one you didn't place in you post - how to fake EntityPlayer. Ofc thanks for your post :)

 

Spawning an EntityPlayer and putting data from EntityPlayer (clonning) that logged out brought me questions about how it will be handled by game. EntityPlayer is quite an unique object (one per session) which left me with questions about what happens to stuff like playerUUIDs (which is held not-in EntityPlayer) or playerIP.

 

In the end I'll probably just get it done like in "idea 2." and see what happens. If I can't save that data I'll probably use some caching that will be read on rejoin like diesieben suggested.

 

Any further knowledge ofc always appreciated. :)

1.7.10 is no longer supported by forge, you are on your own.

Posted

I did tell you how, read again. 

 

Hint on what to read again "Spawn a Custom NPC with the skin (name) of the player"

 

 

Long time Bukkit & Forge Programmer

Happy to try and help

Posted

If by Custom NPC you mean EntityPlayer then yeah, that's what I'll do.

 

"Im pretty sure the mod Sync uses this aswell"

Love you, checking out Repo right now :)

 

I'll just experiment a bit and post solutions/questions later :)

 

Thanks all.

 

 

1.7.10 is no longer supported by forge, you are on your own.

Posted

By Custom_NPC, i meant Custom_NPC.

 

I've never like the result of making a fake player.  I've found it much easier to create an NPC that will act like a player, stick a nametag above it, and copy the inventory over. 

Long time Bukkit & Forge Programmer

Happy to try and help

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Version 1.19 - Forge 41.0.63 I want to create a wolf entity that I can ride, so far it seems to be working, but the problem is that when I get on the wolf, I can’t control it. I then discovered that the issue is that the server doesn’t detect that I’m riding the wolf, so I’m struggling with synchronization. However, it seems to not be working properly. As I understand it, the server receives the packet but doesn’t register it correctly. I’m a bit new to Java, and I’ll try to provide all the relevant code and prints *The comments and prints are translated by chatgpt since they were originally in Spanish* Thank you very much in advance No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. MountableWolfEntity package com.vals.valscraft.entity; import com.vals.valscraft.network.MountSyncPacket; import com.vals.valscraft.network.NetworkHandler; import net.minecraft.client.Minecraft; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.animal.Wolf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.Entity; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.network.PacketDistributor; public class MountableWolfEntity extends Wolf { private boolean hasSaddle; private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(MountableWolfEntity.class, EntityDataSerializers.BYTE); public MountableWolfEntity(EntityType<? extends Wolf> type, Level level) { super(type, level); this.hasSaddle = false; } @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(DATA_ID_FLAGS, (byte)0); } public static AttributeSupplier.Builder createAttributes() { return Wolf.createAttributes() .add(Attributes.MAX_HEALTH, 20.0) .add(Attributes.MOVEMENT_SPEED, 0.3); } @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); if (itemstack.getItem() == Items.SADDLE && !this.hasSaddle()) { if (!player.isCreative()) { itemstack.shrink(1); } this.setSaddle(true); return InteractionResult.SUCCESS; } else if (!level.isClientSide && this.hasSaddle()) { player.startRiding(this); MountSyncPacket packet = new MountSyncPacket(true); // 'true' means the player is mounted NetworkHandler.CHANNEL.sendToServer(packet); // Ensure the server handles the packet return InteractionResult.SUCCESS; } return InteractionResult.PASS; } @Override public void travel(Vec3 travelVector) { if (this.isVehicle() && this.getControllingPassenger() instanceof Player) { System.out.println("The wolf has a passenger."); System.out.println("The passenger is a player."); Player player = (Player) this.getControllingPassenger(); // Ensure the player is the controller this.setYRot(player.getYRot()); this.yRotO = this.getYRot(); this.setXRot(player.getXRot() * 0.5F); this.setRot(this.getYRot(), this.getXRot()); this.yBodyRot = this.getYRot(); this.yHeadRot = this.yBodyRot; float forward = player.zza; float strafe = player.xxa; if (forward <= 0.0F) { forward *= 0.25F; } this.flyingSpeed = this.getSpeed() * 0.1F; this.setSpeed((float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.5F); this.setDeltaMovement(new Vec3(strafe, travelVector.y, forward).scale(this.getSpeed())); this.calculateEntityAnimation(this, false); } else { // The wolf does not have a passenger or the passenger is not a player System.out.println("No player is mounted, or the passenger is not a player."); super.travel(travelVector); } } public boolean hasSaddle() { return this.hasSaddle; } public void setSaddle(boolean hasSaddle) { this.hasSaddle = hasSaddle; } @Override protected void dropEquipment() { super.dropEquipment(); if (this.hasSaddle()) { this.spawnAtLocation(Items.SADDLE); this.setSaddle(false); } } @SubscribeEvent public static void onServerTick(TickEvent.ServerTickEvent event) { if (event.phase == TickEvent.Phase.START) { MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); if (server != null) { for (ServerPlayer player : server.getPlayerList().getPlayers()) { if (player.isPassenger() && player.getVehicle() instanceof MountableWolfEntity) { MountableWolfEntity wolf = (MountableWolfEntity) player.getVehicle(); System.out.println("Tick: " + player.getName().getString() + " is correctly mounted on " + wolf); } } } } } private boolean lastMountedState = false; @Override public void tick() { super.tick(); if (!this.level.isClientSide) { // Only on the server boolean isMounted = this.isVehicle() && this.getControllingPassenger() instanceof Player; // Only print if the state changed if (isMounted != lastMountedState) { if (isMounted) { Player player = (Player) this.getControllingPassenger(); // Verify the passenger is a player System.out.println("Server: Player " + player.getName().getString() + " is now mounted."); } else { System.out.println("Server: The wolf no longer has a passenger."); } lastMountedState = isMounted; } } } @Override public void addPassenger(Entity passenger) { super.addPassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(true)); } } } @Override public void removePassenger(Entity passenger) { super.removePassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is no longer mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(false)); } } } @Override public boolean isControlledByLocalInstance() { Entity entity = this.getControllingPassenger(); return entity instanceof Player; } @Override public void positionRider(Entity passenger) { if (this.hasPassenger(passenger)) { double xOffset = Math.cos(Math.toRadians(this.getYRot() + 90)) * 0.4; double zOffset = Math.sin(Math.toRadians(this.getYRot() + 90)) * 0.4; passenger.setPos(this.getX() + xOffset, this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset(), this.getZ() + zOffset); } } } MountSyncPacket package com.vals.valscraft.network; import com.vals.valscraft.entity.MountableWolfEntity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class MountSyncPacket { private final boolean isMounted; public MountSyncPacket(boolean isMounted) { this.isMounted = isMounted; } public void encode(FriendlyByteBuf buffer) { buffer.writeBoolean(isMounted); } public static MountSyncPacket decode(FriendlyByteBuf buffer) { return new MountSyncPacket(buffer.readBoolean()); } public void handle(NetworkEvent.Context context) { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); // Get the player from the context if (player != null) { // Verifies if the player has dismounted if (!isMounted) { Entity vehicle = player.getVehicle(); if (vehicle instanceof MountableWolfEntity wolf) { // Logic to remove the player as a passenger wolf.removePassenger(player); System.out.println("Server: Player " + player.getName().getString() + " is no longer mounted."); } } } }); context.setPacketHandled(true); // Marks the packet as handled } } networkHandler package com.vals.valscraft.network; import com.vals.valscraft.valscraft; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class NetworkHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel( new ResourceLocation(valscraft.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); public static void init() { int packetId = 0; // Register the mount synchronization packet CHANNEL.registerMessage( packetId++, MountSyncPacket.class, MountSyncPacket::encode, MountSyncPacket::decode, (msg, context) -> msg.handle(context.get()) // Get the context with context.get() ); } }  
    • Do you use features of inventory profiles next (ipnext) or is there a change without it?
    • Remove rubidium - you are already using embeddium, which is a fork of rubidium
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.