-
Posts
852 -
Joined
-
Last visited
Everything posted by Bektor
-
// it is the same path as from the posts before, just in the backup thread which is located in another class, so I'm storing within the // thread a local reference/variable this.directionary = path; this.directionary.resolve("test.zip"); [...] private void createZipFile() { // Delete the file if it already exists try { if(Files.deleteIfExists(this.directionary)) ServerUtilities.LOGGER.info("Deleted file '" + this.directionary.getFileName().toString() + "'."); } catch (IOException e) { ServerUtilities.LOGGER.fatal("Tried to delete an old backup, but failed. Backup: " + this.directionary.getFileName().toString(), e); } try(FileSystem zipFile = FileSystems.newFileSystem(this.directionary, null)) { Files.copy(this.world, this.directionary, StandardCopyOption.REPLACE_EXISTING); } catch(IOException e) { } }
-
If I leave the dot where it is the whole code will run into an exception at the first try to create a file within my backups directionary as it does not exist because windows doesn't permit a directory with a dot within its name. (Thought the code to create the directory doesn't throw the exception, the one who tries to create a file within the directiory does however.) Interestingly enough it is an FileSystemNotFoundException while the backups directory in which it tries to write doesn't even exist. try(FileSystem zipFile = FileSystems.newFileSystem(this.path.resolve("test.zip", null)) {
-
Oh, I do. At some point in my code this code is called: path.resolve(ModConfig.backupDir); It adds the backupDir to my path so it can be created in the next line and afterwards the whole path is passed onto the backup thread to do the backup.
-
Hm, I'm really wondering why this method returns me such a path: Path path = server.getDataDirectory().toPath(); System.out.println(path.toAbsolutePath().toString()); Output: P:\Java\ForgeMods\run\assets\. Notice the dot at the end of the path. I mean, there is no folder with a "." in it's name within my file system (Windows 10, "virtual" NTFS drive [which basically means that P: is some kind of link to a specific folder within my file system]). Can I just remove the dot at the end of the path without risk that it might be different in the release-jar?
-
Ok, I tried this, but to get access to this method I need to have an instance of the world and a dimensionID, but I want to copy the whole world folder with all dimensions and all other files in there into the backup folder. @Nonnull private Path world = Paths.get(Backups.INSTANCE.server.getWorld(int dimensionID).getChunkSaveLocation());
-
Where can I find what these commands do? EDIT: And what is the difference between flushToDisk and saveAllChunks?
-
Thx, thought I ran into another question. While implementing the logic for a backup I stumbled across the variable disableLevelSaving. I'm wondering if this has to be set to true before I can save all chunks to disk for the backup to occur and wether I should reset it afterwards where I'm not quite sure how I would do this as my current logic is this: save player data to disk save world data to disk (foreach loop withing a try-catch block for every world/dimension) start the backup while copying all files over
-
Hi, I want to save a file, for example a world backup. My problem is now: From where should I get the required paths? Path to the world? Path to backup folder (same location as forge.jar and server start-up script) Thx in advance. Bektor
-
[1.12.2] [SOLVED] A* JUnit Tests + Performance improvements
Bektor replied to Bektor's topic in Modder Support
Thx for the answers. Those things should definitly help. Thought I'm also looking into how it is possible to test an A* algorithm in general using JUnit. test this specific A* algorithm using JUnit to avoid the need of starting Minecraft. -
Hi there, I've implemented myself the A* algorithm (mainly just for the purpose of learning) as seen below and looking for a way to test the code with JUnit and improvements. I'm also looking for reviews on best-practice and performance! Just to note, the implementation works in 2D space within the 3D world of Minecraft. public class AStar { /** * A {@link HashSet} of {@link Node} which holds all nodes which have been examined. * Some may refer to this as the <code>interior</code>. */ private HashSet<Node> closedSet = new HashSet<>(); /** * A {@link PriorityQueue} of {@link Node} which holds all candidates for the algorithm to explore. * Some may refer to this as the <code>openList</code>. */ private PriorityQueue<Node> frontier = new PriorityQueue<>( (firstNode, secondNode) -> { if(firstNode.priority > secondNode.priority) return 1; if(firstNode.priority < secondNode.priority) return -1; return 0; }); /** * A {@link HashSet} of {@link BlockPos} which holds all blocks the algorithm can move through. */ private HashSet<BlockPos> passableBlocks = new HashSet<>(); /** * Initialises this class with a list containing the 'level' the algorithm * uses to find the way. * * @param passableBlocks All blocks the algorithm can use. */ public AStar(HashSet<BlockPos> passableBlocks) { this.passableBlocks.addAll(passableBlocks); } /** * A* implementation * * @param start * @param end * @return null if no path was found or the path as a list */ public List<Node> getShortestPath(BlockPos start, BlockPos end) { if(start == null || end == null || !passableBlocks.contains(start) || !passableBlocks.contains(end)) return null; this.frontier.add(new Node(start, null, 0, this.computeHeuristic(start, end))); while(!this.frontier.isEmpty()) { Node current = this.frontier.poll(); if(current.location.equals(end)) { List<Node> path = new ArrayList<>(); while(current.parent != null) { path.add(current); current = current.parent; } this.frontier.clear(); this.closedSet.clear(); return path; } this.closedSet.add(current); this.getAdjacentNodes(current, end); } return null; } /** * The heuristic algorithm to calculate the cost from a * <code>start</code> {@link Node} to the <code>end</code> {@link Node}. * <br>The Manhatten distance is used for this calculation to create * an overestimated heuristics for better search algorithms. * * @param start The coordinates of the starting {@link Node}. * @param end The coordinates of the ending {@link Node}. * @return The calculated cost to get from the <code>start</code> point to the <code>end</code> point. */ private int computeHeuristic(BlockPos start, BlockPos end) { return Math.abs(start.getX() - end.getX()) + Math.abs(start.getY() - end.getY()); } private void getAdjacentNodes(Node node, BlockPos end) { // Create the set containing all neighbouring blocks BlockPos[] neighbourBlocks = new BlockPos[] { node.location.offset(EnumFacing.WEST), // x+1, y+0 node.location.offset(EnumFacing.EAST), // x-1, y+0 node.location.offset(EnumFacing.NORTH), // x+0, y+1 node.location.offset(EnumFacing.SOUTH) // x+0, y-1 }; for(BlockPos neighbourBlock : neighbourBlocks) { Node neighbour = new Node(neighbourBlock, node); if(this.closedSet.contains(neighbour) || !this.passableBlocks.contains(neighbourBlock)) continue; if(!this.frontier.contains(neighbour)) this.frontier.add(neighbour); float distance = node.distance + this.computeHeuristic(neighbour.location, end); if(distance >= neighbour.distance) continue; neighbour.setDistance(distance); } } /** * Represents the location ("node") of a graph within the A* algorithm. */ public class Node { /** * The location of this node in the world. */ private BlockPos location = null; /** * The previous node or the node we came from. */ private Node parent = null; /** * also w or d or l or length */ private float cost = 0.f; /** * also g or d or 'cost so far' */ private float distance = 0.f; /** * also f */ private float priority = 0.f; /** * Default constructor. */ public Node() { this.location = null; this.parent = null; this.cost = 0.f; this.distance = 0.f; this.priority = 0.f; } /** * Creates a {@link Node} at the given location. * * @param pos The location of the {@link Node} in the world. */ public Node(BlockPos pos) { this.location = pos; } /** * Creates a copy of the given {@link Node}. * * @param node The {@link Node} to copy. */ public Node(Node node) { this.location = node.location; this.parent = node.parent; this.cost = node.cost; this.distance = node.distance; this.priority = node.priority; } /** * Creates a new {@link Node}. * * @param pos The location of the {@link Node} in the world. * @param parent The previous {@link Node}. */ public Node(BlockPos pos, Node parent) { this(pos, parent, 0.f, 0.f); } /** * Creates a new {@link Node}. * * @param pos The location of the {@link Node} in the world. * @param parent The previous {@link Node}. * @param cost The cost to "move" through this {@link Node}. * @param distance The cost of all {@link Node}s from the start point to this {@link Node}. */ public Node(BlockPos pos, Node parent, float cost, float distance) { this.location = pos; this.parent = parent; this.setCost(cost); this.setDistance(distance); this.setPriority(); } private void setCost(float cost) { this.cost = cost; } private void setDistance(float distance) { this.distance = distance; } private void setPriority() { this.priority = this.distance + this.cost; } // TODO: research on hashCode & implement this & equals } } Note: I know that the memory usage could be improved by just using one list, but I'm not sure about the impact in performance this change would mean nor how I could implement this with my PriorityQueue. Thx in advance. Bektor
-
[1.12.2] [UNSOLVED] TileEntity priority Multiblock (performance)
Bektor replied to Bektor's topic in Modder Support
Could be that simple but I quite like those small details. ^^ -
Hi, I've just finished my basic fluid tank and I want to have it work now as a multi-block with different priorities: The numbers represent the priorities. Multiply tanks with the same priority mean that those parts of the tank will be filled equaly at the same time. Only when all blocks with the priority 1 are completly full all blocks with the priority 2 will begin to fill. Currently I'm only building up the list of all surrounding blocks. Note: Improvements of the code (regarding look and performance) are highly welcome. public void generateMultiblock() { this.findTanks(); } public void disbandMultiblock() { } private void findTanks() { this.tempTank = new HashSet<>(); ArrayList<BlockPos> adjacentTanks = null; ArrayList<BlockPos> currentTanks = new ArrayList<>(); // add this to the list to initiate the search currentTanks.add(this.getPos()); // searches around all blocks and all adjacent blocks do { for(BlockPos curTank : currentTanks) { adjacentTanks = this.findAdjacentTanks(curTank); for(BlockPos adTank : adjacentTanks) { // add to list but make sure it's no duplicate if(this.tempTank.add(adTank)) currentTanks.add(adTank); } } currentTanks.clear(); } while (currentTanks.size() > 0); } private ArrayList<BlockPos> findAdjacentTanks(BlockPos tank) { if(tank == null) return null; ArrayList<BlockPos> adjacentTanks = new ArrayList<>(); for(EnumFacing face : EnumFacing.VALUES) { // find tile entity in offset direction BlockPos offset = tank.offset(face); TileEntity tile = this.getWorld().getTileEntity(offset); if(tile != null && tile instanceof TileEntityFluidTank) { // check if the tile entity is already connected to another tank as it can't have two masters if(!((TileEntityFluidTank)tile).isConnected()) adjacentTanks.add(offset); } } return adjacentTanks; } It should also be noted that my TileEntityFluidTank is currently emtpy except for the isConnected method which currently always returns false (functionality to return true when already connected to a master block isn't quite there yet) Only the master block contains fluid logic and can hold fluids! The other blocks hold the fluid just client side (in terms of rendering), meaning that they don't have one line and should not have one line of code to handle fluids except for a value used for rendering (like x amount of fluid stored which is only used to render the x amount of fluid inside the tank at the location). I'm just having problems on how to get a performant way to build up the whole priority list. Thx in advance. Bektor
-
In this little post are a few links which describe what your problem most likely is (just guessing because of java.base in your crash): Also you should note this:
-
Due to how old Minecraft and Forge 1.7.10 are is it no longer supported on this forum. I suggest you should update to a newer version.
-
[1.12.2] [SOLVED] Fluid Handling TileEntity (Fluid Tank)
Bektor replied to Bektor's topic in Modder Support
Ok, thx. I guess I'm good to go then. -
[1.12.2] [SOLVED] Fluid Handling TileEntity (Fluid Tank)
Bektor replied to Bektor's topic in Modder Support
Hm, I'm wondering for what these events might be. Ah, ok. I could just implement IFluidTank and IFluidHandler in a custom class and handle it from there on like a normal capability?, nice. Thought now I'm wondering why some mods have a IFluidTank implementation and implement IFluidHandler in the tile entity itself... -
[1.12.2] [SOLVED] Fluid Handling TileEntity (Fluid Tank)
Bektor replied to Bektor's topic in Modder Support
Ok, thx. So I have to use both? That would leave me with the question of how my IFluidHandler should interact with IFluidTank and my tile-entitiy and how that all should work with capabilities. -
[1.12.2] [SOLVED] Fluid Handling TileEntity (Fluid Tank)
Bektor replied to Bektor's topic in Modder Support
Not really helpful. Also the point why I came up with the second question is that I'm used to the system from the capabilities that there is one interface which you implement and you're done, but here I've got two different interfaces. Thus I'm not quite sure what's the difference between both of them (except for that the one is the capability interface and the other one seems just to be there...) nor do I know what the actual use case of the second one should be when there is already the capability interface. -
Hi there. I wish to start mod development. Where do I start?
Bektor replied to XixiPlays's topic in Modder Support
It requires Java 8 as Minecraft 1.12 does while support for Java 9 isn't quite there yet. Note: You can't set the workspace up with Java 9. See here and here. I guess this could help to answer your question. From what I know not much changed there, so it should still be relevant. -
[1.12.2] [SOLVED] Fluid Handling TileEntity (Fluid Tank)
Bektor replied to Bektor's topic in Modder Support
Ok, thx. Should be pretty easy then with the availability of an capability for fluids. Thought a few more questions: I want my tank to output data to the comperator. The problem here is: I've got totally no clue how to calculate the return value for getComparatorInputOverride. What is the difference between IFluidHandler and IFluidTank? -
Hi, I'm wondering how I can create a fluid tank using Forge and what is required to do so. Thx in advance. Bektor EDIT: Some more questions: I want my tank to output data to the comperator. The problem here is: I've got totally no clue how to calculate the return value for getComparatorInputOverride. What is the difference between IFluidHandler and IFluidTank and what is the actual use case of them? (I'm used to work with stuff like the energy capabilities where there is only one interface for everything, so I'm a bit confused here why there are two and when I should use which one or should I use both (and how then?)?)
-
[1.11.2] [UNSOLVED] Block connections & Blockstates
Bektor replied to Bektor's topic in Modder Support
Anyone who might know what's wrong?? -
[1.11.2] [UNSOLVED] Block connections & Blockstates
Bektor replied to Bektor's topic in Modder Support
Bump. -
[1.11.2] [UNSOLVED] Block connections & Blockstates
Bektor replied to Bektor's topic in Modder Support
Thx, didn't know there was such a method. Thought as can be seen in the image: There is also an connection on the wrong side (happens only for west and east sides). protected boolean isValidConnection(IBlockAccess worldIn, BlockPos pos, IBlockState neighbourState, EnumFacing facing) { if(super.isValidConnection(worldIn, pos, neighbourState, facing)) return true; TileEntity tile = worldIn.getTileEntity(pos.offset(facing)); if(tile != null) return EnergyUtils.hasCapability(tile, facing); return false; } private boolean canConnectToMachine(final IBlockAccess worldIn, final IBlockState state, final BlockPos pos, EnumFacing facing) { final BlockPos neighborPos = pos.offset(facing); final IBlockState neighbourState = worldIn.getBlockState(neighborPos); return this.isValidConnection(worldIn, pos, neighbourState, facing) && !(neighbourState instanceof BlockCableConnector) && !(neighbourState instanceof BlockCable); } @Override public IBlockState getActualState(IBlockState state, IBlockAccess worldIn, BlockPos pos) { for(final EnumFacing facing : EnumFacing.VALUES) state = super.getActualState(state, worldIn, pos).withProperty(SPECIAL_PROPERTIES.get(facing.getIndex()), this.canConnectToMachine(worldIn, state, pos, facing)); return state; } @Override protected BlockStateContainer createBlockState() { return new BlockStateContainer.Builder(this) .add(CONNECTED_PROPERTIES.toArray(new IProperty[CONNECTED_PROPERTIES.size()])) .add(SPECIAL_PROPERTIES.toArray(new IProperty[SPECIAL_PROPERTIES.size()])) .build(); } BlockCableConnector is this block while BlockCable is the block on the left side of the image. The SPECIAL_PROPERTIES adds this larger thing on the smaller middle part of the cable while the CONNECTED_PROPERTIES just adds the normal element to the side (which can be seen in there.) -
[1.11.2] [UNSOLVED] Block connections & Blockstates
Bektor replied to Bektor's topic in Modder Support
Any way to do this automatically without having to list each one of the properties manually? (got two arrays)