Warung Bebas

Kamis, 26 Desember 2013

Forge concepts - registering your classes

Forge provides a number of registries to let you extend an existing base class (Block, Item, etc) and then tell the registry about your new Class to integrate it into the game. This is generally the best way to interface with the game, because it is modular, easy to understand and maintain, and relatively robust to changes in the vanilla code.
A broad overview of the different types of registries are listed below.  
  • Registries for adding new Blocks, Items, Entities - These registries are used to assign names to your Blocks, Items, Entities, and TileEntities. These are necessary for Minecraft to be able to save and load them properly.  (It is not automatically the same as the unlocalizedName member variable in each Item and Block.)
  • Registries for rendering objects - In order for your object to be drawn on the screen (Block, Item, Entity, TileEntity) you need to provide a renderer class for that object and register it.
  • Registries for crafting, smelting, spawning, villagers
  • Registries for World generation
  • Miscellaneous Registries - key binding, language, GUI screens, achievement pages


~Overview of Forge (and what it can do for you)
    Forge concepts
           Some general notes
           How Forge starts up your code (@Mod, @SidedProxy, etc) 
           Registering your classes
           Extra methods for vanilla base classes
           Events
     Forge summary - grouped by task
           Blocks
           Items
           TileEntities
           Entities
           World generation, loading, saving
           Miscellaneous - player input, rendering, GUI, chat, sounds

Forge concepts - Events

Forge provides a large number of events that you can subscribe to. When a particular part of the vanilla code is reached, it fires an �event� and calls any EventHandler code that you have subscribed to that particular event. An example is the PlayerSleepInBed event, which gets triggered whenever a player sleeps in a bed.
There are currently three main ways that you subscribe to events.
  1. The first is the Event Bus.  There are a lot of Event Bus events and it looks like this will be the preferred method for new events added in the future.
  2. The second is through the TickRegistry (for TickHandlers).
  3.  The third is through the @Mod and @NetworkMod annotations used at startup of your mod. 
In addition, there are a few miscellaneous others such as GameRegistry.registerPickupHandler and GameRegistry.registerPlayerTracker, EntityMinecart.registerCollisionHandler().

Event Bus

You subscribe your handler to the event bus using the following basic steps:
  1. Create a MyEventHandler class and register it using the .register method of the appropriate event bus � these are
    * MinecraftForge.EVENT_BUS (this is nearly always the one you need)
    * MinecraftForge.TERRAIN_GEN_BUS
    * MinecraftForge-ORE_GEN_BUS
  2.  Use @ForgeSubscribe to annotate each method in your MyEventHandler which handles an event, eg
@ForgeSubscribe
public void interceptMouseInput(MouseEvent event)

Whenever the event occurs, your method will be called, with relevant information passed in using the event variable.
Some events can be canceled, by setting event.setCanceled(true) before returning.  This is typically useful where you want to replace the vanilla behaviour with something different - for example if the LivingDropsEvent (called when a mob dies and drops treasure) is canceled, it skips the vanilla code to spawn dropped items.  Cancelable Events have the annotation @Cancelable immediately before the Event class declaration.
e.g.
@Cancelable
public class LivingDropsEvent extends LivingEvent


Some events have a "result" - "DEFAULT, ALLOW, DENY".  This is sometimes just used as an alternative to setCanceled, in other cases (eg LivingSpawnEvent) it is used to choose between "yes", "no", or "let vanilla decide".  @HasResult is used to annotate these events.

The events are all nicely organised into a package (minecraftforge/event) so it is worth a browse to see what flavours are available.

TickRegistry

The TickRegistry appears to be an older method of handler, it is used for frequent regular occurrences such as the game loop �tick� that is triggered 20 times per second.
The important steps are
  1. Create your class MyTickHandler implements ITickHandler
  2. Give it a ticks() method which returns a Set of the type of ticks that MyTickHandler is interested in.
  3. Override the tickStart() and/or tickEnd() method with the code that should be executed every time this event triggers.
  4. Register the MyTickHandler using TickRegistry.registerTickHandler.

