How do I map a texture onto an Entity in a Minecraft Plugin - minecraft

I'm trying to write a plugin to brand cattle and thought it would be pretty easy, but I'm stuck looking for the information that would help me do this.
Where can I find information that will help me map a texture (from a png, for example) onto an Entity. While there's information about built-in textures for Players etc, I haven't found a resource that would help me understand how I could get something to render on the side of an Entity.
I'm guessing that I'd use something like the following calls...
Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation("tc:textures/gui/my-icon.png"));
Minecraft.getMinecraft().ingameGUI.drawTexturedModalRect(etc);
Not certain how I'd enforce them into the drawing of a cow or a horse.

This isn't possible while using Bukkit, since Bukkit is server-side and can't change textures. There's one exception, though: Servers can send players resource packs. However, there does not appear to be a way to create a unique texture based off of any data, so you'd have to make all cows look the same. It wouldn't really do what you want. (Players are another exception, but protocol-wise, their skins are arbitrary anyways).
However, if you want to use Minecraft Forge, this is far more manageable. You can subclass the entity and change some of the rendering code. Perhaps you can also have an item of some sort (a branding iron, maybe) to convert existing cows into branded cows (they would still spawn as normal cows). I'm not too much of a Forge dev, but something like this should work (though I haven't tested it). This is more of an outline; things like converting the entity and creating an item I'll leave to you.
Here's a basic outline for an entitiy that tracks a texture between the server and the client:
import net.minecraft.entity.passive.EntityCow;
import net.minecraft.util.ResourceLocation;
public class EntityBrandedCow extends EntityCow {
#Override
protected void entityInit() {
super.entityInit();
// Data watcher lets you track data between the server and client
// without handling packets yourself
// http://wiki.vg/Entities
this.dataWatcher.addObject(14, "minecraft:textures/entity/cow/cow.png");
}
public void setTexture(ResourceLocation texture) {
this.dataWatcher.updateObject(14, texture.toString());
}
public ResourceLocation getTexture() {
return new ResourceLocation(this.dataWatcher.getWatchableObjectString(14));
}
}
You'll need to register a custom renderer for your new entity. This would go in the client proxy.
RenderingRegistry.registerEntityRenderingHandler(EntityBrandedCow.class, new RenderBrandedCow(Minecraft.getRenderManager(), new ModelCow(), .7f));
And here's such a render you can use:
import net.minecraft.util.ResourceLocation;
import net.minecraft.client.model.ModelBase;
import net.minecraft.entity.Entity;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.client.renderer.entity.RenderManager;
public class RenderBrandedCow extends RenderLiving {
public RenderBrandedCow(RenderManager manager, ModelBase model, float shadowSize) {
super(manager, model, shadowSize);
}
#Override
protected ResourceLocation getEntityTexture(Entity entity) {
return ((EntityBrandedCow)entity).getTexture();
}
}
That renderer only changes the texture, and doesn't actually overlay anything. This, among other things, means that texture packs won't change branded cows without creating additional textures. An alternative would be to create a second layer. (This is based off of the way sheep wool works - see net.minecraft.client.renderer.entity.layers.LayerSheepWool and net.minecraft.client.renderer.RenderSheep). You can change the renderer to this:
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.client.renderer.entity.RenderManager;
public class RenderBrandedCow extends RenderCow {
public RenderBrandedCow(RenderManager manager, ModelBase model, float shadowSize) {
super(manager, model, shadowSize);
this.addLayer(new LayerCowBrand(this));
}
}
And here's the start of some kind of layer rendering code. This won't work on its own; you'll need to write a ModelBrand (see ModelSheep1 for the basis of that).
public class LayerCowBrand implements LayerRenderer {
private final BrandedCowRenderer renderer;
private final ModelBrand model = new ModelBrand();
public LayerCowBrand(BrandedCowRenderer renderer) {
this.renderer = renderer;
}
public void doRenderLayer(EntityBrandedCow entity, float p_177162_2_, float p_177162_3_, float p_177162_4_, float p_177162_5_, float p_177162_6_, float p_177162_7_, float p_177162_8_) {
// It's common to write a second method with the right parameters...
// I don't know off my hand what the parameters here are.
this.renderer.bindTexture(entity.getTexture());
this.model.setModelAttributes(this.sheepRenderer.getMainModel());
this.model.setLivingAnimations(p_177162_1_, p_177162_2_, p_177162_3_, p_177162_4_);
this.model.render(p_177162_1_, p_177162_2_, p_177162_3_, p_177162_5_, p_177162_6_, p_177162_7_, p_177162_8_);
}
public boolean shouldCombineTextures() {
// I don't know
return true;
}
public void doRenderLayer(EntityLivingBase p_177141_1_, float p_177141_2_, float p_177141_3_, float p_177141_4_, float p_177141_5_, float p_177141_6_, float p_177141_7_, float p_177141_8_) {
// This is the actual render method that implements the interface.
this.doRenderLayer((EntityBrandedCow)p_177141_1_, p_177141_2_, p_177141_3_, p_177141_4_, p_177141_5_, p_177141_6_, p_177141_7_, p_177141_8_);
}
}
Hopefully this at least lets you get started. As I said, I'm not a forge dev, but this should be the basics. If you want to ask more questions about forge, post here on Stack Overflow using minecraft-forge (Gaming Stack Exchange also has a minecraft-forge tag but that's for mod usage, not development).

