Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions modifiedeight-newadditions/headers/ExternalServer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ struct ExternalServer
int32_t field_0;
std::string field_4, field_8;
int32_t field_C;
// Set when this entry is a Minecraft Java Edition 1.8.x server rather than
// an MCPE one, which decides whether joining goes through RakNet or through
// the Java session.
bool_t isJava;

ExternalServer();
ExternalServer(const ExternalServer&);
ExternalServer(int32_t, const std::string&, const std::string&, int32_t);
ExternalServer(int32_t, const std::string&, const std::string&, int32_t, bool_t);
//~ExternalServer();
};
2 changes: 2 additions & 0 deletions modifiedeight-newadditions/headers/ExternalServerFile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ struct ExternalServerFile

ExternalServerFile(const std::string&);
void addServer(const std::string&, const std::string&, int32_t);
void addServer(const std::string&, const std::string&, int32_t, bool_t);
void editServer(int32_t, const std::string&, const std::string&, int32_t);
void editServer(int32_t, const std::string&, const std::string&, int32_t, bool_t);
std::unordered_map<int32_t, ExternalServer>* getExternalServers();
void load();
void removeServer(int32_t);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@ struct AddExternalServerScreen: Screen
std::shared_ptr<TextBox> field_94;
std::shared_ptr<Label> field_9C;
std::shared_ptr<NinePatchLayer> field_A4;
// "Is this a Java server? (1.8.x)" - flips the entry between an MCPE 0.8.1
// server and a Minecraft Java Edition 1.8.x one.
std::shared_ptr<Button> javaToggleButton;
bool_t isJavaServer;

AddExternalServerScreen();

void closeScreen();
void refreshJavaToggle();

virtual ~AddExternalServerScreen();
virtual void render(int32_t, int32_t, float);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ struct EditExternalServerScreen: Screen
std::shared_ptr<Label> field_9C;
std::shared_ptr<NinePatchLayer> field_A4;
ExternalServer server;
// "Is this a Java server? (1.8.x)" - see AddExternalServerScreen.
std::shared_ptr<Button> javaToggleButton;
bool_t isJavaServer;

EditExternalServerScreen(const ExternalServer&);
void closeScreen();
void refreshJavaToggle();

virtual ~EditExternalServerScreen();
virtual void render(int32_t, int32_t, float);
Expand Down
49 changes: 49 additions & 0 deletions modifiedeight-newadditions/headers/java/JavaBridge.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once
#include <_types.h>
#include <string>

struct Minecraft;
struct Packet;
struct JavaSession;

/*
* The one global handle on the Java session.
*
* m8 can only be in one world at a time, so a single session is enough, and
* routing everything through statics keeps the edits in the engine down to
* one-line calls that read the same whether or not a Java server is involved.
*/
struct JavaBridge
{
// Starts a session. host may carry a ":port" suffix; typedPort is the port
// column from the server list and is used when it does not.
static bool_t begin(Minecraft* minecraft, const std::string& displayName,
const std::string& host, int32_t typedPort);

// True from begin() until the session ends (cleanly or not).
static bool_t isActive();

// Called once per frame off RakNetInstance::runEvents. Safe to call always.
static void pump();

/*
* Called once per game tick from LocalPlayer::tick, in place of m8's own
* sendPosition(). A Java server wants to hear from the client every tick;
* m8 reports only after a tenth of a block or a whole degree, which is far
* too sparse for the movement checks on the other side.
*/
static void playerTick();

// Tears the session down and hands the client back to RakNet.
static void shutdown();

// Returns 1 when the packet was consumed by the Java session, in which case
// the caller must not touch RakNet. Returns 0 when no session is running.
static bool_t interceptSend(Packet* pk);

// Routes a typed chat line (commands included) to the Java server.
// Returns 0 when there is no session, so the caller falls back to MCPE.
static bool_t sendChat(const std::string& text);

static JavaSession* session();
};
66 changes: 66 additions & 0 deletions modifiedeight-newadditions/headers/java/JavaByteBuf.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#pragma once
#include <_types.h>
#include <string>
#include <vector>

