Skip to content

Commit

Permalink
Add docs to classes/interfaces, add support for server side light sou…
Browse files Browse the repository at this point in the history
…rces (experimental)
  • Loading branch information
Patbox committed May 10, 2021
1 parent d2b134a commit 24257a1
Show file tree
Hide file tree
Showing 22 changed files with 335 additions and 27 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ After that, it's as easy as making your items implement `VirtualItem`, blocks `V
`VirtualHeadBlock` and entities `VirtualEntity`. Additionally, you need to implement `VirtualObject` on your enchantments and recipe serializers.
It's also recommended registering block entities with `PolymerMod.registerVirtualBlockEntity(Identifier)`.

### Limitations
While it's supported, please limit creation of VirtualBlock light sources. Because of how Minecraft
handles light updates on server/client, these can be little laggy (as it needs to be send updates every time light changes).

### If you are a server owner, you most likely wanted to get [PolyMC](https://github.com/TheEpicBlock/PolyMc)

Some code in this library is based on [PolyMC](https://github.com/TheEpicBlock/PolyMc). So if you are using Polymer, give a star to PolyMC too!
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ org.gradle.jvmargs=-Xmx1G
loader_version=0.11.3

# Mod Properties
mod_version = 0.0.1
mod_version = 0.0.2
maven_group = eu.pb4
archives_base_name = polymer

Expand Down
15 changes: 15 additions & 0 deletions src/main/java/eu/pb4/polymer/PolymerMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,29 @@ public void onInitialize() {
}
}

/**
* Marks BlockEntity type as server-side only
*
* @param identifier BlockEntity's Identifier
*/
public static void registerVirtualBlockEntity(Identifier identifier) {
BLOCK_ENTITY_IDENTIFIERS.add(identifier.toString());
}

/**
* Checks if BlockEntity is server-side only
*
* @param identifier BlockEntity's Identifier
*/
public static boolean isVirtualBlockEntity(Identifier identifier) {
return BLOCK_ENTITY_IDENTIFIERS.contains(identifier.toString());
}

/**
* Checks if BlockEntity is server-side only
*
* @param identifier BlockEntity's Identifier (as string)
*/
public static boolean isVirtualBlockEntity(String identifier) {
return BLOCK_ENTITY_IDENTIFIERS.contains(identifier);
}
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/eu/pb4/polymer/block/BasicVirtualBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;