Related

Minecraft Forge - Place block onItemUse

I'm trying to make my custom item place water when used:
public class Beaker extends Item implements IHasModel {
public Beaker(String name, CreativeTabs tab, int maxStackSize) {
setUnlocalizedName(name);
setRegistryName(name);
setCreativeTab(tab);
setMaxStackSize(maxStackSize);
ItemInit.ITEMS.add(this);
}
#Override
public void registerModels() {
Main.proxy.registerItemRenderer(this, 0, "inventory");
}
#Override
public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
BlockPos clickedBlock = new BlockPos(hitX, hitY, hitZ);
worldIn.setBlockState(clickedBlock, Blocks.WATER.getDefaultState());
return EnumActionResult.SUCCESS;
}
}
However, when I right click, the item gets used (animation plays) but the water is not placed, I'm using Minecraft 1.12.2 and Forge 14.23.2.2613.
hitX hitY and hitZ have no relation to the world location where the action was performed. They are partial values within the clicked block for performing actions based on where the block was clicked (e.g. which button on a number pad).
If we look at ItemBlockSpecial (which handles items like Cake, Repeaters, Brewing Stands, and Cauldrons) we find this code:
public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ)
{
IBlockState iblockstate = worldIn.getBlockState(pos);
Block block = iblockstate.getBlock();
// snow layer stuff we don't care about
if (!block.isReplaceable(worldIn, pos))
{
pos = pos.offset(facing);
}
// placement code
}
The important thing to note here is that the pos parameter is used directly, while being modified by the facing parameter in the event that the block clicked is not replaceable (e.g. Tall Grass is replaceable, Stone is not).
If ItemBlockSpecial isn't sufficient for you (i.e. you can't make your item an instance of ItemBlockSpecial), then the code it uses to do things probably still will be.

Actionscript, can a class be accessed using a variable name?