/*
* JavaByteBuf - big-endian byte buffer with the Minecraft Java Edition
* protocol primitives (VarInt, VarLong, String, UUID, Position).
*
* Reads are bounds checked; once a read runs past the end the buffer latches
* an error flag and every following read returns zero, so a truncated or
* malformed packet can never walk off the end of the storage.
*/
struct JavaByteBuf
{
std::vector<uint8_t> bytes;
size_t readPos;
bool_t bad;

JavaByteBuf();
JavaByteBuf(const uint8_t*, size_t);

void clear();
void reset();
size_t remaining() const;
bool_t failed() const;
const uint8_t* data() const;
size_t size() const;

// ---- reading ----
uint8_t readByte();
int8_t readSByte();
bool_t readBool();
int16_t readShort();
uint16_t readUShort();
int32_t readInt();
int64_t readLong();
float readFloat();
double readDouble();
int32_t readVarInt();
int64_t readVarLong();
std::string readString(int32_t maxLen = 32767);
void readUUID(uint64_t* hi, uint64_t* lo);
void readPosition(int32_t* x, int32_t* y, int32_t* z);
void readBytes(uint8_t*, size_t);
void skip(size_t);

// ---- writing ----
void writeByte(uint8_t);
void writeSByte(int8_t);
void writeBool(bool_t);
void writeShort(int16_t);
void writeUShort(uint16_t);
void writeInt(int32_t);
void writeLong(int64_t);
void writeFloat(float);
void writeDouble(double);
void writeVarInt(int32_t);
void writeVarLong(int64_t);
void writeString(const std::string&);
void writePosition(int32_t, int32_t, int32_t);
void writeBytes(const uint8_t*, size_t);
void writeBuf(const JavaByteBuf&);

static int32_t varIntSize(int32_t);
};
24 changes: 24 additions & 0 deletions modifiedeight-newadditions/headers/java/JavaChat.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once
#include <_types.h>
#include <json/json.h>
#include <string>

/*
* Java's JSON text components, flattened into the plain strings m8 draws.
*
* Chat, disconnect reasons and a server list MOTD are all the same shape, so
* both the live session and the server list ping go through here.
*/

// Append the readable text of one component tree to *out.
void javaChatFlatten(const Json::Value& node, std::string* out);

/*
* Parse a component tree and flatten it, stripping the section-sign colour
* codes m8's font does not understand. A blob that is not valid JSON is handed
* back as-is, because some servers send a bare string.
*/
std::string javaChatToText(const std::string& json);

// Flatten an already-parsed tree and strip its colour codes.
std::string javaChatToText(const Json::Value& node);
38 changes: 38 additions & 0 deletions modifiedeight-newadditions/headers/java/JavaChunkData.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once
#include <_types.h>
#include <stddef.h>

struct Level;
struct LevelChunk;

/*
* JavaChunkData - decodes a Java Edition 1.8 chunk column payload straight into
* an m8 LevelChunk.
*
* The 1.8 payload is section major: for every bit set in the section mask, 4096
* little endian u16 block states (id << 4 | meta), then for every set bit 2048
* bytes of block light nibbles, then - on a dimension with sky - 2048 bytes of
* sky light nibbles per set bit, and finally 256 biome bytes when the column is
* a full "ground up" send.
*
* Neither the block array nor the nibble arrays can be memcpy'd across. Java
* indexes a section as (y << 8) | (z << 4) | x while m8 indexes a whole column
* as y | (x << 11) | (z << 7), so every block and every nibble is transposed
* individually, and every block state goes through JavaIdMap on the way.
*/
struct JavaChunkData
{
// Bytes one column occupies on the wire, for slicing a Map Chunk Bulk blob.
static size_t payloadSize(int32_t sectionMask, bool_t hasSkyLight, bool_t groundUp);

/*
* Writes one column into `chunk`. Returns the number of bytes consumed, or 0
* if the payload was short (in which case nothing is written).
*/
static size_t apply(Level* level, LevelChunk* chunk, const uint8_t* data, size_t len,
int32_t sectionMask, bool_t groundUp, bool_t hasSkyLight);

// Recomputes heightMap[] and topBlockY the way LevelChunk::recalcHeightmap would,
// without touching the sky light the server just gave us.
static void recomputeHeights(LevelChunk* chunk);
};
67 changes: 67 additions & 0 deletions modifiedeight-newadditions/headers/java/JavaChunkSource.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#pragma once
#include <_types.h>
#include <level/gen/ChunkSource.hpp>
#include <string>
#include <vector>

struct LevelChunk;
struct Level;

