refactor: port microblock proxy to java

This commit is contained in:
Algent committed 2026-09-01 00:31:27 +02:00
1 parent 36a0e9c865
commit f063cc94b4
10 files changed
+413 -157

No files matched your search

+9
View File
@@ -1034,3 +1034,12 @@ generated-trait compatibility work. Scala-runtime removal remains a later projec
the inherited server method after Forge strips the client override and its static forwarder.
- All 187 plain-JVM and all 96 Java 8 Forge dedicated-server tests pass. Startup registration and two bit-packing
helpers are not a meaningful focused performance target; `microblock/handler/proxies.scala` is next.
- Characterized `MicroblockProxy` against untouched Scala. Four plain-JVM cases freeze its four-type hierarchy,
complete facade/companion ABI, eight mutable server fields, protected Scala saw list and exact lazy-renderer shape.
Two Forge cases freeze side stripping, inherited server lifecycle resolution, item/ore/recipe registration and saw
order.
- Ported the hierarchy and facade to four Java types. The Scala `MutableList` remains for binary compatibility, the
client renderer retains its field-only side annotation and lazy bitmap, and the saw-renderer closure becomes a
direct iterator loop.
- All 191 plain-JVM and all 98 Java 8 Forge dedicated-server tests pass. This startup-only proxy is not a meaningful
focused performance target; `multipart/handler/packethandlers.scala` is the last Scala handler unit and is next.
+52
View File
@@ -2205,3 +2205,55 @@ four proxy classes. An unused Scala wildcard import was removed from the packet-
public names/descriptors and client-only method annotations.
- Client renderer, packet, key-binding and generated-tile renderer registration require a client and remain on the
manual checklist.
## 2026-09-01 — MicroblockProxy Java port
The ForgeMicroblock server/client proxy hierarchy is now Java, including its static facade and load-bearing companion
singleton. Iguana Tweaks' direct `MicroblockProxy$.MODULE$` item/saw reads and static `MicroblockProxy.sawDiamond()` /
`createSaw(...)` calls retain their original owners and descriptors.
### Observable behavior
No known runtime divergence. Pre-init still registers the microblock item, stone/iron/diamond saws and stone rod in
the same sequence, preserves saw-list order, registers `rodStone` and the event-handler singleton, and reads the same
`useSawIcons` configuration tag. Each saw still uses the named braced config tag, strength, unlocalized name and
texture name.
Init still adds `MicroRecipe$.MODULE$` and, outside Dreamcraft, the four-stone-rod recipe plus all three ore-dictionary
saw recipes. Forge subsequently sorts the global recipe list, so only recipe identity/content and the proxy's own saw
list have meaningful stable order. Post-init still calculates maximum cutting strength, assigns the registry handshake
handler and conditionally registers Postea transformers.
Client init still registers the same renderer for all three saws. Client post-init still loads material icons,
registers the microblock-item renderer and packet handler, and conditionally installs `AngelicaCompat`. The
`RenderBlocks` instance remains lazy, synchronized and published through the same volatile bitmap.
### ABI, annotations and source compatibility
The four callable types remain `MicroblockProxy_serverImpl`, `MicroblockProxy_clientImpl`, `MicroblockProxy`, and
`MicroblockProxy$`, with unchanged inheritance and final flags. The server implementation retains its exact 21 public
methods and eight private fields. Its source-protected `saws` property remains a Scala `MutableList<Item>` with public
JVM accessors, preserving compiled callers. The facade retains its exact 20 static methods, deliberately excluding the
protected saw-list accessors, and the companion still declares only `MODULE$`.
The client implementation retains its private `renderBlocks` field, volatile `bitmap$0`, private
`renderBlocks$lzycompute()` helper and three public methods. As in the Scala reference, only the renderer field is
`@SideOnly(CLIENT)`; the getter and lazy helper are not. Only `init` and `postInit` are client-only on the client
implementation and facade. Consequently dedicated-server reflection across all client methods still encounters the
stripped `RenderBlocks` type, while direct companion lifecycle dispatch resolves to the inherited server methods.
Accepted classfile-only differences are removed Scala signature/marker attributes, a private facade constructor, one
private Java recipe-list helper, and removal of the unreferenced
`MicroblockProxy_clientImpl$$anonfun$init$1` iteration closure. The downstream inventory contains no reference to that
private implementation class.
### Validation
- `MicroblockProxyCharacterizationTest`: 4 plain-JVM tests, unchanged from the Scala baseline.
- `MicroblockProxyFunctionalTest`: 2 Forge tests, unchanged from the Scala baseline.
- Complete plain-JVM suite: 191 tests, 0 failures, 0 errors.
- Java 8 Forge dedicated-server suite: 98 tests, 0 failures, 0 errors.
- A clean build and raw `javap` comparison confirm identical retained class hierarchy, fields, callable public
names/descriptors and side annotations. The sole class-list removal is the private closure above.
- Item-renderer registration, material icon loading, client packet registration and Angelica integration require a
client and remain on the manual checklist.
+18 -11
View File
@@ -12,8 +12,8 @@ what breaks, and what is left. The other documents hold the reasoning.
| `JAVA_MIGRATION_MANUAL_CHECKS.md` | What no automated test can cover, and must be checked by hand in a client |
| `JAVA_MIGRATION_PROFILE.md` | The focused baseline, first measured result, findings, and exact rerun command |
Branch: `algent/java`. Base: `master`. 109 commits including the API-cleanup plan and separate characterization and
port commits for `MultipartProxy`.
Branch: `algent/java`. Base: `master`. 111 commits including the API-cleanup plan and separate characterization and
port commits for both proxy hierarchies.
## The one rule that matters
@@ -67,7 +67,7 @@ awk -F'"' '/<testsuite /{t+=$4;f+=$8;e+=$10} END{print "tests="t" failures="f" e
grep -o 'tests="[0-9]*" skipped="[0-9]*" failures="[0-9]*" errors="[0-9]*"' run/server/junit-out/TEST-*.xml
```
Current baseline: **187 plain-JVM tests and 96 Java 8 Forge dedicated-server tests passing.** The ignored local server
Current baseline: **191 plain-JVM tests and 98 Java 8 Forge dedicated-server tests passing.** The ignored local server
EULA is accepted in this checkout.
### ABI diff against the reference
@@ -251,7 +251,7 @@ All eight load-bearing `$class` helpers from the inventory, both registries, and
`MultipartEventHandler`, `MicroblockMod`, `MicroblockEventHandler`, and the complete `MicroblockPH`/
`MicroblockCPH`/`MicroblockSPH` packet-handler unit, plus `MultipartSaveLoad`, `MissingMicroMaterial`,
`DefaultContent`, and `GrassMicroMaterial`/`TopMicroMaterial`.
The complete `MultipartProxy` server/client hierarchy and static facade are also Java.
The complete `MultipartProxy` and `MicroblockProxy` server/client hierarchies and static facades are also Java.
Plus the six marker interfaces: `TSlottedPart`, `IRandomDisplayTick`, `INeighborTileChange`, `TRandomUpdateTick`,
`ISidedHollowConnect`, `IMicroMaterialRender`, plus `MultipartHelper`, `TileCache`, `PacketScheduler` and the `ControlKeyModifer` pair.
@@ -266,7 +266,7 @@ across the port. It is also where the two shim constraints in the gotchas list w
`rayTraceAll`'s index production is now characterized, closing the gap the read-path cleanup left: the index written
into `ExtendedMOP.data` is what `reduceMOP` hands back to every click, activate, harvest and pick block.
121 Java files, 27 Scala files, ~4,647 Scala lines left (non-blank; that is the metric this figure has always used).
125 Java files, 26 Scala files, ~4,519 Scala lines left (non-blank; that is the metric this figure has always used).
## What is left, and in what order
@@ -408,7 +408,14 @@ and matching static forwarders on a dedicated server; common generated-tile regi
companion directly and resolves to the inherited server implementation. Client renderer, packet, key-binding and
generated-tile renderer registration remain on the manual checklist.
**Medium.** The `handler` packages on both sides, `ItemMicroPart`,
`MicroblockProxy` is now Java. Its four load-bearing types retain all item/saw/logger/config access used by Iguana
Tweaks and in-repo recipes/rendering, including the protected-source/public-bytecode Scala `MutableList` accessors.
The client implementation preserves the exact lazy `RenderBlocks` field/bitmap shape and the reference's unusual
field-only side annotation; Forge strips the two lifecycle overrides and facade forwarders while companion dispatch
falls back to the server implementation. Actual item-renderer registration, client packets and Angelica integration
remain on the manual checklist.
**Medium.** The remaining multipart packet handler, `ItemMicroPart`,
`MicroblockPlacement`, `PlacementGrids`, `BlockMicroMaterial`, `ConfigContent`,
and the remaining material/render units.
@@ -416,11 +423,11 @@ and the remaining material/render units.
narrow generator relaxation: Java-trait parent linearization, explicit field-accessor recognition, and exclusion of
transient runtime caches from generated copying.
Take `microblock/handler/proxies.scala` next. At 127 nonblank lines it is the other remaining handler proxy unit and
owns load-bearing `MicroblockProxy` item/saw access used by Iguana Tweaks and in-repo rendering/recipes. Freeze the
server/client inheritance, all mutable accessors, protected saw collection, static facade plus `MODULE$`, item/recipe
registration order and the lazy client renderer with its side stripping. Keep item renderers, packet registration and
Angelica integration on the manual checklist, and keep the characterization and port commits separate.
Take `multipart/handler/packethandlers.scala` next. At 224 nonblank lines it is the last Scala file in either handler
package and owns central registry, tile-description, tile-update and chunk-watch traffic. Freeze all facade/companion
interfaces, the `MultipartMod$.MODULE$` channel descriptor, private prefixed watcher/update-map accessors already used
by tests, disconnect behavior, packet framing/terminators, unload cleanup and watch/tick ordering. Keep real client
decode/render integration on the manual checklist, and keep the characterization and port commits separate.
**Phase 6/7, last.** `Microblock` and the microblock shape hierarchy, `MicroblockGenerator`, `MultipartGenerator`, and
all of `multipart/asm/`. The ASM subsystem should be last; freeze generated-class fixtures before touching it.
+1
View File
@@ -23,6 +23,7 @@ release that includes those ports.
| Change a mixed multipart tile containing static and dynamically rendered parts | Static parts remain in the block render, dynamic parts remain in the TESR pass, and neither disappears after a part update | `TileMultipartClient` render caches |
| Watch a multipart torch long enough to emit display particles | Only parts implementing `IRandomDisplayTick` emit particles, with no duplicate or missing callbacks | `TRandomDisplayTickTile.randomDisplayTick` |
| Start a client, join a server, place/update a multipart and use the multipart control key | Block and generated-tile rendering work, client packets arrive, and control-key state changes are sent once without duplicate registrations | `MultipartProxy_clientImpl.postInit` / `onTileClassBuilt` |
| Start a client with 3D saws enabled, inspect all three saw tiers and the microblock item, then repeat with Angelica installed | Each renderer is registered once, saw models use the correct tier, microblock icons load, client packets register, and the Angelica hook initializes without errors | `MicroblockProxy_clientImpl.init` / `postInit` |
## Placement and interaction
@@ -2,7 +2,6 @@ package codechicken.microblock
import net.minecraft.item.Item
import codechicken.lib.config.ConfigTag
import codechicken.microblock.handler.MicroblockProxy._
import net.minecraft.item.ItemStack
import net.minecraftforge.client.IItemRenderer
import codechicken.lib.render.{TextureUtils, CCModel, CCRenderState}
@@ -0,0 +1,8 @@
package codechicken.microblock.handler;
public final class MicroblockProxy$ extends MicroblockProxy_clientImpl {
public static final MicroblockProxy$ MODULE$ = new MicroblockProxy$();
private MicroblockProxy$() {}
}
@@ -0,0 +1,98 @@
package codechicken.microblock.handler;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.item.Item;
import org.apache.logging.log4j.Logger;
import codechicken.lib.config.ConfigFile;
import codechicken.microblock.ItemMicroPart;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public final class MicroblockProxy {
private MicroblockProxy() {}
public static Logger logger() {
return MicroblockProxy$.MODULE$.logger();
}
public static void logger_$eq(Logger logger) {
MicroblockProxy$.MODULE$.logger_$eq(logger);
}
public static ItemMicroPart itemMicro() {
return MicroblockProxy$.MODULE$.itemMicro();
}
public static void itemMicro_$eq(ItemMicroPart itemMicro) {
MicroblockProxy$.MODULE$.itemMicro_$eq(itemMicro);
}
public static Item sawStone() {
return MicroblockProxy$.MODULE$.sawStone();
}
public static void sawStone_$eq(Item sawStone) {
MicroblockProxy$.MODULE$.sawStone_$eq(sawStone);
}
public static Item sawIron() {
return MicroblockProxy$.MODULE$.sawIron();
}
public static void sawIron_$eq(Item sawIron) {
MicroblockProxy$.MODULE$.sawIron_$eq(sawIron);
}
public static Item sawDiamond() {
return MicroblockProxy$.MODULE$.sawDiamond();
}
public static void sawDiamond_$eq(Item sawDiamond) {
MicroblockProxy$.MODULE$.sawDiamond_$eq(sawDiamond);
}
public static Item stoneRod() {
return MicroblockProxy$.MODULE$.stoneRod();
}
public static void stoneRod_$eq(Item stoneRod) {
MicroblockProxy$.MODULE$.stoneRod_$eq(stoneRod);
}
public static boolean useSawIcons() {
return MicroblockProxy$.MODULE$.useSawIcons();
}
public static void useSawIcons_$eq(boolean useSawIcons) {
MicroblockProxy$.MODULE$.useSawIcons_$eq(useSawIcons);
}
public static void preInit(Logger logger) {
MicroblockProxy$.MODULE$.preInit(logger);
}
public static Item createSaw(ConfigFile config, String name, int strength) {
return MicroblockProxy$.MODULE$.createSaw(config, name, strength);
}
public static void addSawRecipe(Item saw, Item blade) {
MicroblockProxy$.MODULE$.addSawRecipe(saw, blade);
}
public static RenderBlocks renderBlocks() {
return MicroblockProxy$.MODULE$.renderBlocks();
}
@SideOnly(Side.CLIENT)
public static void init() {
MicroblockProxy$.MODULE$.init();
}
@SideOnly(Side.CLIENT)
public static void postInit() {
MicroblockProxy$.MODULE$.postInit();
}
}
@@ -0,0 +1,60 @@
package codechicken.microblock.handler;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.item.Item;
import net.minecraftforge.client.MinecraftForgeClient;
import codechicken.lib.packet.PacketCustom;
import codechicken.microblock.AngelicaCompat;
import codechicken.microblock.ItemMicroPartRenderer$;
import codechicken.microblock.ItemSawRenderer$;
import codechicken.microblock.MicroMaterialRegistry;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import scala.collection.Iterator;
public class MicroblockProxy_clientImpl extends MicroblockProxy_serverImpl {
@SideOnly(Side.CLIENT)
private RenderBlocks renderBlocks;
private volatile boolean bitmap$0;
private RenderBlocks renderBlocks$lzycompute() {
synchronized (this) {
if (!bitmap$0) {
renderBlocks = new RenderBlocks();
bitmap$0 = true;
}
return renderBlocks;
}
}
public RenderBlocks renderBlocks() {
return bitmap$0 ? renderBlocks : renderBlocks$lzycompute();
}
@Override
@SideOnly(Side.CLIENT)
public void postInit() {
super.postInit();
MicroMaterialRegistry.loadIcons();
MinecraftForgeClient.registerItemRenderer(itemMicro(), ItemMicroPartRenderer$.MODULE$);
PacketCustom.assignHandler(MicroblockCPH.registryChannel(), MicroblockCPH$.MODULE$);
if (Loader.isModLoaded("angelica")) {
MicroblockMod.angelicaCompat_$eq(new AngelicaCompat());
}
}
@Override
@SideOnly(Side.CLIENT)
public void init() {
super.init();
Iterator<Item> iterator = saws().iterator();
while (iterator.hasNext()) {
MinecraftForgeClient.registerItemRenderer(iterator.next(), ItemSawRenderer$.MODULE$);
}
}
}
@@ -0,0 +1,167 @@
package codechicken.microblock.handler;
import java.util.List;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.oredict.OreDictionary;
import net.minecraftforge.oredict.ShapedOreRecipe;
import org.apache.logging.log4j.Logger;
import codechicken.lib.config.ConfigFile;
import codechicken.lib.packet.PacketCustom;
import codechicken.microblock.ItemMicroPart;
import codechicken.microblock.ItemSaw;
import codechicken.microblock.MicroMaterialRegistry;
import codechicken.microblock.MicroRecipe$;
import codechicken.microblock.compat.PosteaCompat;
import codechicken.multipart.handler.MultipartProxy;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.registry.GameRegistry;
import scala.collection.mutable.MutableList;
public class MicroblockProxy_serverImpl {
private Logger logger;
private ItemMicroPart itemMicro;
private Item sawStone;
private Item sawIron;
private Item sawDiamond;
private Item stoneRod;
private boolean useSawIcons;
private MutableList<Item> saws = new MutableList<>();
public Logger logger() {
return logger;
}
public void logger_$eq(Logger logger) {
this.logger = logger;
}
public ItemMicroPart itemMicro() {
return itemMicro;
}
public void itemMicro_$eq(ItemMicroPart itemMicro) {
this.itemMicro = itemMicro;
}
public Item sawStone() {
return sawStone;
}
public void sawStone_$eq(Item sawStone) {
this.sawStone = sawStone;
}
public Item sawIron() {
return sawIron;
}
public void sawIron_$eq(Item sawIron) {
this.sawIron = sawIron;
}
public Item sawDiamond() {
return sawDiamond;
}
public void sawDiamond_$eq(Item sawDiamond) {
this.sawDiamond = sawDiamond;
}
public Item stoneRod() {
return stoneRod;
}
public void stoneRod_$eq(Item stoneRod) {
this.stoneRod = stoneRod;
}
public boolean useSawIcons() {
return useSawIcons;
}
public void useSawIcons_$eq(boolean useSawIcons) {
this.useSawIcons = useSawIcons;
}
public void preInit(Logger logger) {
this.logger = logger;
itemMicro = new ItemMicroPart();
GameRegistry.registerItem(itemMicro, "microblock");
sawStone = createSaw(MultipartProxy.config(), "sawStone", 1);
sawIron = createSaw(MultipartProxy.config(), "sawIron", 2);
sawDiamond = createSaw(MultipartProxy.config(), "sawDiamond", 3);
stoneRod = new Item().setUnlocalizedName("microblock:stoneRod").setTextureName("microblock:stoneRod");
GameRegistry.registerItem(stoneRod, "stoneRod");
OreDictionary.registerOre("rodStone", stoneRod);
MinecraftForge.EVENT_BUS.register(MicroblockEventHandler$.MODULE$);
useSawIcons = MultipartProxy.config().getTag("useSawIcons")
.setComment("Set to true to use mc style icons for the saw instead of the 3D model")
.getBooleanValue(false);
}
public MutableList<Item> saws() {
return saws;
}
public void saws_$eq(MutableList<Item> saws) {
this.saws = saws;
}
public Item createSaw(ConfigFile config, String name, int strength) {
Item saw = new ItemSaw(config.getTag(name).useBraces(), strength).setUnlocalizedName("microblock:" + name)
.setTextureName("microblock:" + name);
GameRegistry.registerItem(saw, name);
saws.$plus$eq(saw);
return saw;
}
public void addSawRecipe(Item saw, Item blade) {
recipes().add(
new ShapedOreRecipe(
new ItemStack(saw),
"srr",
"sbr",
Character.valueOf('s'),
"stickWood",
Character.valueOf('r'),
"rodStone",
Character.valueOf('b'),
blade));
}
public void init() {
recipes().add(MicroRecipe$.MODULE$);
if (!Loader.isModLoaded("dreamcraft")) {
CraftingManager.getInstance()
.addRecipe(new ItemStack(stoneRod, 4), "s", "s", Character.valueOf('s'), Blocks.stone);
addSawRecipe(sawStone, Items.flint);
addSawRecipe(sawIron, Items.iron_ingot);
addSawRecipe(sawDiamond, Items.diamond);
}
}
public void postInit() {
MicroMaterialRegistry.calcMaxCuttingStrength();
PacketCustom.assignHandshakeHandler(MicroblockSPH.registryChannel(), MicroblockSPH$.MODULE$);
if (Loader.isModLoaded("postea")) {
PosteaCompat.registerTransformers();
}
}
@SuppressWarnings("unchecked")
private static List<IRecipe> recipes() {
return CraftingManager.getInstance().getRecipeList();
}
}
@@ -1,145 +0,0 @@
package codechicken.microblock.handler
import net.minecraftforge.common.MinecraftForge
import codechicken.multipart.handler.MultipartProxy._
import codechicken.microblock._
import net.minecraftforge.client.MinecraftForgeClient
import cpw.mods.fml.relauncher.SideOnly
import cpw.mods.fml.relauncher.Side
import net.minecraft.item.crafting.CraftingManager
import net.minecraft.item.Item
import net.minecraft.item.crafting.IRecipe
import java.util.{List => JList}
import codechicken.lib.config.ConfigFile
import net.minecraftforge.oredict.OreDictionary
import net.minecraft.item.ItemStack
import net.minecraftforge.oredict.ShapedOreRecipe
import codechicken.lib.packet.PacketCustom
import codechicken.microblock.compat.PosteaCompat
import cpw.mods.fml.common.Loader
import cpw.mods.fml.common.registry.GameRegistry
import net.minecraft.client.renderer.RenderBlocks
import net.minecraft.init.{Blocks, Items}
import org.apache.logging.log4j.Logger
import scala.collection.mutable
class MicroblockProxy_serverImpl {
var logger: Logger = _
var itemMicro: ItemMicroPart = _
var sawStone: Item = _
var sawIron: Item = _
var sawDiamond: Item = _
var stoneRod: Item = _
var useSawIcons: Boolean = _
def preInit(logger: Logger) {
this.logger = logger
itemMicro = new ItemMicroPart
GameRegistry.registerItem(itemMicro, "microblock")
sawStone = createSaw(config, "sawStone", 1)
sawIron = createSaw(config, "sawIron", 2)
sawDiamond = createSaw(config, "sawDiamond", 3)
stoneRod = new Item()
.setUnlocalizedName("microblock:stoneRod")
.setTextureName("microblock:stoneRod")
GameRegistry.registerItem(stoneRod, "stoneRod")
OreDictionary.registerOre("rodStone", stoneRod)
MinecraftForge.EVENT_BUS.register(MicroblockEventHandler$.MODULE$)
useSawIcons = config
.getTag("useSawIcons")
.setComment(
"Set to true to use mc style icons for the saw instead of the 3D model"
)
.getBooleanValue(false)
}
protected var saws = mutable.MutableList[Item]()
def createSaw(config: ConfigFile, name: String, strength: Int) = {
val saw = new ItemSaw(config.getTag(name).useBraces(), strength)
.setUnlocalizedName("microblock:" + name)
.setTextureName("microblock:" + name)
GameRegistry.registerItem(saw, name)
saws += saw
saw
}
def addSawRecipe(saw: Item, blade: Item) {
CraftingManager.getInstance.getRecipeList
.asInstanceOf[JList[IRecipe]]
.add(
new ShapedOreRecipe(
new ItemStack(saw),
"srr",
"sbr",
's': Character,
"stickWood",
'r': Character,
"rodStone",
'b': Character,
blade
)
)
}
def init() {
CraftingManager.getInstance.getRecipeList
.asInstanceOf[JList[IRecipe]]
.add(MicroRecipe$.MODULE$)
if (!Loader.isModLoaded("dreamcraft")) {
CraftingManager.getInstance.addRecipe(
new ItemStack(stoneRod, 4),
"s",
"s",
's': Character,
Blocks.stone
)
addSawRecipe(sawStone, Items.flint)
addSawRecipe(sawIron, Items.iron_ingot)
addSawRecipe(sawDiamond, Items.diamond)
}
}
def postInit() {
MicroMaterialRegistry.calcMaxCuttingStrength()
PacketCustom.assignHandshakeHandler(
MicroblockSPH.registryChannel(),
MicroblockSPH$.MODULE$
)
if (Loader.isModLoaded("postea")) {
PosteaCompat.registerTransformers()
}
}
}
class MicroblockProxy_clientImpl extends MicroblockProxy_serverImpl {
@SideOnly(Side.CLIENT)
lazy val renderBlocks = new RenderBlocks
@SideOnly(Side.CLIENT)
override def postInit() {
super.postInit()
MicroMaterialRegistry.loadIcons()
MinecraftForgeClient.registerItemRenderer(itemMicro, ItemMicroPartRenderer)
PacketCustom.assignHandler(
MicroblockCPH.registryChannel(),
MicroblockCPH$.MODULE$
)
if (Loader.isModLoaded("angelica"))
MicroblockMod.angelicaCompat_$eq(new AngelicaCompat)
}
@SideOnly(Side.CLIENT)
override def init() {
super.init()
saws.foreach(MinecraftForgeClient.registerItemRenderer(_, ItemSawRenderer))
}
}
object MicroblockProxy extends MicroblockProxy_clientImpl {}