Some general notes

  • ITickHandler is used when you want the handler to be called every single tick.
  • IScheduledHandler is useful if you only want the handler to be called occasionally, for example every 400 ticks. It is registered using registerScheduledTickHandler.
  • The various types of Tick that you have available are listed in TickType; the most useful are
    CLIENT � the client tick loop
    SERVER � the server tick loop
    PLAYER � whenever an EntityPlayer�s onUpdate is called
    WORLD � each time a WorldServer is ticked
    WORLDLOAD � on the server, when a world is loaded

 @Mod and @NetworkMod for code startup 

The @Mod annotation is used to control startup of your code. See here.
The @NetworkMod annotation is used to register your custom packet handlers (IPacketHandler).

Others

The miscellaneous other handlers are all registered by calling a method specific for that handler, for example
  • GameRegistry.registerPickupHandler � when player picks up an item, superceded by EntityItemPickupEvent.
  • GameRegistry.registerPlayerTracker for tracking players � login, logout, respawn, dimension change.
  • EntityMinecart.registerCollisionHandler for minecart collisions
  • GameRegistry.registerCraftingHandler (ICraftingHandler) for when an item is crafted or smelted.
  • NetworkRegistry.registerChatListener(using IChatListener) for intercepting chat messages including commands
  • NetworkRegistry.registerConnectionHandler(IConnectionHandler) which gives control over clients and players connecting to the server.


~Overview of Forge (and what it can do for you)
    Forge concepts
           Some general notes
           How Forge starts up your code (@Mod, @SidedProxy, etc) 
           Registering your classes
           Extra methods for vanilla base classes
           Events
     Forge summary - grouped by task
           Blocks
           Items
           TileEntities
           Entities
           World generation, loading, saving
           Miscellaneous - player input, rendering, GUI, chat, sounds

Forge concepts - some general notes

Forge is comprised of a couple of main components
  • FML � forge mod loader � which is mostly concerned with loading mods and initialising them, but also provides most of the Registries.
  • Minecraftforge � adds a large number of extra events and hooks
They were developed independently and are stored in different packages (cpw.mods.fml vs net.minecraftforge), but apart from that you�ll use them in the same way. The biggest symptom you might notice is that the paradigms are sometimes a bit inconsistent � naming conventions, hook methods, event handlers, commenting style � but nothing too hard to get used to.

Often it is difficult to know exactly which forge methods or hooks are going to be useful to create the behaviour you want.  A general strategy I have found effective is:
  1. Think of a part of the vanilla minecraft which does something similar to what you want to do.
  2. Open up that item, block, entity (or whatever) and browse through the vanilla code to see how it works.
  3. Look for ways to divert the program flow to your own code:
    * Methods that you can override in your own classes (especially for Blocks, Items, Entities)
    * A forge event or hook inserted into the vanilla code, which you can register for.
Sometimes, if there is no appropriate event or class method to override, it is possible to check for a condition using a tickhandler (called 20 times per second) and act on that � for example, checking if the player is holding a particular item in their hand and making sparks fly from their head if it is.



~Overview of Forge (and what it can do for you)
    Forge concepts
           Some general notes
           How Forge starts up your code (@Mod, @SidedProxy, etc) 
           Registering your classes
           Extra methods for vanilla base classes
           Events
     Forge summary - grouped by task
           Blocks
           Items
           TileEntities
           Entities
           World generation, loading, saving
           Miscellaneous - player input, rendering, GUI, chat, sounds

Forge concepts - extra methods for vanilla base classes

In a number of cases, Forge has added extra methods to the base classes, or sometimes moved methods from a core class (eg World) to a different class which can be extended and registered (eg WorldProvider). These forge methods are generally very easy to spot because
  • They are usually moved to the end of the class, placed after a comment like /*===========Forge Start ========*/
  • The JavaDoc documentation (before each class declaration) is usually much better than the rest of the vanilla code.

A number of the extra methods have been added as completely separate interfaces, for example IPlantable for plants and IShearable for entities which can be shorn.


