Jump to content

Recommended Posts

Posted

Hi there!

It is my first question in this forum, so excuse me if I ask very basic questions. And I don't have a very good English, so forgive me for that too.

I am developing a mod (my first mod, have not experience in mc modding but have it in java programming). My mod is a Pyromaniac mod. I'll explain: the user executes a command (/pyro start) and clicks on some blocks. When finished executes '/pyro stop', and finally executes '/pyro fire' to start all fires at the same time.

Ok. No problem with the commands, they work fine:

  Quote

public class PyroCommand {
    
    private static final Logger LOGGER = LogManager.getLogger();
    private PyromaniacMod pyro;
    

    public void register(CommandDispatcher<CommandSourceStack> dispatcher) {
        LiteralArgumentBuilder<CommandSourceStack> PyroCommand = Commands.literal("pyro");
        PyroCommand.then(Commands.literal("start").executes((caca)->{return start();
        }));
        PyroCommand.then(Commands.literal("stop").executes((caca)->{return stop();
        }));
        PyroCommand.then(Commands.literal("fire").executes((caca)->{return fire();
        }));

        dispatcher.register(PyroCommand);
      }
    
    private int start() {
        this.pyro.start();
        return 1;
    }
    
    private int stop() {
        this.pyro.stop();
        return 1;
    }
    
    private int fire() {
        this.pyro.fire();
        return 1;
    }

    public PyromaniacMod getPyro() {
        return pyro;
    }

    public void setPyro(PyromaniacMod pyro) {
        this.pyro = pyro;
    }

Expand  

 The problem comes when setting the fire blocks. In this test version, all fires start in the .above() block of the targeted position. I can see how fires start, but they don't interact with their fireable neightbours, and nothing of I have done is being saved. I know (or I think I know xD) that the problem is because I am not updating both sides correctly. Could you help me in doing that? Here is my extremely naïve fire function in the PyromaniacMod class:

  Quote

