Issue Details#950 Prism r:we problems with WE 6.0+ and not logging WE 6.0+ changes

  • Priority: Normal
  • Number: 950
  • Type: Bug
  • Status: New
  • Age: 961 Days

Description

Prism 2.0.4 snapshot 17 blows up on using /pr rb r:we.... I have fixed that by making the appropriate adjustments in WorldEditBridge after cloning the git repository. That was easy.

The logging problem is more knotty. No WorldEdit 6.0 changes are being recorded in Prism, period. No errors, no nothing. After staring at the code in Prism and WorldEdit for a while, it is apparent that the approach Prism takes to logging block changes, namely, extending EditSession and EditSessionFactory, and overriding the rawSetBlock method to record block changes in the Prism queue will no longer work.

The approach that sk89q wants is to use the AbstractLoggingEvent class to override the onBlockChange to record the block change on a block change event...

WorldEdit.getInstance().getEventBus().register(new Object() { @Subscribe public void wrapForLogging(EditSessionEvent event) { LocalPlayer player = event.getPlayer();

    event.setExtent(new AbstractLoggingExtent(event.getExtent()) {
        @Override
        protected void onBlockChange(Vector position, BaseBlock newBlock) {
            System.out.println(player + " set block @ " + position);
        }
    });
}

});

Obviously the intent is to replace the System.out.Println statement with the actual code that does the logging...

My idea to replumb this in Prism is to do something like creating a class under me.botsko.prism.bridge called PrismLoggingExtent.java that would roughly be the following:

package me.botsko.prism.bridge;

import org.bukkit.Bukkit; import org.bukkit.Location;

import me.botsko.prism.Prism; import me.botsko.prism.actionlibs.ActionFactory; import me.botsko.prism.actionlibs.RecordingQueue;

import com.sk89q.worldedit.LocalPlayer; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.logging.AbstractLoggingExtent; import com.sk89q.worldedit.util.eventbus.Subscribe;

public class PrismLoggingExtent extends AbstractLoggingExtent {

protected PrismLoggingExtent(Extent extent) {
super(extent);
// TODO Auto-generated constructor stub

final Player player;


WorldEdit.getInstance().getEventBus().register(new Object() {

    @Subscribe
    public void wrapForLogging(EditSessionEvent event) {
        final Actor actor = event.getActor();

        event.setExtent(new AbstractLoggingExtent(event.getExtent()) {

            @Override
            protected void onBlockChange(Vector position, BaseBlock newBlock) {
                // System.out.println(actor + " set block @ " + position);

                if( !( ((Location) actor).getWorld() instanceof BukkitWorld ) || !Prism.config.getBoolean( "prism.tracking.world-edit" )
                        ) { }

                // final int typeBefore = ??something??;
                // final byte dataBefore = ??something??;
                final Location loc = new Location( Bukkit.getWorld( player.getWorld().getName() ), position.getBlockX(),
                        position.getBlockY(), position.getBlockZ() );

                RecordingQueue.addToQueue( ActionFactory.createBlockChange("world-edit", loc, typeBefore, dataBefore, loc.getBlock()
                            .getTypeId(), loc.getBlock().getData(), player.getName()) );

                }
            });
        }
    });
}

}

One of the problems I have is that I am not sure how to get the typeBefore and dataBefore, because I think they have already been changed by the time the event fires. Any comments or ideas? If I can straighten this out with the help of other folks, I will be happy to submit this as a pull request if people think it is helpful. Note that this is very relevant for the future of Prism with Sponge, as other than the few bukkit specific lines above this is really a manifestion of worldedit-core, which is implementation agnostic.

I am very rusty at this stuff but am willing to give it a go if I can get a little help.

History

jamescowens Gravatar

jamescowens December 29, 2014 3:56 AM

Issue reported.

jamescowens Gravatar

jamescowens December 30, 2014 3:52 AM