Forge adds a few completely new classes and methods to make life easier-
  • Fluids:- A variety of classes to let you define your own fluids (like lava and water) and control their behaviour; comprised of BlockFluidBase, BlockFluidClassic, Fluid and FluidStack.
  • Models: A few classes related to rendering, not actually sure if they�re ever used since it seems people nearly always use Techne and that appears to use vanilla Models.
  • Ores: OreDictionary, ShapedOreRecipes, ShapelessOreRecipes - As far as I can tell, this lets you make recipes using ores provided by other mods, in particular BuildCraft.
  • RotationHelper: a couple of functions to help rotate vanilla blocks to face the desired direction (eg piston, doors, etc), convert from the block�s metadata to a standard �direction value�.
  • Configuration: class to help you create configuration files to store settings for your mod

Forge also adds a number of packets with base class ForgePackets or FMLPacket, they act �behind the scenes� and you�re unlikely to use them directly.



~Overview of Forge (and what it can do for you)
    Forge concepts
           Some general notes
           How Forge starts up your code (@Mod, @SidedProxy, etc) 
           Registering your classes
           Extra methods for vanilla base classes
           Events
     Forge summary - grouped by task
           Blocks
           Items
           TileEntities
           Entities
           World generation, loading, saving
           Miscellaneous - player input, rendering, GUI, chat, sounds

Kamis, 19 Desember 2013

Items

 Items are things that the player can carry, such as Pickaxe, Sword, Gemstone, Wood.  There are many types of Item, all derived from the Item base class. They are rendered in a number of different ways as described here

Like Blocks, there is generally only one instance of each Item class.  The Item class holds information that defines what that type of Item is (for example - what it looks like, how much damage it can take before breaking, how it interacts with blocks or entities, etc).

ItemStack is the class used when an Item is actually "created" - in addition to the Item type, it also stores the item count (eg a stack of 46 planks), "damage" (eg pickaxe "wear-and-tear" indicator), and several other pieces of information. ItemStacks are stored in "Slots" in the inventory, in the hotbar, in Containers (eg Chest, Furnace, etc).

Some general notes
  • In order to compare two different ItemStacks, you can't use the == operator (a common trap -see here for a discussion based around Strings).  Use areItemStacksEqual(itemStack1, itemStack2); instead.
  • Each Item defines a maximum stack size for the corresponding ItemStack, up to 64.  If this is >=2, the item is "Stackable", otherwise not.
  • If an Item can be damaged (maxDamage > 0) then it isDamageable, and the ItemStack.itemDamage is intepreted as the current damage (or "health") of the item.  Otherwise, ItemStack.itemDamage is interpreted as the type of item - for example ItemCloth (wool) which uses the itemDamage to specify the colour of the wool.  .hasSubTypes = true and .getMetadata are also required.
  • If an item is Stackable, it can't be Damageable.
  • An ItemStack can store custom information about the item, in the NBT stackTagCompound; see ItemStack.setTagInfo, .setTagCompound, .getTagCompound, etc.  Used by vanilla for enchantments.
  • An item which is in the world (eg sitting on the ground after the player has thrown it) is represented by the corresponding EntityItem, not an ItemStack. 
  • ItemBlocks are a special type of Item used to represent a Block when you have harvested it - for example Bedrock.  The vanilla code automatically generates an ItemBlock for each vanilla Block with an ID less than 256, giving it the same ID number, which unfortunately makes things complicated if you try to create your own ItemBlock.  For your own custom Blocks, when you register them with GameRegistry.registerBlock a matching ItemBlock will automatically be created - alternatively you can supply your own ItemBlock to GameRegistry.registerBlock to explicitly associate it with the target Block.


Sabtu, 23 November 2013

How Forge starts up your code

One of the things I found very confusing when first starting modding was the way that Forge starts up your code - @Mod, @SidedProxy, @EventHandler and the rest.  By following Havvy's tutorial I got it to work, but I didn't really understand what I was doing.  After working with Forge for a while I've finally figured it out....

Base Mod Class


When you start Minecraft, the Forge code prepares a couple of things and then starts searching for mods.  It looks through the java code in the mods folder until it finds a class which is preceded by the @Mod annotation.

