Problem with adding Blocks to Minecraft Mod (1.15.2) - minecraft-forge

I have spent the last few hours adding a block to my Minecraft Mod. I have looked at several tutorials and none of them work. The blocks are not added to the Creative Inventory and I can't set them by command either. Unfortunately I didn't have any bugs in the console that I could show here. At some point I gave up and tried to do armor, here the same problem. On the other hand: normal items work (You can see the Item "ruby" which woked finde).
Here the code of my main class:
package de.thom.clashOfClasses;
import de.thom.clashOfClasses.init.ArmorMaterialList;
import de.thom.clashOfClasses.init.BlockList;
import de.thom.clashOfClasses.init.ItemList;
import net.minecraft.block.Block;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
#Mod("clashofclasses")
public class ClashOfClasses {
public static ClashOfClasses instance;
public static final String modid = "clashofclasses";
public static final Logger logger = LogManager.getLogger(modid);
public ClashOfClasses() {
instance = this;
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::clientRegistries);
MinecraftForge.EVENT_BUS.register(this);
}
public void setup(final FMLCommonSetupEvent event) {
logger.info("Setup method complete");
}
public void clientRegistries(final FMLClientSetupEvent event) {
logger.info("ClientRegistries method complete");
}
#Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public static class RegistryEvents {
#SubscribeEvent
public static void registerItems(final RegistryEvent.Register<Item> event) {
logger.info("Item Registry started");
event.getRegistry().registerAll(
ItemList.RUBY,
ItemList.ruby_block = new BlockItem(BlockList.ruby_block,new Item.Properties().group(ItemGroup.MISC)).setRegistryName(BlockList.ruby_block.getRegistryName())
);
logger.info("Items registerd");
}
#SubscribeEvent
public static void registerBlocks(final RegistryEvent.Register<Block> event) {
logger.info("Block Registry started");
event.getRegistry().registerAll
(
BlockList.ruby_block = new Block(Block.Properties.create(Material.IRON).hardnessAndResistance(2.0f,3.0f).lightValue(5).sound(SoundType.METAL)).setRegistryName(location("ruby_block"))
);
logger.info("Blocks registerd");
}
private static ResourceLocation location(String name){
return new ResourceLocation(ClashOfClasses.modid, name);
}
}
}
Here is the code of BlockList
package de.thom.clashOfClasses.init;
import net.minecraft.block.Block;
public class BlockList {
public static Block ruby_block;
}
Here is the code of ItemList:
package de.thom.clashOfClasses.init;
import de.thom.clashOfClasses.ClashOfClasses;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.util.ResourceLocation;
public class ItemList
{
//Test Items
public static Item RUBY = new Item(new Item.Properties().group(ItemGroup.MATERIALS)).setRegistryName(location("ruby"));
public static Item ruby_block;
private static ResourceLocation location(String name){
return new ResourceLocation(ClashOfClasses.modid, name);
}
}

A block in the world and a “block” in an inventory are very different things. A block in the world is represented by an IBlockState, and its behavior defined by an instance of Block. Meanwhile, an item in an inventory is an ItemStack, controlled by an Item. As a bridge between the different worlds of Block and Item, there exists the class ItemBlock. ItemBlock is a subclass of Item that has a field block that holds a reference to the Block it represents. ItemBlock defines some of the behavior of a “block” as an item, like how a right click places the block. It’s possible to have a Block without an ItemBlock. (E.g. minecraft:water exists a block, but not an item. It is therefore impossible to hold it in an inventory as one.)
When a block is registered, only a block is registered. The block does not automatically have an ItemBlock. To create a basic ItemBlock for a block, one should use new ItemBlock(block).setRegistryName(block.getRegistryName()). The unlocalized name is the same as the block’s. Custom subclasses of ItemBlock may be used as well. Once an ItemBlock has been registered for a block, Item.getItemFromBlock can be used to retrieve it. Item.getItemFromBlock will return null if there is no ItemBlock for the Block, so if you are not certain that there is an ItemBlock for the Block you are using, check for null.
from https://mcforge.readthedocs.io/en/latest/blocks/blocks/.
I short, if everything works, your blocks shoudnt appear in your

