Jump to content

Recommended Posts

Posted

I have my work-space set up like in mr.crayfish's playlist on youtube here: https://www.youtube.com/watch?v=0ULz-oCUbEg&list=PLy11IosblXIExa6zzhjhYNXeBW9o6FhPU

 

now, here's my idea that i have no idea how to even start coding, asside from a vague idea how to create blocks that do nothing:

 

Basically i want there to be a type of block called "obduction seeds". yes, i spelled obduction that way intentionally, as this idea is inspired by the game with a name of the same spelling. basically heres what i want the blocks to do:

 

each block has a GUI that pops up allowing the player to type in a number ID and a radios for that block, but only in survival or creative mode. only 2 blocks can have the same number id, after that it is not possible for the player to assign the same id to additional blocks. 

 

when either one is activated by redstone, 2 blocks of the same id will "swap" with each-other, along with a spherical radios of blocks and entities around them. 

 

to explain further, suppose that there is a block on the mountain and a block  next to a wall in a building. when one of them is activated and they swap, not only do the 2 blocks switch places but now the spherical radios around them has too- so a spherical part of the mountain is now in the place where that wall in the building was, and meanwhile a spherical cut-out of the building is where that part of the mountain was. does that make sense...?

 

if your confused, take a look at cyan worlds' game, obduction, that this is inspired by.

 

another block i want to possibly add is a small pedestal that sends a redstone signal to the block on top of it when right-clicked in any game mode. this would be for the seeds to be placed on top of.

Posted

You'll have to use a TileEntity for this. TileEntities exists inside of blocks and allow the block to do stuff. (Furnace, chest, Sign etc are TileEntities)

(Blocks(and items) are Singletons, meaning there is only 1 of each, with each placed block/itemstack holding a representation of them. If you store any data, or change anything in one, the same thing will happen to every other block/item)

 

Store the id/channel in each TileEntity. Preferably with a 0 or -1 id when placed initially, and this id won't allow the teleportation/switch.

Don't allow a new id to be assigned if there already exists 2 or more TileEntities with that id. (You don't want 3 or 745 of these to switch with eachother)

The radius has to be the same as well, otherwise you'll get a small sphere floating in a crater on one side, and the opposite on the other, which will overwrite blocks, destroying them.

 

Scan the surrounding areas twice; Once to store the blockstates, and a second time to store any other TileEntities in the area.

Do this for both TileEntities.

 

Once everything is done, have the tiles send the arrays/lists of blockstates & tileentities, have your tiles set the blockstates & tiles that they got, in the same way you scanned them (so a furnace placed to the north of your first tile gets placed to the north of your second tile)

 

 

One more thing: Please find a different tutorial. Mr.Crayfish's tutorials are quite outdated when it comes to registration & rendering of blocks/items. A large majority of the "why isn't [Thing] rendering!?" threads here stem from people using his tutorials.