 public void fire() {
        player = Minecraft.getInstance().player;
        Level level = Minecraft.getInstance().level;   
        
        if(!this.readyToFire) {
            player.sendMessage(new TextComponent("[Pyro] Run '/pyro fire' again to start the magic."), null);
            this.readyToFire = true;
            return;
        }else {
            player.sendMessage(new TextComponent("[Pyro] Firing. Muuaaaahahahahahaha :D"), null);
            
            for(BlockPos pos:blocs) {
               
                try {                   
                    //level.setBlock(pos.above(), Blocks.FIRE.defaultBlockState(), 3);
                    level.setBlockAndUpdate(pos.above(), Blocks.FIRE.defaultBlockState());
                }catch(Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

Expand  

Tell me if you need any more code part. And be nice, please ;).

Thaaaaaanks!

Posted
  On 3/3/2022 at 3:09 PM, diesieben07 said:

You are reaching across logical sides. Commands run server side (at least by default, and that is correct here), but this is accessing stuff that is client side. You must use the player from the command context and its level.

Expand  

Ok. Understood. Now I am saving the player who rightclicks the blocks to fire and finally it works :D. I'm sure there are other things that I'm doing the worst way, but it is easier to learn from a working code xD.

  On 3/3/2022 at 3:09 PM, diesieben07 said:

This is not how you handle exceptions, ever.

Expand  

I used this as a java standard way of seeing what is crashing. Can you link me some documentation about mc forge exceptions handling?

Thanks!

Posted
  On 3/3/2022 at 5:28 PM, baku said:

Ok. Understood. Now I am saving the player who rightclicks the blocks to fire and finally it works :D. I'm sure there are other things that I'm doing the worst way, but it is easier to learn from a working code xD.

I used this as a java standard way of seeing what is crashing. Can you link me some documentation about mc forge exceptions handling?

Thanks!

Expand  

the idea is to do checks instead of using a trycatch.

an if statement testing if pos is an air block with a sub check to avoid waterlog / fluid (lava/lava) sources around the targeted block to place the fire would be the way to avoid any problems.   

Minecraft can handle derpy fire (like spawning in mid air & just vanishing after the fact), but being over/near fluid sources can lead to stupidity with how things interact. 

  • Like 1
Posted (edited)

Finally I have a first complete version of the mod. Here are all my classes for if someone considers them useful. I also add some questions below about how to improve it. Here it goes :D

  Quote

// MAIN MOD CLASS


@Mod("pyromaniac")
public class PyromaniacMod
{

    public PyromaniacMod() {
               
        MinecraftForge.EVENT_BUS.register(this);
        
//        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onRegisterCapabilities);
        FMLJavaModLoadingContext.get().getModEventBus().addListener(PyroCapability::register);
        
        MinecraftForge.EVENT_BUS.register(PyroCapabilityAttacher.class);
        
    }
    
    @SubscribeEvent
    public void onCommandsRegister(RegisterCommandsEvent event) {
        
        CommandDispatcher<CommandSourceStack> commandDispatcher = event.getDispatcher();
      
        PyroCommand pyroCommand = new PyroCommand();
        
        pyroCommand.register(commandDispatcher);
        
      
    }   
    
    @SubscribeEvent
    public void onPlayerRightClickBlock(PlayerInteractEvent.RightClickBlock event){
        
        if(PyroCapability.PYRO.isRegistered()) {
            PyroCapabilityInterface pyro = event.getPlayer().getCapability(PyroCapability.PYRO).orElse(null);
            if(pyro.isRunning()) {
                LOGGER.info("Click!");
                event.setCanceled(true);
                
                BlockPos pos = event.getPos();
                Direction dir = event.getFace();
                Player p = event.getPlayer();
                Level l = event.getWorld();
                
                Objectiu obj = new Objectiu(l, p, pos, dir);
                
                if(!pyro.hasObjectiu(obj)) {
                    pyro.addObjectiu(obj);
                    LOGGER.info(pos.toShortString());
                    LOGGER.info(dir.toString());
                }
            }
        }
    }
    
}

Expand  
  Quote

//CUSTOM COMMAND CLASS

public class PyroCommand {
    
    public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
        
        dispatcher.register(Commands.literal("pyro")
            .then(Commands.literal("start")
                    .executes(PyroCommand::start))
            .then(Commands.literal("stop")
                    .executes(PyroCommand::stop))
            .then(Commands.literal("fire")
                    .executes(PyroCommand::fire))
            );
        
      }
    
    private static int start(CommandContext<CommandSourceStack> context)  throws CommandSyntaxException {
        LOGGER.info(PREFIX+"START");
        Player sender = context.getSource().getPlayerOrException();
        if(PyroCapability.PYRO.isRegistered()) {
            PyroCapabilityInterface pyro = sender.getCapability(PyroCapability.PYRO).orElse(null);
            if(!pyro.isRunning()) {
                pyro.setRunning(true);
                pyro.setReadyToFire(false);
                pyro.clearBlocs();
                sender.sendMessage(new TextComponent(PREFIX + "Pyromaniac selection started. Right click blocks to fire."), sender.getUUID());
            }else {
                sender.sendMessage(new TextComponent(PREFIX + "Pyromaniac selection already started."), sender.getUUID());
            }            
        }else {
            sender.sendMessage(new TextComponent(PREFIX + "[ERROR] You don't have the pyromaniac capability :("), sender.getUUID());
        }
        return 1;
    }
    
    private static int stop(CommandContext<CommandSourceStack> context)  throws CommandSyntaxException {
        LOGGER.info(PREFIX+"STOP");
        
        Player sender = context.getSource().getPlayerOrException();
        if(PyroCapability.PYRO.isRegistered()) {
            PyroCapabilityInterface pyro = sender.getCapability(PyroCapability.PYRO).orElse(null);
            if(pyro.isRunning()) {
                pyro.setRunning(false);
                sender.sendMessage(new TextComponent(PREFIX + "Pyromaniac selection stopped. Please run twice '/pyro fire' to start fires."), sender.getUUID());
            }else {
                sender.sendMessage(new TextComponent(PREFIX + "Pyromaniac selection not started. Please run /pyro start."), sender.getUUID());
            }
        }
        return 1;
    }
    
    private static int fire(CommandContext<CommandSourceStack> context)  throws CommandSyntaxException {
        LOGGER.info(PREFIX+"FIRE");
        
        Player sender = context.getSource().getPlayerOrException();
        if(PyroCapability.PYRO.isRegistered()) {
            PyroCapabilityInterface pyro = sender.getCapability(PyroCapability.PYRO).orElse(null);
            if(!pyro.isReadyToFire()) {
                sender.sendMessage(new TextComponent(PREFIX + "Run '/pyro fire' again to start the magic."), sender.getUUID());
                pyro.setReadyToFire(true);
            }else {
                sender.sendMessage(new TextComponent(PREFIX + "Firing. Muuaaaahahahahahaha :D"), sender.getUUID());
                for(Objectiu obj : pyro.getObjectius()) {
                    Block bloc = Blocks.FIRE;
                    
                    Level l = obj.getLevel();
                    Player p = obj.getPlayer();
                    BlockPos pos = obj.getPos();
                    Direction dir = obj.getDir();
                    
                    BlockPos pos2 = pos.relative(dir);
                    
                    if (BaseFireBlock.canBePlacedAt(l, pos2, dir)) {
                        l.setBlock(pos2, bloc.defaultBlockState(), 3);
                        bloc.setPlacedBy(l, pos2, bloc.defaultBlockState(), p, ItemStack.EMPTY);
                    }
                }
            }
        }
        return 1;
    }
    
}

Expand  
  Quote

//CUSTOM CAPABILITY INTERFACE

public interface PyroCapabilityInterface extends INBTSerializable<CompoundTag> {
    
    boolean running = false;
    boolean readyToFire = false;
    static final ArrayList<Objectiu> blocs = new ArrayList<Objectiu>();    
        
    boolean isRunning();
    void setRunning(boolean running);
    
    boolean isReadyToFire();
    void setReadyToFire(boolean readyToFire);
    
    
    boolean hasObjectiu(Objectiu obj);
    void addObjectiu(Objectiu obj);
    ArrayList<Objectiu> getObjectius();
    
    void clearBlocs();    
}
 

Expand  
  Quote

//CUSTOM CAPABILITY IMPLEMENTATION

public class PyroCapabilityImplementation implements PyroCapabilityInterface {

    private boolean running = false;
    private boolean readyToFire = false;
    private ArrayList<Objectiu> blocs;    

    @Override
    public CompoundTag serializeNBT() {
        LOGGER.info(PREFIX+"SERIALIZE NBT");

        final CompoundTag tag = new CompoundTag();
        
        tag.putBoolean("RUNNING", this.running);
        tag.putBoolean("READYTOFIRE", this.readyToFire);
        
        // TODO
        // Serialize class Objectiu
        
        return tag;
    }

    @Override
    public void deserializeNBT(CompoundTag nbt) {
        LOGGER.info(PREFIX+"DESERIALIZE NBT");

        this.running = nbt.getBoolean("RUNNING");
        this.readyToFire = nbt.getBoolean("READYTOFIRE");
        
        // TODO
        // Deserialize class Objectiu
        
    }

    @Override
    public boolean isRunning() {
        return running;
    }

    @Override
    public void setRunning(boolean running) {
        this.running = running;
    }

    @Override
    public boolean isReadyToFire() {
        return readyToFire;
    }

    @Override
    public void setReadyToFire(boolean readyToFire) {
        this.readyToFire = readyToFire;
    }

    @Override
    public boolean hasObjectiu(Objectiu obj) {
        return this.blocs.contains(obj);
    }

    @Override
    public void addObjectiu(Objectiu obj) {
        this.blocs.add(obj);
    }

    @Override
    public void clearBlocs() {
        this.blocs = new ArrayList<Objectiu>();    
    }

    @Override
    public ArrayList<Objectiu> getObjectius() {
        return this.blocs;
    }

}

Expand  
  Quote

//CUSTOM CAPABILITY ATTACHER

public class PyroCapabilityAttacher {

    private static class PyroCapabilityProvider implements ICapabilityProvider, INBTSerializable<CompoundTag> {
        
        public static final ResourceLocation IDENTIFIER = new ResourceLocation("pyromaniac", "pyro");
        
        private final PyroCapabilityInterface backend = new PyroCapabilityImplementation();
        private final LazyOptional<PyroCapabilityInterface> optionalData = LazyOptional.of(() -> backend);

        
        void invalidate() {
            this.optionalData.invalidate();
        }

        @Nonnull
        @Override
        public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
            return PyroCapability.PYRO.orEmpty(cap, this.optionalData);
        }

        @Override
        public CompoundTag serializeNBT() {
            return this.backend.serializeNBT();
        }

        @Override
        public void deserializeNBT(CompoundTag nbt) {
            this.backend.deserializeNBT(nbt);
            
        }
    }

    @SubscribeEvent
    public static void attach(final AttachCapabilitiesEvent<Entity> event) {
        if(event.getObject() instanceof Player) {
            final PyroCapabilityProvider provider = new PyroCapabilityProvider();
            
            event.addCapability(PyroCapabilityProvider.IDENTIFIER, provider);
            event.addListener(provider::invalidate);
        }
    }

    private PyroCapabilityAttacher() {
    }

}

Expand  
  Quote

//CUSTOM CAPABILITY

public class PyroCapability{

    public static final Capability<PyroCapabilityInterface> PYRO = CapabilityManager.get(new CapabilityToken<>() {});
    
    public static void register(RegisterCapabilitiesEvent event) {
        event.register(PyroCapabilityInterface.class);
    }
    
    private PyroCapability() {
        
    }
}

Expand  
  Quote

//OBJECTIU (target, in English)

public class Objectiu {
    
    private Level level;
    private Player player;
    private BlockPos pos;
    private Direction dir;
    
    public Objectiu(Level level, Player player, BlockPos pos, Direction dir) {
        this.level = level;
        this.player = player;
        this.pos = pos;
        this.dir = dir;
    }

    public Level getLevel() {
        return level;
    }

    public void setLevel(Level level) {
        this.level = level;
    }

    public Player getPlayer() {
        return player;
    }

    public void setPlayer(Player player) {
        this.player = player;
    }

    public BlockPos getPos() {
        return pos;
    }

    public void setPos(BlockPos pos) {
        this.pos = pos;
    }

    public Direction getDir() {
        return dir;
    }

    public void setDir(Direction dir) {
        this.dir = dir;
    }

    // TODO
    // Create equals function
    
//    @Override
//    public boolean equals(Object o) {

//    }
    
    
}

Expand  

Let's go with some questions:

As I never created a capability, I used this https://gist.github.com/N1K-x/a17812bac9de4cf064baa789e9ccb96a as a basic example. Did I implement it well or is a best way of doing it?

I am checking if the target seleccion is running from the PlayerRightClickEvent, and if so, I'm cancelling the event. Is there a way to tell Minecraft to always disable it for a certain player and not having to do it from inside itself? Easier explain of the question: can I tell MC that a player can't place blocks while the boolean "running" of the mod is true?

I am coding the command execution from the command class. Shall I put the start/stop/fire funcions in the Capability implementation or it is ok to do it here?

 

That's all. I hope my code would be useful as an example of implementing commands or capabilities. And thanks to whoever answers my questions :D.

Edited by baku
my bad English xD

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

    • my game keeps crashing right before launching the game before full screen and keeps poping up this error message "error code 1 " The game crashed: rendering overlay Error: java.lang.IllegalAccessError: failed to access class com.mojang.blaze3d.platform.GlStateManager$TextureState from class net.coderbot.iris.gl.IrisRenderSystem$DSAARB (com.mojang.blaze3d.platform.GlStateManager$TextureState is in module minecraft@1.18.2 of loader 'TRANSFORMER' @d919544; net.coderbot.iris.gl.IrisRenderSystem$DSAARB is in module oculus@1.6.4 of loader 'TRANSFORMER' @d919544)
    • removing oculus or any of ETF or EMF or even embeddium doesn't change anything it just crashes again with error -1  https://gist.github.com/Tikalian-coconut/d49e8fb83bf57d5e04eb042522046786 this time i removed all 4 at same time and that gave it something is wrong with the game seriously..
    • crash report -> https://gist.github.com/Tikalian-coconut/18c41f97bdacef54725e5141f57697d7 from what i see it seems like Entity Texture Features doesn't like Oculus doing something or invert.. not sure it's why everything is all black textured but that causes a -1 error
    • well that's bad, cuz there's no crash report at all (the last crash report is from previous replies) it's probably another issue that doesn't fit in this bug report, the game works fine except that everything is black, no texture except the sky and skin, everything else is just black i've tried reloading the textures in game, see for drivers updates but it did nothing, seems like an issue with Embeddium or Oculus i think, but i know nothing compared to you i can still send the latest debug and latest.log files.. edit: it seems that when i re-add rechiseled (1.1.6-1.20.1) it crashes as error 1 (i can't remove it off from the modpack cuz that'll break all my builds on some maps) lemme start the game and get it to crash to get a crash report done)
    • If you've fallen victim to a crypto scam, you're not alone and thankfully, you're not without options. I highly recommend iBolt Cyber Hacker Company for anyone seeking professional and effective assistance in recovering scammed cryptocurrency. After extensive research and hearing from multiple satisfied clients, it's clear that iBolt stands out in a crowded and often unreliable market. Their team of experienced cyber experts and blockchain analysts uses advanced tracking techniques to follow stolen funds across the blockchain and engage with crypto exchanges when possible. They’re not just tech-savvy—they’re strategic and persistent. WHY CHOOSE iBOLT CYBER HACKER COMPANY? (1) Proven success in crypto asset recovery (2) Fast, professional, and discreet service (3) Skilled in blockchain forensics and cyber investigation (4) Committed to fighting online fraud and supporting victims Don’t give up. I strongly recommend reaching out to iBolt Cyber Hacker Company. ENQUIRIES: info @ iboltcyberhack . org/ www . iboltcyberhack. org/ +39. 351. 105. 3619.
  • Topics

×
×
  • Create New...

Important Information

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