/*
* A server authoritative ChunkSource used only by Java (1.8.x) sessions.
*
* The stock ChunkCache pulls columns out of a local terrain generator and a
* local chunk file. For a Java session neither of those exist: every column we
* are ever allowed to show comes straight out of the socket. This source
* therefore never generates and never saves - it hands out blank columns and
* JavaChunkData fills them in when the matching Chunk Data packet arrives.
*
* Residency uses the same bounded 64x64 grid ChunkCache uses
* (`(x & 0x3F) + 64 * (z & 0x3F)`), so walking a long way recycles slots
* instead of growing without bound, and it does it through the same code shape
* the engine already trusts for entity/renderer bookkeeping.
*
* A blank column is not entirely empty: it carries one layer of bedrock at
* m8 y 0. That mirrors a real Java overworld (which always has bedrock at
* y 0, so the first Chunk Data packet overwrites it with the same thing), it
* stops the player falling out of the world through a column the server has
* not sent yet, and - critically - it keeps Level::validateSpawn() from
* spinning forever: that loop runs before any chunk data can arrive and only
* terminates once getTopTile() finds something that is neither air nor
* invisible_bedrock.
*/
struct JavaChunkSource: ChunkSource {
static const int32_t GRID = 64;
static const int32_t GRID_MASK = 63;
static const int32_t SLOTS = 4096;

Level* level;
LevelChunk* emptyChunk;
LevelChunk* chunks[JavaChunkSource::SLOTS];
int32_t lastChunkX, lastChunkZ;
LevelChunk* lastChunk;
int32_t residentCount;

JavaChunkSource(Level* level);

static int32_t slotOf(int32_t x, int32_t z);

// Lookup that never allocates. Returns 0 when the column is not resident.
LevelChunk* find(int32_t x, int32_t z);
// Lookup that allocates a blank column (bedrock floor) when missing.
LevelChunk* obtain(int32_t x, int32_t z);
// Server told us to forget this column.
void drop(int32_t x, int32_t z);
void dropAll();

virtual ~JavaChunkSource();
virtual bool_t hasChunk(int32_t, int32_t);
virtual LevelChunk* getChunk(int32_t, int32_t);
virtual LevelChunk* create(int32_t, int32_t);
virtual void postProcess(ChunkSource*, int32_t, int32_t);
virtual bool_t tick();
virtual bool_t shouldSave();
virtual void saveAll(bool_t);
virtual std::vector<Biome::MobSpawnerData> getMobsAt(const MobCategory&, int32_t, int32_t, int32_t);
virtual std::string gatherStats();
};
43 changes: 43 additions & 0 deletions modifiedeight-newadditions/headers/java/JavaIdMap.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once
#include <_types.h>

/*
* JavaIdMap - ID translation between Minecraft Java Edition 1.8 and m8.
*
* This is the single place that knows the two ID spaces are different, and it
* has to be a real table rather than the identity: modifiedeight-newadditions
* has claimed a lot of the higher vanilla block IDs for its own blocks.
* Java 115-122 are nether wart / enchanting table / brewing stand / ... while
* in m8 those same IDs are coloured logs; Java 174-189 are packed ice, double
* plants, banners and red sandstone while in m8 they are coloured fences; and
* so on for 125-137, 143-166, 159-162, 190-197. Feeding a Java block ID
* straight into Tile would fill the world with coloured fences, so every ID is
* mapped explicitly.
*
* Where m8 has no equivalent at all the mapping falls back to the closest
* lookalike (packed ice -> ice, red sandstone -> sandstone, mycelium -> grass,
* hopper -> iron block) and to air for purely technical or flat blocks
* (redstone wire, tripwire, pistons extensions, banners).
*/
struct JavaIdMap
{
// Java 1.8 block state -> m8 tile id + meta. Writes 0/0 for "nothing here".
static void javaBlockToM8(int32_t javaId, int32_t javaMeta, int32_t* outId, int32_t* outMeta);
// m8 tile -> Java 1.8 block state. Used when we have to name a block to the server.
static void m8BlockToJava(int32_t m8Id, int32_t m8Meta, int32_t* outId, int32_t* outMeta);

// Item ids. Both sides use 1..197 for block items and 256.. for real items.
static int32_t javaItemToM8(int32_t javaItemId);
static int32_t m8ItemToJava(int32_t m8ItemId);

/*
* Mob types. m8 only implements nine mobs (chicken 10, cow 11, pig 12,
* sheep 13, zombie 32, creeper 33, skeleton 34, spider 35, pig zombie 36),
* so every Java mob is folded onto the nearest one - endermen and villagers
* become humanoids, slimes and magma cubes become creepers, bats and
* rabbits become chickens. Returns 0 when there is nothing sensible.
*/
static int32_t javaMobToM8(int32_t javaType);
// Java "object" spawn types (SpawnObject) -> m8 EntityFactory types.
static int32_t javaObjectToM8(int32_t javaObjectType);
};
26 changes: 26 additions & 0 deletions modifiedeight-newadditions/headers/java/JavaLog.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once
#include <_types.h>

/*
* Diagnostics for the Java Edition session.
*
* javaLog is for the handful of milestones (and failures) a player or a bug
* report needs to see; it always prints. javaDebug is per packet noise and only
* prints when M8_JAVA_DEBUG is set to something other than 0 in the
* environment, so a normal session stays quiet.
*/
/*
* Let the compiler check the varargs. Android builds five ABIs, three of them
* 32 bit, where handing a 64 bit or size_t value to %d prints rubbish.
*/
#if defined(__GNUC__) || defined(__clang__)
#define JAVA_LOG_FORMAT __attribute__((format(printf, 1, 2)))
#else
#define JAVA_LOG_FORMAT
#endif

void javaLog(const char_t* fmt, ...) JAVA_LOG_FORMAT;
void javaDebug(const char_t* fmt, ...) JAVA_LOG_FORMAT;
bool_t javaDebugEnabled();
// M8_JAVA_DEBUG=2: also name every packet in both directions.
bool_t javaTraceEnabled();
Loading
Loading