Ok. The following works... instead of a new class, I simply changed the initialize() in PrismBlockEditSessionFactory to the following. Notice that I have temporarily commented out the old initialization, as it would only be applicable for WorldEdit < 6.0. The register(new Object(... will have to be conditional on WorlEdit > 6.0 also, but I haven't done that yet. I had to change the type of onBlockChange from void to BaseBlock and imlement an oldBlock parameter in WorldEdit's AbstractLoggingExtent because the override was giving me trouble with nothing to return, and we need the oldBlock for the Prism database record. The only real remaining issue is that three records are being created for each change. This is probably because the event is being fired for each of the three stages BEFORE_HISTORY, BEFORE_REORDER, and BEFORE_CHANGE. I am not sure how to just select one in this approach, and having the extra records doesn't really affect the rollbacks. Anyone that knows how to select just one can let me know. I tested the rollbacks after doing WE changes and they work!!

file PrismBlockEditSessionFactory.java

package me.botsko.prism.bridge;

...various imports...

...older Factory methods...

public class PrismBlockEditSessionFactory extends EditSessionFactory {

public static void initialize() {
    try {
        // Check to see if the world edit version is compatible
        // Class.forName( "com.sk89q.worldedit.EditSessionFactory" ).getDeclaredMethod( "getEditSession",
        // World.class, int.class, BlockBag.class, Player.class );
        // WorldEdit.getInstance().setEditSessionFactory( new PrismBlockEditSessionFactory() );

        WorldEdit.getInstance().getEventBus().register(new Object() {
            @Subscribe
            public void wrapForLogging(EditSessionEvent event) {
                final Actor player = event.getActor();

                event.setExtent(new AbstractLoggingExtent(event.getExtent()) {
                    @Override
                    protected BaseBlock onBlockChange(Vector position, BaseBlock oldBlock, BaseBlock newBlock) {

                        if( !( ((Player) player).getWorld() instanceof BukkitWorld ) || !Prism.config.getBoolean( "prism.tracking.world-edit" )
                                ) { return super.onBlockChange(position, oldBlock, newBlock); }

                        final Location loc = new Location( Bukkit.getWorld( ((Player) player).getWorld().getName() ), position.getBlockX(),
                                position.getBlockY(), position.getBlockZ() );

                        RecordingQueue.addToQueue( ActionFactory.createBlockChange("world-edit", loc, oldBlock.getId(),
                                (byte) oldBlock.getData(), newBlock.getId(), (byte) newBlock.getData(), player.getName()) );

                        return super.onBlockChange(position, oldBlock, newBlock);
                    }
                });
            }
        });


    } catch ( final Throwable ignored ) {

    }

}

file AbstractLoggingExtent.java

package com.sk89q.worldedit.extent.logging;

public abstract class AbstractLoggingExtent extends AbstractDelegateExtent {

/**
 * Create a new instance.
 *
 * @param extent the extent
 */
protected AbstractLoggingExtent(Extent extent) {
    super(extent);
}

/**
 * Called when a block is being changed.
 *
 * @param position the position
 * @param newBlock the new block to replace the old one
 */
protected BaseBlock onBlockChange(Vector position, BaseBlock oldBlock, BaseBlock newBlock) {
    return newBlock;
}

@Override
public final boolean setBlock(Vector position, BaseBlock block) throws WorldEditException {

    BaseBlock oldBlock = getBlock(position);
    onBlockChange(position, oldBlock, block);

    return super.setBlock(position, block);
}

}

jamescowens Gravatar

jamescowens December 30, 2014 4:16 PM

Ok. I have solved the multiple row logging problem by checking the value of getStage() on the event, and only registering for BEFORE_CHANGE. I have attached the two files in their current form from Prism and WorldEdit 6.0 (latest). The logging appears to be working correctly now.

It may be better to move the initialization code out of PrismBlockEditSessionFactory altogether and deprecate it, because the EditSessionFactory is not really being used anymore. We could create a class of a different name and change the checkPluginDependencies() in Prism.java to refer to the new class.

Anyone have any comments?

icabash Gravatar

icabash March 24, 2015 12:05 PM

Jamescowens, do you think that your code would work on the most recent dev builds of WorldEdit and Prism? I'm getting errors when I try to compile the latest dev build of Prism with your modified .java file, but that might just be an issue on my end with dependencies and such. My IDE is complaining about prismBlockEditSession() and onBlockChange(), inside of PrismBlockEditSessionFactory.java. I've only just recently started with plugin development, and so troubleshooting has been quite difficult. Do you have any advice, or would you perhaps be willing to supply a compiled .jar of WorldEdit and Prism? Thanks, by the way, for the time that you put into your writeup of the issue.

For anyone else reading, I'd like to confirm that this bug does indeed exist in the most recent dev build of Prism, build #31 of Prism 2.0.6, when used with the most recent dev build of WorldEdit 6.0. Here is some more detailed version information. This error now occurs on startup, giving information about why WorldEdit logging ceases to function, along with a message to contact the plugin's maintainer.

icabash Gravatar

icabash March 24, 2015 12:16 PM

Hmm, my hyperlinks don't seem to be working. Here is my detailed version information:

>prism version
[05:04:47 INFO]: Prism // Prism - By viveleroi v2.0.6-31
[05:04:47 INFO]: Prism // Help: /pr ?
[05:04:47 INFO]: Prism // IRC: irc.esper.net #prism
[05:04:47 INFO]: Prism // Wiki: http://discover-prism.com
>we version
[05:04:55 INFO]: WorldEdit version (unknown)
[05:04:55 INFO]: https://github.com/sk89q/worldedit/
[05:04:55 INFO]: ----------- Platforms -----------
[05:04:55 INFO]: * Bukkit-Official (6.0.2-SNAPSHOT;3370-58aac973)
[05:04:55 INFO]: ----------- Capabilities -----------
[05:04:55 INFO]: GAME_HOOKS: Bukkit-Official
[05:04:55 INFO]: CONFIGURATION: Bukkit-Official
[05:04:55 INFO]: USER_COMMANDS: Bukkit-Official
[05:04:55 INFO]: PERMISSIONS: Bukkit-Official
[05:04:55 INFO]: WORLDEDIT_CUI: Bukkit-Official
[05:04:55 INFO]: WORLD_EDITING: Bukkit-Official

And here is the error that now occurs on startup:

[04:52:14 ERROR]: [WorldEdit] Got request to set EditSessionFactory of type me.botsko.prism.bridge.PrismBlockEditSessionFactor
y from me.botsko.prism.bridge but EditSessionFactories have been removed in favor of extending EditSession's extents.
 This may mean that any block logger / intercepters addons/plugins/mods that you have installed will not intercept WorldEdit's 
changes! Please notify the maintainer of the other addon about this.

Update Issue

Add your comments to this issue!

Creating a free account will let you immediately report issues on this project, as well as comment on existing issues, save your filters, and more!!