I wish to access many classes and variables, I would like to do this by dynamically setting the class name and variable name. Currently I am using
MyClass["myVariable1"]
to dynamically access the variable name
MyClass.myVariable1
I want to also dynanmically acces the class name, something like
["MyClass"]["myVariable1"]
But this does not work.
The purpose is that I have shared object with many user settings, I want to iterate through the shared object and set all the user settings across all the classes. I think if I cant dynamically access the class I must have a statement for each and every class name/variable.
I advise against such a practice. Although technically possible, it is like welcoming a disaster into the app architecture:
You rely on something you have no apparent control of: on the way Flash names the classes.
You walk out of future possibility to protect your code with identifier renaming obfuscation because it will render your code invalid.
Compile time error checks is better than runtime, and you are leaving it to runtime. If it happens to fail in non-debug environment, you will never know.
The next developer to work with your code (might be you in a couple of years) will have hard time finding where the initial data coming from.
So, having all of above, I encourage you to switch to another model:
package
{
import flash.net.SharedObject;
public class SharedData
{
static private var SO:SharedObject;
static public function init():void
{
SO = SharedObject.getLocal("my_precious_shared_data", "/");
}
static public function read(key:String):*
{
// if (!SO) init();
return SO.data[key];
}
static public function write(key:String, value:*):void
{
// if (!SO) init();
SO.data[key] = value;
SO.flush();
}
// Returns stored data if any, or default value otherwise.
// A good practice of default application values that might
// change upon user activity, e.g. sound volume or level progress.
static public function readSafe(key:String, defaultValue:*):*
{
// if (!SO) init();
return SO.data.hasOwnProperty(key)? read(key): defaultValue;
}
}
}
In the main class you call
SharedData.init();
// So now your shared data are available.
// If you are not sure you can call it before other classes will read
// the shared data, just uncomment // if (!SO) init(); lines in SharedData methods.
Then each class that feeds on these data should have an initialization block:
// It's a good idea to keep keys as constants
// so you won't occasionally mistype them.
// Compile time > runtime again.
static private const SOMAXMANA:String = "maxmana";
static private const SOMAXHP:String = "maxhp";
private var firstTime:Boolean = true;
private var maxmana:int;
private var maxhp:int;
// ...
if (firstTime)
{
// Make sure it does not read them second time.
firstTime = false;
maxhp = SharedData.readSafe(SOMAXHP, 100);
maxmana = SharedData.readSafe(SOMAXMANA, 50);
}
Well, again. The code above:
does not employ weird practices and easy to understand
in each class anyone can clearly see where the data come from
will be checked for errors at compile time
can be obfuscated and protected
You can try getting the class into a variable and going from there:
var myClass:Class = getDefinitionByName("MyClass") as Class;
myClass["myVariable1"] = x;

Render glitch with custom block boundaries minecraft

I'm creating a mod for Minecraft. Recently, I've tried to make a custom block, and I'm having two issues with it.
My main issue is that the block is rendering incorrectly. I want the block to be smaller in size than a full block. I successfully changed the block boundaries with setBlockBounds(), and while that did make the block render smaller and use the smaller boundaries, it causes other rendering issues. When I place the block, the floor below is becomes invisible and I can see through it, either to caves below, blocks behind it, or the void if there is nothing there. How do I fix that block not rendering? Here's a screenshot:
Additionally, my goal for this block is to emit an "aura" that gives players around it speed or some other potion effect. I have the basic code for finding players around the block and giving them speed, but I can't find a way to activate this method every tick or every X amount of ticks to ensure that it gives players within the box speed in a reliable manner. There are already some blocks in the normal game that do this, so it must be possible. How can I do this?
For your first issue, you need to override isOpaqueCube to return false. You'll also want to override isFullCube for other parts of the code, but that isn't as important for rendering. Example:
public class YourBlock {
// ... existing code ...
/**
* Used to determine ambient occlusion and culling when rebuilding chunks for render
*/
#Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
#Override
public boolean isFullCube(IBlockState state) {
return false;
}
}
Here's some info on rendering that mentions this.
Regarding your second problem, that's more complicated. It's generally achieved via a tile entity, though you can also use block updates (which is much slower). Good examples of this are BlockBeacon and TileEntityBeacon (for using tile entities) and BlockFrostedIce (for block updates). Here's some (potentially out of date) info on tile entities.
Here's an (untested) example of getting an update each tick this with tile entities:
public class YourBlock {
// ... existing code ...
/**
* Returns a new instance of a block's tile entity class. Called on placing the block.
*/
#Override
public TileEntity createNewTileEntity(World worldIn, int meta) {
return new TileEntityYourBlock();
}
}
/**
* Tile entity for your block.
*
* Tile entities normally store data, but they can also receive an update each
* tick, but to do so they must implement ITickable. So, don't forget the
* "implements ITickable".
*/
public class TileEntityYourBlock extends TileEntity implements ITickable {
#Override
public void update() {
// Your code to give potion effects to nearby players would go here
// If you only want to do it every so often, you can check like this:
if (this.worldObj.getTotalWorldTime() % 80 == 0) {
// Only runs every 80 ticks (4 seconds)
}
}
// The following code isn't required to make a tile entity that gets ticked,
// but you'll want it if you want (EG) to be able to set the effect.
/**
* Example potion effect.
* May be null.
*/
private Potion effect;
public void setEffect(Potion potionEffect) {
this.effect = potionEffect;
}
public Potion getEffect() {
return this.effect;
}
#Override
public void readFromNBT(NBTTagCompound compound) {
super.readFromNBT(compound);
int effectID = compound.getInteger("Effect")
this.effect = Potion.getPotionById(effectID);
}
public void writeToNBT(NBTTagCompound compound) {
super.writeToNBT(compound);
int effectID = Potion.getIdFromPotion(this.effect);
compound.setInteger("Effect", effectID);
}
}
// This line needs to go in the main registration.
// The ID can be anything so long as it isn't used by another mod.
GameRegistry.registerTileEntity(TileEntityYourBlock.class, "YourBlock");

