Minecraft Forge - Place block onItemUse - minecraft

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.

Related

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");

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

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).

nullPointerException error greenfoot

I'm working on a project for an intro to programming class, and I've run into a slight problem. We're making a side scroller, and I'm working on the score counter right now. My issue is that when I try to create a reference to the counter class in anything other than the act method(called once every frame) I get a null pointer exception error. You can download the zip file with my code in it here if you want to take a look.
EDIT:
Here's the offending code:
public class HeroMissile extends Missiles
{
/**
* Act - do whatever the HeroMissile wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
public void act()
{
move(8);
remove();
}
public void remove() {
if(isTouching(Drone.class)) {
removeTouching(Drone.class);
getWorld().addObject(new Explosion(), getX(), getY());
getWorld().removeObject(this);
addScore();
return;
}
}
public void addScore() {
City cityWorld = (City) getWorld();
**Counter scoreCounter = cityWorld.getCounter();**
scoreCounter.add(1);
}
}
You are calling getWorld() [in addScore()] after you removed yourself from the world. In this case, getWorld() will return null, so you will get a null pointer exception. Try changing the order in remove() to add the score before you remove yourself from the world.

Flow of initializing objects in XAML?

I'm not sure but from my hours of debugging, this should be the best description of my problem I can give.
I'm creating a WinRT app, there are two pages- Main Page and Details Page. Inside Main Page constructor, I have initialized a listbox. On click of any of the element of listbox, user is taken to the Details page.
I'm just learning all this and design may not be best but here is what I did.
I took a static variable in MainPage.cs, and set it to point to the element which is clicked by the user. Now in the constructor of the Details page, I used this static variable to set the datacontext of Details Page itself.
What flow I'm expecting is:-
MainPage is created first. Listbox is setup.
User will click on any of the element of listbox. Itemclick event handler runs. It will set the static variable (of Mainpage.cs) to hold the infomation which item is clicked and navigate user to the Details page.
In Details page constructor, I have set the datacontext to point to some information based on the value of static variable mentioned in the previous step.
It works for most of the times, but once in like every 5 times, The Details page constructor throws an exception stating the static variable is not initialized yet. Why is Details page's constructor running when I'm starting the app? and why only sometimes? Do I need to set DataContext of Details Page in some other method instead of constructor?
The code is somewhat complex and too much in terms of domain of the problem so I'm avoiding posting it. But if I'm failing to explain the problem please tell, I'll post it keeping it as related as I can.
CODE:-
This is the method called when an item in listbox is clicked--will take user to the Details page.
private void overviewlistbox_Tapped_1(object sender, TappedRoutedEventArgs e)
{
MatchOverview selectedmatch = (sender as ListBox).SelectedItem as MatchOverview;
matchFullDetails = new ObservableCollection<Match>();
foreach (Match m in UpdateController.matchList)
{
if (m.matchDescription == selectedmatch.matchDesc)
{
matchFullDetails.Add(m);
break;
}
}
if(!(matchFullDetails.Count == 0))
this.Frame.Navigate(typeof(Details));
}
This is the constructor for Main Page:-
public static ObservableCollection<Match> matchFullDetails;
public MainPage()
{
matchFullDetails = new ObservableCollection<Match>();
this.InitializeComponent();
UpdateController update = new UpdateController(); // Creating new object will update the overview_list of UpdateController(static list).
overviewlistbox.ItemsSource = UpdateController.overview_list;
}
And this is the code for constructor of details page, where the exception occurs:-
public static ObservableCollection<Match> matchdetails = new ObservableCollection<Match>();
DispatcherTimer dtm_detailspage = null;
public Details()
{
this.InitializeComponent();
matchdetails = MainPage.matchFullDetails; // matchdetails.Last<>() is take because we only need item which is added latest to the collection.
if (matchdetails.Last<Match>().type == "TEST") // Exception is thrown here--Initialization
// error. When I check MainPage.matchFullDetails,
// no data is shown which means its not yet
// initialized. Also the exception is thrown either at
// the start of the app, or when details page is visited. That too once in 4-5 times, not always.
{
matchdetails.Add(matchdetails.First<Match>() as TestMatch);
}
if (matchdetails.Last<Match>().type == "ODI")
{
matchdetails.Add(matchdetails.Last<Match>() as ODIMatch);
}
if (matchdetails.Last<Match>().type == "T20")
{
matchdetails.Add(matchdetails.Last<Match>() as T20Match);
}
}
Exception Screenshot:-
Call Stack data on bug encounter:-
[Cricket Expert.exe!Cricket_Expert.Details.Details() Line 33 + 0x5 bytes
[External Code]
Cricket Expert.exe!Cricket_Expert.Common.SuspensionManager.RestoreFrameNavigationState(Windows.UI.Xaml.Controls.Frame frame) Line 236 + 0x5 bytes
Cricket Expert.exe!Cricket_Expert.Common.SuspensionManager.RestoreAsyn() Line 124 0x8 bytes
Cricket Expert.exe!Cricket_Expert.App.OnLaunched(Windows.ApplicationModel.Activation.LaunchActivatedEventArgs args) Line 74 + 0x5 bytes
[External Code]
MAJOR UPDATE:
I finally found the flaw. If the Details page is still active, and the app is restarted, the problem occurs.
Is there a solution to this problem??
You can pass information on what needs to be displayed on the Details page through the Navigate call and set the DataContext in OnNavigatedTo override to avoid using static variables. Pages don't get created unless you do it specifically e.g. by navigating to one. They might not be recreated if a page has NavigationCacheMode changed from the default (Disabled) so instances of the page can be reused during navigation calls. Ultimately it's hard to say what's wrong but it seems like something in your code and we couldn't help you if you don't share a sample that reproduces the problem.
*EDIT
One way to debug Details being created before MainPage would be to add this code at the beginning of the Details constructor:
if (MainPage.matchFullDetails == null)
{
System.Diagnostics.Debugger.Break();
}
Then look at the Call Stack panel in Visual Studio to see how it gets constructed.
One way to see if matchFullDetails is ever set to null is to search for its assignment (put a cursor on matchFullDetails in Visual Studio code editor and hit Shift+F12).
Another way would be to make matchFullDetails into a property and test it like this:
private static ObservableCollection<Match> _matchFullDetails;
public static ObservableCollection<Match> matchFullDetails
{
get
{
return _matchFullDetails;
}
set
{
if (value == null)
{
System.Diagnostics.Debugger.Break();
}
_matchFullDetails = value;
}
}
*EDIT 2
You can initialize your static property in a static constructor like this:
public static ObservableCollection<Match> matchFullDetails;
static MainPage()
{
matchFullDetails = new ObservableCollection<Match>();
}
public MainPage()
{
this.InitializeComponent();
UpdateController update = new UpdateController(); // Creating new object will update the overview_list of UpdateController(static list).
overviewlistbox.ItemsSource = UpdateController.overview_list;
}
this will prevent the null reference exception but won't fix your problem overall. When your app gets suspended and resumed - you have to restore the full state and it seems like your matchFullDetails collection would need to be serialized and saved to disk when your app gets suspended. Alternatively you might simply ignore the suspension manager call in App.xaml.cs and always start on home page, though that's not a very good experience and I am not sure if it satisfies app certification.

Controller selection

In my title screen, i have a code saying that the first controller using A is the PlayerIndex.one.
Here is the code:
public override void HandleInput(InputState input)
{
for (int anyPlayer = 0; anyPlayer <4; anyPlayer++)
{
if (GamePad.GetState((PlayerIndex)anyPlayer).Buttons.A == ButtonState.Pressed)
{
FirstPlayer = (PlayerIndex)anyPlayer;
this.ExitScreen();
AddScreen(new Background());
}
}
}
My question is: How can i use the "FirstPlayer" in other classes? (without this, there is no interest in this code)
I tried the Get Set thing but i can't make it work. Does i need to put my code in another class? Do you use other code to make this?
Thanks.
You can make a static variable say : SelectedPlayer,
and assign first player to it!
then you can call the first player through this class,
for example
class GameManager
{
public static PlayerIndex SelectedPlayer{get;set;}
..
..
..
}
and right after the loop in your code, you can say:
GameManager.SelectedPlayer = FirstPlayer;
I hope this helps, if your code cold be clearer that would be easier to help :)
Ok, so to do this properly you're going to have to redesign a little.
First off, you should be checking for a new gamepad input (i.e. you should be exiting the screen only when 'A' has been newly pressed). To do this you should be storing previous and current gamepad states:
private GamePadState currentGamePadState;
private GamePadState lastGamePadState;
// in your constructor
currentGamePadState = new GamePadState();
lastGamePadState = new GamePadState();
// in your update
lastGamePadState = currentGamePadState;
currentGamePadState = GamePad.GetState(PlayerIndex.One);
Really what you need to do is modify your class that deals with input. The basic functionality from your HandleInput function should be moved into your input class. Input should have a collection of functions that test for new/current input. For example, for the case you posted:
public Bool IsNewButtonPress(Buttons buton)
{
return (currentGamePadState.IsButtonDown(button) && lastGamePadState.IsButtonUp(button));
}
Then you can write:
public override void HandleInput(InputState input)
{
if (input.IsNewButtonPress(Buttons.A)
{
this.ExitScreen();
AddScreen(new Background());
}
}
Note: this will only work for one controller. To extend the implementation, you'll need to do something like this:
private GamePadState[] currentGamePadStates;
private GamePadState[] lastGamePadStates;
// in your constructor
currentGamePadStates = new GamePadState[4];
currentGamePadStates[0] = new GamePadState(PlayerIndex.One);
currentGamePadStates[1] = new GamePadController(PlayerIndex.Two);
// etc.
lastGamePadStates[0] = new GamePadState(PlayerIndex.One);
// etc.
// in your update
foreach (GamePadState s in currentGamePadStates)
{
// update all of this as before...
}
// etc.
Now, you want to test every controller for input, so you'll need to generalise by writing a function that returns a Bool after checking each GamePadState in the arrays for a button press.
Check out the MSDN Game State Management Sample for a well developed implementation. I can't remember if it supports multiple controllers, but the structure is clear and can easily be adapted if not.