Skip to content

Commit

Permalink
Modded ItemInstance Data and TileInteractionCallback (#19)
Browse files Browse the repository at this point in the history
* version bumps

* add tick callback

* more world gen events

* changes

* update loader version

* specify stuff

* bump version

* improve docs

* Better copying

* warning it's broken

* so save/load works

* f*kn mojang

* progress

* attached data

* attached data 2

* attached data 3

* e

* update mappings

* make datamanager constructor public; make DataManager#copyData

* Delete MixinItemEntity.java

* remove item entity mixin

* Update MixinClientInteractionManager.java

* Update MixinClass_70.java

* Final touches?

* docs
  • Loading branch information
valoeghese authored Aug 15, 2020
1 parent 2e21811 commit 3ef85ad
Show file tree
Hide file tree
Showing 19 changed files with 468 additions and 19 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ dependencies {
//to change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}"

mappings loom.fromCommit("minecraft-cursed-legacy/Plasma", "b464f27") {spec ->
spec.version = "b1.7.3-12"
mappings loom.fromCommit("minecraft-cursed-legacy/Plasma", "f900cd3") {spec ->
spec.version = "b1.7.3-14"
}

// for config api
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ org.gradle.jvmargs=-Xmx1G
loader_version=8f014a3

# Mod Properties
mod_version = 0.6.2
mod_version = 0.6.3
maven_group = io.github.minecraftcursedlegacy.api
archives_base_name = cursed-legacy-api
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.github.minecraftcursedlegacy.api.data;

import io.github.minecraftcursedlegacy.api.registry.Id;
import net.minecraft.util.io.CompoundTag;

/**
* Data which can be attached to various vanilla objects, such as items and blocks.
* @see {@link DataManager}.
*/
public interface AttachedData {
/**
* @return the id of this modded data.
*/
Id getId();
/**
* @return a tag representation of this data.
*/
CompoundTag toTag(CompoundTag tag);
/**
* @param tag the tag from which to load data.
*/
void fromTag(CompoundTag tag);
/**
* Creates a deep copy of this {@link AttachedData}, similar to the recommendations for {@link Object#clone}.
*/
AttachedData copy();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package io.github.minecraftcursedlegacy.api.data;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

import io.github.minecraftcursedlegacy.api.registry.Id;
import io.github.minecraftcursedlegacy.impl.data.DataStorage;
import net.minecraft.item.ItemInstance;
import net.minecraft.util.io.CompoundTag;

/**
* Manager for data which can be attached to various vanilla objects, such as items and blocks.
*/
public final class DataManager<T> {
private final Map<Id, Function<T, ? extends AttachedData>> attachedDataFactories = new HashMap<>();

/**
* Adds the specified attached data to the {@link DataManager} instance. This data can later be accessed on an instance of the object via {@link #getAttachedData}.
* @return a key to use to retrieve the attached data from an object.
*/
public <E extends AttachedData> DataKey<E> addAttachedData(Id id, Function<T, E> dataProvider) {
this.attachedDataFactories.put(id, dataProvider);
return new DataKey<>(id);
}

/**
* Retrieves the specified attached data from the object.
*/
public <E extends AttachedData> E getAttachedData(T object, DataKey<E> key) throws ClassCastException {
return key.apply(((DataStorage) object).getAttachedData(key.id, () -> this.attachedDataFactories.get(key.id).apply(object)));
}

/**
* Used by the implementation.
* @return a {@linkplain Set set} of all {@linkplain Id ids} of {@link AttachedData} instances registered to this manager.
*/
public Set<Id> getDataKeys() {
return this.attachedDataFactories.keySet();
}

/**
* Used by the implementation.
* @return an attached data instance of the given type constructed by the given tag.
*/
public AttachedData deserialize(T object, Id id, CompoundTag data) {
AttachedData result = this.attachedDataFactories.get(id).apply(object);
result.fromTag(data);
return result;
}

/**
* Used by the implementation.
* @param from the object to use the data of.
* @param to the object to receive the data.
*/
public void copyData(T from, T to) {
DataStorage to_ = (DataStorage) (Object) to;

((DataStorage) (Object) from).getAllAttachedData().forEach(entry -> {
Id dataId = entry.getKey();
AttachedData data = entry.getValue();
to_.putAttachedData(dataId, data.copy());
});
}

public static final DataManager<ItemInstance> ITEM_INSTANCE = new DataManager<>();

public static final class DataKey<T extends AttachedData> {
private DataKey(Id id) throws NullPointerException {
if (id == null) {
throw new NullPointerException("DataKey cannot store a null ID!");
}

this.id = id;
}

private final Id id;

@SuppressWarnings("unchecked")
private T apply(AttachedData data) throws ClassCastException {
return (T) data;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.github.minecraftcursedlegacy.api.event;

import javax.annotation.Nullable;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.player.Player;
import net.minecraft.item.ItemInstance;
import net.minecraft.level.Level;
import net.minecraft.tile.Tile;

/**
* Callback for right clicking a tile. This is run both client and server side.
*
* <p>Upon return:
* <ul>
* <li> SUCCESS cancels further event processing and vanilla code, and the method this is event is called from returns true (succeeds).
* <li> PASS falls back to further event processing. If all events PASS, then vanilla behaviour runs.
* <li> FAIL cancels further event processing and vanilla code, and the method this is event is called from returns false (fails).
* </ul>
*/
@FunctionalInterface
public interface TileInteractionCallback {
Event<TileInteractionCallback> EVENT = EventFactory.createArrayBacked(TileInteractionCallback.class,
(listeners) -> (player, level, item, tile, x, y, z, face) -> {
for (TileInteractionCallback listener : listeners) {
ActionResult result = listener.onTileInteract(player, level, item, tile, x, y, z, face);

if (result != ActionResult.PASS) {
return result;
}
}

return ActionResult.PASS;
});

/**
* @param player the player causing the tile interaction.
* @param level the level the tile is being interacted with in.
* @param item the item instance that the player is using to interact with the tile.
* @param tile the tile being interacted with at the time of this event firing. This does not change if an event subscriber alters the tile at that position.
* @param face probably the tile face. The last parameter of {@link ItemInstance#useOnTile(Player, Level, int, int, int, int)};
* @return the action result, as specified in the javadoc of {@link TileInteractionCallback}.
*/
ActionResult onTileInteract(Player player, Level level, @Nullable ItemInstance item, Tile tile, int x, int y, int z, int face);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@

import javax.imageio.ImageIO;

import net.minecraft.client.texture.TextureManager;

import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.texture.TextureManager;

class CustomAtlas implements Atlas {
private static final short MAX_SLOTS = 16 * 16;
Expand Down Expand Up @@ -65,7 +64,7 @@ public int allocate(BufferedImage sprite) {
@Environment(EnvType.CLIENT)
public int getTextureID(TextureManager manager) {
if (textureID < 0) {
textureID = manager.method_1088(image);
textureID = manager.glLoadImage(image);
needsRefresh = false;
} else if (needsRefresh) {
needsRefresh = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.github.minecraftcursedlegacy.impl.data;

import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Supplier;

import io.github.minecraftcursedlegacy.api.data.AttachedData;
import io.github.minecraftcursedlegacy.api.registry.Id;
import net.minecraft.util.io.CompoundTag;

public interface DataStorage {
CompoundTag getModdedTag();
void putAttachedData(Id id, AttachedData data);
AttachedData getAttachedData(Id id, Supplier<AttachedData> supplier);
Set<Entry<Id,AttachedData>> getAllAttachedData();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.github.minecraftcursedlegacy.impl.event;

import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import io.github.minecraftcursedlegacy.api.event.ActionResult;
import io.github.minecraftcursedlegacy.api.event.TileInteractionCallback;
import net.minecraft.entity.player.Player;
import net.minecraft.item.ItemInstance;
import net.minecraft.level.Level;
import net.minecraft.tile.Tile;

public class TileInteractionImpl {
public static void onTileInteract(Player player, Level level, ItemInstance item, int x, int y, int z, int i1, CallbackInfoReturnable<Boolean> info) {
int tile = level.getTileId(x, y, z);
ActionResult result = TileInteractionCallback.EVENT.invoker().onTileInteract(player, level, item, Tile.BY_ID[tile], x, y, z, i1);

if (result != ActionResult.PASS) {
info.setReturnValue(result == ActionResult.SUCCESS);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public void onInitialize() {
int xToGen = x + rand.nextInt(16) + 8;
int zToGen = z + rand.nextInt(16) + 8;
Feature var18 = biome.getTree(rand);
var18.method_1143(1.0D, 1.0D, 1.0D);
var18.setupTreeGeneration(1.0D, 1.0D, 1.0D);
var18.generate(level, rand, xToGen, level.getHeight(xToGen, zToGen), zToGen);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.minecraftcursedlegacy.mixin;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import io.github.minecraftcursedlegacy.impl.event.TileInteractionImpl;
import net.minecraft.client.ClientInteractionManager;
import net.minecraft.entity.player.Player;
import net.minecraft.item.ItemInstance;
import net.minecraft.level.Level;

@Mixin(ClientInteractionManager.class)
public class MixinClientInteractionManager {
@Inject(at = @At("HEAD"), method = "useItemOnTile", cancellable = true)
private void api_onTileInteract(Player player, Level level, ItemInstance item, int x, int y, int z, int i1, CallbackInfoReturnable<Boolean> info) {
TileInteractionImpl.onTileInteract(player, level, item, x, y, z, i1, info);
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
package io.github.minecraftcursedlegacy.mixin;

import org.objectweb.asm.Opcodes;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import net.minecraft.class_556;
import io.github.minecraftcursedlegacy.impl.client.AtlasMapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.render.HandItemRenderer;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemInstance;

import io.github.minecraftcursedlegacy.impl.client.AtlasMapper;

@Mixin(class_556.class)
abstract class MixinClass_556 {
@Mixin(HandItemRenderer.class)
abstract class MixinHandItemRenderer {
@Shadow
private Minecraft field_2401;

@Inject(method = "method_1862",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/Tessellator;INSTANCE:Lnet/minecraft/client/render/Tessellator;", opcode = Opcodes.GETSTATIC)
)
)
private void fixAtlas(LivingEntity entity, ItemInstance item, CallbackInfo info) {
AtlasMapper.getAtlas(field_2401.textureManager, item.itemId, item.getDamage()).ifPresent(field_2401.textureManager::bindTexture);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package io.github.minecraftcursedlegacy.mixin;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Supplier;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import io.github.minecraftcursedlegacy.api.data.AttachedData;
import io.github.minecraftcursedlegacy.api.data.DataManager;
import io.github.minecraftcursedlegacy.api.registry.Id;
import io.github.minecraftcursedlegacy.impl.data.DataStorage;
import net.minecraft.item.ItemInstance;
import net.minecraft.util.io.CompoundTag;

@Mixin(ItemInstance.class)
public abstract class MixinItemInstance implements DataStorage {
private CompoundTag api_data = new CompoundTag();
private Map<Id, AttachedData> api_attachedDataMap = new HashMap<>();

@Inject(at = @At("RETURN"), method = "copy")
private void api_copyData(CallbackInfoReturnable<ItemInstance> info) {
DataStorage ds = ((DataStorage) (Object) info.getReturnValue());

this.api_attachedDataMap.forEach((id, data) -> {
ds.putAttachedData(id, data.copy());
});
}

@Inject(at = @At("RETURN"), method = "toTag")
private void api_addData(CompoundTag tag, CallbackInfoReturnable<CompoundTag> info) {
tag.put("moddedData", this.getModdedTag());
}

@Inject(at = @At("RETURN"), method = "split")
private void api_copySplitData(int countToTake, CallbackInfoReturnable<ItemInstance> info) {
DataStorage ds = ((DataStorage) (Object) info.getReturnValue());

this.api_attachedDataMap.forEach((id, data) -> {
ds.putAttachedData(id, this.api_attachedDataMap.get(id).copy());
});
}

@Inject(at = @At("RETURN"), method = "fromTag")
private void api_readData(CompoundTag tag, CallbackInfo info) {
if (tag.containsKey("moddedData")) {
this.api_data = tag.getCompoundTag("moddedData");
}

// Load Data
DataManager.ITEM_INSTANCE.getDataKeys().forEach(id -> {
if (this.api_data.containsKey(id.toString())) {
this.putAttachedData(id, DataManager.ITEM_INSTANCE.deserialize((ItemInstance) (Object) this, id, this.api_data.getCompoundTag(id.toString())));
}
});
}

@Override
public CompoundTag getModdedTag() {
this.api_attachedDataMap.forEach((id, data) -> {
this.api_data.put(id.toString(), data.toTag(new CompoundTag()));
});

return this.api_data;
}

@Override
public Set<Entry<Id,AttachedData>> getAllAttachedData() {
return this.api_attachedDataMap.entrySet();
}

@Override
public void putAttachedData(Id id, AttachedData data) {
this.api_attachedDataMap.put(id, data);
}

@Override
public AttachedData getAttachedData(Id id, Supplier<AttachedData> supplier) {
return this.api_attachedDataMap.computeIfAbsent(id, i -> supplier.get());
}
}
Loading

0 comments on commit 3ef85ad

Please sign in to comment.