mirror of
https://github.com/GTNewHorizons/ForgeMultipart.git
synced 2026-11-13 17:04:25 +00:00
refactor: port MultiPartRegistry to Java
Replaces MultiPartRegistry.scala with a Java registry, its companion singleton and the three nested interfaces. All three interfaces are descriptor-identical to the reference and MODULE$ keeps every instance method downstream links against. Twelve jars reference this type. Both Scala-typed registerParts descriptors are preserved, since ForgeRelocationFMP links against the Function2 form and ProjRed against the IPartFactory2 Seq form. That leaves TileMultipart.partList as the last Scala-typed descriptor in the inventory. The two array overloads are declared varargs. The descriptor is unchanged and ACC_VARARGS does not affect linkage, but MicroblockClass called the Scala varargs form with a single string, which no longer resolves against a plain array parameter. readIDMap moves to java.util.List and the mangled accessors Scala emitted for its closures are gone; neither is referenced by any jar. Eight anonfun classes and one anonymous class are replaced by the two Java adapters the deprecated overloads build. Validated with 78 plain-JVM tests, a clean build, and the Java 8 Forge dedicated-server suite, which is the only layer where registration can run at all since it needs FML's active mod container.
This commit is contained in:
1 parent
ff380ee3bc
commit
b9d5e6ab52
4 files changed
+439
-247
No files matched your search
@@ -559,3 +559,57 @@ replacement classes.
|
||||
startup calls `setupIDMap`, `calcMaxCuttingStrength` and the default content registration.
|
||||
- Error paths remain uncovered by tests: they call the microblock logger, which is null until `MicroblockProxy.preInit`
|
||||
runs, so they cannot execute headless. They are unchanged from the reference.
|
||||
|
||||
## 2026-08-14 — MultiPartRegistry Java port
|
||||
|
||||
Covers `MultiPartRegistry`, `MultiPartRegistry$` and the three nested interfaces. Twelve jars reference the type and
|
||||
Schematica reaches the singleton reflectively.
|
||||
|
||||
### Observable behavior
|
||||
|
||||
No known divergence. `beforeServerStart` still sorts the type map by name so ids are indexes into it, part ids still
|
||||
round trip through the shared `IDWriter`, converters are still grouped per block with the first non-null result
|
||||
winning, registration still refuses to run once the registry is closed and still requires an active mod container, a
|
||||
duplicate part id still throws, and `writePartID` and `getModContainer` still throw rather than returning null for an
|
||||
unknown name.
|
||||
|
||||
### Preserved Scala-typed descriptors
|
||||
|
||||
Both remain, because ForgeRelocationFMP and ProjRed link against them:
|
||||
|
||||
- `registerParts(Lscala/Function2;Lscala/collection/Seq;)V`
|
||||
- `registerParts(Lcodechicken/multipart/MultiPartRegistry$IPartFactory2;Lscala/collection/Seq;)V`
|
||||
|
||||
The `Seq` overload drains through `JavaConversions.seqAsJavaList`. The `Function2` overload applies the function with
|
||||
a boxed `Boolean`, matching what the Scala closure received.
|
||||
|
||||
### Array overloads become Java varargs
|
||||
|
||||
`registerParts(IPartFactory, String[])` and `registerParts(IPartFactory2, String[])` are declared `String...`. The
|
||||
descriptor is unchanged, verified against the reference dev jar; `ACC_VARARGS` is a compiler flag and does not affect
|
||||
linkage. This was needed because `MicroblockClass` called the Scala varargs form with a single string, which no longer
|
||||
resolves against a plain array parameter. It also makes the Java call sites more natural without adding API.
|
||||
|
||||
### Changed and removed API
|
||||
|
||||
- `readIDMap` returns `java.util.List<String>` instead of `scala.collection.Seq<String>`, as with
|
||||
`MicroMaterialRegistry`. It is `private[multipart]` in Scala, so it has no static forwarder, and no jar references
|
||||
it.
|
||||
- The mangled public accessors Scala emitted so its closures could reach private state
|
||||
(`codechicken$multipart$MultiPartRegistry$$typeMap()` and the four others) are gone. No jar references them.
|
||||
|
||||
### Compiler artifacts
|
||||
|
||||
Accepted divergence: the eight `MultiPartRegistry$$anonfun$*` classes and `MultiPartRegistry$$anon$1` are replaced by
|
||||
two Java anonymous classes, `MultiPartRegistry$1` and `$2`, which are the two `IPartFactory2` adapters the deprecated
|
||||
overloads build.
|
||||
|
||||
### Validation
|
||||
|
||||
- `MultiPartRegistryCharacterizationTest`: 5 tests, 0 failures, 0 errors, unchanged from the Scala baseline.
|
||||
- Complete plain-JVM suite: 78 tests, 0 failures, 0 errors.
|
||||
- Clean `spotlessApply checkstyleTest build`: passing.
|
||||
- Java 8 Forge dedicated-server suite: 5 tests, 0 failures, 0 errors. This is the layer that matters for this class:
|
||||
registration needs FML's active mod container, so real startup is the only place both factory overloads actually
|
||||
run, and the suite resolves a part registered through each.
|
||||
- Error paths that log remain uncovered headless, as before, because the multipart logger is null until preInit.
|
||||
@@ -0,0 +1,98 @@
|
||||
package codechicken.multipart;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import codechicken.lib.data.MCDataInput;
|
||||
import codechicken.lib.data.MCDataOutput;
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
import codechicken.lib.vec.BlockCoord;
|
||||
import codechicken.multipart.MultiPartRegistry.IPartConverter;
|
||||
import codechicken.multipart.MultiPartRegistry.IPartFactory;
|
||||
import codechicken.multipart.MultiPartRegistry.IPartFactory2;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
/**
|
||||
* Scala companion singleton. Retained because compiled Scala consumers read MODULE$ and call these instance methods.
|
||||
*/
|
||||
public final class MultiPartRegistry$ {
|
||||
|
||||
public static final MultiPartRegistry$ MODULE$ = new MultiPartRegistry$();
|
||||
|
||||
private MultiPartRegistry$() {}
|
||||
|
||||
@Deprecated
|
||||
public void registerParts(IPartFactory partFactory, String... types) {
|
||||
MultiPartRegistry.registerParts(partFactory, types);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void registerParts(scala.Function2<String, Object, TMultiPart> partFactory,
|
||||
scala.collection.Seq<String> types) {
|
||||
MultiPartRegistry.registerParts(partFactory, types);
|
||||
}
|
||||
|
||||
public void registerParts(IPartFactory2 partFactory, String... types) {
|
||||
MultiPartRegistry.registerParts(partFactory, types);
|
||||
}
|
||||
|
||||
public void registerParts(IPartFactory2 partFactory, scala.collection.Seq<String> types) {
|
||||
MultiPartRegistry.registerParts(partFactory, types);
|
||||
}
|
||||
|
||||
public void registerConverter(IPartConverter c) {
|
||||
MultiPartRegistry.registerConverter(c);
|
||||
}
|
||||
|
||||
public void beforeServerStart() {
|
||||
MultiPartRegistry.beforeServerStart();
|
||||
}
|
||||
|
||||
public void writeIDMap(PacketCustom packet) {
|
||||
MultiPartRegistry.writeIDMap(packet);
|
||||
}
|
||||
|
||||
public List<String> readIDMap(PacketCustom packet) {
|
||||
return MultiPartRegistry.readIDMap(packet);
|
||||
}
|
||||
|
||||
public boolean required() {
|
||||
return MultiPartRegistry.required();
|
||||
}
|
||||
|
||||
public boolean loaded() {
|
||||
return MultiPartRegistry.loaded();
|
||||
}
|
||||
|
||||
public void postInit() {
|
||||
MultiPartRegistry.postInit();
|
||||
}
|
||||
|
||||
public void writePartID(MCDataOutput data, TMultiPart part) {
|
||||
MultiPartRegistry.writePartID(data, part);
|
||||
}
|
||||
|
||||
public TMultiPart readPart(MCDataInput data) {
|
||||
return MultiPartRegistry.readPart(data);
|
||||
}
|
||||
|
||||
public TMultiPart loadPart(String name, NBTTagCompound nbt) {
|
||||
return MultiPartRegistry.loadPart(name, nbt);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public TMultiPart createPart(String name, boolean client) {
|
||||
return MultiPartRegistry.createPart(name, client);
|
||||
}
|
||||
|
||||
public TMultiPart convertBlock(World world, BlockCoord pos, Block block) {
|
||||
return MultiPartRegistry.convertBlock(world, pos, block);
|
||||
}
|
||||
|
||||
public ModContainer getModContainer(String name) {
|
||||
return MultiPartRegistry.getModContainer(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
package codechicken.multipart;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
|
||||
import codechicken.lib.data.MCDataInput;
|
||||
import codechicken.lib.data.MCDataOutput;
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
import codechicken.lib.vec.BlockCoord;
|
||||
import codechicken.multipart.handler.MultipartProxy;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import scala.Tuple2;
|
||||
import scala.collection.JavaConversions;
|
||||
|
||||
/** This class handles the registration and internal ID mapping of all multipart classes. */
|
||||
public final class MultiPartRegistry {
|
||||
|
||||
/**
|
||||
* Interface to be registered for constructing parts. Every instance of every multipart is constructed from an
|
||||
* implementor of this.
|
||||
*
|
||||
* @deprecated Use IPartFactory2
|
||||
*/
|
||||
@Deprecated
|
||||
public interface IPartFactory {
|
||||
|
||||
/**
|
||||
* Create a new instance of the part with the specified type name identifier.
|
||||
*
|
||||
* @param client If the part instance is for the client or the server
|
||||
*/
|
||||
TMultiPart createPart(String name, boolean client);
|
||||
}
|
||||
|
||||
/** Will replace IPartFactory in 1.8. */
|
||||
public interface IPartFactory2 {
|
||||
|
||||
/**
|
||||
* Create a new server instance of the part with the specified type name identifier.
|
||||
*
|
||||
* @param nbt The tag compound that will be passed to part.load, can be used to change the class of part
|
||||
* returned
|
||||
*/
|
||||
TMultiPart createPart(String name, NBTTagCompound nbt);
|
||||
|
||||
/**
|
||||
* Create a new client instance of the part with the specified type name identifier.
|
||||
*
|
||||
* @param packet The packet that will be passed to part.readDesc, can be used to change the class of part
|
||||
* returned
|
||||
*/
|
||||
TMultiPart createPart(String name, MCDataInput packet);
|
||||
}
|
||||
|
||||
/** An interface for converting existing blocks/tile entities to multipart versions. */
|
||||
public interface IPartConverter {
|
||||
|
||||
/**
|
||||
* Return true if this converter can handle the specific blockID (may or may not actually convert the block).
|
||||
*/
|
||||
Iterable<Block> blockTypes();
|
||||
|
||||
/** Return a multipart version of the block at pos in world. Return null if no conversion is possible. */
|
||||
TMultiPart convert(World world, BlockCoord pos);
|
||||
}
|
||||
|
||||
private static final Map<String, IPartFactory2> typeMap = new HashMap<>();
|
||||
private static final Map<String, Integer> nameMap = new HashMap<>();
|
||||
private static Tuple2<String, IPartFactory2>[] idMap;
|
||||
private static final IDWriter idWriter = new IDWriter();
|
||||
private static final ArrayListMultimap<Block, IPartConverter> converters = ArrayListMultimap.create();
|
||||
private static final Map<String, ModContainer> containers = new HashMap<>();
|
||||
|
||||
/** The state of the registry. 0 = no parts, 1 = registering, 2 = registered. */
|
||||
private static int state = 0;
|
||||
|
||||
private MultiPartRegistry() {}
|
||||
|
||||
/**
|
||||
* Register a part factory with an array of types it is capable of instantiating. Must be called before postInit.
|
||||
*
|
||||
* @deprecated Use IPartFactory2
|
||||
*/
|
||||
@Deprecated
|
||||
public static void registerParts(IPartFactory partFactory, String... types) {
|
||||
registerParts(new IPartFactory2() {
|
||||
|
||||
@Override
|
||||
public TMultiPart createPart(String name, MCDataInput packet) {
|
||||
return partFactory.createPart(name, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TMultiPart createPart(String name, NBTTagCompound nbt) {
|
||||
return partFactory.createPart(name, false);
|
||||
}
|
||||
}, types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scala function version of registerParts.
|
||||
*
|
||||
* @deprecated Use IPartFactory2
|
||||
*/
|
||||
@Deprecated
|
||||
public static void registerParts(scala.Function2<String, Object, TMultiPart> partFactory,
|
||||
scala.collection.Seq<String> types) {
|
||||
registerParts(new IPartFactory2() {
|
||||
|
||||
@Override
|
||||
public TMultiPart createPart(String name, MCDataInput packet) {
|
||||
return partFactory.apply(name, Boolean.TRUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TMultiPart createPart(String name, NBTTagCompound nbt) {
|
||||
return partFactory.apply(name, Boolean.FALSE);
|
||||
}
|
||||
}, types);
|
||||
}
|
||||
|
||||
/** Scala va-args version of registerParts. */
|
||||
public static void registerParts(IPartFactory2 partFactory, scala.collection.Seq<String> types) {
|
||||
registerParts(partFactory, JavaConversions.seqAsJavaList(types).toArray(new String[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a part factory with an array of types it is capable of instantiating. Must be called before postInit.
|
||||
*/
|
||||
public static void registerParts(IPartFactory2 partFactory, String... types) {
|
||||
if (loaded()) {
|
||||
throw new IllegalStateException("Parts must be registered in the init methods.");
|
||||
}
|
||||
state = 1;
|
||||
|
||||
ModContainer container = Loader.instance().activeModContainer();
|
||||
if (container == null) {
|
||||
throw new IllegalStateException(
|
||||
"Parts must be registered during the initialization phase of a mod container");
|
||||
}
|
||||
|
||||
for (String s : types) {
|
||||
if (typeMap.containsKey(s)) {
|
||||
throw new IllegalStateException("Part with id " + s + " is already registered.");
|
||||
}
|
||||
|
||||
typeMap.put(s, partFactory);
|
||||
containers.put(s, container);
|
||||
}
|
||||
}
|
||||
|
||||
/** Register a part converter instance. */
|
||||
public static void registerConverter(IPartConverter c) {
|
||||
for (Block block : c.blockTypes()) {
|
||||
converters.put(block, c);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void beforeServerStart() {
|
||||
List<Map.Entry<String, IPartFactory2>> entries = new ArrayList<>(typeMap.entrySet());
|
||||
entries.sort(Comparator.comparing(Map.Entry::getKey));
|
||||
|
||||
idMap = new Tuple2[entries.size()];
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
idMap[i] = new Tuple2<>(entries.get(i).getKey(), entries.get(i).getValue());
|
||||
}
|
||||
|
||||
idWriter.setMax(idMap.length);
|
||||
nameMap.clear();
|
||||
for (int i = 0; i < idMap.length; i++) {
|
||||
nameMap.put(idMap[i]._1(), i);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeIDMap(PacketCustom packet) {
|
||||
packet.writeInt(idMap.length);
|
||||
for (Tuple2<String, IPartFactory2> entry : idMap) {
|
||||
packet.writeString(entry._1());
|
||||
}
|
||||
}
|
||||
|
||||
/** Reads the server's id map, returning the names this client has no factory for. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<String> readIDMap(PacketCustom packet) {
|
||||
int k = packet.readInt();
|
||||
idWriter.setMax(k);
|
||||
idMap = new Tuple2[k];
|
||||
nameMap.clear();
|
||||
List<String> missing = new ArrayList<>();
|
||||
for (int i = 0; i < k; i++) {
|
||||
String s = packet.readString();
|
||||
IPartFactory2 v = typeMap.get(s);
|
||||
if (v == null) {
|
||||
missing.add(s);
|
||||
} else {
|
||||
idMap[i] = new Tuple2<>(s, v);
|
||||
nameMap.put(s, i);
|
||||
}
|
||||
}
|
||||
return missing;
|
||||
}
|
||||
|
||||
/** Return true if any multiparts have been registered. */
|
||||
public static boolean required() {
|
||||
return state > 0;
|
||||
}
|
||||
|
||||
/** Return true if no more parts can be registered. */
|
||||
public static boolean loaded() {
|
||||
return state == 2;
|
||||
}
|
||||
|
||||
public static void postInit() {
|
||||
state = 2;
|
||||
}
|
||||
|
||||
/** Writes the id of part to data. */
|
||||
public static void writePartID(MCDataOutput data, TMultiPart part) {
|
||||
Integer id = nameMap.get(part.getType());
|
||||
if (id == null) {
|
||||
throw new NoSuchElementException("None.get");
|
||||
}
|
||||
idWriter.write(data, id);
|
||||
}
|
||||
|
||||
/** Uses instantiators to create a new part from the id read from data. */
|
||||
public static TMultiPart readPart(MCDataInput data) {
|
||||
Tuple2<String, IPartFactory2> e = idMap[idWriter.read(data)];
|
||||
return e._2().createPart(e._1(), data);
|
||||
}
|
||||
|
||||
/** Uses instantiators to create a new part from a tag compound. */
|
||||
public static TMultiPart loadPart(String name, NBTTagCompound nbt) {
|
||||
IPartFactory2 factory = typeMap.get(name);
|
||||
if (factory == null) {
|
||||
MultipartProxy.logger().error("Missing mapping for part with ID: " + name);
|
||||
return null;
|
||||
}
|
||||
return factory.createPart(name, nbt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses instantiators to create a new part with specified identifier on side.
|
||||
*
|
||||
* @deprecated currently calls the nbt/packet version with a null parameter, use readPart or loadPart instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static TMultiPart createPart(String name, boolean client) {
|
||||
IPartFactory2 factory = typeMap.get(name);
|
||||
if (factory == null) {
|
||||
MultipartProxy.logger().error("Missing mapping for part with ID: " + name);
|
||||
return null;
|
||||
}
|
||||
return client ? factory.createPart(name, (MCDataInput) null) : factory.createPart(name, (NBTTagCompound) null);
|
||||
}
|
||||
|
||||
/** Calls converters to create a multipart version of the block at pos. */
|
||||
public static TMultiPart convertBlock(World world, BlockCoord pos, Block block) {
|
||||
for (IPartConverter c : converters.get(block)) {
|
||||
TMultiPart ret = c.convert(world, pos);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ModContainer getModContainer(String name) {
|
||||
ModContainer container = containers.get(name);
|
||||
if (container == null) {
|
||||
throw new NoSuchElementException("key not found: " + name);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
package codechicken.multipart
|
||||
|
||||
import scala.collection.mutable.{Map => MMap}
|
||||
import codechicken.lib.packet.PacketCustom
|
||||
import codechicken.lib.data.MCDataOutput
|
||||
import codechicken.lib.data.MCDataInput
|
||||
import net.minecraft.world.World
|
||||
import codechicken.lib.vec.BlockCoord
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import cpw.mods.fml.common.ModContainer
|
||||
import cpw.mods.fml.common.Loader
|
||||
import net.minecraft.block.Block
|
||||
import java.lang.Iterable
|
||||
import com.google.common.collect.ArrayListMultimap
|
||||
import scala.collection.JavaConversions._
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
|
||||
/** This class handles the registration and internal ID mapping of all multipart
|
||||
* classes.
|
||||
*/
|
||||
object MultiPartRegistry {
|
||||
|
||||
/** Interface to be registered for constructing parts. Every instance of every
|
||||
* multipart is constructed from an implementor of this.
|
||||
*/
|
||||
@Deprecated
|
||||
trait IPartFactory {
|
||||
|
||||
/** Create a new instance of the part with the specified type name
|
||||
* identifier
|
||||
* @param client
|
||||
* If the part instance is for the client or the server
|
||||
*/
|
||||
def createPart(name: String, client: Boolean): TMultiPart
|
||||
}
|
||||
|
||||
/** Will replace IPartFactory in 1.8
|
||||
*/
|
||||
trait IPartFactory2 {
|
||||
|
||||
/** Create a new server instance of the part with the specified type name
|
||||
* identifier
|
||||
* @param nbt
|
||||
* The tag compound that will be passed to part.load, can be used to
|
||||
* change the class of part returned
|
||||
*/
|
||||
def createPart(name: String, nbt: NBTTagCompound): TMultiPart
|
||||
|
||||
/** Create a new client instance of the part with the specified type name
|
||||
* identifier
|
||||
* @param packet
|
||||
* The packet that will be passed to part.readDesc, can be used to change
|
||||
* the class of part returned
|
||||
*/
|
||||
def createPart(name: String, packet: MCDataInput): TMultiPart
|
||||
}
|
||||
|
||||
/** An interface for converting existing blocks/tile entities to multipart
|
||||
* versions.
|
||||
*/
|
||||
trait IPartConverter {
|
||||
|
||||
/** Return true if this converter can handle the specific blockID (may or
|
||||
* may not actually convert the block)
|
||||
*/
|
||||
def blockTypes: Iterable[Block]
|
||||
|
||||
/** Return a multipart version of the block at pos in world. Return null if
|
||||
* no conversion is possible.
|
||||
*/
|
||||
def convert(world: World, pos: BlockCoord): TMultiPart
|
||||
}
|
||||
|
||||
private val typeMap = MMap[String, IPartFactory2]()
|
||||
private val nameMap = MMap[String, Int]()
|
||||
private var idMap: Array[(String, IPartFactory2)] = _
|
||||
private val idWriter = new IDWriter
|
||||
private val converters = ArrayListMultimap.create[Block, IPartConverter]()
|
||||
private val containers = MMap[String, ModContainer]()
|
||||
|
||||
/** The state of the registry. 0 = no parts, 1 = registering, 2 = registered
|
||||
*/
|
||||
private var state: Int = 0
|
||||
|
||||
/** Register a part factory with an array of types it is capable of
|
||||
* instantiating. Must be called before postInit
|
||||
* @deprecated
|
||||
* Use IPartFactory2
|
||||
*/
|
||||
@Deprecated
|
||||
def registerParts(partFactory: IPartFactory, types: Array[String]) {
|
||||
registerParts(partFactory.createPart _, types: _*)
|
||||
}
|
||||
|
||||
/** Scala function version of registerParts
|
||||
* @deprecated
|
||||
* Use IPartFactory2
|
||||
*/
|
||||
@Deprecated
|
||||
def registerParts(
|
||||
partFactory: (String, Boolean) => TMultiPart,
|
||||
types: String*
|
||||
) {
|
||||
registerParts(
|
||||
new IPartFactory2 {
|
||||
override def createPart(name: String, packet: MCDataInput) =
|
||||
partFactory(name, true)
|
||||
override def createPart(name: String, nbt: NBTTagCompound) =
|
||||
partFactory(name, false)
|
||||
},
|
||||
types: _*
|
||||
)
|
||||
}
|
||||
|
||||
/** Register a part factory with an array of types it is capable of
|
||||
* instantiating. Must be called before postInit
|
||||
*/
|
||||
def registerParts(partFactory: IPartFactory2, types: Array[String]) {
|
||||
registerParts(partFactory, types: _*)
|
||||
}
|
||||
|
||||
/** Scala va-args version of registerParts
|
||||
*/
|
||||
def registerParts(partFactory: IPartFactory2, types: String*) {
|
||||
if (loaded)
|
||||
throw new IllegalStateException(
|
||||
"Parts must be registered in the init methods."
|
||||
)
|
||||
state = 1
|
||||
|
||||
val container = Loader.instance.activeModContainer
|
||||
if (container == null)
|
||||
throw new IllegalStateException(
|
||||
"Parts must be registered during the initialization phase of a mod container"
|
||||
)
|
||||
|
||||
types.foreach { s =>
|
||||
if (typeMap.contains(s))
|
||||
throw new IllegalStateException(
|
||||
"Part with id " + s + " is already registered."
|
||||
)
|
||||
|
||||
typeMap.put(s, partFactory)
|
||||
containers.put(s, container)
|
||||
}
|
||||
}
|
||||
|
||||
/** Register a part converter instance
|
||||
*/
|
||||
def registerConverter(c: IPartConverter) {
|
||||
c.blockTypes.foreach(converters.put(_, c))
|
||||
}
|
||||
|
||||
private[multipart] def beforeServerStart() {
|
||||
idMap = typeMap.toList.sortBy(_._1).toArray
|
||||
idWriter.setMax(idMap.length)
|
||||
nameMap.clear()
|
||||
for (i <- 0 until idMap.length)
|
||||
nameMap.put(idMap(i)._1, i)
|
||||
}
|
||||
|
||||
private[multipart] def writeIDMap(packet: PacketCustom) {
|
||||
packet.writeInt(idMap.length)
|
||||
idMap.foreach(e => packet.writeString(e._1))
|
||||
}
|
||||
|
||||
private[multipart] def readIDMap(packet: PacketCustom): Seq[String] = {
|
||||
val k = packet.readInt()
|
||||
idWriter.setMax(k)
|
||||
idMap = new Array(k)
|
||||
nameMap.clear()
|
||||
val missing = ListBuffer[String]()
|
||||
for (i <- 0 until k) {
|
||||
val s = packet.readString()
|
||||
val v = typeMap.get(s)
|
||||
if (v.isEmpty)
|
||||
missing += s
|
||||
else {
|
||||
idMap(i) = (s, v.get)
|
||||
nameMap.put(s, i)
|
||||
}
|
||||
}
|
||||
return missing
|
||||
}
|
||||
|
||||
/** Return true if any multiparts have been registered
|
||||
*/
|
||||
private[multipart] def required = state > 0
|
||||
|
||||
/** Return true if no more parts can be registered
|
||||
*/
|
||||
def loaded = state == 2
|
||||
|
||||
private[multipart] def postInit() {
|
||||
state = 2
|
||||
}
|
||||
|
||||
/** Writes the id of part to data
|
||||
*/
|
||||
def writePartID(data: MCDataOutput, part: TMultiPart) {
|
||||
idWriter.write(data, nameMap.get(part.getType).get)
|
||||
}
|
||||
|
||||
/** Uses instantiators to creat a new part from the id read from data
|
||||
*/
|
||||
def readPart(data: MCDataInput) = {
|
||||
val e = idMap(idWriter.read(data))
|
||||
e._2.createPart(e._1, data)
|
||||
}
|
||||
|
||||
/** Uses instantiators to creat a new part from the a tag compound
|
||||
*/
|
||||
def loadPart(name: String, nbt: NBTTagCompound) = typeMap.get(name) match {
|
||||
case Some(factory) => factory.createPart(name, nbt)
|
||||
case None =>
|
||||
logger.error("Missing mapping for part with ID: " + name)
|
||||
null
|
||||
}
|
||||
|
||||
/** Uses instantiators to create a new part with specified identifier on side
|
||||
* @deprecated
|
||||
* currently calls the nbt/packet version with a null parameter, use
|
||||
* readPart or loadPart instead
|
||||
*/
|
||||
@Deprecated
|
||||
def createPart(name: String, client: Boolean) = typeMap.get(name) match {
|
||||
case Some(factory) =>
|
||||
if (client) factory.createPart(name, null: MCDataInput)
|
||||
else factory.createPart(name, null: NBTTagCompound)
|
||||
case None =>
|
||||
logger.error("Missing mapping for part with ID: " + name)
|
||||
null
|
||||
}
|
||||
|
||||
/** Calls converters to create a multipart version of the block at pos
|
||||
*/
|
||||
def convertBlock(world: World, pos: BlockCoord, block: Block): TMultiPart = {
|
||||
for (c <- converters.get(block)) {
|
||||
val ret = c.convert(world, pos)
|
||||
if (ret != null)
|
||||
return ret
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
def getModContainer(name: String) = containers(name)
|
||||
}
|
||||
Reference in new issue
Block a user