#ObjectHolder(modid)
#Mod.EventBusSunscriber(modid = modid, bus = Bus.Mod)
public class BlockInit {
public static final Block example_block = null;
#SubscribeEvent
public static void registerBlocks(final RegistryEvent.Register<Block> event) {
event.getRegistry().register(new Block(Block.Properties.create(Material)).setRegistry("example_block"));
}
#SubscribeEvent
public static void registerBlockItems(final RegistryEvent.Register<Item> event){
event.getRegistry().register(new BlockItem(example_item, new Item.Properties().group(ItemGroup)).setRegistry("example_block"));
}
That works for me just replace example_block with the name of your block and add more properties if you want
for another block just repeat the event.getRegistry stuff and use the name of your new block instead of example_block.
and don't forget to do the json files

Related

HERE SDK TrafficUpdater.request(Geocordinate, TrafficUpdater.Listener) not returning traffic results

I have been working on integrating several HERE features into an app I am working on. Right now I am trying to add traffic data to the application. The default auto-updates aren't quite frequent enough for me (~1 min), so I am trying to use the TrafficUpdater.request(GeoCoordinate, TrafficUpdater.Listener) to manually retrieve traffic information every 5 seconds or so. The problem is, although the request line executes, the listener is never called, and I never receive any traffic updates. Below is my activity:
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.here.android.mpa.common.GeoCoordinate;
import com.here.android.mpa.common.GeoPosition;
import com.here.android.mpa.common.MapSettings;
import com.here.android.mpa.common.OnEngineInitListener;
import com.here.android.mpa.common.PositioningManager;
import com.here.android.mpa.guidance.TrafficUpdater;
import com.here.android.mpa.mapping.Map;
import com.here.android.mpa.mapping.MapFragment;
import com.here.android.mpa.mapping.MapTrafficLayer;
import com.here.android.mpa.mapping.MapView;
import com.here.android.mpa.mapping.TrafficEvent;
import java.io.File;
import java.lang.ref.WeakReference;
public class MainActivity extends AppCompatActivity {
private Map map;
private MapFragment mapFragment;
private TrafficUpdater trafficUpdater;
private PositioningManager.OnPositionChangedListener onPositionChangedListener = new PositioningManager.OnPositionChangedListener() {
#Override
public void onPositionUpdated(PositioningManager.LocationMethod locationMethod, GeoPosition geoPosition, boolean b) {
onLocationUpdate(geoPosition);
}
#Override
public void onPositionFixChanged(PositioningManager.LocationMethod locationMethod, PositioningManager.LocationStatus locationStatus) {
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MapSettings.setIsolatedDiskCacheRootPath(
getApplicationContext().getExternalFilesDir(null) + File.separator + ".here-maps",
"MAP_SERVICE");
mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.init(new OnEngineInitListener() {
#Override
public void onEngineInitializationCompleted(Error error) {
if (error == Error.NONE) {
map = mapFragment.getMap();
initTracker();
}
}
});
}
private void initTracker() {
trafficUpdater = TrafficUpdater.getInstance();
trafficUpdater.enableUpdate(false);
PositioningManager positioningManager = PositioningManager.getInstance();
positioningManager.addListener(new WeakReference<PositioningManager.OnPositionChangedListener>(onPositionChangedListener));
mapFragment.getPositionIndicator().setVisible(true);
positioningManager.start(PositioningManager.LocationMethod.GPS_NETWORK);
}
private boolean isTimerRunning = false;
CountDownTimer trafficTimer = new CountDownTimer(5000,5000) {
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
isTimerRunning = false;
getTrafficInfo();
}
};
private GeoPosition lastGeoPosition;
private void onLocationUpdate(GeoPosition geoPosition) {
map.setCenter(geoPosition.getCoordinate(), Map.Animation.NONE);
Log.i("____MAINACTIVITY", "location update");
lastGeoPosition = geoPosition;
if(!isTimerRunning) {
trafficTimer.cancel();
trafficTimer.start();
isTimerRunning = true;
}
}
private TrafficUpdater.Listener trafficListener = new TrafficUpdater.Listener() {
#Override
public void onStatusChanged(TrafficUpdater.RequestState requestState) {
Log.i("____MAINACTIVITY", requestState.name());
}
};
private void getTrafficInfo() {
if(lastGeoPosition != null) {
TrafficUpdater.RequestInfo requestInfo = trafficUpdater.request(lastGeoPosition.getCoordinate(), trafficListener);
Log.i("___MAINACTIVITY", requestInfo.getError().name());
}
}
}
I have tried several things to remedy this issue. First, I have checked all of my app permissions and project dashboard on the developer portal to ensure everything is setup properly, and it is. I was providing the listener as an anonymous method in the line we execute the request, and that did not work. I moved the listener to be a private member variable of the activity, and provided it that way, but it still isn't working. I've checked the RequestInfo returned by the method, and it always indicates an error code of NONE, so it seems as though no errors are occurring. Lastly, I set my updater frequency to once every 1.5 seconds (well above the default value), and I still receive nothing. Does anyone know a solution to this problem? I feel as though it's something simple that I'm missing. Updates from the Positioning Manager are coming through just fine, and the app is talking to our server with no problems, so I don't think it's a connectivity issue.
The traffic feed does provide updates only in a one minute time frame. To force the application to request this in a higher frequency won't provide fresher data. I would recommend to keep the default auto-updates.

Jsoup to parse multiple websites for links published today

I am currently using jsoup (below) to output a .csv of links which include a string date format in the url from just one website.
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import java.io.FileOutputStream;
import java.io.PrintStream;
import org.jsoup.nodes.Element;
public class readAllLinks {
public static Set<String> uniqueURL = new HashSet<String>();
public static String my_site;
public static String published = ("20180731");
public static void main(String[] args) {
readAllLinks obj = new readAllLinks();
my_site = ("news24.com/SouthAfrica/News");
obj.get_links("https://www.news24.com/SouthAfrica/News/");
}
private void get_links(String url) {
try {
Document doc = Jsoup.connect(url).get();
Elements links = doc.select("a");
FileOutputStream fout=new FileOutputStream("links.csv");
PrintStream csv=new PrintStream(fout);
links.stream().map((link) -> link.attr("abs:href")).forEachOrdered((this_url) -> {
boolean add = uniqueURL.add(this_url);
if (add && this_url.contains(my_site) && this_url.contains(published)) {
System.out.println(this_url);
get_links(this_url);
}
if (this_url.contains(published))
csv.println(this_url);
} );
} catch (IOException ex) {
}
}
}
Instead I would like to make a csv of links published today (i.e using today's date) from multiple websites.
How do you specify the .select for the newly published links to get the date contained in a span?
And how do you parse multiple websites from a list?
Many thanks for your help.
This will select all links that contains value of variable 'published'.
Elements links = doc.select("a[href*="+published+"]");

What's a good observable appendable base for a TextArea?

I have a StringBuffer that is occasionally appended with new information.
In a separate module, I have a JavaFX TextArea that displays that StringBuffer.
Right now, I have to manually update the TextArea every time the underlying data is modified.
Is there something like an ObservableList (which I use for TableViews) that I can use as the back-end data for the TextArea instead, so I don't have to manually manage pushing the changes to the display?
I am not attached to using a StringBuffer. I'm glad to use any appendable data structure to hold text.
You can consider something simple like this:
import javafx.beans.binding.StringBinding;
public class ObservableStringBuffer extends StringBinding {
private final StringBuffer buffer = new StringBuffer() ;
#Override
protected String computeValue() {
return buffer.toString();
}
public void set(String content) {
buffer.replace(0, buffer.length(), content);
invalidate();
}
public void append(String text) {
buffer.append(text);
invalidate();
}
// wrap other StringBuffer methods as needed...
}
This enables easy coding for binding to a text area. You can simply do
TextArea textArea = new TextArea();
ObservableStringBuffer buffer = new ObservableStringBuffer();
textArea.textProperty().bind(buffer);
// ...
buffer.append("Hello world");
However, it's important to note here that you don't transfer the efficiency of the buffer API to the text area: the text area simply has a textProperty() representing its text, which can still only really be modified by set(...) and setValue(...). In other words, when you append to the buffer, you essentially end up with textArea.setText(textArea.getText() + "Hello world") (not textArea.appendText("Hello world"). If you're just looking for a clean API, then this should work for you; if you're looking for something efficient, you would have to "wire" the calls to appendText yourself, since that is simply not supported by the text area's textProperty().
Here's a SSCCE using the above class:
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ObservableStringBufferTest extends Application {
private int counter ;
#Override
public void start(Stage primaryStage) {
ObservableStringBuffer buffer = new ObservableStringBuffer();
TextArea textArea = new TextArea();
textArea.setEditable(false);
textArea.textProperty().bind(buffer);
buffer.set("Item 0");
Timeline timeline = new Timeline(new KeyFrame(
Duration.seconds(1),
e -> buffer.append("\nItem "+(++counter))));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
primaryStage.setScene(new Scene(new StackPane(textArea)));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Mediaplayer in JAR

This code compile in Intellij, but it does not work in jar.
Working with getResourceAsStream() or getResource doest not solve the problem.
(I have tried out with Image like Image image = newImage(getClass().getResourceAsStream("image.png");and it does work)
package Sound;
import javafx.application.Application;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.File;
/**
*/
public class TestSound extends Application{
public TestSound() {
play();
}
#Override
public void start(Stage primaryStage) throws Exception {
new TestSound().play();
}
private void play(){
String mainsound = "src/res/sound/main.mp3";
Media i = null;
i = new Media( new File(mainsound).toURI().toString());
MediaPlayer mediaPlayer = new MediaPlayer(i);
mediaPlayer.play();
mediaPlayer.setStopTime(new Duration(120000));
mediaPlayer.setCycleCount(MediaPlayer.INDEFINITE);
}
public static void main (String[] args){
launch(args);
}
}
EDIT:
Media i = new Media(getClass().getClassLoader().getResource(mainsound));
wont work, because the constructor need a String.
but also
Media i = new Media(getClass().getClassLoader().getResource(mainsound).toString());
new MediaPlayer(i).play();
does not work.
ofcourse mainsound="res/sound/main.mp3";
After extraction of jar with winrar
I got dictionary of sound with include the
testsound.class and main.mp3
And another dictionary of res with include main.mp3
Both dictionary are in the same root.
getClass().getResource("res/sound/main.mp3") is going to look for a resource named res/sound/main.mp3 relative to the current class. Since your class is in the sound package, it's effectively going to look for /sound/res/sound/main.mp3, which is not where the resource is located in your jar.
If the list of entries in the jar file is showing
/sound/main.mp3
then the following should work:
String mediaURL = getClass().getResource("/sound/main.mp3").toExternalForm();
// for debugging:
System.out.println(mediaURL);
Media i = new Media(mediaURL);
Instead of using getClass ().getResource (...) it would be ideal to use it like
Media m = new Media ("/myMedia.mp3");//if the media exists in default package
or
Media m = new Media ("/mypackage/myMedia.mp3");//if the media exists in mypackage

JavaFX ChoiceBox add separator with type safety

I'm looking to add a separator into a choice box and still retain the type safety.
On all of the examples I've seen, they just do the following:
ChoiceBox<Object> cb = new ChoiceBox<>();
cb.getItems().addAll("one", "two", new Separator(), "fadfadfasd", "afdafdsfas");
Has anyone come up with a solution to be able to add separators and still retain type safety?
I would expect that if I wanted to add separators, I should be able do something along the following:
ChoiceBox<T> cb = new ChoiceBox<T>();
cb.getSeparators().add(1, new Separator()); // 1 is the index of where the separator should be
I shouldn't have to sacrifice type safety just to add separators.
As already noted, are Separators only supported if added to the items (dirty, dirty). To support them along the lines expected in the question, we need to:
add the notion of list of separator to choiceBox
make its skin aware of that list
While the former is not a big deal, the latter requires a complete re-write (mostly c&p) of its skin, as everything is tightly hidden in privacy. If the re-write has happened anyway, then it's just a couple of lines more :-)
Just for fun, I'm experimenting with ChoiceBoxX that solves some nasty bugs in its selection handling, so couldn't resist to try.
First, add support to the ChoiceBoxx itself:
/**
* Adds a separator index to the list. The separator is inserted
* after the item with the same index. Client code
* must keep this list in sync with the data.
*
* #param separator
*/
public final void addSeparator(int separator) {
if (separatorsList.getValue() == null) {
separatorsList.setValue(FXCollections.observableArrayList());
}
separatorsList.getValue().add(separator);
};
Then some changes in ChoiceBoxXSkin
must listen to the separatorsList
must expect index-of-menuItem != index-of-choiceItem
menuItem must keep its index-of-choiceItem
At its simplest, the listener re-builds the popup, the menuItem stores the dataIndex in its properties and all code that needs to access a popup by its dataIndex is delegated to a method that loops through the menuItems until it finds one that fits:
protected RadioMenuItem getMenuItemFor(int dataIndex) {
if (dataIndex < 0) return null;
int loopIndex = dataIndex;
while (loopIndex < popup.getItems().size()) {
MenuItem item = popup.getItems().get(loopIndex);
ObservableMap<Object, Object> properties = item.getProperties();
Object object = properties.get("data-index");
if ((object instanceof Integer) && dataIndex == (Integer) object) {
return item instanceof RadioMenuItem ? (RadioMenuItem)item : null;
}
loopIndex++;
}
return null;
}
Well you can work around it by creating an interface and then subclassing Separator to implement this interface:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Separator;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class ChoiceBoxIsSafe extends Application {
interface FruitInterface { }
static public class Fruit implements FruitInterface {
private StringProperty name = new SimpleStringProperty();
Fruit(String name) {
this.name.set(name);
}
public StringProperty nameProperty() {
return name;
}
#Override
public String toString() {
return name.get();
}
}
static public class FruitySeparator extends Separator implements FruitInterface { }
#Override
public void start(Stage primaryStage) throws Exception {
GridPane grid = new GridPane();
grid.setHgap(10); grid.setVgap(10); grid.setPadding(new Insets(10));
ChoiceBox<FruitInterface> cb = new ChoiceBox<>();
cb.getItems().addAll(new Fruit("Apple"), new Fruit("Orange"), new FruitySeparator(), new Fruit("Peach"));
Text text = new Text("");
ReadOnlyObjectProperty<FruitInterface> selected = cb.getSelectionModel().selectedItemProperty();
text.textProperty().bind(Bindings.select(selected, "name"));
grid.add(cb, 0, 0);
grid.add(text, 1, 0);
Scene scene = new Scene(grid);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
but that is hardly an "elegant" solution and cannot be done in all cases (e.g. ChoiceBox<String>).
From the implementation of ChoiceBox it certainly looks like it wasn't a good idea to treat Separators like items in the ChoiceBox :-(.
FOR THE REST OF US:
There is a MUCH easier way to do this using code (there are easy ways to do it using FXML too, doing it in code offers more flexibility).
You simply create an ObservableList, then populate it with your items, including the separator then assign that list to the ChoiceBox like this:
private void fillChoiceBox(ChoiceBox choiceBox) {
ObservableList items = FXCollections.observableArrayList();
items.add("one");
items.add("two");
items.add("three");
items.add(new Separator());
items.add("Apples");
items.add("Oranges");
items.add("Pears");
choiceBox.getItems().clear();
choiceBox.getItems().addAll(items);
}

Resources