Jump to content

Recommended Posts

Posted

Started modding Minecraft a few weeks ago, doing good but simple, but i can't seem to find any api documentation of the classes, hooks, endpoints, enums, etc. Lots of tutorial lingering the world but no documentation it seems.

 

I'm kinda tired reading tutorials that say copy and paste this, do that and it'll work... I want to understand what i am doing and not listen to 13 videos to know how to do a custom furnace with a person that doesn't even seem to know what he's doing!

 

So where is that documentation?

Posted

So... Your asking for minecrafts documentation? Have fun with that. I wish you luck. Forges documentation on the other hand... Have you looked into Javadocs? Specifically the forge ones?

 

If you want to understand the what you are doing, start reading. Go up through the classes reading what method calls and this and what does this do etc.. It takes a lot of work and effort, but its worth it.

We all stuff up sometimes... But I seem to be at the bottom of that pot.

Posted

Hi

 

There isn't much around to be honest.  Some of the Forge documentation is really good, some of it... isn't.

 

I have put together some things myself about how vanilla works, enough to help folks get a grasp of the basic concepts and how the various bits hang together, but isn't not comprehensive by any stretch (and it's currently based on 1.6.4, which is a bit different to 1.7.2 sometimes).

 

http://greyminecraftcoder.blogspot.com.au/p/list-of-topics.html

 

Most of the time, I find a useful strategy is

1) think of a vanilla object that does similar to what I want

2) look at the code, flip back and forth until I figure out how it works (can sometime take a while!) and then test it myself.

 

-TGG

 

Posted

I'll need to check out your docs, but right off the start, it looks good. At least, that's some documentation.

 

Looking at the javadoc comments and interpretting obfuscated source code... that has to be even less efficient than watching 15h of video tutorial about someone trying to do something and not knowing how to explain and do it :P

Posted
Looking at the javadoc comments and interpretting obfuscated source code... that has to be even less efficient than watching 15h of video tutorial about someone trying to do something and not knowing how to explain and do it :P

 

@crazycodr, I think you have to understand what Minecraft modding is.  Minecraft was not really meant to be modded -- so Mojang does not document and in fact obfuscates their code.  So any modding has to essentially be reverse engineered by the community of interested modders.  The people that are reverse engineering it are (as far as I know) essentially a volunteer group that is painstakingly tracing the undocumented result of decompilation and creating mapping to human-readable method and field names and adding comments to the code.  Then there is FML and Forge, which again are volunteer group adding hooks to the code to make it easier to intercept and interact with the vanilla code.

 

The key here is that this is volunteer community.  So the work is incomplete and inconsistent, and even buggy at times.  There are some functions that are well understood and named well and documented well, and there are others that are still called something like f_423435_a() with no documentation at all.  I've found bugs where things are mis-named, sometimes dangerously (i.e. the logic is backwards).

 

Lastly, every time Mojang does a major update the entire process has to be done over again.  That is why there are only a couple supported versions of Forge (common are 1.6.4 and 1.7.2) and frankly 1.7.2 is still a work in progress (although it is pretty useable now).

 

Basically I'm saying you're asking for too much.  There is no commercial company providing this, there are several different contributors that are loosely working together, and it is still a work in progress.

 

So the best way to learn it is simply to follow the decompiled source provided and put that together with your knowledge of Minecraft (like if you see code that treats an anvil differently, you should know that is because an anvil is different in behavior in Minecraft) and get hints from tutorials.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Give that man a jar of cookies for that answer.

 

Thank you for explaining that Jabelar, but i still think, for the good of the whole minecraft modding community, there should be a documentation effort put in place. It would help all modders get the best of Forge and Minecraft... Yes, the work has to be done again on each new supported version but hey, the code can move, but it's not a whole new version each time, some principles stay, some change. So creating a multi-version documentation shouldn't be too hard.

 

If you think at how much time is put all around the web at people creating countless video tutorials, text tutorials and then all the work put into the forums to help each other, i'm sure it possible to convert a bit of that into a documentation base that can be reused over time.

 

I actually like documenting a lot, and if there is support from the community, i wouldn't mind putting my efforts into documenting Forge, FML and Minecraft along with directing a small team of dedicated people that want to make this possible.

 

What would be the best way to launch this initiative in your opinion?

Posted

I like documentation too.  That is why I've been trying to write a number of text tutorials that actually explain (rather than just give example).

 

Since it is a really big project and I assume you'd want to allow multiple contributors, I think wiki format would be suitable.  But I think the problem is still the format of the information.  Do you want this to just be a simple API documentation where every public method is explained? 

 

The question then is what the level of explanation is.  For example, listing methods and parameter types isn't much more useful than the code itself in my opinion.  That is why I've been concentrating on tutorials -- they may be haphazard in terms of topics covered, but when they cover a topic a tutorial give a lot of explanation that is difficult to document except in the context of trying to implement something specific.

 

Anyway, can you give an example of what kind of documentation you're really interested in providing/collecting?

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

I think that documentation must always focus on 3 aspects:

 

- Concepts : They explain the general item of something or a group of things. For example, a really important aspect to conceptualize in minecraft is the concept of Items and Blocks. It's the first thing a modder will want to do and the first thing that every modder should know how to handle.

 

- Tutorials : They explain how to achieve something. Direct links from the concept pages would link to those tutorials. So, how to do your custom "furnace" or "crusher" or "mechanical block", how to create blocks with adaptive structure (block lookups), etc.

 

- Reference : Listing of the different classes and parameters using a javadoc analyser to extract that information. Someone that doesn't know where to look in the code is bound to look for a long time. A well defined wiki with a search engine is always faster to find what you are looking for. User comments, examples, links to corresponding tutorials maybe, etc.

 

The documentation would use a Wiki approach for sure, we need to make version branches so we can keep the whole documentation for each version change. I think documentation should not be open to all, but thats me, i think it's a collective decision of all the initial writters that has to be taken into account.

 

What do you think?

Posted

I found something interresting this morning that can simplify our work greatly and promote easier collaboration on the documentation aspect of Forge and Minecraft.

 

First of all, I love Markdown as a documentation language. Is it very similar to most wiki language but just better and it's pretty much a standard now in community based projects due to GitHub's adoption of it. GitHub flavored markdown is even better at this and there are libraries to parse github flavored markdown and render it to HTML.

 

How i see the reference being built is by generating a markdown documentation using a javadoc scanner and you push the changes to a GitHub profile. The rest of the documentation can simply be another folder in the doc, one for tutorials and one for concepts. So you'd have folders like :

 

  • 1.6.4
    • Concepts
    • Tutorials
    • Reference

     

    [*]1.7.2

    • Concepts
    • Tutorials
    • Reference

 

People can fork the documentation and issue pull requests to update the documentation... Makes it simpler to review changes and promotes community work. And then, we could have a server that check's out the documentation from GitHub and use "http://parsedown.org/" to render it to HTML and get it styled easily.

 

What do you think?

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.