Jump to content

Create mod that exposes subset of Forge through an IPC/RPC API?


LuciferK9

Recommended Posts

I just started playing minecraft after a few years of not playing anymore, so I don't know much about Forge. Sorry for my ignorance in advance.

 

I was thinking about a mod that exposes an API to allow players to create a "mod" in any programming language (I'm going to refer to these "mods" as "xmods" to differentiate them from forge mods). Not the full Forge's API, just a subset of it, like events, or anything that can be exposed.

 

Basically, the mod would receive messages from xmods and do whatever they say and send messages to them telling them whatever it is happening in the minecraft world.

 

I haven't thought about the specific details of the implementation, but for the messages we could use something like protobuf or flatbuffers, this way we could specificate the schema for the API and use it in different languages easily. The communication could be over TCP, or maybe the mod could spawn the xmods in child processes and communicate over stdin/stdout.

 

The schema could look something like:

message CommonEntityProps {
	Vector3 coordinates;
	int32 life;
	...
}

message ServerEvent {
	optional PlayerPlacedBlockEvent player_placed_block = 1;
	...
}

message Entity {
	...
}

message Player {
	required CommonEntityProps common;
	...
}

message Block {
	required Vector3 coordinates;
	required BlockType type;
	...
}

message PlayerPlacedBlockEvent {
	required Player player;
	required Block block;
	...
}

 

This is not supposed to be a replacement to mods. Just a way to easily create custom content without having to download and learn forge and without the trouble that java brings (for people that don't like it).

 

Maybe someone has an idea and needs to quickly make a prototype and they decide to use python or javascript, just to test it and have fun in single player or lan with friends.

 

This would also allow to create, automatize and invent new stuff very quickly. Imagine a player trying to build a giant pyramid where every 3 blocks there is a diamond block or something, this could be easily created in a script with less than 10 lines of code, and when you get to the top, you get burn because there's a god punishing you.

 

Yesterday I was trying to create a basic game mode where you have to throw a player out of a platform, kill the player automatically if they're below an Y coordinate, and give them full armor and custom items after they respawn, I had problems making it with just command blocks. I would've liked to use some if statements but could not afford setting up forge, read the documentation, and probably download intellij because from what I remember, it's a pain in the *** to code java in something like vim or any other editor that is not an IDE.

 

Some code in Rust on how I would like this to look like:

use forge_xmod::{
    Client, Event,
    player::{ Player, Inventory },
    minecraft::{ Enchantment, Item },
};

fn main() {
    let client = Client::connect("127.0.0.1:9999");

    loop {
        while let Some(event) = client.poll_event() {
            match event {
                Event::PlayerPlacedBlock(player, block) => {
                    println!("The player {} placed a block ({}) on: {}", player, block, block.coordinates);
                },
                Event::PlayerMoved(player) => {
                    if player.coordinates.y < 50 {
                        // this would send a TCP? packet, telling the mod to kill said player. Serialized with protobuf?
                        player.kill();
                    }
                },
            }
        }
        for player in client.players() {
            if !player.inventory.contains(Item::DiamondSword) {
                let mut item = Item::DiamondSword;
                item.enchant(Enchantment::Sharpness, 4);
                player.inventory.insert(item); // send packet
            }
        }
    }
}

I could just then compile it, run it and it would already work. Other person could do the same in JavaScript, C++, etc.

 

I want to read your opinions and see if anyone is interested in working on something like this. As I said, I don't know much about Forge, so I would like some help since I plan to make this anyways, at least to fit my needs. I would help to find where the main Forge APIs are located to see if I can generate the schema programatically.

Edited by LuciferK9
Minor edit
Link to comment
Share on other sites

Java is pretty easy with intelliJ really. Also lex has said in the past he's not including other languages in forge. Forge is for java. If you need another language lib / cross compatability, you best make your own in java. 

 

At that point honestly just write it in java. Or Kotlin / Scala etc which have their libs you can include and run on JVM bytecode. Better then having to bog things down with cross language stuff.  Writing using intelliJ is easy. You can write without, i used to write C# in notepad++ to be frank and it never bothered me much, just got to check them compile errors and your code is trash and slow because you have no IDE assists.

Java is honestly one of the easier OO languages. Less to worry about then say C++ etc. or any of the big languages, Rust is trying to replace C++ along with Golang and Dlang so it in theory would be quite more low level the java but honestly out of the 4, i'd probably be more inclined to learn D / Go if i had to. Either way point is i don't really like rust and have never really learned it so i could be off the mark on how easy it is to learn but when it's trying to replace C++ you would assume it would be more low level. 

Edited by ShinyAfro
Link to comment
Share on other sites

5 hours ago, ShinyAfro said:

Java is pretty easy with intelliJ really. Also lex has said in the past he's not including other languages in forge. Forge is for java. If you need another language lib / cross compatability, you best make your own in java.

I know Java is easy with intelliJ, the post was not about java being difficult, was about just wanting to code in a better language. I wasn't asking to include compatibility in Forge with another language, I was talking about creating a mod that exposes the API through RPC/IPC. It's not a feature request, that's why it's here in general discussion.

 

5 hours ago, ShinyAfro said:

At that point honestly just write it in java. Or Kotlin / Scala etc which have their libs you can include and run on JVM bytecode. Better then having to bog things down with cross language stuff.  Writing using intelliJ is easy. You can write without, i used to write C# in notepad++ to be frank and it never bothered me much, just got to check them compile errors and your code is trash and slow because you have no IDE assists.

I don't think a language should depend on an IDE. The only language (that I know) that lacks command line tools is java. Even C# with .NET Core already has better tooling that allows people to write code efficiently without using a full IDE.

 

5 hours ago, ShinyAfro said:

Java is honestly one of the easier OO languages. Less to worry about then say C++ etc. or any of the big languages, Rust is trying to replace C++ along with Golang and Dlang so it in theory would be quite more low level the java but honestly out of the 4, i'd probably be more inclined to learn D / Go if i had to. Either way point is i don't really like rust and have never really learned it so i could be off the mark on how easy it is to learn but when it's trying to replace C++ you would assume it would be more low level. 

D, GoLang, Rust and modern C++ are just as easy as java. But using these languages you have a set of features that you can opt-in if you want to write lower-level code or make some hand-crafted optimizations.

Link to comment
Share on other sites

Personally, this is probably not necessary.

This would means that the developer need to write a hook in all the said languages to expose the Forge API. This of course includes the circumvention of non dynamically loadable languages like C++. Unless you meant to parse the said languages into a intermediate form (which probably require more effort, as a compiler is needed), which is then loaded by the "xmod", but this would make the user unable to access Minecraft and Forge with reflection and ASM.

 

18 hours ago, LuciferK9 said:

The only language (that I know) that lacks command line tools is java.

You can compile and run Java code from the command line. However, writing Java (and most other static languages) without an IDE would be a pain and is not recommended.

Some tips:

Spoiler

Modder Support:

Spoiler

1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code.

2. Always post your code.

3. Never copy and paste code. You won't learn anything from doing that.

4. 

Quote

Programming via Eclipse's hotfixes will get you nowhere

5. Learn to use your IDE, especially the debugger.

6.

Quote

The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it.

Support & Bug Reports:

Spoiler

1. Read the EAQ before asking for help. Remember to provide the appropriate log(s).

2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.

 

 

Link to comment
Share on other sites

On 9/11/2019 at 2:48 AM, LuciferK9 said:

I know Java is easy with intelliJ, the post was not about java being difficult, was about just wanting to code in a better language. I wasn't asking to include compatibility in Forge with another language, I was talking about creating a mod that exposes the API through RPC/IPC. It's not a feature request, that's why it's here in general discussion.

 

I don't think a language should depend on an IDE. The only language (that I know) that lacks command line tools is java. Even C# with .NET Core already has better tooling that allows people to write code efficiently without using a full IDE.

 

D, GoLang, Rust and modern C++ are just as easy as java. But using these languages you have a set of features that you can opt-in if you want to write lower-level code or make some hand-crafted optimizations.

Well a little while ago there was a bunch of hackers on the 1.7.10 mods and i noticed a few mods used RPC from netty to execute java bytecode. You might want to look into that if you want to make a mod for any language you want to make some sort of library.

 

And hell yes i have written C# in a text editor and you can do the same with java, I just don't see the why when said tools greatly accelerate my workflow. Eclipse is another good editor.

 

Link to comment
Share on other sites

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

    • This is now replaced in the latest version, under Advanced Settings. Not available under the registry anymore.
    • You have to set the java path in your start script
    • i tried that and i got rid of java to install the new one but it still says i have the old one and i cant get the new one because of the old one  
    • I created a boss for Minecraft and when is it called «An unexpected error occurred while trying to run this command» "net.minecraft.world.entity.ai.attributes.attribute instance.m_22100_ (double)" because the return value "net.minecraft.world.entity.monster.zombie.m_21051_(net.minecraft.world.entity.ai.attributes.attribute)" is null. I don't fully understand what the error is. But it seems to be related to attributes. Please help me figure it out   Here is the boss class itself: package org.mymod.afraid; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.goal.*; import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; import net.minecraft.world.entity.monster.Zombie; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.phys.Vec3; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.entity.projectile.SmallFireball; import org.jetbrains.annotations.NotNull; public class AfraidBoss extends Zombie { private static final int MAX_HEALTH = 1000; private static final double ATTACK_DAMAGE = 10.0D; private static final double FOLLOW_RANGE = 50.0D; private static final double ATTACK_KNOCKBACK = 1.0D; private static final double MOVEMENT_SPEED = 0.25D; private static final int TELEPORT_RADIUS = 20; private static final int FIREBALL_COOLDOWN = 100; // 5 seconds (20 ticks per second) private static final int FIREBALL_COUNT = 3; private int fireballCooldown = 0; private int fireDashCooldown = 0; public AfraidBoss(EntityType<? extends Zombie> type, Level level) { super(type, level); this.setHealth(MAX_HEALTH); this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.DIAMOND_SWORD)); this.setItemSlot(EquipmentSlot.OFFHAND, new ItemStack(Items.DIAMOND_SWORD)); } @Override protected void registerGoals() { this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0, true)); this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 1.0, (float) TELEPORT_RADIUS)); this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(4, new WaterAvoidingRandomStrollGoal(this, 1.0)); this.goalSelector.addGoal(5, new HurtByTargetGoal(this)); this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, true)); } @Override public void aiStep() { super.aiStep(); if (this.getTarget() instanceof Player) { Player player = (Player) this.getTarget(); double distanceToPlayer = this.distanceToSqr(player); // Fire Dash ability if (distanceToPlayer <= TELEPORT_RADIUS * TELEPORT_RADIUS && fireDashCooldown == 0) { this.fireDash(player); fireDashCooldown = 200; // Cooldown for fire dash (10 seconds) } // Fireball attack if (fireballCooldown == 0) { this.shootFireballs(player); fireballCooldown = FIREBALL_COOLDOWN; // Cooldown for fireball attack (5 seconds) } // Decrement cooldowns if (fireDashCooldown > 0) { fireDashCooldown--; } if (fireballCooldown > 0) { fireballCooldown--; } } } private void fireDash(Player player) { Vec3 direction = player.position().subtract(this.position()).normalize(); Vec3 newPos = this.position().add(direction.scale(10)); this.teleportTo(newPos.x, newPos.y, newPos.z); this.createFireTrail(newPos); player.hurt(DamageSource.mobAttack(this), 20.0F); // Damage the player } private void createFireTrail(Vec3 position) { for (int x = -2; x <= 2; x++) { for (int z = -2; z <= 2; z++) { BlockPos firePos = new BlockPos(position.x + x, position.y, position.z + z); this.level.setBlock(firePos, Blocks.FIRE.defaultBlockState(), 11); } } } private void shootFireballs(Player player) { Vec3 direction = player.position().subtract(this.position()).normalize(); for (int i = 0; i < FIREBALL_COUNT; i++) { SmallFireball fireball = new SmallFireball(this.level, this, direction.x, direction.y, direction.z); fireball.setPos(this.getX() + direction.x, this.getY() + direction.y, this.getZ() + direction.z); this.level.addFreshEntity(fireball); } } public static AttributeSupplier.Builder createAttributes() { return Zombie.createMobAttributes() .add(Attributes.MAX_HEALTH, MAX_HEALTH) .add(Attributes.ATTACK_DAMAGE, ATTACK_DAMAGE) .add(Attributes.FOLLOW_RANGE, FOLLOW_RANGE) .add(Attributes.ATTACK_KNOCKBACK, ATTACK_KNOCKBACK) .add(Attributes.MOVEMENT_SPEED, MOVEMENT_SPEED); } @Override public boolean hurt(@NotNull DamageSource source, float amount) { boolean flag = super.hurt(source, amount); if (flag && source.getEntity() instanceof Player) { Player player = (Player) source.getEntity(); if (this.random.nextInt(10) == 0) { this.teleportAndAttack(player); } } return flag; } private void teleportAndAttack(Player player) { Vec3 randomPos = player.position().add((this.random.nextDouble() - 0.5) * 4, 0, (this.random.nextDouble() - 0.5) * 4); if (this.randomTeleport(randomPos.x, randomPos.y, randomPos.z, true)) { player.hurt(DamageSource.mobAttack(this), 10.0F); // Damage the player } } }  
  • Topics

×
×
  • Create New...

Important Information

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