MultiScaleImageSource GetTileLayers Explanation

I have been doing reading on MultiScaleImage source, and finding anything useful has proven to be quite difficult, thus I turn to the experts here. The specific knowledge I would like to have pertains to the GetTileLayers method. I know this method is used to get the image tiles. But I have no idea where this method is called from, or where the parameters come from or how I would use it if I subclassed the MultiScaleTileSource Class. Any insight into this method or the MSI model would be amazing but I have 3 main questions:
1. Where should/is the method GetTileLayers called from?
2. How should I change this method if I wanted to draw png's from a non-local URI?
3. Where can I find some reading to help with this?
In order to create a custom tile source, you would subclass MultiScaleTileSource and override the GetTileLayers method, as shown in the example below, which defines an image consisting of 1000*1000 tiles of size 256x256 pixels each.
public class MyTileSource : MultiScaleTileSource
{
public MyTileSource()
: base(1000 * 256, 1000 * 256, 256, 256, 0)
{
}
protected override void GetTileLayers(
int tileLevel, int tilePositionX, int tilePositionY,
IList<object> tileImageLayerSources)
{
// create an appropriate URI for tileLevel, tilePositionX and tilePositionY
// and add it to the tileImageLayerSources collection
var uri = new Uri(...);
tileImageLayerSources.Add(uri);
}
}
Now you would assign an instance of your MyTileSource class to your MultiScaleImage control:
MultiScaleImage msImage = ...
msImage.Source = new MyTileSource();

AspectJ - Doubt

An aspect can be used to measure the performance of method invocations,
as illustrated in the example below:
public aspect MonitorRequests {
void around() : monitoredRequestO {
PerfStats stats = getPerfStats(thisDoinPointStaticPart);
long start = System-currentTimeMillisO;
proceedO;
stats.ecunter++;
stats.time += System.currentTimeMillisC)-start;
}
pointcut monitoredRequestO :
execution(void HttpServ1et.do*(..)) && if(enabled);
// can expose stats via JMX, dump method, getstats etc.
public static class PerfStats { _. }
private Map<StaticPart,PerfStats> perfStatMap • //...
private boolean enabled;
}
By default, an aspect instance is associated with the Java Virtual Machine, rather with
specific execution flows, similar to a static class.
Another aspect below uses percflow() to associate an aspect instance differently from
the default:
public aspect MonitorDatabaseRequests
percflow(monitoredRequest() && !cflowbelow(mon-5toredRequest()) {
void around() : monitoredRequestO {
PerfStats stats = getPerfStats(thisJoinPointStaticPart);
long time.= System.currentTimeMi 11 i s O ;
proceed();
stats.counter++;
stats.databaseTime += accumulatedoatabaseTime;
stats.time 4= System.currentTimeMi 11 isO-time;
}
}
What is the difference that adding the percflow() declaration makes in this example
I'm confused how percflow works and how this is different from not using it....
percflow is the aspect instantiation model. See here:
http://eclipse.org/aspectj/doc/released/progguide/quick-aspectAssociations.html
This means that one instance of this aspect is created for every cflow entered.
The first aspect is a singleton and so it must store a map for all of the performance stats it keeps track of. The second aspect is instantiated as needed, so performance stats are implicitly stored and associated with the proper dynamic call graph.