/**
* Minimalistic implementation of VirtualBlock
*/
public class BasicVirtualBlock extends Block implements VirtualBlock {
private Block virtualBlock;

Expand Down
31 changes: 31 additions & 0 deletions src/main/java/eu/pb4/polymer/block/BlockHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package eu.pb4.polymer.block;

import eu.pb4.polymer.mixin.block.AbstractBlockAccessor;
import eu.pb4.polymer.mixin.block.AbstractBlockSettingAccessor;
import it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;

import java.util.function.ToIntFunction;

public class BlockHelper {
private static Object2BooleanArrayMap<Block> IS_LIGHT_SOURCE_CACHE = new Object2BooleanArrayMap();

public static boolean isLightSource(Block block) {
if (BlockHelper.IS_LIGHT_SOURCE_CACHE.containsKey(block)) {
return BlockHelper.IS_LIGHT_SOURCE_CACHE.getBoolean(block);
} else {
ToIntFunction<BlockState> luminance = ((AbstractBlockSettingAccessor) ((AbstractBlockAccessor) block).getSettings()).getLuminance();

for (BlockState state : block.getStateManager().getStates()) {
if (luminance.applyAsInt(state) != 0) {
BlockHelper.IS_LIGHT_SOURCE_CACHE.put(block, true);
return true;
}
}

BlockHelper.IS_LIGHT_SOURCE_CACHE.put(block, false);
return false;
}
}
}
29 changes: 29 additions & 0 deletions src/main/java/eu/pb4/polymer/block/VirtualBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,44 @@
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.math.BlockPos;


/**
* Interface used for creation of server side blocks
*/
public interface VirtualBlock extends VirtualObject {
/**
* Returns main/default block used on client
*
* @return Vanilla (or other) Block instance
*/
Block getVirtualBlock();

/**
* Returns default virtual BlockState
*
* @return Default BlockState of Vanilla/other block
*/
default BlockState getDefaultVirtualBlockState() {
return this.getVirtualBlock().getDefaultState();
}

/**
* Main method used for replacing BlockStates on client
*
* @param state Server side/real BlockState
* @return BlockState visible on client
*/
default BlockState getVirtualBlockState(BlockState state) {
return this.getDefaultVirtualBlockState();
};

/**
* This method can be used to send additional packets after block is send to client
* Allows to add client-only BlockEntities (for signs, heads, etc)
*
* @param player Player packets should be send to
* @param pos Position of block
* @param blockState Real BlockState of block
*/
default void sendPacketsAfterCreation(ServerPlayerEntity player, BlockPos pos, BlockState blockState) {}
}
26 changes: 25 additions & 1 deletion src/main/java/eu/pb4/polymer/block/VirtualHeadBlock.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package eu.pb4.polymer.block;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.network.Packet;
Expand All @@ -9,9 +11,25 @@
import net.minecraft.util.math.BlockPos;

public interface VirtualHeadBlock extends VirtualBlock {
/**
* This method is used to determine texture/skin of client sided head
* Player Skin can be generated by https://mineskin.org/
*
* @param state Server-side BlockState
* @return Skin Value
*/
String getVirtualHeadSkin(BlockState state);

default Block getVirtualBlock() {
return Blocks.PLAYER_HEAD;
}

/**
* Creates tag of Skull block entity
*
* @param state Server-side BlockState
* @return CompoundTag representing client-side
*/
default CompoundTag getVirtualHeadSkullOwner(BlockState state) {
CompoundTag skullOwner = new CompoundTag();
CompoundTag properties = new CompoundTag();
Expand All @@ -27,6 +45,13 @@ default CompoundTag getVirtualHeadSkullOwner(BlockState state) {
return skullOwner;
}

/**
* Creates client-side skull BlockEntity
*
* @param state Server-side BlockState
* @param pos Block's position
* @return A Packet
*/
default Packet<?> getVirtualHeadPacket(BlockState state, BlockPos pos) {
CompoundTag main = new CompoundTag();
CompoundTag skullOwner = this.getVirtualHeadSkullOwner(state);
Expand All @@ -38,7 +63,6 @@ default Packet<?> getVirtualHeadPacket(BlockState state, BlockPos pos) {
return new BlockEntityUpdateS2CPacket(pos, 4, main);
}


default void sendPacketsAfterCreation(ServerPlayerEntity player, BlockPos pos, BlockState blockState) {
player.networkHandler.sendPacket(((VirtualHeadBlock) blockState.getBlock()).getVirtualHeadPacket(blockState, pos));
}
Expand Down
24 changes: 23 additions & 1 deletion src/main/java/eu/pb4/polymer/entity/VirtualEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,25 @@
import java.util.Map;
import java.util.function.Consumer;


/**
* Interface used for creation of server-side entities
*/
public interface VirtualEntity extends VirtualObject {
/**
* This method is used to determine what this entity will look like on client
*
* @return Vanilla/Modded entity type
*/
default EntityType<?> getVirtualEntityType() {
return EntityType.ZOMBIE;
}

/**
* This method is used for replacing entity's equipment on client
*
* @param map Map of EquipmentSlot and ItemStack on entity server-side
* @return List of Pair of EquipmentSlot and ItemStack sent to client
*/
default List<Pair<EquipmentSlot, ItemStack>> getVirtualEntityEquipment(Map<EquipmentSlot, ItemStack> map) {
List<Pair<EquipmentSlot, ItemStack>> list = Lists.newArrayListWithCapacity(map.size());
for (Map.Entry<EquipmentSlot, ItemStack> entry : map.entrySet()) {
Expand All @@ -32,7 +45,16 @@ default List<Pair<EquipmentSlot, ItemStack>> getVirtualEntityEquipment(Map<Equip
return list;
}

/**
* This method can be used to send packets after entity is visuble to players
*
* @param sender Consumer of packets
*/
default void sendPacketsAfterCreation(Consumer<Packet<?>> sender) {}

/**
* This method allows to modify DataTracker values before they are send to the client
* @param data Current values
*/
default void modifyTrackedData(List<DataTracker.Entry<?>> data) {}
}
6 changes: 5 additions & 1 deletion src/main/java/eu/pb4/polymer/interfaces/VirtualObject.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
package eu.pb4.polymer.interfaces;

// Used to mark general virtual objects like BlockEntities, Enchantments, Recipe Serializers, etc
/**
* Used to mark general virtual objects like BlockEntities, Enchantments, Recipe Serializers, etc
*
* Doesn't implement anything by itself
*/
public interface VirtualObject {}
3 changes: 3 additions & 0 deletions src/main/java/eu/pb4/polymer/item/BasicVirtualItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import net.minecraft.item.Item;

/**
* Basic implementation of VirtualItem
*/
public class BasicVirtualItem extends Item implements VirtualItem {
private final Item virtualItem;

Expand Down
34 changes: 18 additions & 16 deletions src/main/java/eu/pb4/polymer/item/ItemHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@ public class ItemHelper {
protected static final UUID ATTACK_DAMAGE_MODIFIER_ID = UUID.fromString("CB3F55D3-645C-4F38-A497-9C13A33DB5CF");
protected static final UUID ATTACK_SPEED_MODIFIER_ID = UUID.fromString("FA233E1C-4180-4865-B01B-BCCE9785ACA3");

public static String VIRTUAL_ITEM_ID = "Polymer$itemId";
public static String REAL_TAG = "Polymer$itemTag";
public static final String VIRTUAL_ITEM_ID = "Polymer$itemId";
public static final String REAL_TAG = "Polymer$itemTag";

public static Style CLEAN_STYLE = Style.EMPTY.withItalic(false).withColor(Formatting.WHITE);
public static Style NON_ITALIC_STYLE = Style.EMPTY.withItalic(false);
public static final Style CLEAN_STYLE = Style.EMPTY.withItalic(false).withColor(Formatting.WHITE);
public static final Style NON_ITALIC_STYLE = Style.EMPTY.withItalic(false);

public static ItemStack getVirtualItemStack(ItemStack itemStack, ServerPlayerEntity player) {
if (itemStack.getItem() instanceof VirtualItem) {
VirtualItem item = (VirtualItem) itemStack.getItem();
return item.getVirtualItemStack(itemStack, player);
} if (itemStack.hasEnchantments()) {
} else if (itemStack.hasEnchantments()) {
for (net.minecraft.nbt.Tag enchantment : itemStack.getEnchantments()) {
String id = ((CompoundTag) enchantment).getString("id");

Expand All @@ -68,18 +68,20 @@ public static ItemStack getVirtualItemStack(ItemStack itemStack, ServerPlayerEnt
public static ItemStack getRealItemStack(ItemStack itemStack) {
ItemStack out = itemStack;

String id = out.getOrCreateTag().getString(VIRTUAL_ITEM_ID);
if (id != null && !id.isEmpty()) {
try {
Identifier identifier = Identifier.tryParse(id);
Item item = Registry.ITEM.get(identifier);
out = new ItemStack(item, itemStack.getCount());
CompoundTag tag = itemStack.getSubTag(REAL_TAG);
if (tag != null) {
out.setTag(tag);
if (itemStack.hasTag()) {
String id = itemStack.getTag().getString(VIRTUAL_ITEM_ID);
if (id != null && !id.isEmpty()) {
try {
Identifier identifier = Identifier.tryParse(id);
Item item = Registry.ITEM.get(identifier);
out = new ItemStack(item, itemStack.getCount());
CompoundTag tag = itemStack.getSubTag(REAL_TAG);
if (tag != null) {
out.setTag(tag);
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/java/eu/pb4/polymer/item/VirtualBlockItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;

/**
* Basic implementation of VirtualItem for blocks
*/
public class VirtualBlockItem extends BlockItem implements VirtualItem {
private final Item virtualItem;

Expand Down
3 changes: 3 additions & 0 deletions src/main/java/eu/pb4/polymer/item/VirtualHeadBlockItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import net.minecraft.item.Items;
import net.minecraft.server.network.ServerPlayerEntity;

/**
* Basic implementation of VirtualItem for blocks implementing VirtualHeadBlock
*/
public class VirtualHeadBlockItem extends BlockItem implements VirtualItem {
private final VirtualHeadBlock virtualBlock;

Expand Down
26 changes: 25 additions & 1 deletion src/main/java/eu/pb4/polymer/item/VirtualItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,36 @@

import java.util.List;

/**
* Interface used for creation of server-side items
*/
public interface VirtualItem extends VirtualObject {
/**
* Returns main/default item used on client
*
* @return Vanilla (or other) Item instance
*/
Item getVirtualItem();


/**
* Method used for creation of client-side ItemStack
*
* @param itemStack Server-side ItemStack
* @param player Player for which it's send
* @return Client-side ItemStack
*/
default ItemStack getVirtualItemStack(ItemStack itemStack, ServerPlayerEntity player) {
return ItemHelper.createBasicVirtualItemStack(itemStack, player);
}


/**
* This method allows to add (or modify) tooltip text
*
* @param tooltip Currient tooltip text
* @param stack Server-side ItemStack
* @param player Target player
*/
default void addTextToTooltip(List<Text> tooltip, ItemStack stack, ServerPlayerEntity player) {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package eu.pb4.polymer.mixin.block;

import net.minecraft.block.AbstractBlock;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

@Mixin(AbstractBlock.class)
public interface AbstractBlockAccessor {
@Accessor("settings")
AbstractBlock.Settings getSettings();
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public class AbstractBlockMixin {
private void replaceWithFakeBlock(BlockState state, BlockView world, BlockPos pos, ShapeContext context, CallbackInfoReturnable<VoxelShape> cir) {
if (this instanceof VirtualBlock) {
VirtualBlock block = (VirtualBlock) this;

cir.setReturnValue(block.getVirtualBlockState(state).getOutlineShape(world, pos, context));
}
}
Expand Down
Loading

0 comments on commit 24257a1

Please sign in to comment.