It's a heart of Polymer. It allows you to create server side content. It also contains lots of extra mod compatibility for client mods,
+
It's the heart of Polymer. It allows you to create server side content. It also contains lots of extra mod compatibility for client mods,
to make your mod better fit for any modpack.
For [TAG]/translations api version I recommend you checking this maven.
Usage
-
To use i, you just need to use vanilla TranslationText with key specified by you in your code.
-
Then you just need to create data/modid/lang folder in your mod resources.
-Then you can create there en_us.json for default translation and other language files for other.
+
To use it, you just need to use vanilla Text.translation(...) with key specified by you in your code.
+
Then you just need to create data/modid/lang folder in your mod's resources.
+Then you can create there en_us.json for default translation and similar files for other languages (same format as vanilla translations).
It's a set of libraries designed for creation of server side content, that work for player's without mods or (required) resource packs! You can create blocks, items and entities, that not only will work fully on server side (and singleplayer), but also are represented on server the same as normal (vanilla/modded) ones allowing for way better mod compatibility and way less weird edge-cases.
It is also should be fully compatible with close to all other mods and in case of found issues they are patched as soon as possible.
"},{"location":"#updating-from-02x","title":"Updating from 0.2.x","text":"
With Minecraft 1.19.3 being globally breaking update. I took this as a good time to make breaking changes to polymer itself.
It's a heart of Polymer. It allows you to create server side content. It also contains lots of extra mod compatibility for client mods, to make your mod better fit for any modpack.
To use i, you just need to use vanilla TranslationText with key specified by you in your code.
Then you just need to create data/modid/lang folder in your mod resources. Then you can create there en_us.json for default translation and other language files for other.
"},{"location":"other/updating-0.2.x-to-0.3/","title":"Updating from Polymer 0.2.x to 0.3.x","text":""},{"location":"other/updating-0.2.x-to-0.3/#polymer-library-got-split-up","title":"polymer library got split up","text":"
The polymer library was broken into multiple ones, most notably:
polymer-common - Common code shared between modules
polymer-core - All core functionality of polymer. Contains everything required for making server side content + client mod compatibility
polymer-resource-pack - Resource pack support
polymer-networking - Polymer's previous networking api
All modules (excluding polymer-reg-sync-manipulator) also depend (and include) common module. Core additionally depends on polymer-networking, which is used for client sync.
Autohost module now depends only on polymer-networking and polymer-resource-pack.
"},{"location":"other/updating-0.2.x-to-0.3/#packagesclass-name-changes","title":"Packages/Class name changes","text":"
With the split up, many classes changed their packages.
polymer-blocks-ext got renamed to polymer-blocks
From polymer (polymer-core, polymer-resource-pack, polymer-networking)
eu.pb4.polymer.api.networking -> eu.pb4.polymer.networking.api (in polymer-networking):
PolymerPacketUtils is now PolymerServerNetworking
Networking parts of eu.pb4.polymer.api.client.PolymerClientUtils are moved to eu.pb4.polymer.api.networking.PolymerClientNetworking
eu.pb4.polymer.api.resourcepack -> eu.pb4.polymer.resourcepack.api (in polymer-resource-pack):
PolymerRPUtils -> PolymerResourcePackUtils
PolymerRPBuilder -> ResourcePackBuilder
Rest of eu.pb4.polymer.api -> eu.pb4.polymer.core.api (in polymer-core):
eu.pb4.polymer.ext.blocks -> eu.pb4.polymer.blocks (in polymer-blocks)
Additionally, a bunch of method parameters changed to make them more consistent (making ServerPlayerEntity last argument). Many old duplicate context-less methods got removed if they were only accessed by one with player context.
All modules now use same version. This mostly makes it easier to update everything, but also makes some version bumps that don't change anything in some.
"},{"location":"polymer-blocks/basics/","title":"Basics","text":""},{"location":"polymer-blocks/basics/#creating-a-block","title":"Creating a block.","text":"
Creating a block is mostly the same as with regular polymer ones. Only difference is implementation of PolymerTexturedBlock interface, which acts as a marker.
Polymer Blocks supports few types of models/shapes. However, possible amount of blocks is limited, because we can't really add fully custom blocks on client yet.
Every block type has its own functionality and behaviour:
FULL_BLOCK - Noteblocks, have full collision and don't allow transparency, (limit: 799)
VINES_BLOCK - All centered vine blocks, Cave Vines, Twisted Vines and Weeping Vines, (limit: 100)
PLANT_BLOCK - Small plant blocks, sugarcane and saplings, (limit: 21)
KELP_BLOCK - Just kelp, (limit: 25)
CACTUS_BLOCK - Just cactus, (limit: 15!)
They all are accessible from BlockModelType enum.
"},{"location":"polymer-blocks/basics/#defining-a-global-model","title":"Defining a global model","text":"
First thing you do, is creating a model definition. You should do that by calling one of PolymerBlockModel.of(...) methods. It takes the same argument as vanilla definition in assets/(namespace)/blockstate/(block).json file.
Then you need to request a model. It's as simple as calling PolymerBlockResourceUtils.requestBlock(BlockModelType type, PolymerBlockModel... model) with one or more models. It returns a blockstate, that you need to use in your PolymerTexturedBlock as result of getPolymerBlockState(...). If it runs out of free BlockStates to use, it will return null instead. You can also check amount of free blocks with PolymerBlockResourceUtils.getBlocksLeft(BlockModelType type).
If you've done everything correctly, it should now display as your model. Otherwise, you either skipped some step or didn't apply server resource pack. Remember that you still need to register your assets with PolymerRPUtils.addAssetSource(String modId) method.
"},{"location":"polymer-blocks/basics/#just-keep-in-mind","title":"Just keep in mind","text":"
Some block model types have very small amount of free BlockStates. For that reason, while making public registering blocks globally, please allow for disabling of them and handle running out of them for best compatibility and mod support!
These docs will only take care about polymer-related part of creation of blocks. You might want to see official Fabric Wiki for more in depth look into how to create blocks. You can skip some client side specific things, as it won't take effect server side (for example models and textures).
"},{"location":"polymer-core/blocks/#creation-of-blocks","title":"Creation of blocks","text":"
Creation of blocks, similarly to items, is mostly the same as vanilla. Only real difference is that your blocks need to implement Polymer's PolymerBlock interface. It exposes few defaulted methods for manipulation of client side visuals.
For most basic uses, there are default implementation of PolymerBlock:
PolymerHeadBlock - It's an interface (!), that has basic implementation of player head based blocks, you still need to apply it to your Block class,
SimplePolymerBlock - Same as vanilla Block.
"},{"location":"polymer-core/blocks/#selecting-base-polymer-block-type","title":"Selecting base polymer block type.","text":"
To change base block, you need to override Block getPolymerBlock(BlockState) method.
You can also override Block getPolymerBlock(ServerPlayerEntity, BlockState) to replace blocks per player, however keep in mind they should ideally have same collisions.
Both of these methods can't return null. They can also point to other PolymerBlock instances, but keep in mind to make validation if it's configurable by user!
"},{"location":"polymer-core/blocks/#changing-client-side-and-collision-blockstates","title":"Changing client-side and collision BlockStates","text":"
If you want to change what BlockState will be used for server side collision and client side you need to override BlockState getPolymerBlockState(BlockState state) method. You can also override BlockState getPolymerBlockState(BlockState state, ServerPlayerEntity player) for player context, similar to getPolymerBlock. You can return other BlockState of PolymerBlock, but keep in mind you can only nest them up to 32!
Example use:
Changing BlockState to furnace with the same facing, but inverted \"lit\" BlockState property
"},{"location":"polymer-core/blocks/#sending-additional-data-signsheads-or-even-custom","title":"Sending additional data (signs/heads or even custom)","text":"
In case if you want to send additional (to more customize look on client for signs/heads or additional data for companion mod), you need to override onPolymerBlockSend(BlockState blockState, BlockPos.Mutable pos, ServerPlayerEntity player). Technically you can do anything there, but ideally it should be only used for packets.
Example use:
Sending data required to render player head with skin
PolymerHeadBlock is an interface extending PolymerBlock with methods prepared for usage of player heads as a block. To modify texture, you just need to override String getPolymerSkinValue(BlockState state, BlockPos pos, ServerPlayerEntity entity) which should return texture value.
To generate it you can use websites like https://mineskin.org/.
Additionally, you can override BlockState getPolymerBlockState(BlockState state) to change rotation of Player Head Block.
The only thing you need to do to remove BlockEntity from being sent to client is registering its BlockEntityType with PolymerBlockUtils.registerBlockEntity(BlockEntityType types).
If you want to get client-friendly representation of block, you need to call PolymerBlockUtils.getBlockStateSafely(PolymerBlock block, BlockState blockState) method. It should return block safe to use (or air in case of failure).
While it's supported, please limit creation of PolymerBlock light sources. Because of how Minecraft handles light updates on server/client, these can be little laggy (as it needs to be sent updates every time light changes) and not perfect, as client is emulating light by itself.
Similarly, client recalculates some BlockStates, which can cause some desyncs.
"},{"location":"polymer-core/client-side/","title":"Client side features","text":"
While Polymer by itself is mainly server side api, it includes some client side functionality for mods to use. It allows you for example to display vanilla friendly item for normal clients and custom models if it's present on server.
"},{"location":"polymer-core/client-side/#keeping-modded-itemblock-on-compatible-client","title":"Keeping modded item/block on compatible client.","text":"
To keep client side model for loading, you need to implement PolymerKeepModel interface on your modded object. To enable it's decoding, just add PolymerClientDecoded interface for it.
After that, you just need to return server side items/block in corresponding player-aware getPolymerX methods.
To \"sync\" presence/version of your mod you can use Polymer's handshake feature.
You can do that by registering packets for which you should check Polymer Networking documentation
After that you can just validate if player supports it with this check it like this
SomeObject getPolymerX(ServerPlayerEntity player) {\n if (PolymerServerNetworking.getSupportedVersion(player.networkHandler, PACKET_ID) > 0) {\n // Client state for modded\n return this;\n } else {\n // Client state for vanilla\n return VanillaObjects.SOMETHING;\n }}\n
"},{"location":"polymer-core/client-side/#this-section-is-incomplete-i-hope-in-code-comments-will-guide-you-well","title":"This section is incomplete... I hope in code comments will guide you well...","text":""},{"location":"polymer-core/entities/","title":"Entities","text":"
Note
These docs will only take care about polymer-related part of creation of entities. You might want to see official Fabric Wiki for more in depth look into how to create entities. You can skip most client side specific things, as it won't take effect server side (for example rendering/models)
"},{"location":"polymer-core/entities/#creation-of-entities","title":"Creation of entities","text":"
Creation of entities is mostly the same as vanilla. You just need to implement PolymerEntity interface on your entity's class. It exposes few defaulted methods for manipulation of client side visuals.
You also need to register your entity type as virtual, by using PolymerEntityUtils.registerType(EntityType... types).
"},{"location":"polymer-core/entities/#changing-client-side-entity","title":"Changing client side entity.","text":"
To select visual entity type, you just need to override EntityType<?> getPolymerEntityType(ServerPlayerEntity player)
This method can't return null or another EntityType that points to other virtual entity, as it won't work.
"},{"location":"polymer-core/entities/#modifying-held-items","title":"Modifying held items","text":"
You most likely want to modify items held by entity, to indicate its type. To do it you need to override List<Pair<EquipmentSlot, ItemStack>> getPolymerVisibleEquipment(List<Pair<EquipmentSlot, ItemStack>> items, ServerPlayerEntities player).
Example use:
Displaying real items with helmet replacement.
@Override\npublic List<Pair<EquipmentSlot, ItemStack>> getPolymerVisibleEquipment(List<Pair<EquipmentSlot, ItemStack>> items, ServerPlayerEntities player) {\n var list = new ArrayList<Pair<EquipmentSlot, ItemStack>>(map.size());\n for (var entry : items) {\n if (entry.getKey() == EquipmentSlot.HEAD) {\n continue;\n } else {\n list.add(Pair.of(entry.getKey(), entry.getValue()));\n }\n }\n list.add(new Pair<>(EquipmentSlot.HEAD, new ItemStack(Items.WITHER_SKELETON_SKULL)));\n\n return list;\n}\n
"},{"location":"polymer-core/entities/#modifying-client-side-data-trackers","title":"Modifying client-side data trackers","text":"
For more control over entity, you can modify DataTracker values send to client directly. To do it, you need to override void modifyRawTrackedData(List<DataTracker.SerializedEntry<?>> data, ServerPlayerEntity player, boolean initial) method. You should also be safe around it, as sending DataTracker.Entry's, that don't exist on client-side entity representation will cause issues and errors!
To get TrackedData, which is needed to create Entries, you can either use accessors, or manually construct the data.
This is the first and most important library for server side development.
It allows you to create blocks, items and entities, that not only will work fully on server side (and singleplayer), but also are represented on server the same as normal (vanilla/modded) ones allowing for way better mod compatibility and way less weird edge-cases.
This library also handles all mod compatibility with client only mods (when it's present), so it can be safely used in a modpack.
"},{"location":"polymer-core/getting-started/#adding-to-dependencies","title":"Adding to dependencies","text":"
repositories {\n maven { url 'https://maven.nucleoid.xyz' } // You should have it\n}\n\ndependencies {\n modImplementation include(\"eu.pb4:polymer-core:[TAG]\")\n}\n
For [TAG]/polymer-core version I recommend you checking this maven.
These docs will only take care about polymer-related part of creation of items. You might want to see official Fabric Wiki for more in depth look into how to create items. You can skip some client side specific things, as it won't take effect server side (excluding item groups, as they can be used by other mods)
"},{"location":"polymer-core/items/#creation-of-items","title":"Creation of items","text":"
Creation of items is mostly the same as vanilla. Only real difference is that your items need to implement Polymer's PolymerItem interface. It exposes few defaulted methods for manipulation of client side visuals.
"},{"location":"polymer-core/items/#manipulation-of-client-side-itemstack","title":"Manipulation of client side ItemStack","text":"
Sometimes it's useful to manipulate entire ItemStack, as it allows achieving better effects. To do so, you need to override the ItemStack getPolymerItemStack(ItemStack itemStack, TooltipContext context, @Nullable ServerPlayerEntity player) method. However, keep in mind that making nbt incorrect might create some issues (for example breaking items in creative mode)!
Ideally you should modify output of PolymerItem.super.getPolymerItemStack(itemStack, context, player), PolymerItemUtils.createItemStack(itemStack, player) or PolymerItemUtils.createMinimalItemStack(itemStack, player), as they contain all required NBT.
"},{"location":"polymer-core/items/#support-of-modelscustommodeldata","title":"Support of models/CustomModelData","text":"
You can change custom model data of virtual model by simple overriding int getPolymerCustomModelData(ItemStack itemStack, @Nullable ServerPlayerEntity player). You can return -1 to disable it, or any number above it to set value of it.
Ideally you should return value created with polymer's resource pack utils, but nothing blocks you from using any other ones.
Example usage:
Changing client-side item CustomModelData to previously stored value.
@Override\npublic int getPolymerCustomModelData(ItemStack itemStack, @Nullable ServerPlayerEntity player) {\n // Instance of PolymerModelData, see info above\n return this.cmd.value();\n}\n
"},{"location":"polymer-core/items/#item-groups-support","title":"Item Groups support","text":"
You can create server side Item Groups, which will be later synced with Polymer-compatible clients. They also allow you to create server side Creative categories, that are accessible via /polymer creative command.
To create, it, you just need to call one of provided PolymerItemGroupUtils.builder(Identifier) static method. Then you can create it just like regular ItemGroup.
"},{"location":"polymer-core/items/#manipulation-of-non-polymer-items","title":"Manipulation of non-polymer items","text":"
Sometimes, you might want to manipulate other vanilla/modded items without implementing PolymerItem on them. You can do it by using few events from PolymerItemUtils.
"},{"location":"polymer-core/items/#forcing-items-to-go-through-polymer","title":"Forcing items to go through Polymer","text":"
To force items to go through polymer's client side item creation, you need to register event handler for PolymerItemUtils.ITEM_CHECK event. You can register it by using PolymerItemUtils.ITEM_CHECK.register(ItemStack -> boolean) lambda.
Example use:
Making every item with string NBT tag of \"Test\" go through polymer
"},{"location":"polymer-core/items/#modification-of-client-side-item","title":"Modification of Client side item","text":"
After getting vanilla (or for any PolymerItem by default) you can modify any client side item with PolymerItemUtils.ITEM_MODIFICATION_EVENT event. Just keep in mind doing it incorrectly can cause issues (mostly around creative mode, but also in case you modify original item). You change the client side item by either directly modifying client ItemStack or creating new one and returning it. Ideally you should also keep previous nbt, just so it can work nicely, You can register this event by using PolymerItemUtils.ITEM_MODIFICATION_EVENT.register(((ItemStack original, ItemStack client, ServerPlayerEntity player) -> ItemStack) lambda.
Example use:
Hiding enchantment glint for items with HideEnchantments: 1b nbt tag
The only thing to make your enchantment fully server side is implementation of PolymerSyncedObject or PolymerEnchantment interface. You also might want to manipulate some things from Polymer Block/Item events.
Polymer has support for creating custom sound events, that can fallback to vanilla sounds for players without resource packs and resource pack ones if they are present.
To use it, you just need to create new instance of PolymerSoundEvent. You can use it similarly to vanilla ones.
To register custom, server side statistic you just need to call PolymerStat.registerStat(Identifier, StatFormatter). Then you can use it just like vanilla ones.
To create custom, server side status effects, you just need to implement PolymerStatusEffect on your custom StatusEffect class. You can also override StatusEffect getPolymerStatusEffect() to display it as vanilla one (otherwise they are hidden).
This is module of Polymer containing all client <-> server networking apis, including some more uncommon ones.
"},{"location":"polymer-networking/getting-started/#adding-to-dependencies","title":"Adding to dependencies","text":"
repositories {\n maven { url 'https://maven.nucleoid.xyz' } // You should have it\n}\n\ndependencies {\n modImplementation include(\"eu.pb4:polymer-networking:[TAG]\")\n}\n
For [TAG]/polymer-blocks version I recommend you checking this maven.
This is quite simple. You just need to do things written below. Ideally it all should run at your mod's initialization.
"},{"location":"polymer-resource-pack/basics/#adding-mod-assets-to-resource-pack","title":"Adding mod assets to resource pack","text":"
First step for adding assets to resource pack is marking mod as asset source. To do it you just need to call boolean PolymerResourcePackUtils.addModAssets(String modid), which returns true if modid is valid.
This should be called ideally in your mod initializer.
Additionally, you can add assets manually by calling PolymerRPBuilder.addData(String path, byte[] data). You can get instance of it by listening to PolymerResourcePackUtils.RESOURCE_PACK_CREATION_EVENT. Just keep in minds that new one will be created every time resource pack is generated.
"},{"location":"polymer-resource-pack/basics/#requesting-model-for-item","title":"Requesting model for item","text":"
After that you can register your models by calling PolymerModelData PolymerResourcePackUtils.requestModel(Item vanillaItem, Identifier modelPath). It returns PolymerModelData with contains all information you need for applying custom model data to your items. You need to keep in mind, that modelPath needs to contain main directory (in similar way to vanilla models). While model is created, all it's overrides are copied and applied, so you don't need to request them manually (useful for bows).
You can execute this function before making your mod an asset source, but it should be run before resource pack is build.
Example use:
PolymerModelData modelData = PolymerResourcePackUtils.requestModel(Items.IRON_SWORD, new Identifier(\"mymod\", \"item/silver_sword\"));\n
Polymer supports custom armor textures thanks to usage of Ancientkingg's fancyPants resource pack.
To request it you need to use PolymerResourcePackUtils.requestArmor(Identifier). It will automatically create variant of every armor peace, however you aren't required to use/define them all.
To apply it to your armor, you need to set your client side item to leather armor peace. Then you need to override PolymerItem.getPolymerArmorColor() method and return used color.
Checking if player has resource pack is quite simple. You just need to call boolean PolymerResourcePackUtils.hasPack(ServerPlayerEntity player).
Example use:
Identifier font;\n\nif (PolymerResourcePackUtils.hasPack(player)) {\n font = new Identifier(\"mymod\", \"myfont\");\n} else {\n font = new Identifier(\"minecraft\", \"default\");\n}\n
To make font required, you just need to call PolymerResourcePackUtil.markAsRequired().
However, Polymer doesn't contain any utilities for sending packs, as it should be implemented by other mods (or use vanilla one). One exception is resource pack on client, which will get effected by that.
I also recommend you to keep it optional if it's possible.
To create resource pack you only need to execute /polymer generate-pack command. Resource pack will be located in your server folder as polymer-resourcepack.zip.
This is additional module/extension of Polymer, adding support for textured blocks. It requires server resource pack to be active work correctly.
"},{"location":"polymer-resource-pack/getting-started/#adding-to-dependencies","title":"Adding to dependencies","text":"
repositories {\n maven { url 'https://maven.nucleoid.xyz' } // You should have it\n}\n\ndependencies {\n modImplementation include(\"eu.pb4:polymer-resource-pack:[TAG]\")\n}\n
For [TAG]/polymer-blocks version I recommend you checking this maven.
Polymer Virtual Entity API was created to simplify usage of virtual (packet-based) entities with special visual properties. While they might require additional setup for player to be able to see them, they don't affect on server's performance as much. Additionally, they can't be removed by other mods or commands, making them more persistent against accidental breaking and crashes.
VirtualElements are object controlling single instances of packet entities on client. It allows you to position, rotate and modify any supported properties of selected entities. This api provides multiple builtin ones that are most likely to be used. They need to be used with ElementHolder to be visible. See more in section below.
BlockDisplayElement - Used for displaying blocks. Shows as minecraft:block_display on client,
ItemDisplayElement - Used for displaying items. Shows as minecraft:item_display on client,
TextDisplayElement - Used for displaying text. Shows as minecraft:text_display on client,
InteractionElement - Used for detecting interactions. Shows as minecraft:interaction on client,
MarkerElement - Used for attaching other entities (more later). Shows as minecraft:armor_stand with marker properties on client,
MobAnchorElement - Similar to MarkerElement, but allows for more effects. Shows as invisible minecraft:slime of size 0.
There are also multiple abstract classes and main VirtualElement interface you can use to implement things in more flexible way.
Example usage:
// Creation\nvar element = new TextDisplayElement();\n// Changing entity-specific property\nelement.setText(Text.literal(\"Hello world\");\n// Changing offset\nelement.setOffset(new Vec3d(0, 5, 0));\n// Adding to holder. More info below!\nholder.addElement(element);\n
"},{"location":"polymer-virtual-entity/basics/#creating-a-elementholder","title":"Creating a ElementHolder","text":"
ElementHolder is main object, that holds and manages ticking and sending of groups of VirtualElements. It can be (and in many cases should be) extended, which can be used to create more dynamic elements without requirement of backing it with BlockEntity or Entity objects. However, you still need to attach it to make it visible and tick. This can be done by using attachments. (more in section below).
Example usage:
var holder = new ElementHolder();\n\nvar element1 = createElement(...);\nvar element2 = createElement(...);\nvar element3 = createElement(...);\n\n// Adding elements\nholder.addElement(element1);\nholder.addElement(element2);\nholder.addElement(element3);\n\n// Removing elements\nholder.removeElement(element3);\n\n/* Attach here */ \n
HolderAttachments are final element, that connects ElementHolders with their position and ticking. There are multiple builtin ones, which different purposes:
EntityAttachment - attaches to any entity. Can be created with EntityAttachement.of(ElementHolder, Entity), which requires manual ticking or EntityAttachement.ofTicking(ElementHolder, Entity) which does that automatically.
ChunkAttachment - attaches to a chunk. It's destroyed after chunk gets unloaded. Can be created with ChunkAttachment.of(ElementHolder, ServerWorld, BlockPos/Vec3d) for manual ticking, or ChunkAttachment.ofTicking(ElementHolder, ServerWorld, BlockPos/Vec3d) to tick automatically.
ManualAttachment - Used as a stub, doesn't handle anything by default. You need to call methods by hand.
Example usage:
var holder = new ElementHolder();\n\n/* ... */\n\nEntityAttachment.ofTicking(holder, player);\n
This is module of Polymer allowing you to create virtual (packet-only) entities is a quick and simple way. It's mostly designed around using it with Display Entities, but it can be extended to work with any other. You can attach them to regular (or Polymer) entities and chunks.
"},{"location":"polymer-virtual-entity/getting-started/#adding-to-dependencies","title":"Adding to dependencies","text":"
repositories {\n maven { url 'https://maven.nucleoid.xyz' } // You should have it\n}\n\ndependencies {\n modImplementation include(\"eu.pb4:polymer-virtual-entity:[TAG]\")\n}\n
For [TAG]/polymer-blocks version I recommend you checking this maven.
Latest version:
"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"About Polymer","text":"
It's a set of libraries designed for creation of server side content, that work for player's without mods or (required) resource packs! You can create blocks, items and entities, that not only will work fully on server side (and singleplayer), but also are represented on server the same as normal (vanilla/modded) ones allowing for way better mod compatibility and way less weird edge-cases.
It is also should be fully compatible with close to all other mods and in case of found issues they are patched as soon as possible.
It's the heart of Polymer. It allows you to create server side content. It also contains lots of extra mod compatibility for client mods, to make your mod better fit for any modpack.
To use it, you just need to use vanilla Text.translation(...) with key specified by you in your code.
Then you just need to create data/modid/lang folder in your mod's resources. Then you can create there en_us.json for default translation and similar files for other languages (same format as vanilla translations).
"},{"location":"other/updating-0.2.x-to-0.3/","title":"Updating from Polymer 0.2.x to 0.3.x","text":""},{"location":"other/updating-0.2.x-to-0.3/#polymer-library-got-split-up","title":"polymer library got split up","text":"
The polymer library was broken into multiple ones, most notably:
polymer-common - Common code shared between modules
polymer-core - All core functionality of polymer. Contains everything required for making server side content + client mod compatibility
polymer-resource-pack - Resource pack support
polymer-networking - Polymer's previous networking api
All modules (excluding polymer-reg-sync-manipulator) also depend (and include) common module. Core additionally depends on polymer-networking, which is used for client sync.
Autohost module now depends only on polymer-networking and polymer-resource-pack.
"},{"location":"other/updating-0.2.x-to-0.3/#packagesclass-name-changes","title":"Packages/Class name changes","text":"
With the split up, many classes changed their packages.
polymer-blocks-ext got renamed to polymer-blocks
From polymer (polymer-core, polymer-resource-pack, polymer-networking)
eu.pb4.polymer.api.networking -> eu.pb4.polymer.networking.api (in polymer-networking):
PolymerPacketUtils is now PolymerServerNetworking
Networking parts of eu.pb4.polymer.api.client.PolymerClientUtils are moved to eu.pb4.polymer.api.networking.PolymerClientNetworking
eu.pb4.polymer.api.resourcepack -> eu.pb4.polymer.resourcepack.api (in polymer-resource-pack):
PolymerRPUtils -> PolymerResourcePackUtils
PolymerRPBuilder -> ResourcePackBuilder
Rest of eu.pb4.polymer.api -> eu.pb4.polymer.core.api (in polymer-core):
eu.pb4.polymer.ext.blocks -> eu.pb4.polymer.blocks (in polymer-blocks)
Additionally, a bunch of method parameters changed to make them more consistent (making ServerPlayerEntity last argument). Many old duplicate context-less methods got removed if they were only accessed by one with player context.
All modules now use same version. This mostly makes it easier to update everything, but also makes some version bumps that don't change anything in some.
"},{"location":"polymer-blocks/basics/","title":"Basics","text":""},{"location":"polymer-blocks/basics/#creating-a-block","title":"Creating a block.","text":"
Creating a block is mostly the same as with regular polymer ones. Only difference is implementation of PolymerTexturedBlock interface, which acts as a marker.
Polymer Blocks supports few types of models/shapes. However, possible amount of blocks is limited, because we can't really add fully custom blocks on client yet.
Every block type has its own functionality and behaviour:
FULL_BLOCK - Noteblocks, have full collision and don't allow transparency, (limit: 799)
VINES_BLOCK - All centered vine blocks, Cave Vines, Twisted Vines and Weeping Vines, (limit: 100)
PLANT_BLOCK - Small plant blocks, sugarcane and saplings, (limit: 21)
KELP_BLOCK - Just kelp, (limit: 25)
CACTUS_BLOCK - Just cactus, (limit: 15!)
They all are accessible from BlockModelType enum.
"},{"location":"polymer-blocks/basics/#defining-a-global-model","title":"Defining a global model","text":"
First thing you do, is creating a model definition. You should do that by calling one of PolymerBlockModel.of(...) methods. It takes the same argument as vanilla definition in assets/(namespace)/blockstate/(block).json file.
Then you need to request a model. It's as simple as calling PolymerBlockResourceUtils.requestBlock(BlockModelType type, PolymerBlockModel... model) with one or more models. It returns a blockstate, that you need to use in your PolymerTexturedBlock as result of getPolymerBlockState(...). If it runs out of free BlockStates to use, it will return null instead. You can also check amount of free blocks with PolymerBlockResourceUtils.getBlocksLeft(BlockModelType type).
If you've done everything correctly, it should now display as your model. Otherwise, you either skipped some step or didn't apply server resource pack. Remember that you still need to register your assets with PolymerRPUtils.addAssetSource(String modId) method.
"},{"location":"polymer-blocks/basics/#just-keep-in-mind","title":"Just keep in mind","text":"
Some block model types have very small amount of free BlockStates. For that reason, while making public registering blocks globally, please allow for disabling of them and handle running out of them for best compatibility and mod support!
These docs will only take care about polymer-related part of creation of blocks. You might want to see official Fabric Wiki for more in depth look into how to create blocks. You can skip some client side specific things, as it won't take effect server side (for example models and textures).
"},{"location":"polymer-core/blocks/#creation-of-blocks","title":"Creation of blocks","text":"
Creation of blocks, similarly to items, is mostly the same as vanilla. Only real difference is that your blocks need to implement Polymer's PolymerBlock interface. It exposes few defaulted methods for manipulation of client side visuals.
For most basic uses, there are default implementation of PolymerBlock:
PolymerHeadBlock - It's an interface (!), that has basic implementation of player head based blocks, you still need to apply it to your Block class,
SimplePolymerBlock - Same as vanilla Block.
"},{"location":"polymer-core/blocks/#selecting-base-polymer-block-type","title":"Selecting base polymer block type.","text":"
To change base block, you need to override Block getPolymerBlock(BlockState) method.
You can also override Block getPolymerBlock(ServerPlayerEntity, BlockState) to replace blocks per player, however keep in mind they should ideally have same collisions.
Both of these methods can't return null. They can also point to other PolymerBlock instances, but keep in mind to make validation if it's configurable by user!
"},{"location":"polymer-core/blocks/#changing-client-side-and-collision-blockstates","title":"Changing client-side and collision BlockStates","text":"
If you want to change what BlockState will be used for server side collision and client side you need to override BlockState getPolymerBlockState(BlockState state) method. You can also override BlockState getPolymerBlockState(BlockState state, ServerPlayerEntity player) for player context, similar to getPolymerBlock. You can return other BlockState of PolymerBlock, but keep in mind you can only nest them up to 32!
Example use:
Changing BlockState to furnace with the same facing, but inverted \"lit\" BlockState property
"},{"location":"polymer-core/blocks/#sending-additional-data-signsheads-or-even-custom","title":"Sending additional data (signs/heads or even custom)","text":"
In case if you want to send additional (to more customize look on client for signs/heads or additional data for companion mod), you need to override onPolymerBlockSend(BlockState blockState, BlockPos.Mutable pos, ServerPlayerEntity player). Technically you can do anything there, but ideally it should be only used for packets.
Example use:
Sending data required to render player head with skin
PolymerHeadBlock is an interface extending PolymerBlock with methods prepared for usage of player heads as a block. To modify texture, you just need to override String getPolymerSkinValue(BlockState state, BlockPos pos, ServerPlayerEntity entity) which should return texture value.
To generate it you can use websites like https://mineskin.org/.
Additionally, you can override BlockState getPolymerBlockState(BlockState state) to change rotation of Player Head Block.
The only thing you need to do to remove BlockEntity from being sent to client is registering its BlockEntityType with PolymerBlockUtils.registerBlockEntity(BlockEntityType types).
If you want to get client-friendly representation of block, you need to call PolymerBlockUtils.getBlockStateSafely(PolymerBlock block, BlockState blockState) method. It should return block safe to use (or air in case of failure).
While it's supported, please limit creation of PolymerBlock light sources. Because of how Minecraft handles light updates on server/client, these can be little laggy (as it needs to be sent updates every time light changes) and not perfect, as client is emulating light by itself.
Similarly, client recalculates some BlockStates, which can cause some desyncs.
"},{"location":"polymer-core/client-side/","title":"Client side features","text":"
While Polymer by itself is mainly server side api, it includes some client side functionality for mods to use. It allows you for example to display vanilla friendly item for normal clients and custom models if it's present on server.
"},{"location":"polymer-core/client-side/#keeping-modded-itemblock-on-compatible-client","title":"Keeping modded item/block on compatible client.","text":"
To keep client side model for loading, you need to implement PolymerKeepModel interface on your modded object. To enable it's decoding, just add PolymerClientDecoded interface for it.
After that, you just need to return server side items/block in corresponding player-aware getPolymerX methods.
To \"sync\" presence/version of your mod you can use Polymer's handshake feature.
You can do that by registering packets for which you should check Polymer Networking documentation
After that you can just validate if player supports it with this check it like this
SomeObject getPolymerX(ServerPlayerEntity player) {\n if (PolymerServerNetworking.getSupportedVersion(player.networkHandler, PACKET_ID) > 0) {\n // Client state for modded\n return this;\n } else {\n // Client state for vanilla\n return VanillaObjects.SOMETHING;\n }}\n
"},{"location":"polymer-core/client-side/#this-section-is-incomplete-i-hope-in-code-comments-will-guide-you-well","title":"This section is incomplete... I hope in code comments will guide you well...","text":""},{"location":"polymer-core/entities/","title":"Entities","text":"
Note
These docs will only take care about polymer-related part of creation of entities. You might want to see official Fabric Wiki for more in depth look into how to create entities. You can skip most client side specific things, as it won't take effect server side (for example rendering/models)
"},{"location":"polymer-core/entities/#creation-of-entities","title":"Creation of entities","text":"
Creation of entities is mostly the same as vanilla. You just need to implement PolymerEntity interface on your entity's class. It exposes few defaulted methods for manipulation of client side visuals.
You also need to register your entity type as virtual, by using PolymerEntityUtils.registerType(EntityType... types).
"},{"location":"polymer-core/entities/#changing-client-side-entity","title":"Changing client side entity.","text":"
To select visual entity type, you just need to override EntityType<?> getPolymerEntityType(ServerPlayerEntity player)
This method can't return null or another EntityType that points to other virtual entity, as it won't work.
"},{"location":"polymer-core/entities/#modifying-held-items","title":"Modifying held items","text":"
You most likely want to modify items held by entity, to indicate its type. To do it you need to override List<Pair<EquipmentSlot, ItemStack>> getPolymerVisibleEquipment(List<Pair<EquipmentSlot, ItemStack>> items, ServerPlayerEntities player).
Example use:
Displaying real items with helmet replacement.
@Override\npublic List<Pair<EquipmentSlot, ItemStack>> getPolymerVisibleEquipment(List<Pair<EquipmentSlot, ItemStack>> items, ServerPlayerEntities player) {\n var list = new ArrayList<Pair<EquipmentSlot, ItemStack>>(map.size());\n for (var entry : items) {\n if (entry.getKey() == EquipmentSlot.HEAD) {\n continue;\n } else {\n list.add(Pair.of(entry.getKey(), entry.getValue()));\n }\n }\n list.add(new Pair<>(EquipmentSlot.HEAD, new ItemStack(Items.WITHER_SKELETON_SKULL)));\n\n return list;\n}\n
"},{"location":"polymer-core/entities/#modifying-client-side-data-trackers","title":"Modifying client-side data trackers","text":"
For more control over entity, you can modify DataTracker values send to client directly. To do it, you need to override void modifyRawTrackedData(List<DataTracker.SerializedEntry<?>> data, ServerPlayerEntity player, boolean initial) method. You should also be safe around it, as sending DataTracker.Entry's, that don't exist on client-side entity representation will cause issues and errors!
To get TrackedData, which is needed to create Entries, you can either use accessors, or manually construct the data.
This is the first and most important library for server side development.
It allows you to create blocks, items and entities, that not only will work fully on server side (and singleplayer), but also are represented on server the same as normal (vanilla/modded) ones allowing for way better mod compatibility and way less weird edge-cases.
This library also handles all mod compatibility with client only mods (when it's present), so it can be safely used in a modpack.
"},{"location":"polymer-core/getting-started/#adding-to-dependencies","title":"Adding to dependencies","text":"
repositories {\n maven { url 'https://maven.nucleoid.xyz' } // You should have it\n}\n\ndependencies {\n modImplementation include(\"eu.pb4:polymer-core:[TAG]\")\n}\n
For [TAG]/polymer-core version I recommend you checking this maven.
These docs will only take care about polymer-related part of creation of items. You might want to see official Fabric Wiki for more in depth look into how to create items. You can skip some client side specific things, as it won't take effect server side (excluding item groups, as they can be used by other mods)
"},{"location":"polymer-core/items/#creation-of-items","title":"Creation of items","text":"
Creation of items is mostly the same as vanilla. Only real difference is that your items need to implement Polymer's PolymerItem interface. It exposes few defaulted methods for manipulation of client side visuals.
"},{"location":"polymer-core/items/#manipulation-of-client-side-itemstack","title":"Manipulation of client side ItemStack","text":"
Sometimes it's useful to manipulate entire ItemStack, as it allows achieving better effects. To do so, you need to override the ItemStack getPolymerItemStack(ItemStack itemStack, TooltipContext context, @Nullable ServerPlayerEntity player) method. However, keep in mind that making nbt incorrect might create some issues (for example breaking items in creative mode)!
Ideally you should modify output of PolymerItem.super.getPolymerItemStack(itemStack, context, player), PolymerItemUtils.createItemStack(itemStack, player) or PolymerItemUtils.createMinimalItemStack(itemStack, player), as they contain all required NBT.
"},{"location":"polymer-core/items/#support-of-modelscustommodeldata","title":"Support of models/CustomModelData","text":"
You can change custom model data of virtual model by simple overriding int getPolymerCustomModelData(ItemStack itemStack, @Nullable ServerPlayerEntity player). You can return -1 to disable it, or any number above it to set value of it.
Ideally you should return value created with polymer's resource pack utils, but nothing blocks you from using any other ones.
Example usage:
Changing client-side item CustomModelData to previously stored value.
@Override\npublic int getPolymerCustomModelData(ItemStack itemStack, @Nullable ServerPlayerEntity player) {\n // Instance of PolymerModelData, see info above\n return this.cmd.value();\n}\n
"},{"location":"polymer-core/items/#item-groups-support","title":"Item Groups support","text":"
You can create server side Item Groups, which will be later synced with Polymer-compatible clients. They also allow you to create server side Creative categories, that are accessible via /polymer creative command.
To create, it, you just need to call one of provided PolymerItemGroupUtils.builder(Identifier) static method. Then you can create it just like regular ItemGroup.
"},{"location":"polymer-core/items/#manipulation-of-non-polymer-items","title":"Manipulation of non-polymer items","text":"
Sometimes, you might want to manipulate other vanilla/modded items without implementing PolymerItem on them. You can do it by using few events from PolymerItemUtils.
"},{"location":"polymer-core/items/#forcing-items-to-go-through-polymer","title":"Forcing items to go through Polymer","text":"
To force items to go through polymer's client side item creation, you need to register event handler for PolymerItemUtils.ITEM_CHECK event. You can register it by using PolymerItemUtils.ITEM_CHECK.register(ItemStack -> boolean) lambda.
Example use:
Making every item with string NBT tag of \"Test\" go through polymer
"},{"location":"polymer-core/items/#modification-of-client-side-item","title":"Modification of Client side item","text":"
After getting vanilla (or for any PolymerItem by default) you can modify any client side item with PolymerItemUtils.ITEM_MODIFICATION_EVENT event. Just keep in mind doing it incorrectly can cause issues (mostly around creative mode, but also in case you modify original item). You change the client side item by either directly modifying client ItemStack or creating new one and returning it. Ideally you should also keep previous nbt, just so it can work nicely, You can register this event by using PolymerItemUtils.ITEM_MODIFICATION_EVENT.register(((ItemStack original, ItemStack client, ServerPlayerEntity player) -> ItemStack) lambda.
Example use:
Hiding enchantment glint for items with HideEnchantments: 1b nbt tag
The only thing to make your enchantment fully server side is implementation of PolymerSyncedObject or PolymerEnchantment interface. You also might want to manipulate some things from Polymer Block/Item events.
Polymer has support for creating custom sound events, that can fallback to vanilla sounds for players without resource packs and resource pack ones if they are present.
To use it, you just need to create new instance of PolymerSoundEvent. You can use it similarly to vanilla ones.
To register custom, server side statistic you just need to call PolymerStat.registerStat(Identifier, StatFormatter). Then you can use it just like vanilla ones.
To create custom, server side status effects, you just need to implement PolymerStatusEffect on your custom StatusEffect class. You can also override StatusEffect getPolymerStatusEffect() to display it as vanilla one (otherwise they are hidden).
This is module of Polymer containing all client <-> server networking apis, including some more uncommon ones.
"},{"location":"polymer-networking/getting-started/#adding-to-dependencies","title":"Adding to dependencies","text":"
repositories {\n maven { url 'https://maven.nucleoid.xyz' } // You should have it\n}\n\ndependencies {\n modImplementation include(\"eu.pb4:polymer-networking:[TAG]\")\n}\n
For [TAG]/polymer-blocks version I recommend you checking this maven.
This is quite simple. You just need to do things written below. Ideally it all should run at your mod's initialization.
"},{"location":"polymer-resource-pack/basics/#adding-mod-assets-to-resource-pack","title":"Adding mod assets to resource pack","text":"
First step for adding assets to resource pack is marking mod as asset source. To do it you just need to call boolean PolymerResourcePackUtils.addModAssets(String modid), which returns true if modid is valid.
This should be called ideally in your mod initializer.
Additionally, you can add assets manually by calling PolymerRPBuilder.addData(String path, byte[] data). You can get instance of it by listening to PolymerResourcePackUtils.RESOURCE_PACK_CREATION_EVENT. Just keep in minds that new one will be created every time resource pack is generated.
"},{"location":"polymer-resource-pack/basics/#requesting-model-for-item","title":"Requesting model for item","text":"
After that you can register your models by calling PolymerModelData PolymerResourcePackUtils.requestModel(Item vanillaItem, Identifier modelPath). It returns PolymerModelData with contains all information you need for applying custom model data to your items. You need to keep in mind, that modelPath needs to contain main directory (in similar way to vanilla models). While model is created, all it's overrides are copied and applied, so you don't need to request them manually (useful for bows).
You can execute this function before making your mod an asset source, but it should be run before resource pack is build.
Example use:
PolymerModelData modelData = PolymerResourcePackUtils.requestModel(Items.IRON_SWORD, new Identifier(\"mymod\", \"item/silver_sword\"));\n
Polymer supports custom armor textures thanks to usage of Ancientkingg's fancyPants resource pack.
To request it you need to use PolymerResourcePackUtils.requestArmor(Identifier). It will automatically create variant of every armor peace, however you aren't required to use/define them all.
To apply it to your armor, you need to set your client side item to leather armor peace. Then you need to override PolymerItem.getPolymerArmorColor() method and return used color.
Checking if player has resource pack is quite simple. You just need to call boolean PolymerResourcePackUtils.hasPack(ServerPlayerEntity player).
Example use:
Identifier font;\n\nif (PolymerResourcePackUtils.hasPack(player)) {\n font = new Identifier(\"mymod\", \"myfont\");\n} else {\n font = new Identifier(\"minecraft\", \"default\");\n}\n
To make font required, you just need to call PolymerResourcePackUtil.markAsRequired().
However, Polymer doesn't contain any utilities for sending packs, as it should be implemented by other mods (or use vanilla one). One exception is resource pack on client, which will get effected by that.
I also recommend you to keep it optional if it's possible.
To create resource pack you only need to execute /polymer generate-pack command. Resource pack will be located in your server folder as polymer-resourcepack.zip.
This is additional module/extension of Polymer, adding support for textured blocks. It requires server resource pack to be active work correctly.
"},{"location":"polymer-resource-pack/getting-started/#adding-to-dependencies","title":"Adding to dependencies","text":"
repositories {\n maven { url 'https://maven.nucleoid.xyz' } // You should have it\n}\n\ndependencies {\n modImplementation include(\"eu.pb4:polymer-resource-pack:[TAG]\")\n}\n
For [TAG]/polymer-blocks version I recommend you checking this maven.
Polymer Virtual Entity API was created to simplify usage of virtual (packet-based) entities with special visual properties. While they might require additional setup for player to be able to see them, they don't affect on server's performance as much. Additionally, they can't be removed by other mods or commands, making them more persistent against accidental breaking and crashes.
VirtualElements are object controlling single instances of packet entities on client. It allows you to position, rotate and modify any supported properties of selected entities. This api provides multiple builtin ones that are most likely to be used. They need to be used with ElementHolder to be visible. See more in section below.
BlockDisplayElement - Used for displaying blocks. Shows as minecraft:block_display on client,
ItemDisplayElement - Used for displaying items. Shows as minecraft:item_display on client,
TextDisplayElement - Used for displaying text. Shows as minecraft:text_display on client,
InteractionElement - Used for detecting interactions. Shows as minecraft:interaction on client,
MarkerElement - Used for attaching other entities (more later). Shows as minecraft:armor_stand with marker properties on client,
MobAnchorElement - Similar to MarkerElement, but allows for more effects. Shows as invisible minecraft:slime of size 0.
There are also multiple abstract classes and main VirtualElement interface you can use to implement things in more flexible way.
Example usage:
// Creation\nvar element = new TextDisplayElement();\n// Changing entity-specific property\nelement.setText(Text.literal(\"Hello world\");\n// Changing offset\nelement.setOffset(new Vec3d(0, 5, 0));\n// Adding to holder. More info below!\nholder.addElement(element);\n
"},{"location":"polymer-virtual-entity/basics/#creating-a-elementholder","title":"Creating a ElementHolder","text":"
ElementHolder is main object, that holds and manages ticking and sending of groups of VirtualElements. It can be (and in many cases should be) extended, which can be used to create more dynamic elements without requirement of backing it with BlockEntity or Entity objects. However, you still need to attach it to make it visible and tick. This can be done by using attachments. (more in section below).
Example usage:
var holder = new ElementHolder();\n\nvar element1 = createElement(...);\nvar element2 = createElement(...);\nvar element3 = createElement(...);\n\n// Adding elements\nholder.addElement(element1);\nholder.addElement(element2);\nholder.addElement(element3);\n\n// Removing elements\nholder.removeElement(element3);\n\n/* Attach here */ \n
HolderAttachments are final element, that connects ElementHolders with their position and ticking. There are multiple builtin ones, which different purposes:
EntityAttachment - attaches to any entity. Can be created with EntityAttachement.of(ElementHolder, Entity), which requires manual ticking or EntityAttachement.ofTicking(ElementHolder, Entity) which does that automatically.
ChunkAttachment - attaches to a chunk. It's destroyed after chunk gets unloaded. Can be created with ChunkAttachment.of(ElementHolder, ServerWorld, BlockPos/Vec3d) for manual ticking, or ChunkAttachment.ofTicking(ElementHolder, ServerWorld, BlockPos/Vec3d) to tick automatically.
ManualAttachment - Used as a stub, doesn't handle anything by default. You need to call methods by hand.
Example usage:
var holder = new ElementHolder();\n\n/* ... */\n\nEntityAttachment.ofTicking(holder, player);\n
This is module of Polymer allowing you to create virtual (packet-only) entities is a quick and simple way. It's mostly designed around using it with Display Entities, but it can be extended to work with any other. You can attach them to regular (or Polymer) entities and chunks.
"},{"location":"polymer-virtual-entity/getting-started/#adding-to-dependencies","title":"Adding to dependencies","text":"
repositories {\n maven { url 'https://maven.nucleoid.xyz' } // You should have it\n}\n\ndependencies {\n modImplementation include(\"eu.pb4:polymer-virtual-entity:[TAG]\")\n}\n
For [TAG]/polymer-blocks version I recommend you checking this maven.
Latest version:
"}]}
\ No newline at end of file
diff --git a/0.6.x/sitemap.xml.gz b/0.6.x/sitemap.xml.gz
index 612a4062b5fbf887751785a64e873693bef81cfc..0e0c6258e320b37f22933d9a64efdf22d81b28f7 100644
GIT binary patch
delta 13
Ucmb=gXP58h;CLtIH<7&p035{xA^-pY
delta 13
Ucmb=gXP58h;7E$`oycAR02