Skip to content

Commit

Permalink
Add MCPI API.
Browse files Browse the repository at this point in the history
  • Loading branch information
torralbaalla committed Mar 11, 2021
1 parent 4c8919d commit 9fde9ce
Show file tree
Hide file tree
Showing 10 changed files with 504 additions and 24 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ VERSION:=v0.4.0

all: config
javac -Xlint:deprecation -d ./build/ ./mc4k/*.java
javac -Xlint:deprecation -d ./build/ ./mc4k/api/*.java
cd build && jar cfm Minecraft4K.jar manifest_minecraft4k.txt mc4k/* res/*

config:
Expand Down
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ Minecraft 4K, but fixed.
![screenshot](https://raw.githubusercontent.com/Alvarito050506/mc4k/master/screenshot.png)

## Requirements
To run this, you will need the Java Runtime Environment (JRE) `>= 8.0`, to build this you will need the Java Development Kit (JDK) `>= 8.0`. Both Oracle and OpenJDK versions of the programs were tested and work correctly.
To run mc4k, you will need the Java Runtime Environment (JRE) `>= 8.0`, to build this you will need the Java Development Kit (JDK) `>= 8.0`. Both Oracle and OpenJDK versions of the programs were tested and work correctly.

## Building and usage
To build this, do:
To build mc4k, do:
```sh
make
```
Expand Down Expand Up @@ -55,6 +55,7 @@ java -jar ./build/Minecraft4K.jar
+ Added multiple worlds support.
+ Added basic HUD and show/hide HUD keys.
+ Added support for a `scale` command line argument.
+ Added partial support for the MCPI API.
+ Fixed some bugs.

Player and world data are saved under `$HOME/.mc4k` (UNIX-like systems) or `%APPDATA%\.mc4k` (Windows). Screenshots, are saved to the current directory. To change the game scale on startup, execute it from the command line, like:
Expand All @@ -63,7 +64,28 @@ JAVA_CMD -jar JAR SCALE
```
Where `JAVA_CMD` is the command or path to Java, `JAR` is the path to the `Minecraft4K.jar` file, and `SCALE` is a floating point value equal to or greater than `1.0`.

## API
mc4k now partially supports the [Minecraft: Pi Edition](https://mcpi.tk/) API. Currently the list of supported functions is:
+ `world.getBlock(x,y,z)`
+ `world.setBlock(x,y,z,id)`
+ `world.getHeight(x,y)`
+ `world.setting(key,value)`
+ `world.checkpoint.save()`
+ `world.checkpoint.restore()`
+ `player.getPos()`
+ `player.getTile()`
+ `player.setPos(x,y,z)`
+ `player.setTile(x,y,z)`

### Notes
+ The coordinates should be in MCPI format, but without negative numbers (i.e. valid coordinates are `0,0,0`-`63,63,63`).
+ Currenlty the only valid setting `key` is `world_immutable`, and the only valid `value`s are `0` and `!0` (`False` and `True`).
+ Block IDs should be in MCPI format (e.g. `45` for brick, not `5`), but unavailable blocks will be replaced by dirt (`3` in MCPI, `2` in mc4k).

## Credits and licensing
I don't even know from where the original code comes, but I downloaded it from a [post](https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/minecraft-mods/1290821-minecraft-4k-improved-by-crunchycat-download-now?comment=60) in the MCForums. It looks like it was a modified version of the original reverse-engineered Minecraft 4K code.

All my modifications were made for the only purpose of making it more enjoyable, feel free to modify and distribute them.
All my modifications were made for the only purpose of making it more enjoyable, feel free to modify and distribute them, with the following conditions:
+ Redistribute the modified sources.
+ Keep the attributions in the files.
+ Redistribute a copy of this file, with this section unmodified.
15 changes: 13 additions & 2 deletions mc4k/MCApplet.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ public void mousePressed(MouseEvent paramEvent) {
}
events.mouseX = paramEvent.getX();
events.mouseY = paramEvent.getY();
if ((paramEvent.getModifiers() & 4) <= 0)
if ((paramEvent.getModifiers() & 4) <= 0) {
events.buttons[0] = 1;
else
} else {
events.buttons[1] = 1;
}
}

private void setKeyEvent(KeyEvent paramEvent, int val) {
Expand Down Expand Up @@ -156,6 +157,16 @@ public void mouseEntered(MouseEvent paramEvent) {

@Override
public void mouseReleased(MouseEvent paramEvent) {
if (events.mouseLocked != 0) {
return;
}
events.mouseX = paramEvent.getX();
events.mouseY = paramEvent.getY();
if ((paramEvent.getModifiers() & 4) <= 0) {
events.buttons[0] = 0;
} else {
events.buttons[1] = 0;
}
return;
}

Expand Down
20 changes: 20 additions & 0 deletions mc4k/MCSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ public class MCSettings extends Panel implements Runnable, KeyListener {

String titleString = "mc4k - Minecraft 4k";
String worldNameLabelString = "World name: ";
String versionString = versionCodeToString(Minecraft4K.versionCode);
int titleWidth = 0;
int worldNameWidth = 0;
int worldNameLabelWidth = 0;
int versionWidth = 0;
int width = 0;
int height = 0;
int i = 1;
Expand Down Expand Up @@ -69,6 +71,7 @@ public void start() {
titleWidth = graphics.getFontMetrics().stringWidth(titleString);
graphics.setFont(inputFont);
worldNameLabelWidth = graphics.getFontMetrics().stringWidth(worldNameLabelString);
versionWidth = graphics.getFontMetrics().stringWidth(versionString);
(new Thread(this)).start();
addKeyListener(this);
}
Expand All @@ -82,6 +85,7 @@ public void run() {
graphics.setFont(inputFont);
graphics.drawString(worldNameLabelString, width / 2 - worldNameLabelWidth, 110);
graphics.drawString(inputBuffer.toString(), width / 2, 110);
graphics.drawString(versionString, width - 8 - versionWidth, height - 32);
worldNameWidth = graphics.getFontMetrics().stringWidth(inputBuffer.toString());
if (i % 25 != 0) {
graphics.drawRect(width / 2 + worldNameWidth + 2, 95, 6, 15);
Expand Down Expand Up @@ -112,6 +116,22 @@ public void mkdirp(String directoryName) {
}
}

public String versionCodeToString(int versionCode) {
int major = ((versionCode % 10000) - (versionCode % 10000) % 1000) / 1000;
int minor = ((versionCode % 1000) - (versionCode % 1000) % 100) / 100;
int patch = ((versionCode % 100) - (versionCode % 100) % 10) / 10;
int rc = (versionCode % 10);
StringBuffer versionBuffer = new StringBuffer("v");

versionBuffer.append(String.valueOf(major) + ".");
versionBuffer.append(String.valueOf(minor) + ".");
versionBuffer.append(String.valueOf(patch));
if (rc > 0) {
versionBuffer.append("-rc" + String.valueOf(rc));
}
return versionBuffer.toString();
}

@Override
public void keyPressed(KeyEvent paramEvent) {
int keyCode = paramEvent.getKeyCode();
Expand Down
53 changes: 34 additions & 19 deletions mc4k/Minecraft4K.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.net.URL;
import java.net.SocketAddress;
import javax.imageio.ImageIO;

import mc4k.MCApplet;
Expand All @@ -32,29 +33,33 @@
import mc4k.MCSettings;
import mc4k.MCFrame;

import mc4k.api.MCPIServer;

public class Minecraft4K extends MCApplet implements Runnable {
// v0.4.0, MAJOR * 1000 + MINOR * 100 + PATCH * 10 + RC
private static final long versionCode = 0 * 1000 + 4 * 100 + 0 * 10 + 0;
// v0.5.0, MAJOR * 1000 + MINOR * 100 + PATCH * 10 + RC
public static final int versionCode = 0 * 1000 + 5 * 100 + 0 * 10 + 0;

BufferedImage screenImage;

int worldSize = 64 * 64 * 64;
public int worldSize = 64 * 64 * 64;
public int[] worldBlocks = new int[worldSize];
public boolean worldImmutable = false;

int textureSize = 12288;
int[] screenImagePixels;
int[] worldBlocks = new int[worldSize];
int[] texturePixels = new int[textureSize];

float viewFov = 3F;
double DRAW_DISTANCE = 20.0D;
int texturesLoaded = 1;
boolean showHUD = true;

String playerFileName = "player.dat";
String worldFileName = "world.dat";
String texturesFile = "textures.dat";
public String playerFileName = "player.dat";
public String worldFileName = "world.dat";
String texturesFileName = "textures.dat";

MCPlayer player = new MCPlayer();
MCTerrainGenerator generator = new MCTerrainGenerator();
public MCPlayer player = new MCPlayer();
public MCTerrainGenerator generator = new MCTerrainGenerator();

public static void main(String[] args) {
MCSettings settings = new MCSettings();
Expand Down Expand Up @@ -119,6 +124,10 @@ public void windowClosing(WindowEvent paramEvent) {
if (mc4k.initialized == 0) {
mc4k.fileSave(mc4k.worldFileName, mc4k.worldBlocks);
mc4k.playerSave(mc4k.playerFileName, mc4k.player);
File oldWorldFile = new File(mc4k.worldFileName + ".old");
if (oldWorldFile.exists()) {
oldWorldFile.delete();
}
}
System.exit(0);
};
Expand All @@ -133,16 +142,14 @@ public void start() {
addMouseWheelListener(this);

try {
texturePixels = fileLoad(texturesFile, textureSize);
texturePixels = fileLoad(texturesFileName, textureSize);
texturesLoaded = 0;
} catch (Exception err)
{
} catch (Exception err) {
System.out.println("Custom textures not found, falling back to built-in ones.");
}
if (texturesLoaded != 0)
{
if (texturesLoaded != 0) {
try {
texturePixels = resourceLoad(texturesFile, textureSize);
texturePixels = resourceLoad(texturesFileName, textureSize);
} catch (Exception err) {
err.printStackTrace();
System.out.println("Failed to load textures.");
Expand All @@ -161,6 +168,12 @@ public void start() {
} catch (Exception err) {
return;
}

try {
MCPIServer mcpiServer = new MCPIServer("0.0.0.0", 4711, this);
} catch (Exception err) {
err.printStackTrace();
}
}

public void run() {
Expand Down Expand Up @@ -189,7 +202,7 @@ public void gameLoop() {
int smthWithCameraY;

String diamondsString = "Diamonds: " + player.diamondCounter + ", Block: " + player.blockInHand;
String coordsString = "Pos " + (int)player.posX + ", " + (int)player.posY + ", " + (int)player.posZ;
String coordsString = "Pos " + (int)(player.posX - 64) + ", " + (int)(player.posY - 64) + ", " + (int)(64 - (player.posZ - 64));
Graphics graphics = screenImage.getGraphics();

for (smthWithCameraY = 0; smthWithCameraY < imageWidth; ++smthWithCameraY) {
Expand Down Expand Up @@ -334,9 +347,10 @@ public void gameLoop() {
}

// Load world
if (events.worldKeys[1] == 1) { // 'C'
if (events.worldKeys[1] == 1 && !worldImmutable) { // 'C'
try {
worldBlocks = fileLoad(worldFileName, worldSize);
player = playerLoad(playerFileName);
} catch (Exception err) {
err.printStackTrace();
}
Expand All @@ -345,6 +359,7 @@ public void gameLoop() {
// Save world
if (events.worldKeys[2] == 1) { // 'G'
fileSave(worldFileName, worldBlocks);
playerSave(playerFileName, player);
}

// Screenshot
Expand Down Expand Up @@ -470,7 +485,7 @@ public void gameLoop() {
}

// Remove block
if (events.buttons[0] > 0 && blockThatYouLookOn > 0) {
if (events.buttons[0] > 0 && blockThatYouLookOn > 0 && !worldImmutable) {
if (worldBlocks[blockThatYouLookOn] == 3) {
player.diamondCounter++;
}
Expand All @@ -479,7 +494,7 @@ public void gameLoop() {
}

// Place block
if (events.buttons[1] > 0 && blockThatYouLookOn > 0) {
if (events.buttons[1] > 0 && blockThatYouLookOn > 0 && !worldImmutable) {
worldBlocks[blockThatYouLookOn + blockNextToOneThatYouLookOn] = player.blockInHand;
if (player.blockInHand == 3)
{
Expand Down
109 changes: 109 additions & 0 deletions mc4k/api/MCPICommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* MCPICommand.java - MCPI API packet parser and type conversion helper.
*
* Copyright 2021 Alvarito050506 <donfrutosgomez@gmail.com>
*
*/