If you have designed your mod properly, this will be your "Base Mod" class.

For example- your mod contains a file called TestFrameworkMod.java:
@Mod(modid="testframeworkmod", name="Forge Test Framework Mod", version="0.0.1")
public class TestFrameworkMod {

 //.. etc ...
}


Forge finds the @Mod, reads a couple of pieces of information about the mod (a unique "ID" name, the human-readable name, and the version), and now knows that the base class for your mod is TestFrameworkMod.

(NB all the code in this tutorial can be found here).

The general name for this technique is Reflection.
Reflection: the ability of a computer program to examine and modify the structure and behavior of an object at runtime.
Reflection allows inspection of classes, interfaces, fields and methods at runtime without knowing the names of the interfaces, fields, methods at compile time.
Forge uses this quite a bit to integrate with your mod code without knowing in advance what you've called your classes and how they're structured.

Now that Forge has found your Base Mod Class definition, it also needs to know where the instance of your class is.  To do this, it searches a bit further until it finds @Mod.Instance.

// The instance of your mod that Forge uses.
@Mod.Instance("testframeworkmod")
public static TestFrameworkMod instance;


It now knows that instance is the instance of your Base Mod Class, which it uses later on to communicate with your class.

For more technical details, see @Mod in the Forge code-
cpw/mods/fml/common/@Mod.

Proxies


In order to understand the next part, I first need to explain a couple of concepts about Server and Client.
Minecraft is designed from the ground up to be a multiplayer game.  For this reason, it is split into two parts - "server" and "client".
  • the "client" interacts with each user - reading their keyboard and mouse, and drawing things on your computer screen.  Every player will have their own "client".
  • the "server"  maintains the world and everything in it.  It talks to all of the clients to find out what each user is doing, updates the world accordingly, then sends the updated information back to all the clients.  There is only one server.   
Historically, Minecraft actually shipped with two completely separate programs -
  • Dedicated Client - contained all the "client-side" code
  • Dedicated Server - contained all the "server-side" code
But then they figured out that it was pretty user-unfriendly for you to have to run the DedicatedServer if you wanted to play LAN multiplayer with your buddies, so they added an "Integrated Server" into the Client (the "open to LAN" feature) and made what I like to call the "CombinedClient".  (For some reason everyone else just calls it the "Client", which is a bit confusing I think).

So the two different Minecraft programs are now:
  • CombinedClient (which has both client-side code and server-side code in it)
  • Dedicated Server (which has only server-side code).
