diff --git a/0.6.x/404.html b/0.6.x/404.html index 7612e25c..2dc174c8 100644 --- a/0.6.x/404.html +++ b/0.6.x/404.html @@ -61,7 +61,7 @@ -
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.
With Minecraft 1.19.3 being globally breaking update. I took this as a good time to make breaking changes to polymer itself.
See this update guide for more informations!
eu.pb4:polymer-core
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.
It's a library for handling translations server side. It supports +
It's a library for handling translations server side. It supports per player language, by using one provided by client on join/language change.
Add it to your dependencies like this:
For [TAG]/translations api version I recommend you checking this maven.
[TAG]
repositories { + maven { url 'https://maven.nucleoid.xyz' } +} + dependencies { modImplementation include("fr.catcore:server-translations-api:[TAG]") }
To use i, you just need to use vanilla TranslationText with key specified by you in your code.
TranslationText
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.
data/modid/lang
en_us.json
To use it, you just need to use vanilla Text.translation(...) with key specified by you in your code.
Text.translation(...)
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).
Example valid language file looks like this:
{ "block.honeytech.pipe": "Pipe", diff --git a/0.6.x/other/updating-0.2.x-to-0.3/index.html b/0.6.x/other/updating-0.2.x-to-0.3/index.html index 9327b57e..b702af40 100644 --- a/0.6.x/other/updating-0.2.x-to-0.3/index.html +++ b/0.6.x/other/updating-0.2.x-to-0.3/index.html @@ -63,7 +63,7 @@ - + @@ -123,7 +123,7 @@ - + @@ -133,7 +133,7 @@ - + diff --git a/0.6.x/polymer-blocks/basics/index.html b/0.6.x/polymer-blocks/basics/index.html index 23b36058..771c806d 100644 --- a/0.6.x/polymer-blocks/basics/index.html +++ b/0.6.x/polymer-blocks/basics/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-blocks/getting-started/index.html b/0.6.x/polymer-blocks/getting-started/index.html index d4cece71..a92ee3ce 100644 --- a/0.6.x/polymer-blocks/getting-started/index.html +++ b/0.6.x/polymer-blocks/getting-started/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-core/blocks/index.html b/0.6.x/polymer-core/blocks/index.html index f166c97e..5da6e8bf 100644 --- a/0.6.x/polymer-core/blocks/index.html +++ b/0.6.x/polymer-core/blocks/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-core/client-side/index.html b/0.6.x/polymer-core/client-side/index.html index 4cff6d28..59a70274 100644 --- a/0.6.x/polymer-core/client-side/index.html +++ b/0.6.x/polymer-core/client-side/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-core/entities/index.html b/0.6.x/polymer-core/entities/index.html index eb91c89d..187a3975 100644 --- a/0.6.x/polymer-core/entities/index.html +++ b/0.6.x/polymer-core/entities/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-core/getting-started/index.html b/0.6.x/polymer-core/getting-started/index.html index 5e0e1d7c..8fc3ab36 100644 --- a/0.6.x/polymer-core/getting-started/index.html +++ b/0.6.x/polymer-core/getting-started/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-core/items/index.html b/0.6.x/polymer-core/items/index.html index c2ddbc4d..2a7c3b07 100644 --- a/0.6.x/polymer-core/items/index.html +++ b/0.6.x/polymer-core/items/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-core/other/index.html b/0.6.x/polymer-core/other/index.html index 7f83fbea..37c50a4c 100644 --- a/0.6.x/polymer-core/other/index.html +++ b/0.6.x/polymer-core/other/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-networking/getting-started/index.html b/0.6.x/polymer-networking/getting-started/index.html index 7c12022c..9ae51069 100644 --- a/0.6.x/polymer-networking/getting-started/index.html +++ b/0.6.x/polymer-networking/getting-started/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-resource-pack/basics/index.html b/0.6.x/polymer-resource-pack/basics/index.html index e19d1b59..6ad31f3e 100644 --- a/0.6.x/polymer-resource-pack/basics/index.html +++ b/0.6.x/polymer-resource-pack/basics/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-resource-pack/getting-started/index.html b/0.6.x/polymer-resource-pack/getting-started/index.html index 1e2fd610..4f604cb2 100644 --- a/0.6.x/polymer-resource-pack/getting-started/index.html +++ b/0.6.x/polymer-resource-pack/getting-started/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-virtual-entity/basics/index.html b/0.6.x/polymer-virtual-entity/basics/index.html index 7569916b..bd746e4f 100644 --- a/0.6.x/polymer-virtual-entity/basics/index.html +++ b/0.6.x/polymer-virtual-entity/basics/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/polymer-virtual-entity/getting-started/index.html b/0.6.x/polymer-virtual-entity/getting-started/index.html index bd73b256..1fc8a106 100644 --- a/0.6.x/polymer-virtual-entity/getting-started/index.html +++ b/0.6.x/polymer-virtual-entity/getting-started/index.html @@ -65,7 +65,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/0.6.x/search/search_index.json b/0.6.x/search/search_index.json index 036819ba..c06f4401 100644 --- a/0.6.x/search/search_index.json +++ b/0.6.x/search/search_index.json @@ -1 +1 @@ -{"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."},{"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. See this update guide for more informations!"},{"location":"#modules","title":"Modules","text":""},{"location":"#polymer-core","title":"Polymer Core","text":"eu.pb4:polymer-core 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. Getting Started Items Blocks Entities Other custom features (Optional) Client Side features "},{"location":"#polymer-resource-pack","title":"Polymer Resource Pack","text":"eu.pb4:polymer-resource-pack Allows creating global (and mod specific) resource packs. It also patches PolyMc to make it's resource generation work with polymer. Getting Started Basics "},{"location":"#polymer-networking","title":"Polymer Networking","text":"eu.pb4:polymer-networking Polymer's Networking API. Uses its own custom synchronization code. Contains extra API, more specific that aren't available in fabric. Getting Started "},{"location":"#polymer-virtual-entity","title":"Polymer Virtual Entity","text":"eu.pb4:polymer-virtual-entity Allows you to create virtual/packet based entities in a quick and simple way, with support for attaching to any entity and chunks. Getting Started Basics "},{"location":"#polymer-blocks","title":"Polymer Blocks","text":"eu.pb4:polymer-blocks Extension of Polymer Core and Resource Pack. Allows creation of textured blocks. Getting Started Basics "},{"location":"#other-useful-toolsprojects-compatible-with-polymer","title":"Other useful tools/projects compatible with Polymer","text":" Server Translation API "},{"location":"other/server-translation-api/","title":"Server Translation API","text":"It's a library for handling translations server side. It supports per player language, by using one provided by client on join/language change."},{"location":"other/server-translation-api/#adding-as-dependency","title":"Adding as dependency:","text":"Add it to your dependencies like this: repositories {\n maven { url 'https://maven.nucleoid.xyz' }\n}\n\ndependencies {\n modImplementation include(\"fr.catcore:server-translations-api:[TAG]\")\n}\n For [TAG]/translations api version I recommend you checking this maven."},{"location":"other/server-translation-api/#usage","title":"Usage","text":"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. Example valid language file looks like this: {\n \"block.honeytech.pipe\": \"Pipe\",\n \"block.honeytech.item_extractor\": \"Item Extractor\",\n \"block.honeytech.trashcan\": \"Trash Can\",\n \"block.honeytech.cable\": \"Cable\",\n \"item.honeytech.diamond_dust\": \"Diamond Dust\",\n \"item.honeytech.raw_aluminium\": \"Raw Aluminium Ore\",\n \"item.honeytech.aluminium_ingot\": \"Aluminium Ingot\",\n \"item.honeytech.copper_wire\": \"Copper Wire\",\n \"item.honeytech.motor\": \"Motor\",\n \"gui.honeytech.show_recipes\": \"Show Recipes\"\n}\n"},{"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): [...].networking.PolymerSyncUtils -> [...].utils.PolymerSyncUtils PolymerUtils#getPlayer -> PolymerUtils#getPlayerContext Interfaces in client that were used on both sides were moved to utils [...].client.registry -> [...].client PolymerEntity#modifyTrackedData -> PolymerEntity#modifyRawTrackedData 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."},{"location":"other/updating-0.2.x-to-0.3/#submodule-versioning-change","title":"Submodule versioning change.","text":"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."},{"location":"polymer-blocks/basics/#supported-block-shapestypes","title":"Supported block shapes/types","text":"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) TRANSPARENT_BLOCK - Mostly leaves, allow \"cutout\" textures, (limit: 104) FARMLAND_BLOCK - Farmland blocks, (limit: 5!) 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! "},{"location":"polymer-blocks/getting-started/","title":"Getting Started","text":"This is additional module/extension of Polymer, adding support for textured blocks. It requires server resource pack to be active work correctly. It requires Polymer Core and Polymer Resource Pack modules to work."},{"location":"polymer-blocks/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 modImplementation include(\"eu.pb4:polymer-blocks:[TAG]\")\n modImplementation include(\"eu.pb4:polymer-resource-pack:[TAG]\")\n}\n For [TAG]/polymer-blocks version I recommend you checking this maven. Latest version: "},{"location":"polymer-core/blocks/","title":"Blocks","text":"Note 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."},{"location":"polymer-core/blocks/#default-implementation","title":"Default implementation","text":"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! Example use: Making block look like a diamond @Override\npublic Block getPolymerBlock(BlockState state) {\n return Blocks.BARRIER;\n}\n\npublic Block getPolymerBlock(ServerPlayerEntity player, BlockState state) {\n return Something.isRedTeam(player) ? Blocks.RED_WOOL : Blocks.BLUE_WOOL;\n}\n"},{"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 @Override\npublic BlockState getPolymerBlockState(BlockState state) {\n return Blocks.FURNACE.getDefaultState()\n .with(AbstractFurnaceBlock.FACING, state.get(AbstractFurnaceBlock.FACING))\n .with(AbstractFurnaceBlock.LIT, !state.get(AbstractFurnaceBlock.LIT));\n}\n"},{"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 @Override\npublic void onPolymerBlockSend(BlockState blockState, BlockPos.Mutable pos, ServerPlayerEntity player) { \n player.networkHandler.sendPacket(this.getPolymerHeadPacket(blockState, pos.toImmutable()));\n}\n"},{"location":"polymer-core/blocks/#using-polymerheadblock","title":"Using PolymerHeadBlock","text":"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. Example use: Setting skin value for PolymerHeadBlock @Override\npublic String getPolymerSkinValue(BlockState state, BlockPos pos, ServerPlayerEntity entity) {\n return \"ewogICJ0aW1lc3RhbXAiIDogMTYxNzk3NjcxOTAzNSwKICAicHJvZmlsZUlkIiA6ICJlZDUzZGQ4MTRmOWQ0YTNjYjRlYjY1MWRjYmE3N2U2NiIsCiAgInByb2ZpbGVOYW1lIiA6ICI0MTQxNDE0MWgiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTczNTE0YTIzMjQ1ZjE1ZGJhZDVmYjRlNjIyMTYzMDIwODY0Y2NlNGMxNWQ1NmRlM2FkYjkwZmE1YTcxMzdmZCIKICAgIH0KICB9Cn0\";\n}\n"},{"location":"polymer-core/blocks/#textured-non-player-head-blocks","title":"Textured, non-player-head blocks","text":"See Polymer Textured Blocks extension for more informations"},{"location":"polymer-core/blocks/#using-blockentities","title":"Using BlockEntities","text":"The only thing you need to do to remove BlockEntity from being sent to client is registering its BlockEntityType with PolymerBlockUtils.registerBlockEntity(BlockEntityType types)."},{"location":"polymer-core/blocks/#getting-polymer-blocks-client-representation","title":"Getting Polymer Blocks client representation","text":"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)."},{"location":"polymer-core/blocks/#limitations","title":"Limitations","text":"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. Example use: Displaying entity as zombie @Override\npublic EntityType<?> getPolymerEntityType(ServerPlayerEntity player) {\n return EntityType.ZOMBIE;\n}\n"},{"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. Example use: Adding villager data to change how villager looks @Override\npublic void modifyRawTrackedData(List<DataTracker.SerializedEntry<?>> data, ServerPlayerEntity player, boolean initial) {\n data.add(DataTracker.SerializedEntry.of(VillagerEntityAccessor.getVillagerData(), new VillagerData(VillagerType.JUNGLE, VillagerProfession.FARMER, 3);));\n}\n"},{"location":"polymer-core/getting-started/","title":"Getting Started","text":"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. Latest version: "},{"location":"polymer-core/getting-started/#before-starting","title":"Before starting","text":"There are few things you need to keep in mind while using Polymer. All your code that interacts with Polymer should: Be thread safe - code can run on main server thread, player's connection thread or client side rendering thread. Make sure to check every time you cast if it's really instance of it. Sometimes World won't be ServerWorld. Never implement Polymer interfaces on Vanilla Items/Blocks with mixins, it will end up really, really badly. Never add new BlockStates to non-polymer blocks, as it will cause desyncs (see previous point)! Please don't even try using registry replacement, it will break many other mods (and polymer itself). Polymer is split into multiple libraries with varying functionality."},{"location":"polymer-core/items/","title":"Items","text":"Note 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/#default-implementation","title":"Default implementation","text":"For most basic uses, there are default implementation of PolymerItem: SimplePolymerItem - Same as vanilla Item, PolymerSpawnEggItem - Same as vanilla SpawnEggItem, PolymerBlockItem - Same as vanilla BlockItem, PolymerHeadBlockItem - Similar to PolymerBlockItem, but for Blocks implementing PolymerHeadBlock interface. "},{"location":"polymer-core/items/#selecting-visual-item-type","title":"Selecting visual item type.","text":"To select visual item type, you need to implement this method * Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player) They can't return nulls. They can also point to other PolymerItem instance, but keep in mind to make validation if it's configurable by user! Example use: Changing client-side item to diamond @Override\npublic Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player) {\n return itemStack.getCount() > 32 ? Items.DIAMOND_BLOCK : Items.DIAMOND;\n}\n"},{"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. Example use: Adding enchanting glint to item. @Override\npublic ItemStack getPolymerItemStack(ItemStack itemStack, TooltipContext context, ServerPlayerEntity player) {\n ItemStack out = PolymerItemUtils.createItemStack(itemStack, context, player);\n out.addEnchantment(Enchantments.LURE, 0);\n return out;\n}\n"},{"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 PolymerItemUtils.ITEM_CHECK.register(\n (itemStack) -> {\n return itemStack.hasNbt() && itemStack.getNbt().contains(\"Test\", NbtElement.STRING_TYPE);\n }\n);\n"},{"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 PolymerItemUtils.ITEM_MODIFICATION_EVENT.register(\n (original, client, player) -> {\n if (original.hasNbt() && original.getNbt().getBoolean(\"HideEnchantments\")) {\n client.getNbt().remove(\"Enchantments\");\n\n }\n return client;\n }\n);\n Replacing look/name of ItemStack with \"Test\" NBT tag PolymerItemUtils.ITEM_MODIFICATION_EVENT.register(\n (original, client, player) -> {\n if (original.hasNbt() && original.getNbt().contains(\"Test\", NbtElement.STRING_TYPE)) {\n ItemStack out = new ItemStack(Items.DIAMOND_SWORD, client.getCount());\n out.setNbt(client.getNbt());\n out.setCustomName(new LiteralText(\"TEST VALUE: \" + original.getNbt().getString(\"Test\")).formatted(Formatting.WHITE));\n return out;\n }\n return client;\n }\n);\n"},{"location":"polymer-core/items/#making-items-mining-calculated-on-server-side","title":"Making items mining calculated on server side","text":"You can also force item's mining speed to be calculated server side (which happens by default to every PolymerItem). Only thing you need to do is just listening to BlockHelper.SERVER_SIDE_MINING_CHECK event. Example use: PolymerBlockUtils.SERVER_SIDE_MINING_CHECK.register(\n (player, pos, blockState) -> {\n var itemStack = player.getMainHandStack();\n return EnchantmentHelper.getLevel(MyEnchanments.SLOW_MINING, itemStack) > 0;\n }\n);\n"},{"location":"polymer-core/items/#enchantments","title":"Enchantments","text":"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."},{"location":"polymer-core/other/","title":"Other custom features","text":""},{"location":"polymer-core/other/#soundevents","title":"SoundEvents","text":"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."},{"location":"polymer-core/other/#custom-statistics","title":"Custom statistics","text":"To register custom, server side statistic you just need to call PolymerStat.registerStat(Identifier, StatFormatter). Then you can use it just like vanilla ones."},{"location":"polymer-core/other/#statuseffects","title":"StatusEffects","text":"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)."},{"location":"polymer-networking/getting-started/","title":"Getting Started","text":"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. Latest version: "},{"location":"polymer-resource-pack/basics/","title":"Basics","text":""},{"location":"polymer-resource-pack/basics/#registering-assets","title":"Registering assets","text":"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"},{"location":"polymer-resource-pack/basics/#requesting-armor-textures","title":"Requesting armor textures","text":"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. PolymerArmorModel armorModel = PolymerResourcePackUtils.requestArmor(new Identifier(\"mymod\", \"silver\"));\n"},{"location":"polymer-resource-pack/basics/#checking-players","title":"Checking players","text":"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"},{"location":"polymer-resource-pack/basics/#making-pack-required","title":"Making pack required","text":"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."},{"location":"polymer-resource-pack/basics/#building-resource-pack","title":"Building resource pack","text":"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."},{"location":"polymer-resource-pack/getting-started/","title":"Getting Started","text":"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. Latest version: "},{"location":"polymer-virtual-entity/basics/","title":"Basics","text":"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."},{"location":"polymer-virtual-entity/basics/#virtualelements","title":"VirtualElements","text":"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"},{"location":"polymer-virtual-entity/basics/#using-holderattachments","title":"Using HolderAttachments","text":"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"},{"location":"polymer-virtual-entity/getting-started/","title":"Getting Started","text":"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."},{"location":"#modules","title":"Modules","text":""},{"location":"#polymer-core","title":"Polymer Core","text":"eu.pb4:polymer-core 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. Getting Started Items Blocks Entities Other custom features (Optional) Client Side features "},{"location":"#polymer-resource-pack","title":"Polymer Resource Pack","text":"eu.pb4:polymer-resource-pack Allows creating global (and mod specific) resource packs. It also patches PolyMc to make it's resource generation work with polymer. Getting Started Basics "},{"location":"#polymer-networking","title":"Polymer Networking","text":"eu.pb4:polymer-networking Polymer's Networking API. Uses its own custom synchronization code. Contains extra API, more specific that aren't available in fabric. Getting Started "},{"location":"#polymer-virtual-entity","title":"Polymer Virtual Entity","text":"eu.pb4:polymer-virtual-entity Allows you to create virtual/packet based entities in a quick and simple way, with support for attaching to any entity and chunks. Getting Started Basics "},{"location":"#polymer-blocks","title":"Polymer Blocks","text":"eu.pb4:polymer-blocks Extension of Polymer Core and Resource Pack. Allows creation of textured blocks. Getting Started Basics "},{"location":"#other-useful-toolsprojects-compatible-with-polymer","title":"Other useful tools/projects compatible with Polymer","text":" Server Translation API "},{"location":"other/server-translation-api/","title":"Server Translation API","text":"It's a library for handling translations server side. It supports per player language, by using one provided by client on join/language change."},{"location":"other/server-translation-api/#adding-as-dependency","title":"Adding as dependency:","text":"Add it to your dependencies like this: repositories {\n maven { url 'https://maven.nucleoid.xyz' }\n}\n\ndependencies {\n modImplementation include(\"xyz.nucleoid:server-translations-api:[TAG]\")\n}\n For [TAG]/translations api version I recommend you checking this maven."},{"location":"other/server-translation-api/#for-versions-before-1194","title":"For versions before 1.19.4:","text":"repositories {\n maven { url 'https://maven.nucleoid.xyz' }\n}\n\ndependencies {\n modImplementation include(\"fr.catcore:server-translations-api:[TAG]\")\n}\n For [TAG]/translations api version I recommend you checking this maven."},{"location":"other/server-translation-api/#usage","title":"Usage","text":"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). Example valid language file looks like this: {\n \"block.honeytech.pipe\": \"Pipe\",\n \"block.honeytech.item_extractor\": \"Item Extractor\",\n \"block.honeytech.trashcan\": \"Trash Can\",\n \"block.honeytech.cable\": \"Cable\",\n \"item.honeytech.diamond_dust\": \"Diamond Dust\",\n \"item.honeytech.raw_aluminium\": \"Raw Aluminium Ore\",\n \"item.honeytech.aluminium_ingot\": \"Aluminium Ingot\",\n \"item.honeytech.copper_wire\": \"Copper Wire\",\n \"item.honeytech.motor\": \"Motor\",\n \"gui.honeytech.show_recipes\": \"Show Recipes\"\n}\n"},{"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): [...].networking.PolymerSyncUtils -> [...].utils.PolymerSyncUtils PolymerUtils#getPlayer -> PolymerUtils#getPlayerContext Interfaces in client that were used on both sides were moved to utils [...].client.registry -> [...].client PolymerEntity#modifyTrackedData -> PolymerEntity#modifyRawTrackedData 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."},{"location":"other/updating-0.2.x-to-0.3/#submodule-versioning-change","title":"Submodule versioning change.","text":"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."},{"location":"polymer-blocks/basics/#supported-block-shapestypes","title":"Supported block shapes/types","text":"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) TRANSPARENT_BLOCK - Mostly leaves, allow \"cutout\" textures, (limit: 104) FARMLAND_BLOCK - Farmland blocks, (limit: 5!) 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! "},{"location":"polymer-blocks/getting-started/","title":"Getting Started","text":"This is additional module/extension of Polymer, adding support for textured blocks. It requires server resource pack to be active work correctly. It requires Polymer Core and Polymer Resource Pack modules to work."},{"location":"polymer-blocks/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 modImplementation include(\"eu.pb4:polymer-blocks:[TAG]\")\n modImplementation include(\"eu.pb4:polymer-resource-pack:[TAG]\")\n}\n For [TAG]/polymer-blocks version I recommend you checking this maven. Latest version: "},{"location":"polymer-core/blocks/","title":"Blocks","text":"Note 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."},{"location":"polymer-core/blocks/#default-implementation","title":"Default implementation","text":"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! Example use: Making block look like a diamond @Override\npublic Block getPolymerBlock(BlockState state) {\n return Blocks.BARRIER;\n}\n\npublic Block getPolymerBlock(ServerPlayerEntity player, BlockState state) {\n return Something.isRedTeam(player) ? Blocks.RED_WOOL : Blocks.BLUE_WOOL;\n}\n"},{"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 @Override\npublic BlockState getPolymerBlockState(BlockState state) {\n return Blocks.FURNACE.getDefaultState()\n .with(AbstractFurnaceBlock.FACING, state.get(AbstractFurnaceBlock.FACING))\n .with(AbstractFurnaceBlock.LIT, !state.get(AbstractFurnaceBlock.LIT));\n}\n"},{"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 @Override\npublic void onPolymerBlockSend(BlockState blockState, BlockPos.Mutable pos, ServerPlayerEntity player) { \n player.networkHandler.sendPacket(this.getPolymerHeadPacket(blockState, pos.toImmutable()));\n}\n"},{"location":"polymer-core/blocks/#using-polymerheadblock","title":"Using PolymerHeadBlock","text":"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. Example use: Setting skin value for PolymerHeadBlock @Override\npublic String getPolymerSkinValue(BlockState state, BlockPos pos, ServerPlayerEntity entity) {\n return \"ewogICJ0aW1lc3RhbXAiIDogMTYxNzk3NjcxOTAzNSwKICAicHJvZmlsZUlkIiA6ICJlZDUzZGQ4MTRmOWQ0YTNjYjRlYjY1MWRjYmE3N2U2NiIsCiAgInByb2ZpbGVOYW1lIiA6ICI0MTQxNDE0MWgiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTczNTE0YTIzMjQ1ZjE1ZGJhZDVmYjRlNjIyMTYzMDIwODY0Y2NlNGMxNWQ1NmRlM2FkYjkwZmE1YTcxMzdmZCIKICAgIH0KICB9Cn0\";\n}\n"},{"location":"polymer-core/blocks/#textured-non-player-head-blocks","title":"Textured, non-player-head blocks","text":"See Polymer Textured Blocks extension for more informations"},{"location":"polymer-core/blocks/#using-blockentities","title":"Using BlockEntities","text":"The only thing you need to do to remove BlockEntity from being sent to client is registering its BlockEntityType with PolymerBlockUtils.registerBlockEntity(BlockEntityType types)."},{"location":"polymer-core/blocks/#getting-polymer-blocks-client-representation","title":"Getting Polymer Blocks client representation","text":"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)."},{"location":"polymer-core/blocks/#limitations","title":"Limitations","text":"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. Example use: Displaying entity as zombie @Override\npublic EntityType<?> getPolymerEntityType(ServerPlayerEntity player) {\n return EntityType.ZOMBIE;\n}\n"},{"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. Example use: Adding villager data to change how villager looks @Override\npublic void modifyRawTrackedData(List<DataTracker.SerializedEntry<?>> data, ServerPlayerEntity player, boolean initial) {\n data.add(DataTracker.SerializedEntry.of(VillagerEntityAccessor.getVillagerData(), new VillagerData(VillagerType.JUNGLE, VillagerProfession.FARMER, 3);));\n}\n"},{"location":"polymer-core/getting-started/","title":"Getting Started","text":"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. Latest version: "},{"location":"polymer-core/getting-started/#before-starting","title":"Before starting","text":"There are few things you need to keep in mind while using Polymer. All your code that interacts with Polymer should: Be thread safe - code can run on main server thread, player's connection thread or client side rendering thread. Make sure to check every time you cast if it's really instance of it. Sometimes World won't be ServerWorld. Never implement Polymer interfaces on Vanilla Items/Blocks with mixins, it will end up really, really badly. Never add new BlockStates to non-polymer blocks, as it will cause desyncs (see previous point)! Please don't even try using registry replacement, it will break many other mods (and polymer itself). Polymer is split into multiple libraries with varying functionality."},{"location":"polymer-core/items/","title":"Items","text":"Note 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/#default-implementation","title":"Default implementation","text":"For most basic uses, there are default implementation of PolymerItem: SimplePolymerItem - Same as vanilla Item, PolymerSpawnEggItem - Same as vanilla SpawnEggItem, PolymerBlockItem - Same as vanilla BlockItem, PolymerHeadBlockItem - Similar to PolymerBlockItem, but for Blocks implementing PolymerHeadBlock interface. "},{"location":"polymer-core/items/#selecting-visual-item-type","title":"Selecting visual item type.","text":"To select visual item type, you need to implement this method * Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player) They can't return nulls. They can also point to other PolymerItem instance, but keep in mind to make validation if it's configurable by user! Example use: Changing client-side item to diamond @Override\npublic Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player) {\n return itemStack.getCount() > 32 ? Items.DIAMOND_BLOCK : Items.DIAMOND;\n}\n"},{"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. Example use: Adding enchanting glint to item. @Override\npublic ItemStack getPolymerItemStack(ItemStack itemStack, TooltipContext context, ServerPlayerEntity player) {\n ItemStack out = PolymerItemUtils.createItemStack(itemStack, context, player);\n out.addEnchantment(Enchantments.LURE, 0);\n return out;\n}\n"},{"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 PolymerItemUtils.ITEM_CHECK.register(\n (itemStack) -> {\n return itemStack.hasNbt() && itemStack.getNbt().contains(\"Test\", NbtElement.STRING_TYPE);\n }\n);\n"},{"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 PolymerItemUtils.ITEM_MODIFICATION_EVENT.register(\n (original, client, player) -> {\n if (original.hasNbt() && original.getNbt().getBoolean(\"HideEnchantments\")) {\n client.getNbt().remove(\"Enchantments\");\n\n }\n return client;\n }\n);\n Replacing look/name of ItemStack with \"Test\" NBT tag PolymerItemUtils.ITEM_MODIFICATION_EVENT.register(\n (original, client, player) -> {\n if (original.hasNbt() && original.getNbt().contains(\"Test\", NbtElement.STRING_TYPE)) {\n ItemStack out = new ItemStack(Items.DIAMOND_SWORD, client.getCount());\n out.setNbt(client.getNbt());\n out.setCustomName(new LiteralText(\"TEST VALUE: \" + original.getNbt().getString(\"Test\")).formatted(Formatting.WHITE));\n return out;\n }\n return client;\n }\n);\n"},{"location":"polymer-core/items/#making-items-mining-calculated-on-server-side","title":"Making items mining calculated on server side","text":"You can also force item's mining speed to be calculated server side (which happens by default to every PolymerItem). Only thing you need to do is just listening to BlockHelper.SERVER_SIDE_MINING_CHECK event. Example use: PolymerBlockUtils.SERVER_SIDE_MINING_CHECK.register(\n (player, pos, blockState) -> {\n var itemStack = player.getMainHandStack();\n return EnchantmentHelper.getLevel(MyEnchanments.SLOW_MINING, itemStack) > 0;\n }\n);\n"},{"location":"polymer-core/items/#enchantments","title":"Enchantments","text":"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."},{"location":"polymer-core/other/","title":"Other custom features","text":""},{"location":"polymer-core/other/#soundevents","title":"SoundEvents","text":"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."},{"location":"polymer-core/other/#custom-statistics","title":"Custom statistics","text":"To register custom, server side statistic you just need to call PolymerStat.registerStat(Identifier, StatFormatter). Then you can use it just like vanilla ones."},{"location":"polymer-core/other/#statuseffects","title":"StatusEffects","text":"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)."},{"location":"polymer-networking/getting-started/","title":"Getting Started","text":"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. Latest version: "},{"location":"polymer-resource-pack/basics/","title":"Basics","text":""},{"location":"polymer-resource-pack/basics/#registering-assets","title":"Registering assets","text":"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"},{"location":"polymer-resource-pack/basics/#requesting-armor-textures","title":"Requesting armor textures","text":"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. PolymerArmorModel armorModel = PolymerResourcePackUtils.requestArmor(new Identifier(\"mymod\", \"silver\"));\n"},{"location":"polymer-resource-pack/basics/#checking-players","title":"Checking players","text":"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"},{"location":"polymer-resource-pack/basics/#making-pack-required","title":"Making pack required","text":"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."},{"location":"polymer-resource-pack/basics/#building-resource-pack","title":"Building resource pack","text":"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."},{"location":"polymer-resource-pack/getting-started/","title":"Getting Started","text":"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. Latest version: "},{"location":"polymer-virtual-entity/basics/","title":"Basics","text":"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."},{"location":"polymer-virtual-entity/basics/#virtualelements","title":"VirtualElements","text":"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"},{"location":"polymer-virtual-entity/basics/#using-holderattachments","title":"Using HolderAttachments","text":"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"},{"location":"polymer-virtual-entity/getting-started/","title":"Getting Started","text":"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 612a4062..0e0c6258 100644 Binary files a/0.6.x/sitemap.xml.gz and b/0.6.x/sitemap.xml.gz differ
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'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.
eu.pb4:polymer-resource-pack
Allows creating global (and mod specific) resource packs. It also patches PolyMc to make it's resource generation work with polymer.
eu.pb4:polymer-networking
Polymer's Networking API. Uses its own custom synchronization code. Contains extra API, more specific that aren't available in fabric.
eu.pb4:polymer-virtual-entity
Allows you to create virtual/packet based entities in a quick and simple way, with support for attaching to any entity and chunks.
eu.pb4:polymer-blocks
Extension of Polymer Core and Resource Pack. Allows creation of textured blocks.
repositories {\n maven { url 'https://maven.nucleoid.xyz' }\n}\n\ndependencies {\n modImplementation include(\"fr.catcore:server-translations-api:[TAG]\")\n}\n
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.
{\n \"block.honeytech.pipe\": \"Pipe\",\n \"block.honeytech.item_extractor\": \"Item Extractor\",\n \"block.honeytech.trashcan\": \"Trash Can\",\n \"block.honeytech.cable\": \"Cable\",\n \"item.honeytech.diamond_dust\": \"Diamond Dust\",\n \"item.honeytech.raw_aluminium\": \"Raw Aluminium Ore\",\n \"item.honeytech.aluminium_ingot\": \"Aluminium Ingot\",\n \"item.honeytech.copper_wire\": \"Copper Wire\",\n \"item.honeytech.motor\": \"Motor\",\n \"gui.honeytech.show_recipes\": \"Show Recipes\"\n}\n
polymer
The polymer library was broken into multiple ones, most notably:
polymer-common
polymer-core
polymer-resource-pack
polymer-networking
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.
polymer-reg-sync-manipulator
Autohost module now depends only on polymer-networking and polymer-resource-pack.
With the split up, many classes changed their packages.
polymer-blocks-ext got renamed to polymer-blocks
polymer-blocks-ext
polymer-blocks
From polymer (polymer-core, polymer-resource-pack, polymer-networking)
eu.pb4.polymer.api.networking
eu.pb4.polymer.networking.api
PolymerPacketUtils
PolymerServerNetworking
eu.pb4.polymer.api.client.PolymerClientUtils
eu.pb4.polymer.api.networking.PolymerClientNetworking
eu.pb4.polymer.api.resourcepack
eu.pb4.polymer.resourcepack.api
PolymerRPUtils
PolymerResourcePackUtils
PolymerRPBuilder
ResourcePackBuilder
eu.pb4.polymer.api
eu.pb4.polymer.core.api
[...].networking.PolymerSyncUtils
[...].utils.PolymerSyncUtils
PolymerUtils#getPlayer
PolymerUtils#getPlayerContext
client
utils
[...].client.registry
[...].client
PolymerEntity#modifyTrackedData
PolymerEntity#modifyRawTrackedData
eu.pb4.polymer.ext.blocks
eu.pb4.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.
Creating a block is mostly the same as with regular polymer ones. Only difference is implementation of PolymerTexturedBlock interface, which acts as a marker.
PolymerTexturedBlock
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
TRANSPARENT_BLOCK
FARMLAND_BLOCK
VINES_BLOCK
PLANT_BLOCK
KELP_BLOCK
CACTUS_BLOCK
They all are accessible from BlockModelType enum.
BlockModelType
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.
PolymerBlockModel.of(...)
assets/(namespace)/blockstate/(block).json
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).
PolymerBlockResourceUtils.requestBlock(BlockModelType type, PolymerBlockModel... model)
getPolymerBlockState(...)
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.
PolymerRPUtils.addAssetSource(String modId)
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!
This is additional module/extension of Polymer, adding support for textured blocks. It requires server resource pack to be active work correctly.
It requires Polymer Core and Polymer Resource Pack modules to work.
repositories {\n maven { url 'https://maven.nucleoid.xyz' } // You should have it\n}\n\ndependencies {\n modImplementation include(\"eu.pb4:polymer-core:[TAG]\")\n modImplementation include(\"eu.pb4:polymer-blocks:[TAG]\")\n modImplementation include(\"eu.pb4:polymer-resource-pack:[TAG]\")\n}\n
For [TAG]/polymer-blocks version I recommend you checking this maven.
Latest version:
Note
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).
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.
PolymerBlock
For most basic uses, there are default implementation of PolymerBlock:
PolymerHeadBlock
SimplePolymerBlock
Block
To change base block, you need to override Block getPolymerBlock(BlockState) method.
Block getPolymerBlock(BlockState)
You can also override Block getPolymerBlock(ServerPlayerEntity, BlockState) to replace blocks per player, however keep in mind they should ideally have same collisions.
Block getPolymerBlock(ServerPlayerEntity, BlockState)
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!
Example use:
Making block look like a diamond
@Override\npublic Block getPolymerBlock(BlockState state) {\n return Blocks.BARRIER;\n}\n\npublic Block getPolymerBlock(ServerPlayerEntity player, BlockState state) {\n return Something.isRedTeam(player) ? Blocks.RED_WOOL : Blocks.BLUE_WOOL;\n}\n
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!
BlockState getPolymerBlockState(BlockState state)
BlockState getPolymerBlockState(BlockState state, ServerPlayerEntity player)
getPolymerBlock
Changing BlockState to furnace with the same facing, but inverted \"lit\" BlockState property
@Override\npublic BlockState getPolymerBlockState(BlockState state) {\n return Blocks.FURNACE.getDefaultState()\n .with(AbstractFurnaceBlock.FACING, state.get(AbstractFurnaceBlock.FACING))\n .with(AbstractFurnaceBlock.LIT, !state.get(AbstractFurnaceBlock.LIT));\n}\n
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.
onPolymerBlockSend(BlockState blockState, BlockPos.Mutable pos, ServerPlayerEntity player)
Sending data required to render player head with skin
@Override\npublic void onPolymerBlockSend(BlockState blockState, BlockPos.Mutable pos, ServerPlayerEntity player) { \n player.networkHandler.sendPacket(this.getPolymerHeadPacket(blockState, pos.toImmutable()));\n}\n
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.
String getPolymerSkinValue(BlockState state, BlockPos pos, ServerPlayerEntity entity)
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.
Setting skin value for PolymerHeadBlock
@Override\npublic String getPolymerSkinValue(BlockState state, BlockPos pos, ServerPlayerEntity entity) {\n return \"ewogICJ0aW1lc3RhbXAiIDogMTYxNzk3NjcxOTAzNSwKICAicHJvZmlsZUlkIiA6ICJlZDUzZGQ4MTRmOWQ0YTNjYjRlYjY1MWRjYmE3N2U2NiIsCiAgInByb2ZpbGVOYW1lIiA6ICI0MTQxNDE0MWgiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTczNTE0YTIzMjQ1ZjE1ZGJhZDVmYjRlNjIyMTYzMDIwODY0Y2NlNGMxNWQ1NmRlM2FkYjkwZmE1YTcxMzdmZCIKICAgIH0KICB9Cn0\";\n}\n
See Polymer Textured Blocks extension for more informations
The only thing you need to do to remove BlockEntity from being sent to client is registering its BlockEntityType with PolymerBlockUtils.registerBlockEntity(BlockEntityType types).
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).
PolymerBlockUtils.getBlockStateSafely(PolymerBlock block, BlockState blockState)
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.
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.
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.
PolymerKeepModel
PolymerClientDecoded
After that, you just need to return server side items/block in corresponding player-aware getPolymerX methods.
getPolymerX
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
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)
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.
PolymerEntity
You also need to register your entity type as virtual, by using PolymerEntityUtils.registerType(EntityType... types).
PolymerEntityUtils.registerType(EntityType... types)
To select visual entity type, you just need to override EntityType<?> getPolymerEntityType(ServerPlayerEntity player)
EntityType<?> getPolymerEntityType(ServerPlayerEntity player)
This method can't return null or another EntityType that points to other virtual entity, as it won't work.
Displaying entity as zombie
@Override\npublic EntityType<?> getPolymerEntityType(ServerPlayerEntity player) {\n return EntityType.ZOMBIE;\n}\n
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).
List<Pair<EquipmentSlot, ItemStack>> getPolymerVisibleEquipment(List<Pair<EquipmentSlot, ItemStack>> items, ServerPlayerEntities player)
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
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!
void modifyRawTrackedData(List<DataTracker.SerializedEntry<?>> data, ServerPlayerEntity player, boolean initial)
To get TrackedData, which is needed to create Entries, you can either use accessors, or manually construct the data.
TrackedData
Adding villager data to change how villager looks
@Override\npublic void modifyRawTrackedData(List<DataTracker.SerializedEntry<?>> data, ServerPlayerEntity player, boolean initial) {\n data.add(DataTracker.SerializedEntry.of(VillagerEntityAccessor.getVillagerData(), new VillagerData(VillagerType.JUNGLE, VillagerProfession.FARMER, 3);));\n}\n
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.
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.
There are few things you need to keep in mind while using Polymer. All your code that interacts with Polymer should:
World
ServerWorld
Polymer is split into multiple libraries with varying functionality.
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)
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.
PolymerItem
For most basic uses, there are default implementation of PolymerItem:
SimplePolymerItem
Item
PolymerSpawnEggItem
SpawnEggItem
PolymerBlockItem
BlockItem
PolymerHeadBlockItem
To select visual item type, you need to implement this method * Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player)
Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player)
They can't return nulls. They can also point to other PolymerItem instance, but keep in mind to make validation if it's configurable by user!
Changing client-side item to diamond
@Override\npublic Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player) {\n return itemStack.getCount() > 32 ? Items.DIAMOND_BLOCK : Items.DIAMOND;\n}\n
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)!
ItemStack getPolymerItemStack(ItemStack itemStack, TooltipContext context, @Nullable ServerPlayerEntity player)
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.
PolymerItem.super.getPolymerItemStack(itemStack, context, player)
PolymerItemUtils.createItemStack(itemStack, player)
PolymerItemUtils.createMinimalItemStack(itemStack, player)
Adding enchanting glint to item.
@Override\npublic ItemStack getPolymerItemStack(ItemStack itemStack, TooltipContext context, ServerPlayerEntity player) {\n ItemStack out = PolymerItemUtils.createItemStack(itemStack, context, player);\n out.addEnchantment(Enchantments.LURE, 0);\n return out;\n}\n
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.
int getPolymerCustomModelData(ItemStack itemStack, @Nullable ServerPlayerEntity player)
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
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.
/polymer creative
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.
PolymerItemGroupUtils.builder(Identifier)
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.
PolymerItemUtils
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.
PolymerItemUtils.ITEM_CHECK
PolymerItemUtils.ITEM_CHECK.register(ItemStack -> boolean)
Making every item with string NBT tag of \"Test\" go through polymer
PolymerItemUtils.ITEM_CHECK.register(\n (itemStack) -> {\n return itemStack.hasNbt() && itemStack.getNbt().contains(\"Test\", NbtElement.STRING_TYPE);\n }\n);\n
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.
PolymerItemUtils.ITEM_MODIFICATION_EVENT
PolymerItemUtils.ITEM_MODIFICATION_EVENT.register(((ItemStack original, ItemStack client, ServerPlayerEntity player) -> ItemStack)
Hiding enchantment glint for items with HideEnchantments: 1b nbt tag
HideEnchantments: 1b
PolymerItemUtils.ITEM_MODIFICATION_EVENT.register(\n (original, client, player) -> {\n if (original.hasNbt() && original.getNbt().getBoolean(\"HideEnchantments\")) {\n client.getNbt().remove(\"Enchantments\");\n\n }\n return client;\n }\n);\n
Replacing look/name of ItemStack with \"Test\" NBT tag
PolymerItemUtils.ITEM_MODIFICATION_EVENT.register(\n (original, client, player) -> {\n if (original.hasNbt() && original.getNbt().contains(\"Test\", NbtElement.STRING_TYPE)) {\n ItemStack out = new ItemStack(Items.DIAMOND_SWORD, client.getCount());\n out.setNbt(client.getNbt());\n out.setCustomName(new LiteralText(\"TEST VALUE: \" + original.getNbt().getString(\"Test\")).formatted(Formatting.WHITE));\n return out;\n }\n return client;\n }\n);\n
You can also force item's mining speed to be calculated server side (which happens by default to every PolymerItem).
Only thing you need to do is just listening to BlockHelper.SERVER_SIDE_MINING_CHECK event.
BlockHelper.SERVER_SIDE_MINING_CHECK
PolymerBlockUtils.SERVER_SIDE_MINING_CHECK.register(\n (player, pos, blockState) -> {\n var itemStack = player.getMainHandStack();\n return EnchantmentHelper.getLevel(MyEnchanments.SLOW_MINING, itemStack) > 0;\n }\n);\n
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.
PolymerSyncedObject
PolymerEnchantment
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.
PolymerSoundEvent
To register custom, server side statistic you just need to call PolymerStat.registerStat(Identifier, StatFormatter). Then you can use it just like vanilla ones.
PolymerStat.registerStat(Identifier, StatFormatter)
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).
StatusEffect getPolymerStatusEffect()
This is module of Polymer containing all client <-> server networking apis, including some more uncommon ones.
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
This is quite simple. You just need to do things written below. Ideally it all should run at your mod's initialization.
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.
boolean PolymerResourcePackUtils.addModAssets(String modid)
true
modid
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.
PolymerRPBuilder.addData(String path, byte[] data)
PolymerResourcePackUtils.RESOURCE_PACK_CREATION_EVENT
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).
PolymerModelData PolymerResourcePackUtils.requestModel(Item vanillaItem, Identifier modelPath)
PolymerModelData
You can execute this function before making your mod an asset source, but it should be run before resource pack is build.
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.
PolymerResourcePackUtils.requestArmor(Identifier)
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.
PolymerItem.getPolymerArmorColor()
PolymerArmorModel armorModel = PolymerResourcePackUtils.requestArmor(new Identifier(\"mymod\", \"silver\"));\n
Checking if player has resource pack is quite simple. You just need to call boolean PolymerResourcePackUtils.hasPack(ServerPlayerEntity player).
boolean PolymerResourcePackUtils.hasPack(ServerPlayerEntity player)
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().
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.
/polymer generate-pack
polymer-resourcepack.zip
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
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.
ElementHolder
minecraft:block_display
minecraft:item_display
minecraft:text_display
minecraft:interaction
minecraft:armor_stand
minecraft:slime
There are also multiple abstract classes and main VirtualElement interface you can use to implement things in more flexible way.
VirtualElement
// 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
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).
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:
EntityAttachement.of(ElementHolder, Entity)
EntityAttachement.ofTicking(ElementHolder, Entity)
ChunkAttachment.of(ElementHolder, ServerWorld, BlockPos/Vec3d)
ChunkAttachment.ofTicking(ElementHolder, ServerWorld, BlockPos/Vec3d)
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.
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
repositories {\n maven { url 'https://maven.nucleoid.xyz' }\n}\n\ndependencies {\n modImplementation include(\"xyz.nucleoid:server-translations-api:[TAG]\")\n}\n
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).