Files
Documentation/content/reference/buildertools/snapshots.en.md
2026-01-20 20:33:59 +01:00

7.4 KiB

title, type, weight
title type weight
Snapshots docs 5

The snapshot system provides undo/redo functionality for builder tools by capturing and restoring state.

Package: com.hypixel.hytale.builtin.buildertools.snapshot

Architecture

Snapshots
├── Base
│   └── SelectionSnapshot - Snapshot interface
├── Block Snapshots
│   └── BlockSelectionSnapshot - Block selection state
├── Clipboard Snapshots
│   ├── ClipboardSnapshot - Clipboard interface
│   ├── ClipboardContentsSnapshot - Clipboard contents
│   └── ClipboardBoundsSnapshot - Selection bounds
└── Entity Snapshots
    ├── EntitySnapshot - Entity interface
    ├── EntityAddSnapshot - Track entity addition
    ├── EntityRemoveSnapshot - Track entity removal
    └── EntityTransformSnapshot - Track transform changes

SelectionSnapshot Interface

Base interface for all snapshots:

public interface SelectionSnapshot<T extends SelectionSnapshot<?>> {
    // Restore to previous state
    // Returns inverse snapshot for redo
    T restore(Ref<EntityStore> ref, Player player, World world,
              ComponentAccessor<EntityStore> accessor);
}

How Undo/Redo Works

The snapshot pattern creates inverse operations:

  1. Snapshot captures current state before operation
  2. Operation modifies the state
  3. Calling restore() reverts changes
  4. restore() returns new snapshot for redo

Block Selection Snapshots

BlockSelectionSnapshot

Captures block selection state:

public class BlockSelectionSnapshot implements SelectionSnapshot<BlockSelectionSnapshot> {
    private final BlockSelection selection;

    public BlockSelection getBlockSelection();

    // Create copy of selection
    public static BlockSelectionSnapshot copyOf(BlockSelection selection);
}

Usage

// Before modifying selection
BlockSelectionSnapshot snapshot = BlockSelectionSnapshot.copyOf(selection);

// Perform modifications...

// To undo - restore returns redo snapshot
BlockSelectionSnapshot redoSnapshot = snapshot.restore(ref, player, world, accessor);

Clipboard Snapshots

ClipboardSnapshot Interface

Extended interface for clipboard operations:

public interface ClipboardSnapshot<T extends SelectionSnapshot<?>>
        extends SelectionSnapshot<T> {

    T restoreClipboard(Ref<EntityStore> ref, Player player, World world,
                       BuilderToolsPlugin.BuilderState state,
                       ComponentAccessor<EntityStore> accessor);
}

ClipboardContentsSnapshot

Captures clipboard contents:

public class ClipboardContentsSnapshot implements ClipboardSnapshot<ClipboardContentsSnapshot> {
    private final BlockSelection selection;

    // Create copy of clipboard contents
    public static ClipboardContentsSnapshot copyOf(BlockSelection selection);
}

ClipboardBoundsSnapshot

Captures selection bounds only:

public class ClipboardBoundsSnapshot implements ClipboardSnapshot<ClipboardBoundsSnapshot> {
    public static final ClipboardBoundsSnapshot EMPTY;

    private final Vector3i min;
    private final Vector3i max;

    public ClipboardBoundsSnapshot(BlockSelection selection);
    public ClipboardBoundsSnapshot(Vector3i min, Vector3i max);

    public Vector3i getMin();
    public Vector3i getMax();
}

Entity Snapshots

EntitySnapshot Interface

Interface for entity-related snapshots:

public interface EntitySnapshot<T extends SelectionSnapshot<?>>
        extends SelectionSnapshot<T> {

    T restoreEntity(Player player, World world,
                    ComponentAccessor<EntityStore> accessor);
}

Entity snapshots handle thread safety automatically, ensuring restoration runs on the world's tick thread.

EntityAddSnapshot

Tracks entity creation (undo removes entity):

public class EntityAddSnapshot implements EntitySnapshot<EntityRemoveSnapshot> {
    private final Ref<EntityStore> entityRef;

    public Ref<EntityStore> getEntityRef();

    // Restore removes the entity
    // Returns EntityRemoveSnapshot for redo (re-add)
}

EntityRemoveSnapshot

Tracks entity removal (undo adds entity back):

public class EntityRemoveSnapshot implements EntitySnapshot<EntityAddSnapshot> {
    private final Holder<EntityStore> holder;

    public Holder<EntityStore> getHolder();

    // Restore adds entity back
    // Returns EntityAddSnapshot for redo (remove again)
}

The Holder<EntityStore> stores a complete copy of the entity and its components.

EntityTransformSnapshot

Tracks entity position and rotation:

public class EntityTransformSnapshot implements EntitySnapshot<EntityTransformSnapshot> {
    private final Ref<EntityStore> ref;
    private final Transform transform;      // Position and rotation
    private final Vector3f headRotation;    // Head direction

    // Stores current transform state
    public EntityTransformSnapshot(Ref<EntityStore> ref,
                                   ComponentAccessor<EntityStore> accessor);

    // Restore returns snapshot of current state before restoration
}

Snapshot Pairs

Snapshots come in complementary pairs:

Add Operation Undo (Remove) Redo (Add)
EntityAddSnapshot Removes entity EntityRemoveSnapshot
EntityRemoveSnapshot Adds entity back EntityAddSnapshot
Modification Undo Redo
EntityTransformSnapshot Restores previous transform Returns new snapshot
BlockSelectionSnapshot Restores previous blocks Returns new snapshot
ClipboardContentsSnapshot Restores previous contents Returns new snapshot
ClipboardBoundsSnapshot Restores previous bounds Returns new snapshot

Edit History Integration

Snapshots integrate with the edit history system:

// History stores snapshots for each operation
// /undo command restores from history
// /redo command uses inverse snapshots

// Commands related to history:
// /undo [count]
// /redo [count]
// /clearedithistory
// /settoolhistorysize <size>

Thread Safety

Entity snapshots automatically handle world thread requirements:

// EntitySnapshot.restore() implementation
default T restore(...) {
    if (!world.isInThread()) {
        // Run on world tick thread
        return CompletableFuture.supplyAsync(
            () -> this.restoreEntity(player, world, store),
            world
        ).join();
    }
    return this.restoreEntity(player, world, store);
}

API Usage

Working with Block Snapshots

// Before operation
BlockSelectionSnapshot before = BlockSelectionSnapshot.copyOf(selection);

// Perform operation that modifies blocks
// ...

// Store snapshot in history for undo

Working with Entity Snapshots

// Before adding entity
Ref<EntityStore> newEntity = world.spawnEntity(...);
EntityAddSnapshot snapshot = new EntityAddSnapshot(newEntity);

// To undo (remove the entity)
EntityRemoveSnapshot inverse = snapshot.restore(ref, player, world, accessor);

// To redo (add entity back)
EntityAddSnapshot restored = inverse.restore(ref, player, world, accessor);

Working with Transform Snapshots

// Before moving entity
EntityTransformSnapshot before = new EntityTransformSnapshot(entityRef, accessor);

// Move entity
transformComponent.setPosition(newPosition);

// To undo (restore original position)
EntityTransformSnapshot after = before.restore(player, world, accessor);