The Forge authors wanted to make it easy to use the same Mod code in both the "Combined" Client and the Dedicated Server.  (This is not trivial because the Dedicated Server is missing the client-side code, and if your Mod attempts to call any of the client-side code when it's installed in the DedicatedServer, it will crash.)

They use the "SidedProxy" in order to do this. Forge hunts through your Base Mod until it finds @SidedProxy.  It then chooses the appropriate Class from the options you have provided, creates an instance of it, and puts it into the field immediately after the @SidedProxy annotation.
So in the example below:
  • If the mod is installed in a normal Minecraft client, the proxy variable will be set to your class CombinedClientProxy (which inherits from CommonProxy).
  • If the mod is installed in a dedicated server, the proxy variable will be set to your class DedicatedServerProxy (which also inherits from CommonProxy).
// the proxy reference will be set to either CombinedClientProxy or
//   DedicatedServerProxy depending on whether this mod is running in a
//   normal Minecraft client or a dedicated server.
@SidedProxy(clientSide="testframework.clientonly.CombinedClientProxy",
                       serverSide="testframework.serveronly.DedicatedServerProxy")
public static CommonProxy proxy;


Why is this useful?  Because you can now easily split your initialisation code into three parts:
  1. Code in the CombinedClientProxy, which only gets called on the normal Minecraft client.
  2. Code in the DedicatedServerProxy, which only gets called on a dedicated server.
  3. Code in the CommonProxy base class, which is called regardless of where the mod is installed.
Please note - this has NOTHING TO DO with the difference between client-side  and server-side.  That is something totally different.

An example of what the Proxy code might look like:

public class CommonProxy {
  public void doSomething() {
    // do something on both 
  } 
}

public class CombinedClientProxy extends CommonProxy {
  @Override
  public void doSomething() {
     super.doSomething();   // do something on both
     // do something on normal Minecraft only
  } 
}

public class DedicatedServerProxy extends CommonProxy {
  @Override
  public void doSomething() {
     super.doSomething();   // do something on both
     // do something on dedicated server only
  } 
}

EventHandlers

During startup, Forge will call your Mod several times to let you add new blocks, items, read configuration files, and otherwise integrate itself into the game by registering your Classes in the appropriate spots.

Before Forge can call your Mod, it needs to know which methods to use.  This is where @EventHandler comes in.  For example - during startup Forge will go through a number of phases for all of the mods which are loaded:
  • PreInitialization - "Run before anything else. Read your config, create blocks, items, etc, and register them with the GameRegistry."
  • Initialization - "Do your mod setup. Build whatever data structures you care about. Register recipes."
  • PostInitialization -  "Handle interaction with other mods, complete your setup based on this. 
PreInitialization is peformed for all the mods, followed by Initialization for all mods, followed by PostInitialization for all mods.  Initialising the mods in phases is particularly useful when there might be interactions between multiple mods - for example if one mod adds an extra type of wood (during PreInit), and your mod adds a recipe which uses that wood (during Init).

When Forge wants to tell your mod that it's time to run your PreInitialization code, it reads through your mod's code until it finds @EventHandler in front of a method, then checks the parameter definition to see if it matches the FMLPreInitializationEvent Class.  If so, it calls the method.

The PreInitialization, Initialization, and PostInitialization events will often need to do different things depending on whether your mod is in a CombinedClient or a DedicatedServer.  For this reason I suggest that your event handlers should just immediately call a method in the CommonProxy, see below.

@EventHandler
public void preInit(FMLPreInitializationEvent event) {
    proxy.preInit();
}

@EventHandler
public void load(FMLInitializationEvent event) {
    proxy.load();
}

@EventHandler
public void postInit(FMLPostInitializationEvent event) {
    proxy.postInit();
}


There are many other events in addition to these three (not that you're likely to need them unless you're doing some hardcore trickery).  See
cpw/mods/fml/common/event



~Overview of Forge (and what it can do for you)
    Forge concepts
           Some general notes
           How Forge starts up your code (@Mod, @SidedProxy, etc) 
           Registering your classes
           Extra methods for vanilla base classes
           Events
     Forge summary - grouped by task
           Blocks
           Items
           TileEntities
           Entities
           World generation, loading, saving
           Miscellaneous - player input, rendering, GUI, chat, sounds


Kamis, 24 Oktober 2013

Server-side Class Linkage Map

The diagram below shows the cross-references between the most important Server-side vanilla classes. For example:

EntityPlayerMP.playerNetServerHandler contains a NetServerHandler
Entity.worldObj refers to WorldServer
WorldServer.playerEntities contains a collection of EntityPlayers
 The map can be used to find a way to access the particular Class you need, starting with the Class(es) your code has been provided with.
NB - there are several ways of getting to EntityPlayerMP depending on which ones you want:
  1. To get all players on the server, use ServerConfigurationManager.playerEntityList()
  2. To get all players within range of a particular chunk, start from PlayerManager()
  3. For the player corresponding to a particular NetServerHandler, use .playerEntity
  4. For all players within range of a particular Entity, start from EntityTracker.
  5. For all players in a particular dimension, use worldServer.playerEntities, where you get worldServer using MinecraftServer.getServer().worldServerForDimension or DimensionManager.getWorld()
 MinecraftServer is designed as a Singleton (there is only ever one instance of the Class). It can be accessed by MinecraftServer.getServer().
Server-side Class Linkage Map for reference between the major vanilla Classes. Fields which are public are designated by solid arrows; private fields are in curly brackets and have dotted arrows. MinecraftServer is accessible using .getServer()
 

My Blog Copyright © 2012 Fast Loading -- Powered by Blogger