package mc4k.api;

import java.net.*;
import java.io.*;

class Vec3 {
private int intX = 0;
private int intY = 0;
private int intZ = 0;

public float floatX = 0.0F;
public float floatY = 0.0F;
public float floatZ = 0.0F;

public int getIntX() {
return (int)floatX;
}

public int getIntY() {
return (int)floatY;
}

public int getIntZ() {
return (int)floatZ;
}

@Override
public String toString() {
return String.valueOf((int)floatX) + "," + String.valueOf((int)floatY) + "," + String.valueOf((int)floatZ);
}
}

public class MCPICommand {
public String pack;
public String name;
public String[] args;
public int argc = 0;
public int argi = 0;

public MCPICommand(String packet) {
String[] tmp = packet.split("\\.", 2);
pack = tmp[0];
tmp = tmp[1].split("\\(", 2);
name = tmp[0];
args = tmp[1].split("\\)", 2)[0].split(",", 0);
argc = args.length;
}

public float[] getVec3() throws IndexOutOfBoundsException {
float[] vec3 = new float[3];
if (argc - argi < 3) {
throw new IndexOutOfBoundsException("Trying to access unexisting argument number " + argi);
}
vec3[0] = Float.parseFloat(args[argi++]);
vec3[1] = Float.parseFloat(args[argi++]);
vec3[2] = Float.parseFloat(args[argi++]);
return vec3;
}

public int getInt() throws IndexOutOfBoundsException {
if (argc - argi < 1) {
throw new IndexOutOfBoundsException("Trying to access unexisting argument number " + argi);
}
return (int)Float.parseFloat(args[argi++]);
}

public String getString() throws IndexOutOfBoundsException {
if (argc - argi < 1) {
throw new IndexOutOfBoundsException("Trying to access unexisting argument number " + argi);
}
return args[argi++];
}

public static int[] mcpi2mc4kVec3(float[] vec3) {
int[] intVec3 = new int[3];
intVec3[0] = (int)vec3[0];
intVec3[1] = (int)vec3[1];
intVec3[2] = (int)(63 - vec3[2]);
return intVec3;
}

public static int[] mc4k2mcpiVec3(float[] vec3) {
int[] intVec3 = new int[3];
intVec3[0] = (int)(vec3[0] - 64);
intVec3[1] = (int)(vec3[1] - 64);
intVec3[2] = (int)(63 - (vec3[2] - 64));
return intVec3;
}

public static boolean checkVec3(float[] vec3) {
if (vec3[0] < 0 || vec3[0] >= 63) {
return false;
}
if (vec3[1] < 0 || vec3[1] >= 63) {
return false;
}
if (vec3[2] < 0 || vec3[2] > 63) {
return false;
}
return true;
}
}

0 comments on commit 9fde9ce

Please sign in to comment.