MaimMim Man in the middle minetest interceptor
- prototype - between client and server, allow to capture all exchanges and potentially change them - created to capture server maps in laby - first test get only MapBlock, support version serialization version 28 - prepartion for 29 with zstd but untested.
This commit is contained in:
6
.idea/ant.xml
generated
Normal file
6
.idea/ant.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AntConfiguration">
|
||||||
|
<buildFile url="file://$PROJECT_DIR$/build.xml" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
1
.idea/laby.iml
generated
1
.idea/laby.iml
generated
@@ -25,5 +25,6 @@
|
|||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="artgaphics-0.2.0" level="project" />
|
<orderEntry type="library" name="artgaphics-0.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="zstd-jni-1.5.2-2" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
9
.idea/libraries/artgaphics_0_1_0.xml
generated
9
.idea/libraries/artgaphics_0_1_0.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="artgaphics-0.1.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$PROJECT_DIR$/libs/artgaphics-0.1.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/zstd_jni_1_5_2_2.xml
generated
Normal file
9
.idea/libraries/zstd_jni_1_5_2_2.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="zstd-jni-1.5.2-2">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/libs/zstd-jni-1.5.2-2.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
||||||
@@ -10,8 +10,11 @@
|
|||||||
<property name="src" location="java"/>
|
<property name="src" location="java"/>
|
||||||
<property name="build" location="build"/>
|
<property name="build" location="build"/>
|
||||||
<property name="dist" location="dist"/>
|
<property name="dist" location="dist"/>
|
||||||
<!-- Fill me please / todo -->
|
<!-- Fill me please / todo
|
||||||
|
see fetch_dependencies
|
||||||
|
-->
|
||||||
<property name="artgraphicslib" value="artgaphics-0.2.0"/>
|
<property name="artgraphicslib" value="artgaphics-0.2.0"/>
|
||||||
|
<property name="zstd-jnilib" value="zstd-jni-1.5.2-2"/>
|
||||||
<target name="gather_project_params">
|
<target name="gather_project_params">
|
||||||
<!-- original source parameter is in project_params project_version -->
|
<!-- original source parameter is in project_params project_version -->
|
||||||
<loadfile property="distversion" srcfile="${basedir}/project_params">
|
<loadfile property="distversion" srcfile="${basedir}/project_params">
|
||||||
@@ -36,7 +39,7 @@
|
|||||||
<target name="compile" depends="init"
|
<target name="compile" depends="init"
|
||||||
description="compile the source " >
|
description="compile the source " >
|
||||||
<!-- Compile the java code from ${src} into ${build} -->
|
<!-- Compile the java code from ${src} into ${build} -->
|
||||||
<javac srcdir="${src}" destdir="${build}" includeantruntime="false" classpath="libs/${artgraphicslib}.jar">
|
<javac srcdir="${src}" destdir="${build}" includeantruntime="false" classpath="libs/${artgraphicslib}.jar:libs/${zstd-jnilib}.jar">
|
||||||
<exclude name="org/artisanlogiciel/games/javafx/*"/>
|
<exclude name="org/artisanlogiciel/games/javafx/*"/>
|
||||||
<compilerarg value="-Xlint:deprecation,unchecked" />
|
<compilerarg value="-Xlint:deprecation,unchecked" />
|
||||||
</javac>
|
</javac>
|
||||||
|
|||||||
@@ -14,6 +14,18 @@ fetch_jackson_databind()
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetch_zstd-jni()
|
||||||
|
{
|
||||||
|
|
||||||
|
echo "compiled from https://github.com/luben/zstd-jni commit 54d3d50c16d96bd8a30e2d4c0a9648001a52d6f9"
|
||||||
|
# had to hack through jar generation ...
|
||||||
|
# cp ~/artisanlogiciel/ext_projects/java/zstd-jni/target/zstd-jni-1.5.2-2.jar .
|
||||||
|
libversion_zstdjni=1.5.2-2
|
||||||
|
pushd libs
|
||||||
|
wget https://repo1.maven.org/maven2/com/github/luben/zstd-jni/${libversion_zstdjni}/zstd-jni-${libversion_zstdjni}.jar
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
if [[ ! -d ../sharedrawweb ]]
|
if [[ ! -d ../sharedrawweb ]]
|
||||||
then
|
then
|
||||||
echo "[ERROR] expected a sharedrawweb project parent ( for exports )" >&2
|
echo "[ERROR] expected a sharedrawweb project parent ( for exports )" >&2
|
||||||
@@ -35,3 +47,5 @@ if [[ -n $use_jackson ]]
|
|||||||
then
|
then
|
||||||
fetch_jackson_databind
|
fetch_jackson_databind
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
fetch_zstd-jni
|
||||||
|
|||||||
26
java/org/artisanlogiciel/games/maze/MainMim.java
Normal file
26
java/org/artisanlogiciel/games/maze/MainMim.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package org.artisanlogiciel.games.maze;
|
||||||
|
|
||||||
|
import org.artisanlogiciel.games.minetest.net.MiM;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
public class MainMim {
|
||||||
|
|
||||||
|
void minetestMime(String serverName, int port) {
|
||||||
|
MiM mim = new MiM(30002, new InetSocketAddress(serverName, port));
|
||||||
|
mim.launch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String pArgs[])
|
||||||
|
{
|
||||||
|
if ( pArgs.length > 1)
|
||||||
|
{
|
||||||
|
new MainMim().minetestMime(pArgs[0], Integer.parseInt(pArgs[1]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.err.println("[ERROR] please set minetest server hostname and port as arguments");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,6 +4,7 @@ import org.artisanlogiciel.games.maze.*;
|
|||||||
import org.artisanlogiciel.games.maze.model.WidthHeightProvider;
|
import org.artisanlogiciel.games.maze.model.WidthHeightProvider;
|
||||||
import org.artisanlogiciel.games.maze.persist.MazePersistRaw;
|
import org.artisanlogiciel.games.maze.persist.MazePersistRaw;
|
||||||
import org.artisanlogiciel.games.maze.solve.SolvingModel;
|
import org.artisanlogiciel.games.maze.solve.SolvingModel;
|
||||||
|
import org.artisanlogiciel.games.minetest.net.MiM;
|
||||||
import org.artisanlogiciel.graphics.Drawing;
|
import org.artisanlogiciel.graphics.Drawing;
|
||||||
import org.artisanlogiciel.xpm.Xpm;
|
import org.artisanlogiciel.xpm.Xpm;
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -270,6 +272,7 @@ implements StatusListener
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
System.out.println("Default Locale " + Locale.getDefault());
|
System.out.println("Default Locale " + Locale.getDefault());
|
||||||
|
|
||||||
if ((pArgs.length > 0) && (pArgs[0].length() > 0)) {
|
if ((pArgs.length > 0) && (pArgs[0].length() > 0)) {
|
||||||
|
|||||||
97
java/org/artisanlogiciel/games/minetest/MapBlock.java
Normal file
97
java/org/artisanlogiciel/games/minetest/MapBlock.java
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest;
|
||||||
|
|
||||||
|
import com.github.luben.zstd.Zstd;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.Constant;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.PacketException;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.Serialize;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A block of nodes of MAP_BLOCKSIZE in any x,y,z direction
|
||||||
|
*/
|
||||||
|
public class MapBlock {
|
||||||
|
|
||||||
|
final static int nodecount = Constant.MAP_BLOCKSIZE * Constant.MAP_BLOCKSIZE * Constant.MAP_BLOCKSIZE;
|
||||||
|
|
||||||
|
int m_lighting_complete;
|
||||||
|
|
||||||
|
ArrayList<MapNode> nodes;
|
||||||
|
|
||||||
|
ArrayList<MapNode> getNodes()
|
||||||
|
{
|
||||||
|
if ( nodes == null )
|
||||||
|
{
|
||||||
|
nodes = new ArrayList<>(nodecount);
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in memory case
|
||||||
|
public void deSerialize(ByteBuffer buffer, int version)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
|
||||||
|
int flags = 0;
|
||||||
|
int content_width = 0;
|
||||||
|
int params_width = 0;
|
||||||
|
|
||||||
|
if ( version >= 29) {
|
||||||
|
// ByteBuffer byteBuffer = ByteBuffer.wrap(networkPacket.getBuffer(),offset,networkPacket.getLength() - offset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// force to have a direct buffer.
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(networkPacket.getLength());
|
||||||
|
byteBuffer.put(networkPacket.getBuffer());
|
||||||
|
byteBuffer.position(networkPacket.getOffset());
|
||||||
|
|
||||||
|
//System.arraycopy(networkPacket.getBuffer(), 0, byteBuffer.array(), 0, length);
|
||||||
|
// zstd compression
|
||||||
|
// FIXME, can we know original size ? somehow related to BLOCKSIZE³
|
||||||
|
long originalSizeMax = Zstd.decompressedSize(byteBuffer);
|
||||||
|
System.out.println(String.format("originalSizeMax=%d", originalSizeMax));
|
||||||
|
ByteBuffer decompressed = Zstd.decompress(byteBuffer,(int) originalSizeMax);
|
||||||
|
*/
|
||||||
|
byte out[] = new byte[16386];
|
||||||
|
long outLength = Zstd.decompressByteArray(out, 0, out.length, buffer.array(), buffer.arrayOffset(), buffer.limit());
|
||||||
|
|
||||||
|
// Should be a MapBlock
|
||||||
|
MapBlock block = new MapBlock();
|
||||||
|
ByteBuffer decompressed = ByteBuffer.wrap(out, 0, (int) outLength);
|
||||||
|
buffer = decompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = Serialize.readU8(buffer);
|
||||||
|
|
||||||
|
if ( version >= 27 ) {
|
||||||
|
m_lighting_complete = Serialize.readU16(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
content_width = Serialize.readU8(buffer);
|
||||||
|
params_width = Serialize.readU8(buffer);
|
||||||
|
|
||||||
|
System.out.println(String.format(" flags %x lightning_complete %d content_witd %d params_width %d ",flags, m_lighting_complete, content_width, params_width));
|
||||||
|
|
||||||
|
if (( version < 29 ) && ( version >= 11 ))
|
||||||
|
{
|
||||||
|
// ZLib decompression
|
||||||
|
try {
|
||||||
|
byte decompressed[] = Serialize.decompress(buffer);
|
||||||
|
buffer = ByteBuffer.wrap(decompressed);
|
||||||
|
}
|
||||||
|
catch ( Exception e)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
System.err.println(e);
|
||||||
|
e.printStackTrace(System.err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes = getNodes();
|
||||||
|
MapNode.deSerializeBulk(buffer,version, nodes,nodecount,content_width,params_width);
|
||||||
|
|
||||||
|
//m_node_metadata.deSerialize(is, m_gamedef->idef());
|
||||||
|
}
|
||||||
|
}
|
||||||
99
java/org/artisanlogiciel/games/minetest/MapNode.java
Normal file
99
java/org/artisanlogiciel/games/minetest/MapNode.java
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest;
|
||||||
|
|
||||||
|
import org.artisanlogiciel.games.minetest.core.PacketException;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.Serialize;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MapNode {
|
||||||
|
/*
|
||||||
|
Main content
|
||||||
|
*/
|
||||||
|
short param0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Misc parameter. Initialized to 0.
|
||||||
|
- For light_propagates() blocks, this is light intensity,
|
||||||
|
stored logarithmically from 0 to LIGHT_MAX.
|
||||||
|
Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
|
||||||
|
- Contains 2 values, day- and night lighting. Each takes 4 bits.
|
||||||
|
- Uhh... well, most blocks have light or nothing in here.
|
||||||
|
*/
|
||||||
|
byte param1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The second parameter. Initialized to 0.
|
||||||
|
E.g. direction for torches and flowing water.
|
||||||
|
*/
|
||||||
|
byte param2;
|
||||||
|
|
||||||
|
public void deSerialize(ByteBuffer buffer)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
// version >= 24
|
||||||
|
param0 = (short) Serialize.readU16(buffer);
|
||||||
|
buffer.position(buffer.position() + 2);
|
||||||
|
param1 = (byte) Serialize.readU8(buffer);
|
||||||
|
buffer.position(buffer.position() + 1);
|
||||||
|
param2 = (byte) Serialize.readU8(buffer);
|
||||||
|
// network specific ...
|
||||||
|
// readU8(is);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize bulk node data
|
||||||
|
public static void deSerializeBulk(ByteBuffer buffer, int version,
|
||||||
|
List<MapNode> nodes, int nodecount,
|
||||||
|
int content_width, int params_width)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
byte[] intern = buffer.array();
|
||||||
|
int initialOffset = buffer.position();
|
||||||
|
|
||||||
|
// Deserialize content
|
||||||
|
if(content_width == 1)
|
||||||
|
{
|
||||||
|
for(int i=0; i<nodecount; i++) {
|
||||||
|
nodes.add(i, new MapNode());
|
||||||
|
nodes.get(i).param0 = (short) Serialize.readU8( intern, initialOffset + i, intern.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(content_width == 2)
|
||||||
|
{
|
||||||
|
for(int i=0; i<nodecount; i++) {
|
||||||
|
nodes.add(i, new MapNode());
|
||||||
|
nodes.get(i).param0 = (short) Serialize.readU8( intern, initialOffset + (i*2), intern.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize param1
|
||||||
|
int start1 = initialOffset + (content_width * nodecount);
|
||||||
|
for(int i=0; i<nodecount; i++) {
|
||||||
|
nodes.get(i).param1 = (byte) Serialize.readU8( intern, start1 + i, intern.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize param2
|
||||||
|
int start2 = initialOffset + ((content_width + 1) * nodecount);
|
||||||
|
if(content_width == 1)
|
||||||
|
{
|
||||||
|
for(int i=0; i<nodecount; i++) {
|
||||||
|
MapNode node = nodes.get(i);
|
||||||
|
node.param2 = (byte) Serialize.readU8( intern, start2 + i, intern.length);
|
||||||
|
if(node.param0 > 0x7F){
|
||||||
|
node.param0 <<= 4;
|
||||||
|
node.param0 |= (node.param2&0xF0)>>4;
|
||||||
|
node.param2 &= 0x0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(content_width == 2)
|
||||||
|
{
|
||||||
|
for(int i=0; i<nodecount; i++) {
|
||||||
|
nodes.get(i).param2 = (byte) Serialize.readU8(intern, start2 + i, intern.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package org.artisanlogiciel.games.minetest;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class Node {
|
public class Node {
|
||||||
|
// could be a core.v3s16
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
int z;
|
int z;
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.core;
|
||||||
|
|
||||||
|
public class Constant {
|
||||||
|
|
||||||
|
public final static int MAP_BLOCKSIZE = 16;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.core;
|
||||||
|
|
||||||
|
public class PacketException
|
||||||
|
extends Exception
|
||||||
|
{
|
||||||
|
public PacketException(String message)
|
||||||
|
{
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
116
java/org/artisanlogiciel/games/minetest/core/Serialize.java
Normal file
116
java/org/artisanlogiciel/games/minetest/core/Serialize.java
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.core;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.zip.Inflater;
|
||||||
|
|
||||||
|
public class Serialize {
|
||||||
|
|
||||||
|
public final static int BUFFER_SIZE = 16386;
|
||||||
|
|
||||||
|
public static int readS16(byte buffer[], int offset, int length)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
if ( offset + 2 < length) {
|
||||||
|
return 256 * buffer[offset] + buffer[offset + 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PacketException("out of bound offset U16");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MSB network order
|
||||||
|
public static int readU32(byte[] buffer, int offset, int length)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
if ( offset + 4 < length) {
|
||||||
|
return 16777216 * Byte.toUnsignedInt(buffer[offset]) +
|
||||||
|
65536 * Byte.toUnsignedInt(buffer[offset + 1]) +
|
||||||
|
256 * Byte.toUnsignedInt(buffer[offset + 2]) +
|
||||||
|
Byte.toUnsignedInt(buffer[offset + 3]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PacketException("out of bound offset U32");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MSB network order
|
||||||
|
public static int readU16(byte[] buffer, int offset, int length)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
if ( offset + 2 < length) {
|
||||||
|
return 256 * Byte.toUnsignedInt(buffer[offset]) +
|
||||||
|
Byte.toUnsignedInt(buffer[offset + 1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PacketException("out of bound offset U16");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// will update position
|
||||||
|
public static int readU16(ByteBuffer byteBuffer)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
int u16 = readU16(byteBuffer.array(), byteBuffer.position(), byteBuffer.array().length);
|
||||||
|
byteBuffer.position(byteBuffer.position()+2);
|
||||||
|
return u16;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int readU8(byte[] buffer, int offset, int length)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
if ( offset + 1 < length) {
|
||||||
|
return Byte.toUnsignedInt(buffer[offset]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PacketException("out of bound offset U8");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// will update position
|
||||||
|
public static int readU8(ByteBuffer byteBuffer)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
int u8 = readU8(byteBuffer.array(), byteBuffer.position(), byteBuffer.array().length);
|
||||||
|
byteBuffer.position(byteBuffer.position()+1);
|
||||||
|
return u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static v3s16 readV3S16(byte buffer[], int offset, int length)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
if ( offset + 6 <= length) {
|
||||||
|
int x = readS16(buffer, offset, length);
|
||||||
|
int y = readS16(buffer, offset + 2, length);
|
||||||
|
int z = readS16(buffer, offset + 4, length);
|
||||||
|
return new v3s16(x, y, z);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PacketException("out of bound offset v3s16");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zlib decompression
|
||||||
|
public static byte[] decompress(ByteBuffer byteBuffer) throws Exception
|
||||||
|
{
|
||||||
|
final Inflater inflater = new Inflater(false);
|
||||||
|
inflater.setInput(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit() - byteBuffer.position());
|
||||||
|
|
||||||
|
try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(byteBuffer.limit()))
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[BUFFER_SIZE];
|
||||||
|
while (!inflater.finished())
|
||||||
|
{
|
||||||
|
final int count = inflater.inflate(buffer);
|
||||||
|
outputStream.write(buffer, 0, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputStream.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
java/org/artisanlogiciel/games/minetest/core/v2s16.java
Normal file
13
java/org/artisanlogiciel/games/minetest/core/v2s16.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.core;
|
||||||
|
|
||||||
|
public class v2s16 {
|
||||||
|
|
||||||
|
public int X;
|
||||||
|
public int Y;
|
||||||
|
|
||||||
|
public v2s16(int x, int y) {
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
14
java/org/artisanlogiciel/games/minetest/core/v3s16.java
Normal file
14
java/org/artisanlogiciel/games/minetest/core/v3s16.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.core;
|
||||||
|
|
||||||
|
public class v3s16 {
|
||||||
|
|
||||||
|
public int X;
|
||||||
|
public int Y;
|
||||||
|
public int Z;
|
||||||
|
|
||||||
|
public v3s16(int x, int y, int z) {
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
4
java/org/artisanlogiciel/games/minetest/net/Address.java
Normal file
4
java/org/artisanlogiciel/games/minetest/net/Address.java
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
|
||||||
|
public class Address {
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
|
||||||
|
import org.artisanlogiciel.games.minetest.core.PacketException;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.Serialize;
|
||||||
|
|
||||||
|
public class BufferedPacket {
|
||||||
|
|
||||||
|
public static int BASE_HEADER_SIZE = 7;
|
||||||
|
|
||||||
|
// Data of the packet, including headers
|
||||||
|
byte[] m_data;
|
||||||
|
|
||||||
|
BufferedPacket(byte[] data)
|
||||||
|
{
|
||||||
|
m_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSeqNum()
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
return Serialize.readU16(m_data, BASE_HEADER_SIZE + 1, size());
|
||||||
|
}
|
||||||
|
|
||||||
|
int size()
|
||||||
|
{
|
||||||
|
return m_data.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
java/org/artisanlogiciel/games/minetest/net/Channel.java
Normal file
9
java/org/artisanlogiciel/games/minetest/net/Channel.java
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
|
||||||
|
public class Channel {
|
||||||
|
|
||||||
|
int readNextIncomingSeqNum()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
|
||||||
|
public class ConnectionEvent {
|
||||||
|
|
||||||
|
ConnectionEventType m_event_type;
|
||||||
|
int m_peer_id;
|
||||||
|
byte[] m_data;
|
||||||
|
boolean m_timeout;
|
||||||
|
|
||||||
|
|
||||||
|
ConnectionEvent(ConnectionEventType eventType)
|
||||||
|
{
|
||||||
|
m_event_type = eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
String describe()
|
||||||
|
{
|
||||||
|
return m_event_type.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionEventPtr create(ConnectionEventType type)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionEventPtr dataReceived(int peer_id, byte[] data)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionEventPtr peerAdded(int peer_id, Address address)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionEventPtr peerRemoved(int peer_id, boolean is_timeout, Address address)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionEventPtr bindFailed()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
|
||||||
|
public class ConnectionEventPtr {
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
|
||||||
|
public enum ConnectionEventType {
|
||||||
|
CONNEVENT_NONE,
|
||||||
|
CONNEVENT_DATA_RECEIVED,
|
||||||
|
CONNEVENT_PEER_ADDED,
|
||||||
|
CONNEVENT_PEER_REMOVED,
|
||||||
|
CONNEVENT_BIND_FAILED
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
|
||||||
|
import org.artisanlogiciel.games.minetest.core.PacketException;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.Serialize;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class IncomingSplitBuffer {
|
||||||
|
|
||||||
|
int m_seqnum;
|
||||||
|
int m_chunk_count;
|
||||||
|
int m_chunk_num;
|
||||||
|
|
||||||
|
// number of chunks
|
||||||
|
int m_got = 0;
|
||||||
|
|
||||||
|
NetworkPacket m_list[] = null;
|
||||||
|
BufferedPacket m_reassembled = null;
|
||||||
|
|
||||||
|
BufferedPacket insert(NetworkPacket networkPacket)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
|
||||||
|
byte[] buffer = networkPacket.getBuffer();
|
||||||
|
int length = networkPacket.getLength();
|
||||||
|
int offset = networkPacket.getOffset();
|
||||||
|
|
||||||
|
int type = Serialize.readU8(buffer , offset, length);
|
||||||
|
int seqnum = Serialize.readU16(buffer, offset + 1, length);
|
||||||
|
// total number of chunk
|
||||||
|
int chunk_count = Serialize.readU16(buffer, offset + 3, length);
|
||||||
|
// this chunk number
|
||||||
|
int chunk_num = Serialize.readU16(buffer, offset+ 5, length);
|
||||||
|
|
||||||
|
System.out.println("Split length " + length + " type " + type + " seqnum " + seqnum + " chunk_num/chunk_count " + chunk_num + "/" + chunk_count );
|
||||||
|
|
||||||
|
// move to next header
|
||||||
|
networkPacket.addOffset(7);
|
||||||
|
|
||||||
|
if (m_reassembled != null)
|
||||||
|
{
|
||||||
|
return m_reassembled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_list == null )
|
||||||
|
{
|
||||||
|
m_list = new NetworkPacket[chunk_count];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( chunk_num < chunk_count && (m_list[chunk_num] == null) )
|
||||||
|
{
|
||||||
|
m_list[chunk_num] = networkPacket;
|
||||||
|
m_got ++;
|
||||||
|
}
|
||||||
|
//todo seqnum
|
||||||
|
m_seqnum = seqnum;
|
||||||
|
|
||||||
|
// fully obtained
|
||||||
|
if ( m_got == chunk_count )
|
||||||
|
{
|
||||||
|
reassemble();
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_reassembled;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reassemble()
|
||||||
|
{
|
||||||
|
// keep first header since result is a valid BufferedPacket
|
||||||
|
int fullLength = BufferedPacket.BASE_HEADER_SIZE;
|
||||||
|
for (NetworkPacket networkPacket : m_list )
|
||||||
|
{
|
||||||
|
fullLength += networkPacket.getLength() - networkPacket.getOffset();
|
||||||
|
}
|
||||||
|
byte[] reassembled = new byte[fullLength];
|
||||||
|
NetworkPacket first = m_list[0];
|
||||||
|
System.arraycopy(first.getBuffer(),0,reassembled,0,BufferedPacket.BASE_HEADER_SIZE);
|
||||||
|
int offset = BufferedPacket.BASE_HEADER_SIZE;
|
||||||
|
for (NetworkPacket networkPacket : m_list )
|
||||||
|
{
|
||||||
|
int dataLength = networkPacket.getLength() - networkPacket.getOffset();
|
||||||
|
System.arraycopy(networkPacket.getBuffer(), networkPacket.getOffset(),reassembled,offset,dataLength);
|
||||||
|
offset+=dataLength;
|
||||||
|
}
|
||||||
|
m_reassembled = new BufferedPacket(reassembled);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
127
java/org/artisanlogiciel/games/minetest/net/MiM.java
Normal file
127
java/org/artisanlogiciel/games/minetest/net/MiM.java
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
|
||||||
|
import org.artisanlogiciel.games.minetest.core.PacketException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Man in the middle UDP
|
||||||
|
* very simple for one client only
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MiM {
|
||||||
|
|
||||||
|
DatagramSocket serverSocket;
|
||||||
|
boolean running = false;
|
||||||
|
InetSocketAddress serverAddress;
|
||||||
|
// will be captured, incoming address & port
|
||||||
|
SocketAddress fromClient = null;
|
||||||
|
int localPort;
|
||||||
|
PacketHandler handler = null;
|
||||||
|
|
||||||
|
public MiM(int myPort, InetSocketAddress remoteAddress)
|
||||||
|
{
|
||||||
|
localPort = myPort;
|
||||||
|
serverAddress = remoteAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void launch()
|
||||||
|
{
|
||||||
|
// ServerSocket socket = new ServerSocket()
|
||||||
|
try {
|
||||||
|
handler = new PacketHandler();
|
||||||
|
serverSocket = new DatagramSocket(localPort);
|
||||||
|
DatagramSocket in = serverSocket;
|
||||||
|
SocketAddress fromServer = serverAddress;
|
||||||
|
Thread toServer = new Thread( () -> {runFromToServer(in,fromServer);});
|
||||||
|
running = true;
|
||||||
|
toServer.start();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
System.out.println("problem");
|
||||||
|
e.printStackTrace(System.err);
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop()
|
||||||
|
{
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runFromToServer(DatagramSocket in, SocketAddress fromServer) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
while (running) {
|
||||||
|
// quick way, a new buffer at each reception
|
||||||
|
// to handle split packets that are buffered
|
||||||
|
byte[] buf = new byte[4096];
|
||||||
|
SocketAddress toRemote = null;
|
||||||
|
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||||
|
in.receive(packet);
|
||||||
|
SocketAddress from = packet.getSocketAddress();
|
||||||
|
if ( from.equals(fromServer)) {
|
||||||
|
// no client yet
|
||||||
|
if ( fromClient == null )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fromServer(buf,packet.getLength());
|
||||||
|
toRemote = fromClient;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// record client
|
||||||
|
// later on to be smart : could try to record peer id ?
|
||||||
|
// will add a constraint : only one auth at a time
|
||||||
|
if ( fromClient == null ) {
|
||||||
|
fromClient = from;
|
||||||
|
}
|
||||||
|
fromClient(buf,packet.getLength());
|
||||||
|
toRemote = fromServer;
|
||||||
|
}
|
||||||
|
packet = new DatagramPacket(buf, packet.getLength(), toRemote);
|
||||||
|
in.send(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( IOException ioException)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
System.out.println("oops");
|
||||||
|
}
|
||||||
|
// socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fromServer(byte[] buffer, int length)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// reply from server
|
||||||
|
if (handler != null) {
|
||||||
|
handler.fromServer(buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (PacketException packetException)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fromClient(byte[] buffer, int length)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// reply from client
|
||||||
|
if (handler != null) {
|
||||||
|
handler.fromClient(buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (PacketException packetException)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
|
||||||
|
import org.artisanlogiciel.games.minetest.core.PacketException;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.Serialize;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.v3s16;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class NetworkPacket {
|
||||||
|
|
||||||
|
int m_protocol_id;
|
||||||
|
int m_peer_id;
|
||||||
|
int m_channel;
|
||||||
|
public PacketType packetType;
|
||||||
|
|
||||||
|
// somehow a BufferedPacket ...
|
||||||
|
byte[] m_buffer; // m_data
|
||||||
|
// used part in buffer
|
||||||
|
int m_length; // m_datasize ?
|
||||||
|
// current header index in packet
|
||||||
|
int m_offset; // m_read_offset
|
||||||
|
|
||||||
|
short m_command = 0;
|
||||||
|
|
||||||
|
public NetworkPacket(int protocol_id, int peer_id, int channel, PacketType type, byte[] buffer, int length) {
|
||||||
|
this.m_protocol_id = protocol_id;
|
||||||
|
this.m_peer_id = peer_id;
|
||||||
|
this.m_channel = channel;
|
||||||
|
this.packetType = type;
|
||||||
|
m_buffer = buffer;
|
||||||
|
m_length = length;
|
||||||
|
m_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChannel()
|
||||||
|
{
|
||||||
|
return m_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBuffer()
|
||||||
|
{
|
||||||
|
return m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOffset() {
|
||||||
|
return m_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return m_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addOffset(int offset)
|
||||||
|
{
|
||||||
|
m_offset += offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialization
|
||||||
|
public v3s16 v3s16()
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
return Serialize.readV3S16(m_buffer, m_offset, m_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer getByteBuffer()
|
||||||
|
{
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(m_buffer,m_offset,m_length-m_offset);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
287
java/org/artisanlogiciel/games/minetest/net/PacketHandler.java
Normal file
287
java/org/artisanlogiciel/games/minetest/net/PacketHandler.java
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
import com.github.luben.zstd.Zstd;
|
||||||
|
import org.artisanlogiciel.games.minetest.MapBlock;
|
||||||
|
import org.artisanlogiciel.games.minetest.MapNode;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.PacketException;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.Serialize;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.v2s16;
|
||||||
|
import org.artisanlogiciel.games.minetest.core.v3s16;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see src/network/networkprotocol.h of minetest sources
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* === NOTES ===
|
||||||
|
*
|
||||||
|
* A packet is sent through a channel to a peer with a basic header:
|
||||||
|
* Header (7 bytes):
|
||||||
|
* [0] u32 protocol_id
|
||||||
|
* [4] session_t sender_peer_id
|
||||||
|
* [6] u8 channel
|
||||||
|
* sender_peer_id:
|
||||||
|
* Unique to each peer.
|
||||||
|
* value 0 (PEER_ID_INEXISTENT) is reserved for making new connections
|
||||||
|
* value 1 (PEER_ID_SERVER) is reserved for server
|
||||||
|
* these constants are defined in constants.h
|
||||||
|
* channel:
|
||||||
|
* Channel numbers have no intrinsic meaning. Currently only 0, 1, 2 exist.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
|
||||||
|
public class PacketHandler {
|
||||||
|
|
||||||
|
ReliablePacketBuffer reliableBuffer = null;
|
||||||
|
|
||||||
|
IncomingSplitBuffer[] incomingChanneleSplitBuffer = new IncomingSplitBuffer[4];
|
||||||
|
|
||||||
|
// server serialization in hello version
|
||||||
|
int ser_version;
|
||||||
|
|
||||||
|
// minetest protocol should be 0x4f457403
|
||||||
|
static int readProtocolId(byte[] buffer, int length)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
return Serialize.readU32(buffer, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int readPeerId(byte[] buffer, int length)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
return Serialize.readU16(buffer,4,length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int readChannel(byte[] buffer, int length)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
return Serialize.readU8(buffer, 6, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkPacket handleAny(byte[] buffer, int length)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
int protocol_id = readProtocolId(buffer, length);
|
||||||
|
int peer_id = readPeerId(buffer, length);
|
||||||
|
int channel = readChannel(buffer, length);
|
||||||
|
int type = Serialize.readU8(buffer,7,length);
|
||||||
|
PacketType packetType = PacketType.getPacketType(type);
|
||||||
|
|
||||||
|
NetworkPacket networkPacket = new NetworkPacket(protocol_id,peer_id,channel,packetType, buffer, length);
|
||||||
|
|
||||||
|
// offset of packet within buffer.
|
||||||
|
networkPacket.addOffset(BufferedPacket.BASE_HEADER_SIZE);
|
||||||
|
|
||||||
|
System.out.println("length " + length + " protocol_id " + String.format("%x", protocol_id) + " peer_id " + peer_id + " channel " + channel + " type " + packetType);
|
||||||
|
|
||||||
|
return networkPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlePacketType_Control(NetworkPacket networkPacket)
|
||||||
|
throws PacketException {
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlePacketType_Reliable(NetworkPacket networkPacket)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
// TODO handle misordered...
|
||||||
|
/*
|
||||||
|
if ( reliableBuffer == null )
|
||||||
|
{
|
||||||
|
reliableBuffer = new ReliablePacketBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedPacket packet = new BufferedPacket(buffer);
|
||||||
|
int nextExpected = 0;
|
||||||
|
reliableBuffer.insert(packet, nextExpected);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// handle nested packet
|
||||||
|
networkPacket.addOffset(3);
|
||||||
|
int offset = networkPacket.getOffset();
|
||||||
|
byte buffer[] = networkPacket.getBuffer();
|
||||||
|
int length = networkPacket.getLength();
|
||||||
|
|
||||||
|
PacketType packetType = PacketType.getPacketType(Serialize.readU8(buffer,offset,length));
|
||||||
|
|
||||||
|
System.out.println( "reliable " + packetType.toString());
|
||||||
|
|
||||||
|
switch (packetType)
|
||||||
|
{
|
||||||
|
case PACKET_TYPE_CONTROL:
|
||||||
|
//
|
||||||
|
handlePacketType_Control(networkPacket);
|
||||||
|
break;
|
||||||
|
case PACKET_TYPE_ORIGINAL:
|
||||||
|
handlePacketType_Original(networkPacket);
|
||||||
|
break;
|
||||||
|
case PACKET_TYPE_SPLIT:
|
||||||
|
handlePacketType_Split(networkPacket);
|
||||||
|
break;
|
||||||
|
case PACKET_TYPE_RELIABLE:
|
||||||
|
// this is an error, no nested reliable accepted.
|
||||||
|
throw new PacketException("nested reliable");
|
||||||
|
default: // error
|
||||||
|
throw new PacketException("unknown type");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleCommand_Hello(NetworkPacket networkPacket)
|
||||||
|
throws PacketException {
|
||||||
|
|
||||||
|
// u8 deployed serialisation version
|
||||||
|
ByteBuffer buffer = networkPacket.getByteBuffer();
|
||||||
|
int ser_ver = Serialize.readU8(buffer);
|
||||||
|
ser_version = ser_ver;
|
||||||
|
// u16 deployed network compression mode
|
||||||
|
int net_compress = Serialize.readU16(buffer);
|
||||||
|
// u16 deployed protocol version
|
||||||
|
int deployed = Serialize.readU16(buffer);
|
||||||
|
System.out.println(String.format("HELLO ser_ver=%d net_compress %d deployed %d", ser_ver,net_compress,deployed));
|
||||||
|
// u32 supported auth methods
|
||||||
|
// std::string username that should be used for legacy hash (for proper casing)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// clientpackethandler.cpp Client::handleCommand_BlockData(NetworkPacket* pkt)
|
||||||
|
// TOCLIENT_BLOCKDATA
|
||||||
|
void handleCommand_BlockData(NetworkPacket networkPacket)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
v3s16 p = networkPacket.v3s16();
|
||||||
|
|
||||||
|
// will be used to get vector...
|
||||||
|
// v2s16 p2d = new v2s16(p.X,p.Z);
|
||||||
|
|
||||||
|
System.out.println(String.format(" (X,Y,Z) %d %d %d", p.X, p.Y,p.Z));
|
||||||
|
//
|
||||||
|
networkPacket.addOffset(6);
|
||||||
|
|
||||||
|
// FIXME get it from handshake
|
||||||
|
int version = 28;
|
||||||
|
|
||||||
|
// Should be a MapBlock
|
||||||
|
MapBlock block = new MapBlock();
|
||||||
|
block.deSerialize(networkPacket.getByteBuffer(),version);
|
||||||
|
|
||||||
|
// now we have a block ! what to do with it ?
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlePacketCommand(NetworkPacket networkPacket)
|
||||||
|
throws PacketException {
|
||||||
|
|
||||||
|
// consume type and ??? well ... 2
|
||||||
|
int command = Serialize.readU16(networkPacket.getBuffer(),networkPacket.getOffset(),networkPacket.getLength());
|
||||||
|
|
||||||
|
System.out.println(String.format("command %x length %d", command, networkPacket.getLength()));
|
||||||
|
|
||||||
|
networkPacket.addOffset(2);
|
||||||
|
// Original ... toClient - toServer
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case 0x02:
|
||||||
|
{
|
||||||
|
System.out.println("TOCLIENT_HELLO");
|
||||||
|
handleCommand_Hello(networkPacket);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
{
|
||||||
|
System.out.println("TOCLIENT_BLOCKDATA");
|
||||||
|
handleCommand_BlockData(networkPacket);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x4f:
|
||||||
|
{
|
||||||
|
//TOCLIENT_SET_SKY = 0x4f,
|
||||||
|
System.out.println("TOCLIENT_SET_SKY");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlePacketType_Original(NetworkPacket networkPacket)
|
||||||
|
throws PacketException {
|
||||||
|
|
||||||
|
// eat original type 1.
|
||||||
|
networkPacket.addOffset(1);
|
||||||
|
handlePacketCommand(networkPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlePacketType_Split(NetworkPacket networkPacket)
|
||||||
|
throws PacketException {
|
||||||
|
|
||||||
|
int channel = networkPacket.getChannel();
|
||||||
|
if ( channel < incomingChanneleSplitBuffer.length) {
|
||||||
|
IncomingSplitBuffer splitBuffer = incomingChanneleSplitBuffer[channel];
|
||||||
|
if ( splitBuffer == null )
|
||||||
|
{
|
||||||
|
splitBuffer = new IncomingSplitBuffer();
|
||||||
|
incomingChanneleSplitBuffer[channel] = splitBuffer;
|
||||||
|
}
|
||||||
|
if ( splitBuffer != null ) {
|
||||||
|
BufferedPacket bufferedPacket = splitBuffer.insert(networkPacket);
|
||||||
|
if ( bufferedPacket != null ) {
|
||||||
|
// well should handle it.
|
||||||
|
System.out.println("Reassembled packet size " + bufferedPacket.m_data.length);
|
||||||
|
// reset it.
|
||||||
|
incomingChanneleSplitBuffer[channel] = new IncomingSplitBuffer();
|
||||||
|
handleBufferedPacket(bufferedPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new PacketException("invalid channel " + channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleBufferedPacket(BufferedPacket bufferedPacket)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
// FIXME, why a BufferedPacket anyway since we finaly need a NetworkPacket ?
|
||||||
|
NetworkPacket networkPacket = new NetworkPacket(0,0,0, PacketType.PACKET_TYPE_ORIGINAL,bufferedPacket.m_data, bufferedPacket.size());
|
||||||
|
networkPacket.addOffset(BufferedPacket.BASE_HEADER_SIZE);
|
||||||
|
handlePacketCommand(networkPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fromServer(byte[] buffer, int length)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
System.out.print(" <- ");
|
||||||
|
NetworkPacket networkPacket = handleAny(buffer,length);
|
||||||
|
|
||||||
|
switch (networkPacket.packetType)
|
||||||
|
{
|
||||||
|
case PACKET_TYPE_CONTROL:
|
||||||
|
//
|
||||||
|
handlePacketType_Control(networkPacket);
|
||||||
|
break;
|
||||||
|
case PACKET_TYPE_RELIABLE:
|
||||||
|
//
|
||||||
|
handlePacketType_Reliable(networkPacket);
|
||||||
|
break;
|
||||||
|
case PACKET_TYPE_ORIGINAL:
|
||||||
|
handlePacketType_Original(networkPacket);
|
||||||
|
break;
|
||||||
|
case PACKET_TYPE_SPLIT:
|
||||||
|
handlePacketType_Split(networkPacket);
|
||||||
|
break;
|
||||||
|
default: // error
|
||||||
|
throw new PacketException("unknown type");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void fromClient(byte[] buffer, int length)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
System.out.print(" -> ");
|
||||||
|
handleAny(buffer,length);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
27
java/org/artisanlogiciel/games/minetest/net/PacketType.java
Normal file
27
java/org/artisanlogiciel/games/minetest/net/PacketType.java
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
|
||||||
|
public enum PacketType {
|
||||||
|
PACKET_TYPE_CONTROL,
|
||||||
|
PACKET_TYPE_ORIGINAL,
|
||||||
|
PACKET_TYPE_SPLIT,
|
||||||
|
PACKET_TYPE_RELIABLE,
|
||||||
|
PACKET_TYPE_ERROR;
|
||||||
|
|
||||||
|
static PacketType getPacketType(int value)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return PACKET_TYPE_CONTROL;
|
||||||
|
case 1:
|
||||||
|
return PACKET_TYPE_ORIGINAL;
|
||||||
|
case 2:
|
||||||
|
return PACKET_TYPE_SPLIT;
|
||||||
|
case 3:
|
||||||
|
return PACKET_TYPE_RELIABLE;
|
||||||
|
default:
|
||||||
|
return PACKET_TYPE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.artisanlogiciel.games.minetest.net;
|
||||||
|
|
||||||
|
import org.artisanlogiciel.games.minetest.core.PacketException;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ReliablePacketBuffer {
|
||||||
|
|
||||||
|
List<BufferedPacket> m_list = new LinkedList<>();
|
||||||
|
|
||||||
|
void insert(BufferedPacket packet, int nextExpected)
|
||||||
|
throws PacketException
|
||||||
|
{
|
||||||
|
//
|
||||||
|
int seqNum = packet.getSeqNum();
|
||||||
|
m_list.add(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,5 +3,5 @@ project_default=dist
|
|||||||
project_basedir=$(pwd)
|
project_basedir=$(pwd)
|
||||||
project_mainpackage=org.artisanlogiciel.games
|
project_mainpackage=org.artisanlogiciel.games
|
||||||
project_mainclass=$project_mainpackage.maze.gui.Display
|
project_mainclass=$project_mainpackage.maze.gui.Display
|
||||||
project_version=1.1
|
project_version=1.2
|
||||||
default_args='lab/lab30x30.raw'
|
default_args='lab/lab30x30.raw'
|
||||||
|
|||||||
Reference in New Issue
Block a user