(Don't call Minecraft::register, use ModelLoader. Register models and content in ModelRegistryEvent and RegistryEvent respectively etc)

Also previously known as eAndPi.

"Pi, is there a station coming up where we can board your train of thought?" -Kronnn

Published Mods: Underworld

Handy links: Vic_'s Forge events Own WIP Tutorials.

Posted

thanks. Now that i know what to do, how do i do it?

 

I have more experience with unity C# than i do with minecraft java. and limited at that...

 

some more questions i have: how do i set up the ui so that the user can put the id in? how would i make it so that the radius is per-id-number and not per-tileent? how do i scan blocks to put them into an array?

Posted
5 minutes ago, Bluethefox said:

thanks. Now that i know what to do, how do i do it?

 

I have more experience with unity C# than i do with minecraft java. and limited at that...

You should make sure you have a solid basic understanding of Java before trying to make a mod, otherwise you'll get stuck very quickly, and people on this forum generally have very little patience for helping people with Java knowledge.

 

5 minutes ago, Bluethefox said:

some more questions i have: how do i set up the ui so that the user can put the id in?

You'll need to create a GUI class, register a GUI handler and open it when the block is activated. Look at vanilla GUI classes (e.g. command blocks) to see how they work.

5 minutes ago, Bluethefox said:

how would i make it so that the radius is per-id-number and not per-tileent?

You just need to check that the radius is the same in both TEs before confirming the swap.

5 minutes ago, Bluethefox said:

how do i scan blocks to put them into an array?

World#getBlockState(pos) returns the IBlockState at the given position. Then you can store these in whatever way is easiest.

Posted
42 minutes ago, Jay Avery said:

You should make sure you have a solid basic understanding of Java before trying to make a mod, otherwise you'll get stuck very quickly, and people on this forum generally have very little patience for helping people with Java knowledge.

A solid understanding of an object oriented language is enough, really.  Be that C#, Java, or something else.  As long as you can work out what code to write in a language it's easy to figure out how to translate that into the language you're working in.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted (edited)
16 hours ago, Bluethefox said:

each block has a GUI that pops up allowing the player to type in a number ID and a radios

I didn't understand this at first... You want the word "radius". Radios are wireless communication devices.

 

Don't worry about matching the radius when setting it in the GUI. All you need is for the radius of a swap to be determined by the seed that was triggered (so if a matched pair of seeds have unequal radius settings, the radius in the triggered block is the radius used at both ends).

 

In fact, you don't even need to set the radius in a GUI. If you want, you could just use the redstone signal strength that triggers the swap.

 

Your tile entity is going to be tricky. If you choose an ID for a seed, then it must somehow detect whether there are already two seeds with that ID, even if they might be in chunks (and dimensions) that are not currently loaded. Therefore, you will probably need an obduction ID list in dimension or game level data.

 

You need to decide whether to make the IDs unique to each game-world or only unique within each dimension. I recommend treating dimensions separately.

 

When an ID search is complete, if exactly one seed is matched, then each seed's TE should store info (e.g. location) about the other so the search need not be repeated. Pointers can't be trusted because chunks might not remain loaded.

 

Decide what to do if a piston tries to move a seed. Likewise breaking.

 

Don't allow the swap to move/replace bedrock. There may be other perils,  so you will probably want to loop all positions around your swapping seeds, testing the block at each end of each potential swap before swapping them.

 

Ironically, you won't want or need to swap the seeds themselves (think about it).

 

Write as much of this mod as you can using pseudo-code. Then replace as much pseudo-code with Java as you can do yourself. Then search for prior threads on each unknown Forge concept in turn, teaching yourself how to do new things. Also use the full power of your IDE. You should be able to teleport into vanilla classes to see what they require. You should also be able to hunt down vanilla examples of how to accomplish many of the actions you want to do.

 

Finally, come back to this forum when you are stuck on all fronts (can't find a thread that has asked and answered your question before). Start a fresh thread for each Forge concept, and use an informative subject line (including MC version number) so future modders can find it when they have the same question.

 

Edited by jeffryfisher

The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

Posted

As someone who's previously teleported chunks of the world around before, there are a few things you might want to build in to avoid potential problems.

 

Even though you use the setBlockState method that doesn't update neighbors, you might still find that redstone, rails, torches, etc. pop off their surface during the teleport.  There's probably no reliable way to avoid this, and you're going in both directions.  But a few things that might work, or at least help:

  • Try putting the chunk ("the bits you're moving") into a safe middle-space before doing the replacement.  This allows you to make sure that things copy over correctly as you have a non-destructive process (i.e. you can compare the original arrangement after copying).  I recommend a custom dimension, all it needs to do is act as a clipboard.  Put both chunks there, verify integrity, fix as needed, then copy them to their destinations, verify integrity again (this time from the clean copy in the clipboard dimension), fix as needed.
  • Iterate over the area and place blocks by calling canPlaceBlockAt(...) and only placing it if it can go there. This will get all the solid self-supporting blocks first. Then follow up with the remainder. There is no order you can read/write in and avoid having to do this (as torches can attach to any side except underneath).
    • You might still have problems with blocks like doors, tall grass, and falling blocks
  • After pasting blocks into their destination (e.g. the clip board dimension), check for any dropped item entities. If there are any, delete them and validate the copied area with its source. As you haven't copied any entities yet, there shouldn't be any.
  • Do TileEntities last, you'll want to copy the TE data from the source to the destination. Be aware that readFromNBT and writeToNBT encode the TE's position as well, and you don't want to copy that. You may have to manually edit the TE's data.  BE AWARE THAT SOME MOD TEs MAY NOT TAKE KINDLY TO BEING MOVED eg any TEs that assume they're part of a network: by moving them and maintaining that data they might not work correctly (I've seen people do things like "this is a village center block, it keeps track of who owns the village and therefor who can edit blocks" which when you move that TE it's now in a different location than where it thinks it should be).
  • Don't copy entities. Teleport them.  You don't need to shove them into the clipboard dimension, just swap both sets over to the new locations.
  • Restrict how big of an area you'll allow to be teleported. The upper-limit is probably still pretty big (e.g. radius of 32-64) but the more blocks you're moving the longer it'll take, and you really don't want to take more than a few ms, as spreading the process over multiple ticks will cause problems (entities will move, blockstates can update, etc.)

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted
15 minutes ago, Draco18s said:

BE AWARE THAT SOME MOD TEs MAY NOT TAKE KINDLY TO BEING MOVED eg any TEs that assume they're part of a network: by moving them and maintaining that data they might not work correctly (I've seen people do things like "this is a village center block, it keeps track of who owns the village and therefor who can edit blocks" which when you move that TE it's now in a different location than where it thinks it should be).

At some point its best to add a config file which lists Blocks which shouldn't be moved (Or which blocks can stop the "teleport" process from happening). Which lets players get around the issue. Your guaranteed to have at least 1 mod out there which will crash when you try and move its block as they will never add certain checks like if the block they are communicating with is actually still in that spot.

Posted

I probably should have added that you should develop your idea for this complex mod as a background task while doing a basic "beginner mod" to learn Forge first. Maybe create a new kind of block, successfully put a texture on it, and put its ItemBlock into the creative-mode menu. It could even become your seed block later. You just need to get a grip on the basics before adding complications.

The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

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

    • It is 1.12.2 - I have no idea if there is a 1.12 pack
    • Okay, but does the modpack works with 1.12 or just with 1.12.2, because I need the Forge client specifically for Minecraft 1.12, not 1.12.2
    • 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() ); } }  
  • Topics

×
×
  • Create New...

Important Information

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