diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000..5524bc41
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,17 @@
+##### What version of ViaBackwards are you using? Type /ver ViaBackwards:
+
+
+##### What version of ViaVersion are you using? Type /ver ViaVersion:
+
+
+##### What version of Spigot are you using? Type /ver:
+
+
+##### What plugins are you using? Type /plugins:
+
+
+##### How/when does this error happen? login?:
+
+
+##### Is there an error in the console? Use pastebin.com. Is there a kick message?:
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..e9707ed1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,130 @@
+# Created by .ignore support plugin (hsz.mobi)
+### Maven template
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+### NetBeans template
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+nbactions.xml
+.nb-gradle/
+### Eclipse template
+
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+.recommenders
+
+# Eclipse Core
+.project
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# PyDev specific (Python IDE for Eclipse)
+*.pydevproject
+
+# CDT-specific (C/C++ Development Tooling)
+.cproject
+
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+# Java annotation processor (APT)
+.factorypath
+
+# PDT-specific (PHP Development Tools)
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# Tern plugin
+.tern-project
+
+# TeXlipse plugin
+.texlipse
+
+# STS (Spring Tool Suite)
+.springBeans
+
+# Code Recommenders
+.recommenders/
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/dictionaries
+.idea/vcs.xml
+.idea/jsLibraryMappings.xml
+
+# Sensitive or high-churn files:
+.idea/dataSources.ids
+.idea/dataSources.xml
+.idea/dataSources.local.xml
+.idea/sqlDataSources.xml
+.idea/dynamic.xml
+.idea/uiDesigner.xml
+
+# Gradle:
+.idea/gradle.xml
+.idea/libraries
+
+# Mongo Explorer plugin:
+.idea/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+### Java template
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..197a1d22
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+# ViaBackwards
+
+Allows 1.9.x on a 1.10 Spigot server.
+Requires [ViaVersion](http://viaversion.com) to be installed
+
+TODO:
+- [ ] Cleanup code
+- [ ] Improve the rewriters
+- [ ] Make it possible to send metadata with the rewriteEntityId
+- [ ] Add support for sound names
+- [ ] Create JavaDocs
+- [ ] Improve the Entity tracker system to work good with multiple versions.
+- [ ] Make it possible to choose your own replacement blocks
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 00000000..49cff8ae
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,106 @@
+
+
+
+
+ 4.0.0
+
+ nl.matsv
+ viabackwards
+ 1.0
+
+
+
+ spigot-repo
+ https://hub.spigotmc.org/nexus/content/repositories/snapshots/
+
+
+ viaversion-repo
+ https://repo.viaversion.com/
+
+
+
+
+
+ org.spigotmc
+ spigot-api
+ 1.10.2-R0.1-SNAPSHOT
+ provided
+
+
+ us.myles
+ viaversion
+ 0.9.8-SNAPSHOT
+
+
+
+ io.netty
+ netty-all
+ 4.0.20.Final
+ provided
+ true
+
+
+
+ org.projectlombok
+ lombok
+ 1.16.6
+ provided
+
+
+
+
+ ${project.name}-${project.version}
+ src/main/java
+ clean install
+
+
+
+ .
+ false
+ .
+
+ LICENSE
+
+
+
+ .
+ true
+ src/main/resources/
+
+ *
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.3
+
+
+ 1.8
+ false
+ false
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/nl/matsv/viabackwards/ViaBackwards.java b/src/main/java/nl/matsv/viabackwards/ViaBackwards.java
new file mode 100644
index 00000000..7f1d3a99
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/ViaBackwards.java
@@ -0,0 +1,35 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards;
+
+import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.Protocol1_9To1_10;
+import org.bukkit.plugin.java.JavaPlugin;
+import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
+import us.myles.ViaVersion.api.protocol.ProtocolVersion;
+
+import java.util.Collections;
+
+public class ViaBackwards extends JavaPlugin {
+
+ @Override
+ public void onEnable() {
+ // Register the protocol
+ ProtocolRegistry.registerProtocol(new Protocol1_9To1_10(), Collections.singletonList(ProtocolVersion.v1_9_3.getId()), ProtocolVersion.v1_10.getId());
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/api/BackwardsProtocol.java b/src/main/java/nl/matsv/viabackwards/api/BackwardsProtocol.java
new file mode 100644
index 00000000..b6ec4fe6
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/api/BackwardsProtocol.java
@@ -0,0 +1,25 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.api;
+
+import us.myles.ViaVersion.api.protocol.Protocol;
+
+public abstract class BackwardsProtocol extends Protocol {
+
+}
diff --git a/src/main/java/nl/matsv/viabackwards/api/MetaRewriter.java b/src/main/java/nl/matsv/viabackwards/api/MetaRewriter.java
new file mode 100644
index 00000000..68725a21
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/api/MetaRewriter.java
@@ -0,0 +1,26 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.api;
+
+import nl.matsv.viabackwards.api.exceptions.RemovedValueException;
+import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
+
+public interface MetaRewriter {
+ Metadata handleMetadata(boolean isObject, int entityType, Metadata data) throws RemovedValueException;
+}
diff --git a/src/main/java/nl/matsv/viabackwards/api/exceptions/RemovedValueException.java b/src/main/java/nl/matsv/viabackwards/api/exceptions/RemovedValueException.java
new file mode 100644
index 00000000..b8f8131c
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/api/exceptions/RemovedValueException.java
@@ -0,0 +1,24 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.api.exceptions;
+
+import java.io.IOException;
+
+public class RemovedValueException extends IOException {
+}
diff --git a/src/main/java/nl/matsv/viabackwards/api/rewriters/BlockItemRewriter.java b/src/main/java/nl/matsv/viabackwards/api/rewriters/BlockItemRewriter.java
new file mode 100644
index 00000000..287c1929
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/api/rewriters/BlockItemRewriter.java
@@ -0,0 +1,115 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.api.rewriters;
+
+import nl.matsv.viabackwards.api.BackwardsProtocol;
+import nl.matsv.viabackwards.utils.Block;
+import nl.matsv.viabackwards.utils.ItemUtil;
+import us.myles.ViaVersion.api.minecraft.item.Item;
+import us.myles.viaversion.libs.opennbt.conversion.builtin.CompoundTagConverter;
+import us.myles.viaversion.libs.opennbt.tag.builtin.*;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public abstract class BlockItemRewriter extends Rewriter {
+ private static final CompoundTagConverter converter = new CompoundTagConverter();
+ private final Map itemRewriter = new ConcurrentHashMap<>();
+ private final Map blockRewriter = new ConcurrentHashMap<>();
+
+ protected void rewriteItem(int oldItem, Item newItem) {
+ itemRewriter.put((short) oldItem, newItem);
+ }
+
+ protected void rewriteBlockItem(int oldId, Item newItem, Block newBlock) {
+ itemRewriter.put((short) oldId, newItem);
+ blockRewriter.put(oldId, newBlock);
+ }
+
+ protected Item handleItemToClient(Item item) {
+ if (item == null)
+ return null;
+ if (!itemRewriter.containsKey(item.getId()))
+ return item;
+ Item i = ItemUtil.copyItem(itemRewriter.get(item.getId()));
+
+ if (i.getTag() == null)
+ i.setTag(new CompoundTag(""));
+ i.getTag().put(createViaNBT(item));
+
+ if (item.getTag() != null)
+ for (Tag ai : item.getTag())
+ i.getTag().put(ai);
+
+ i.setAmount(item.getAmount());
+ return i;
+ }
+
+ protected Item handleItemToServer(Item item) {
+ if (item == null || item.getTag() == null)
+ return null;
+ CompoundTag tag = item.getTag();
+ if (tag.contains("ViaBackwards")) {
+ CompoundTag via = tag.get("ViaBackwards");
+
+ short id = (short) via.get("id").getValue();
+ short data = (short) via.get("data").getValue();
+ byte amount = (byte) via.get("amount").getValue();
+ CompoundTag extras = via.get("extras");
+
+ item.setId(id);
+ item.setData(data);
+ item.setAmount(amount);
+ item.setTag(converter.convert("", converter.convert(extras)));
+ // Remove data tag
+ tag.remove("ViaBackwards");
+ }
+ return item;
+ }
+
+ protected Block handleBlock(int block) {
+ if (!containsBlock(block))
+ return null;
+
+ return blockRewriter.get(block);
+ }
+
+ protected boolean containsBlock(int block) {
+ return blockRewriter.containsKey(block);
+ }
+
+ private CompoundTag createViaNBT(Item i) {
+ CompoundTag tag = new CompoundTag("ViaBackwards");
+ tag.put(new ShortTag("id", i.getId()));
+ tag.put(new ShortTag("data", i.getData()));
+ tag.put(new ByteTag("amount", i.getAmount()));
+ if (i.getTag() != null) {
+ tag.put(converter.convert("extras", converter.convert(i.getTag())));
+ } else
+ tag.put(new CompoundTag("extras"));
+ return tag;
+ }
+
+ protected CompoundTag getNamedTag(String text) {
+ CompoundTag tag = new CompoundTag("");
+ tag.put(new CompoundTag("display"));
+ ((CompoundTag) tag.get("display")).put(new StringTag("Name", text));
+ return tag;
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/api/rewriters/EntityRewriter.java b/src/main/java/nl/matsv/viabackwards/api/rewriters/EntityRewriter.java
new file mode 100644
index 00000000..33a3e152
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/api/rewriters/EntityRewriter.java
@@ -0,0 +1,115 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.api.rewriters;
+
+import lombok.RequiredArgsConstructor;
+import nl.matsv.viabackwards.api.BackwardsProtocol;
+import nl.matsv.viabackwards.api.MetaRewriter;
+import nl.matsv.viabackwards.api.exceptions.RemovedValueException;
+import nl.matsv.viabackwards.api.storage.EntityTracker;
+import nl.matsv.viabackwards.api.storage.EntityType;
+import us.myles.ViaVersion.api.data.UserConnection;
+import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+@RequiredArgsConstructor
+public abstract class EntityRewriter extends Rewriter {
+ private final Map entityTypes = new ConcurrentHashMap<>();
+ private final Map objectTypes = new ConcurrentHashMap<>();
+
+ private final List metaRewriters = new ArrayList<>();
+
+ protected short getNewEntityType(UserConnection connection, int id) {
+ EntityType type = getEntityType(connection, id);
+ if (type.isObject()) {
+ return getNewObjectId(type.getEntityType());
+ } else {
+ return getNewEntityId(type.getEntityType());
+ }
+ }
+
+ protected EntityType getEntityType(UserConnection connection, int id) {
+ return connection.get(EntityTracker.class).getEntityType(id);
+ }
+
+ protected void addTrackedEntity(UserConnection connection, int entityId, boolean isObject, short typeId) {
+ connection.get(EntityTracker.class).trackEntityType(entityId, new EntityType(isObject, typeId));
+ }
+
+ protected void rewriteEntityId(int oldId, int newId) {
+ entityTypes.put((short) oldId, (short) newId);
+ }
+
+ protected boolean isRewriteEntityId(short id) {
+ return entityTypes.containsKey(id);
+ }
+
+ protected short getNewEntityId(short oldId) {
+ if (!isRewriteEntityId(oldId))
+ return oldId;
+ return entityTypes.get(oldId);
+ }
+
+ protected void rewriteObjectId(int oldId, int newId) {
+ objectTypes.put((short) oldId, (short) newId);
+ }
+
+ protected boolean isRewriteObjectId(short id) {
+ return objectTypes.containsKey(id);
+ }
+
+ protected short getNewObjectId(short oldId) {
+ if (!isRewriteObjectId(oldId))
+ return oldId;
+ return objectTypes.get(oldId);
+ }
+
+ public void registerMetaRewriter(MetaRewriter rewriter) {
+ metaRewriters.add(rewriter);
+ }
+
+ protected List handleMeta(UserConnection userConnection, int entityId, List metaData) {
+ EntityTracker tracker = userConnection.get(EntityTracker.class);
+ EntityType type = tracker.getEntityType(entityId);
+
+ List newMeta = new CopyOnWriteArrayList<>();
+ for (Metadata md : metaData) {
+ Metadata nmd = md;
+ try {
+ for (MetaRewriter rewriter : metaRewriters) {
+ if (type != null)
+ nmd = rewriter.handleMetadata(type.isObject(), type.getEntityType(), nmd);
+ else
+ nmd = rewriter.handleMetadata(false, -1, nmd);
+ if (nmd == null)
+ throw new RemovedValueException();
+ }
+ newMeta.add(nmd);
+ } catch (RemovedValueException ignored) {
+ }
+ }
+
+ return newMeta;
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/api/rewriters/Rewriter.java b/src/main/java/nl/matsv/viabackwards/api/rewriters/Rewriter.java
new file mode 100644
index 00000000..9425e872
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/api/rewriters/Rewriter.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.api.rewriters;
+
+import nl.matsv.viabackwards.api.BackwardsProtocol;
+
+public abstract class Rewriter {
+
+ /**
+ * Register everything
+ */
+ public void register(T protocol) {
+ registerPackets(protocol);
+ registerRewrites();
+ }
+
+ /**
+ * Register packet listeners
+ *
+ * @param protocol Protocol instance
+ */
+ protected abstract void registerPackets(T protocol);
+
+ /**
+ * Register rewrites
+ */
+ protected abstract void registerRewrites();
+}
diff --git a/src/main/java/nl/matsv/viabackwards/api/rewriters/SoundIdRewriter.java b/src/main/java/nl/matsv/viabackwards/api/rewriters/SoundIdRewriter.java
new file mode 100644
index 00000000..3077706d
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/api/rewriters/SoundIdRewriter.java
@@ -0,0 +1,59 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.api.rewriters;
+
+import nl.matsv.viabackwards.api.BackwardsProtocol;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public abstract class SoundIdRewriter extends Rewriter {
+ private Map soundRewriter = new ConcurrentHashMap<>();
+ private Map pitchRewriter = new ConcurrentHashMap<>();
+
+ protected void rewriteSound(int newId, int oldId) {
+ soundRewriter.put(newId, oldId);
+ }
+
+ protected void rewriteSound(int newId, int oldId, float newPitch) {
+ rewriteSound(newId, oldId);
+ pitchRewriter.put(newId, newPitch);
+ }
+
+ public int handleSounds(int soundId) {
+ int newSoundId = soundId;
+ if (soundRewriter.containsKey(soundId))
+ newSoundId = soundId = soundRewriter.get(soundId);
+ for (Integer i : soundRewriter.keySet()) {
+ if (soundId > i)
+ newSoundId--;
+ }
+ return newSoundId;
+ }
+
+ public boolean hasPitch(int soundId) {
+ return pitchRewriter.containsKey(soundId);
+ }
+
+ public float handlePitch(int soundId) {
+ if (pitchRewriter.containsKey(soundId))
+ return pitchRewriter.get(soundId);
+ return -1;
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/api/storage/EntityTracker.java b/src/main/java/nl/matsv/viabackwards/api/storage/EntityTracker.java
new file mode 100644
index 00000000..bb0bb8e3
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/api/storage/EntityTracker.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.api.storage;
+
+import us.myles.ViaVersion.api.data.StoredObject;
+import us.myles.ViaVersion.api.data.UserConnection;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class EntityTracker extends StoredObject {
+ private Map entityMap = new ConcurrentHashMap<>();
+
+ public EntityTracker(UserConnection user) {
+ super(user);
+ }
+
+ public void trackEntityType(int id, EntityType type) {
+ if (entityMap.containsKey(id))
+ return;
+ entityMap.put(id, type);
+ }
+
+ public void removeEntity(int id) {
+ entityMap.remove(id);
+ }
+
+ public EntityType getEntityType(int id) {
+ return entityMap.get(id);
+ }
+
+ public boolean containsEntity(int id) {
+ return entityMap.containsKey(id);
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/api/storage/EntityType.java b/src/main/java/nl/matsv/viabackwards/api/storage/EntityType.java
new file mode 100644
index 00000000..92597009
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/api/storage/EntityType.java
@@ -0,0 +1,31 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.api.storage;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@AllArgsConstructor
+@EqualsAndHashCode
+public class EntityType {
+ private boolean object;
+ private short entityType;
+}
diff --git a/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/Protocol1_9To1_10.java b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/Protocol1_9To1_10.java
new file mode 100644
index 00000000..24d1b994
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/Protocol1_9To1_10.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.protocol.protocol1_9_4to1_10;
+
+import lombok.Getter;
+import nl.matsv.viabackwards.api.BackwardsProtocol;
+import nl.matsv.viabackwards.api.storage.EntityTracker;
+import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.packets.BlockItemPackets;
+import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.packets.ChangedPackets;
+import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.packets.EntityPackets;
+import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.packets.SoundPackets;
+import us.myles.ViaVersion.api.data.UserConnection;
+import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
+
+@Getter
+public class Protocol1_9To1_10 extends BackwardsProtocol {
+ private EntityPackets entityPackets; // Required for the item rewriter
+
+ protected void registerPackets() {
+ new ChangedPackets().register(this);
+ new SoundPackets().register(this);
+ (entityPackets = new EntityPackets()).register(this);
+ new BlockItemPackets().register(this);
+ }
+
+ public void init(UserConnection user) {
+ user.put(new ClientWorld(user));
+
+ // Register EntityTracker if it doesn't exist yet.
+ if (!user.has(EntityTracker.class))
+ user.put(new EntityTracker(user));
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/chunks/Chunk1_10.java b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/chunks/Chunk1_10.java
new file mode 100644
index 00000000..f46b9df9
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/chunks/Chunk1_10.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.chunks;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
+import us.myles.viaversion.libs.opennbt.tag.builtin.CompoundTag;
+
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+public class Chunk1_10 implements Chunk {
+ private int x;
+ private int z;
+ private boolean groundUp;
+ private int bitmask;
+ private ChunkSection1_10[] sections;
+ private byte[] biomeData;
+ List blockEntities;
+
+ @Override
+ public boolean isBiomeData() {
+ return biomeData != null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/chunks/Chunk1_10Type.java b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/chunks/Chunk1_10Type.java
new file mode 100644
index 00000000..e55db7f1
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/chunks/Chunk1_10Type.java
@@ -0,0 +1,122 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.chunks;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.bukkit.World;
+import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
+import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection;
+import us.myles.ViaVersion.api.type.PartialType;
+import us.myles.ViaVersion.api.type.Type;
+import us.myles.ViaVersion.api.type.types.minecraft.BaseChunkType;
+import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
+import us.myles.viaversion.libs.opennbt.tag.builtin.CompoundTag;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.List;
+
+public class Chunk1_10Type extends PartialType {
+
+ public Chunk1_10Type(ClientWorld param) {
+ super(param, Chunk.class);
+ }
+
+ @Override
+ public Chunk read(ByteBuf input, ClientWorld world) throws Exception {
+ int chunkX = input.readInt();
+ int chunkZ = input.readInt();
+
+ boolean groundUp = input.readBoolean();
+ int primaryBitmask = Type.VAR_INT.read(input);
+ int size = Type.VAR_INT.read(input);
+
+ BitSet usedSections = new BitSet(16);
+ ChunkSection1_10[] sections = new ChunkSection1_10[16];
+ // Calculate section count from bitmask
+ for (int i = 0; i < 16; i++) {
+ if ((primaryBitmask & (1 << i)) != 0) {
+ usedSections.set(i);
+ }
+ }
+
+ // Read sections
+ for (int i = 0; i < 16; i++) {
+ if (!usedSections.get(i)) continue; // Section not set
+ ChunkSection1_10 section = new ChunkSection1_10();
+ sections[i] = section;
+ section.readBlocks(input);
+ section.readBlockLight(input);
+ if (world.getEnvironment() == World.Environment.NORMAL) {
+ section.readSkyLight(input);
+ }
+ }
+
+ byte[] biomeData = groundUp ? new byte[256] : null;
+ if (groundUp) {
+ input.readBytes(biomeData);
+ }
+
+ List nbtData = Arrays.asList(Type.NBT_ARRAY.read(input));
+
+ return new Chunk1_10(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData);
+ }
+
+ @Override
+ public void write(ByteBuf output, ClientWorld world, Chunk input) throws Exception {
+ if (!(input instanceof Chunk1_10))
+ throw new Exception("Tried to send the wrong chunk type from 1.9.3-4 chunk: " + input.getClass());
+ Chunk1_10 chunk = (Chunk1_10) input;
+
+ output.writeInt(chunk.getX());
+ output.writeInt(chunk.getZ());
+
+ output.writeBoolean(chunk.isGroundUp());
+ Type.VAR_INT.write(output, chunk.getBitmask());
+
+ ByteBuf buf = Unpooled.buffer();
+ for (int i = 0; i < 16; i++) {
+ ChunkSection section = chunk.getSections()[i];
+ if (section == null) continue; // Section not set
+ section.writeBlocks(buf);
+ section.writeBlockLight(buf);
+
+ if (!section.hasSkyLight()) continue; // No sky light, we're done here.
+ section.writeSkyLight(buf);
+
+ }
+ buf.readerIndex(0);
+ Type.VAR_INT.write(output, buf.readableBytes() + (chunk.isBiomeData() ? 256 : 0));
+ output.writeBytes(buf);
+ buf.release(); // release buffer
+
+ // Write biome data
+ if (chunk.isBiomeData()) {
+ output.writeBytes(chunk.getBiomeData());
+ }
+
+ Type.NBT_ARRAY.write(output, chunk.getBlockEntities().toArray(new CompoundTag[0]));
+ }
+
+ @Override
+ public Class extends Type> getBaseClass() {
+ return BaseChunkType.class;
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/chunks/ChunkSection1_10.java b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/chunks/ChunkSection1_10.java
new file mode 100644
index 00000000..f1c84c6b
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/chunks/ChunkSection1_10.java
@@ -0,0 +1,314 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.chunks;
+
+import com.google.common.collect.Lists;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import lombok.Getter;
+import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection;
+import us.myles.ViaVersion.api.minecraft.chunks.NibbleArray;
+import us.myles.ViaVersion.api.type.Type;
+
+import java.util.List;
+
+/**
+ * From the ViaVersion code {@link us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.chunks.ChunkSection1_9_1_2}
+ */
+public class ChunkSection1_10 implements ChunkSection {
+ /**
+ * Size (dimensions) of blocks in a chunks section.
+ */
+ public static final int SIZE = 16 * 16 * 16; // width * depth * height
+ /**
+ * Length of the sky and block light nibble arrays.
+ */
+ public static final int LIGHT_LENGTH = 16 * 16 * 16 / 2; // size * size * size / 2 (nibble bit count)
+ /**
+ * Length of the block data array.
+ */
+ @Getter
+ private final List palette = Lists.newArrayList();
+ private final int[] blocks;
+ private final NibbleArray blockLight;
+ private NibbleArray skyLight;
+
+ public ChunkSection1_10() {
+ this.blocks = new int[SIZE];
+ this.blockLight = new NibbleArray(SIZE);
+ palette.add(0); // AIR
+ }
+
+ /**
+ * Set a block in the chunks
+ *
+ * @param x Block X
+ * @param y Block Y
+ * @param z Block Z
+ * @param type The type of the block
+ * @param data The data value of the block
+ */
+ public void setBlock(int x, int y, int z, int type, int data) {
+ setBlock(index(x, y, z), type, data);
+ }
+
+ public int getBlockId(int x, int y, int z) {
+ int index = blocks[index(x, y, z)];
+ return palette.get(index) >> 4;
+ }
+
+ /**
+ * Set a block in the chunks based on the index
+ *
+ * @param idx Index
+ * @param type The type of the block
+ * @param data The data value of the block
+ */
+ public void setBlock(int idx, int type, int data) {
+ int hash = type << 4 | (data & 0xF);
+ int index = palette.indexOf(hash);
+ if (index == -1) {
+ index = palette.size();
+ palette.add(hash);
+ }
+
+ blocks[idx] = index;
+ }
+
+ /**
+ * Set the block light array
+ *
+ * @param data The value to set the block light to
+ */
+ public void setBlockLight(byte[] data) {
+ blockLight.setHandle(data);
+ }
+
+ /**
+ * Set the sky light array
+ *
+ * @param data The value to set the sky light to
+ */
+ public void setSkyLight(byte[] data) {
+ if (data.length != LIGHT_LENGTH) throw new IllegalArgumentException("Data length != " + LIGHT_LENGTH);
+ this.skyLight = new NibbleArray(data);
+ }
+
+ private int index(int x, int y, int z) {
+ return y << 8 | z << 4 | x;
+ }
+
+ /**
+ * Read blocks from input stream.
+ * This reads all the block related data:
+ *
+ *
Block length/palette type
+ *
Palette
+ *
Block hashes/palette reference
+ *
+ *
+ * @param input The buffer to read from.
+ * @throws Exception
+ */
+ public void readBlocks(ByteBuf input) throws Exception {
+ palette.clear();
+
+ // Reaad bits per block
+ int bitsPerBlock = input.readUnsignedByte();
+ long maxEntryValue = (1L << bitsPerBlock) - 1;
+
+ if (bitsPerBlock == 0) {
+ bitsPerBlock = 13;
+ }
+ if (bitsPerBlock < 4) {
+ bitsPerBlock = 4;
+ }
+ if (bitsPerBlock > 8) {
+ bitsPerBlock = 13;
+ }
+ int paletteLength = Type.VAR_INT.read(input);
+ // Read palette
+ for (int i = 0; i < paletteLength; i++) {
+ if (bitsPerBlock != 13) {
+ palette.add(Type.VAR_INT.read(input));
+ } else {
+ Type.VAR_INT.read(input);
+ }
+ }
+
+ // Read blocks
+ Long[] blockData = Type.LONG_ARRAY.read(input);
+ if (blockData.length > 0) {
+ for (int i = 0; i < blocks.length; i++) {
+ int bitIndex = i * bitsPerBlock;
+ int startIndex = bitIndex / 64;
+ int endIndex = ((i + 1) * bitsPerBlock - 1) / 64;
+ int startBitSubIndex = bitIndex % 64;
+ int val;
+ if (startIndex == endIndex) {
+ val = (int) (blockData[startIndex] >>> startBitSubIndex & maxEntryValue);
+ } else {
+ int endBitSubIndex = 64 - startBitSubIndex;
+ val = (int) ((blockData[startIndex] >>> startBitSubIndex | blockData[endIndex] << endBitSubIndex) & maxEntryValue);
+ }
+
+ if (bitsPerBlock == 13) {
+ int type = val >> 4;
+ int data = val & 0xF;
+
+ setBlock(i, type, data);
+ } else {
+ blocks[i] = val;
+ }
+ }
+ }
+ }
+
+ /**
+ * Read block light from buffer.
+ *
+ * @param input The buffer to read from
+ */
+ public void readBlockLight(ByteBuf input) {
+ byte[] handle = new byte[LIGHT_LENGTH];
+ input.readBytes(handle);
+ blockLight.setHandle(handle);
+ }
+
+ /**
+ * Read sky light from buffer.
+ * Note: Only sent in overworld!
+ *
+ * @param input The buffer to read from
+ */
+ public void readSkyLight(ByteBuf input) {
+ byte[] handle = new byte[LIGHT_LENGTH];
+ input.readBytes(handle);
+ if (skyLight != null) {
+ skyLight.setHandle(handle);
+ return;
+ }
+
+ this.skyLight = new NibbleArray(handle);
+ }
+
+ /**
+ * Write the blocks to a buffer.
+ *
+ * @param output The buffer to write to.
+ * @throws Exception Throws if it failed to write.
+ */
+ public void writeBlocks(ByteBuf output) throws Exception {
+ // Write bits per block
+ int bitsPerBlock = 4;
+ while (palette.size() > 1 << bitsPerBlock) {
+ bitsPerBlock += 1;
+ }
+ long maxEntryValue = (1L << bitsPerBlock) - 1;
+ output.writeByte(bitsPerBlock);
+
+ // Write pallet (or not)
+ Type.VAR_INT.write(output, palette.size());
+ for (int mappedId : palette) {
+ Type.VAR_INT.write(output, mappedId);
+ }
+
+ int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0);
+ Type.VAR_INT.write(output, length);
+ long[] data = new long[length];
+ for (int index = 0; index < blocks.length; index++) {
+ int value = blocks[index];
+ int bitIndex = index * bitsPerBlock;
+ int startIndex = bitIndex / 64;
+ int endIndex = ((index + 1) * bitsPerBlock - 1) / 64;
+ int startBitSubIndex = bitIndex % 64;
+ data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex;
+ if (startIndex != endIndex) {
+ int endBitSubIndex = 64 - startBitSubIndex;
+ data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex;
+ }
+ }
+ for (long l : data) {
+ Type.LONG.write(output, l);
+ }
+ }
+
+ /**
+ * Write the block light to a buffer
+ *
+ * @param output The buffer to write to
+ */
+ public void writeBlockLight(ByteBuf output) {
+ output.writeBytes(blockLight.getHandle());
+ }
+
+ /**
+ * Write the sky light to a buffer
+ *
+ * @param output The buffer to write to
+ */
+ public void writeSkyLight(ByteBuf output) {
+ output.writeBytes(skyLight.getHandle());
+ }
+
+ /**
+ * Check if sky light is present
+ *
+ * @return True if skylight is present
+ */
+ public boolean hasSkyLight() {
+ return skyLight != null;
+ }
+
+ /**
+ * Get expected size of this chunks section.
+ *
+ * @return Amount of bytes sent by this section
+ * @throws Exception If it failed to calculate bits properly
+ */
+ public int getExpectedSize() throws Exception {
+ int bitsPerBlock = palette.size() > 255 ? 16 : 8;
+ int bytes = 1; // bits per block
+ bytes += paletteBytes(); // palette
+ bytes += countBytes(bitsPerBlock == 16 ? SIZE * 2 : SIZE); // block data length
+ bytes += (palette.size() > 255 ? 2 : 1) * SIZE; // block data
+ bytes += LIGHT_LENGTH; // block light
+ bytes += hasSkyLight() ? LIGHT_LENGTH : 0; // sky light
+ return bytes;
+ }
+
+ private int paletteBytes() throws Exception {
+ // Count bytes used by pallet
+ int bytes = countBytes(palette.size());
+ for (int mappedId : palette) {
+ bytes += countBytes(mappedId);
+ }
+ return bytes;
+ }
+
+ private int countBytes(int value) throws Exception {
+ // Count amount of bytes that would be sent if the value were sent as a VarInt
+ ByteBuf buf = Unpooled.buffer();
+ Type.VAR_INT.write(buf, value);
+ buf.readerIndex(0);
+ int bitCount = buf.readableBytes();
+ buf.release();
+ return bitCount;
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/BlockItemPackets.java b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/BlockItemPackets.java
new file mode 100644
index 00000000..32f92be2
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/BlockItemPackets.java
@@ -0,0 +1,289 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.packets;
+
+import nl.matsv.viabackwards.api.rewriters.BlockItemRewriter;
+import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.Protocol1_9To1_10;
+import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.chunks.Chunk1_10;
+import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.chunks.Chunk1_10Type;
+import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.chunks.ChunkSection1_10;
+import nl.matsv.viabackwards.utils.Block;
+import us.myles.ViaVersion.api.PacketWrapper;
+import us.myles.ViaVersion.api.minecraft.item.Item;
+import us.myles.ViaVersion.api.remapper.PacketHandler;
+import us.myles.ViaVersion.api.remapper.PacketRemapper;
+import us.myles.ViaVersion.api.type.Type;
+import us.myles.ViaVersion.packets.State;
+import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
+
+// TODO REWRITE PLUGINS MESSAGE ITEMS
+public class BlockItemPackets extends BlockItemRewriter {
+
+ protected void registerPackets(Protocol1_9To1_10 protocol) {
+ /* Item packets */
+
+ // Set slot packet
+ protocol.registerOutgoing(State.PLAY, 0x16, 0x16, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.BYTE); // 0 - Window ID
+ map(Type.SHORT); // 1 - Slot ID
+ map(Type.ITEM); // 2 - Slot Value
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ Item stack = wrapper.get(Type.ITEM, 0);
+ wrapper.set(Type.ITEM, 0, handleItemToClient(stack));
+ }
+ });
+ }
+ });
+
+ // Window items packet
+ protocol.registerOutgoing(State.PLAY, 0x14, 0x14, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.UNSIGNED_BYTE); // 0 - Window ID
+ map(Type.ITEM_ARRAY); // 1 - Window Values
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ Item[] stacks = wrapper.get(Type.ITEM_ARRAY, 0);
+ for (int i = 0; i < stacks.length; i++)
+ stacks[i] = handleItemToClient(stacks[i]);
+ }
+ });
+ }
+ });
+
+ // Entity Equipment Packet
+ protocol.registerOutgoing(State.PLAY, 0x3C, 0x3C, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.VAR_INT); // 0 - Entity ID
+ map(Type.VAR_INT); // 1 - Slot ID
+ map(Type.ITEM); // 2 - Item
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ Item stack = wrapper.get(Type.ITEM, 0);
+ wrapper.set(Type.ITEM, 0, handleItemToClient(stack));
+ }
+ });
+ }
+ });
+
+ // Plugin message Packet -> Trading
+ protocol.registerOutgoing(State.PLAY, 0x18, 0x18, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.STRING); // 0 - Channel
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ if (wrapper.get(Type.STRING, 0).equalsIgnoreCase("MC|TrList")) {
+ wrapper.passthrough(Type.INT); // Passthrough Window ID
+
+ int size = wrapper.passthrough(Type.BYTE);
+ for (int i = 0; i < size; i++) {
+ wrapper.write(Type.ITEM, handleItemToClient(wrapper.read(Type.ITEM))); // Input Item
+ wrapper.write(Type.ITEM, handleItemToClient(wrapper.read(Type.ITEM))); // Output Item
+
+ boolean secondItem = wrapper.passthrough(Type.BOOLEAN); // Has second item
+ if (secondItem)
+ wrapper.write(Type.ITEM, handleItemToClient(wrapper.read(Type.ITEM))); // Second Item
+
+ wrapper.passthrough(Type.BOOLEAN); // Trade disabled
+ wrapper.passthrough(Type.INT); // Number of tools uses
+ wrapper.passthrough(Type.INT); // Maximum number of trade uses
+ }
+ }
+ }
+ });
+ }
+ });
+
+ // Click window packet
+ protocol.registerIncoming(State.PLAY, 0x07, 0x07, new
+
+ PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.UNSIGNED_BYTE); // 0 - Window ID
+ map(Type.SHORT); // 1 - Slot
+ map(Type.BYTE); // 2 - Button
+ map(Type.SHORT); // 3 - Action number
+ map(Type.VAR_INT); // 4 - Mode
+ map(Type.ITEM); // 5 - Clicked Item
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ Item item = wrapper.get(Type.ITEM, 0);
+ handleItemToServer(item);
+ }
+ });
+ }
+ }
+
+ );
+
+ // Creative Inventory Action
+ protocol.registerIncoming(State.PLAY, 0x18, 0x18, new
+
+ PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.SHORT); // 0 - Slot
+ map(Type.ITEM); // 1 - Clicked Item
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ Item item = wrapper.get(Type.ITEM, 0);
+ handleItemToServer(item);
+ }
+ });
+ }
+ }
+
+ );
+
+ /* Block packets */
+
+ // Chunk packet
+ protocol.registerOutgoing(State.PLAY, 0x20, 0x20, new
+
+ PacketRemapper() {
+ @Override
+ public void registerMap() {
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
+
+ Chunk1_10Type type = new Chunk1_10Type(clientWorld);
+ Chunk1_10 chunk = (Chunk1_10) wrapper.passthrough(type);
+
+ for (int i = 0; i < chunk.getSections().length; i++) {
+ ChunkSection1_10 section = chunk.getSections()[i];
+ if (section == null)
+ continue;
+
+ for (int x = 0; x < 16; x++) {
+ for (int y = 0; y < 16; y++) {
+ for (int z = 0; z < 16; z++) {
+ int block = section.getBlockId(x, y, z);
+ if (containsBlock(block)) {
+ Block b = handleBlock(block);
+ section.setBlock(x, y, z, b.getId(), b.getData());
+ }
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+ }
+
+ );
+
+ // Block Change Packet
+ protocol.registerOutgoing(State.PLAY, 0x0B, 0x0B, new
+
+ PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.POSITION); // 0 - Block Position
+ map(Type.VAR_INT); // 1 - Block
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ int idx = wrapper.get(Type.VAR_INT, 0);
+ wrapper.set(Type.VAR_INT, 0, handleBlockID(idx));
+ }
+ });
+ }
+ }
+
+ );
+
+ // Multi Block Change Packet
+ protocol.registerOutgoing(State.PLAY, 0x10, 0x10, new
+
+ PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.INT); // 0 - Chunk X
+ map(Type.INT); // 1 - Chunk Z
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ int count = wrapper.passthrough(Type.VAR_INT); // Array length
+
+ for (int i = 0; i < count; i++) {
+ wrapper.passthrough(Type.UNSIGNED_BYTE); // Horizontal position
+ wrapper.passthrough(Type.UNSIGNED_BYTE); // Y coords
+
+ int id = wrapper.read(Type.VAR_INT); // Block ID
+ wrapper.write(Type.VAR_INT, handleBlockID(id));
+ }
+ }
+ });
+ }
+ }
+
+ );
+
+ /* Register Metadata */
+ protocol.getEntityPackets().registerMetaRewriter((isObject, entityType, data) -> {
+ if (data.getTypeID() == 5) // Is Item
+ data.setValue(handleItemToClient((Item) data.getValue()));
+
+ return data;
+ });
+ }
+
+ protected int handleBlockID(int idx) {
+ int type = idx >> 4;
+
+ if (!containsBlock(type))
+ return idx;
+
+ Block b = handleBlock(type);
+ return (b.getId() << 4 | (b.getData() & 15));
+ }
+
+ @Override
+ protected void registerRewrites() {
+ rewriteItem(255, new Item((short) 166, (byte) 1, (short) 0, getNamedTag("1.10 Structure Block"))); // Structure block only item since the structure block is in 1.9
+ rewriteBlockItem(217, new Item((short) 287, (byte) 1, (short) 0, getNamedTag("1.10 Structure Void")), new Block(287, 0)); // Structure void to string
+ rewriteBlockItem(213, new Item((short) 159, (byte) 1, (short) 1, getNamedTag("1.10 Magma Block")), new Block(159, 1)); // Magma block to orange clay
+ rewriteBlockItem(214, new Item((short) 159, (byte) 1, (short) 14, getNamedTag("1.10 Nether Ward Block")), new Block(159, 14)); // Nether wart block to red clay
+ rewriteBlockItem(215, new Item((short) 112, (byte) 1, (short) 0, getNamedTag("1.10 Red Nether Bricks")), new Block(112, 0)); // Red nether brick to nether brick
+ rewriteBlockItem(216, new Item((short) 155, (byte) 1, (short) 0, getNamedTag("1.10 Bone Block")), new Block(155, 0)); // Bone block to quartz
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/ChangedPackets.java b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/ChangedPackets.java
new file mode 100644
index 00000000..8dff0e88
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/ChangedPackets.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.packets;
+
+import nl.matsv.viabackwards.api.BackwardsProtocol;
+import us.myles.ViaVersion.api.remapper.PacketRemapper;
+import us.myles.ViaVersion.api.type.Type;
+import us.myles.ViaVersion.packets.State;
+
+public class ChangedPackets {
+
+ public void register(BackwardsProtocol protocol) {
+ /* ServerBound packets */
+
+ // ResourcePack status
+ protocol.registerIncoming(State.PLAY, 0x16, 0x16, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.STRING, Type.NOTHING); // 0 - Hash
+ map(Type.VAR_INT); // 1 - Result
+ }
+ });
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/EntityPackets.java b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/EntityPackets.java
new file mode 100644
index 00000000..8fa3924a
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/EntityPackets.java
@@ -0,0 +1,366 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.packets;
+
+import nl.matsv.viabackwards.api.exceptions.RemovedValueException;
+import nl.matsv.viabackwards.api.rewriters.EntityRewriter;
+import nl.matsv.viabackwards.api.storage.EntityTracker;
+import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.Protocol1_9To1_10;
+import us.myles.ViaVersion.api.PacketWrapper;
+import us.myles.ViaVersion.api.remapper.PacketHandler;
+import us.myles.ViaVersion.api.remapper.PacketRemapper;
+import us.myles.ViaVersion.api.type.Type;
+import us.myles.ViaVersion.api.type.types.version.Types1_9;
+import us.myles.ViaVersion.packets.State;
+import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
+import us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata.NewType;
+
+public class EntityPackets extends EntityRewriter {
+
+ @Override
+ protected void registerPackets(Protocol1_9To1_10 protocol) {
+
+ // Spawn Object
+ protocol.registerOutgoing(State.PLAY, 0x00, 0x00, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.VAR_INT); // 0 - Entity id
+ map(Type.UUID); // 1 - UUID
+ map(Type.BYTE); // 2 - Type
+
+ // Track Entity
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ addTrackedEntity(
+ wrapper.user(),
+ wrapper.get(Type.VAR_INT, 0),
+ true,
+ wrapper.get(Type.BYTE, 0)
+ );
+ }
+ });
+ }
+ });
+
+ // Spawn Experience Orb
+ protocol.registerOutgoing(State.PLAY, 0x01, 0x01, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.VAR_INT); // 0 - Entity id
+
+ // Track entity
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ addTrackedEntity(
+ wrapper.user(),
+ wrapper.get(Type.VAR_INT, 0),
+ true,
+ (short) 2
+ );
+ }
+ });
+ }
+ });
+
+ // Spawn Global Entity
+ protocol.registerOutgoing(State.PLAY, 0x02, 0x02, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.VAR_INT); // 0 - Entity ID
+ map(Type.BYTE); // 1 - Type
+
+ // Track entity
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ addTrackedEntity(
+ wrapper.user(),
+ wrapper.get(Type.VAR_INT, 0),
+ true,
+ wrapper.get(Type.BYTE, 0)
+ );
+ }
+ });
+ }
+ });
+
+ // Spawn Mob
+ protocol.registerOutgoing(State.PLAY, 0x03, 0x03, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.VAR_INT); // 0 - Entity id
+ map(Type.UUID); // 1 - UUID
+ map(Type.UNSIGNED_BYTE); // 2 - Entity Type
+ map(Type.DOUBLE); // 3 - X
+ map(Type.DOUBLE); // 4 - Y
+ map(Type.DOUBLE); // 5 - Z
+ map(Type.BYTE); // 6 - Yaw
+ map(Type.BYTE); // 7 - Pitch
+ map(Type.BYTE); // 8 - Head Pitch
+ map(Type.SHORT); // 9 - Velocity X
+ map(Type.SHORT); // 10 - Velocity Y
+ map(Type.SHORT); // 11 - Velocity Z
+ map(Types1_9.METADATA_LIST); // 12 - Metadata
+
+ // Track entity
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ addTrackedEntity(
+ wrapper.user(),
+ wrapper.get(Type.VAR_INT, 0),
+ false,
+ wrapper.get(Type.UNSIGNED_BYTE, 0)
+ );
+ }
+ });
+
+ // Rewrite entity ids
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ wrapper.set(Type.UNSIGNED_BYTE, 0,
+ getNewEntityType(
+ wrapper.user(),
+ wrapper.get(Type.VAR_INT, 0)
+ ));
+
+
+ }
+ });
+
+ // Rewrite metadata
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ wrapper.set(
+ Types1_9.METADATA_LIST,
+ 0,
+ handleMeta(
+ wrapper.user(),
+ wrapper.get(Type.VAR_INT, 0),
+ wrapper.get(Types1_9.METADATA_LIST, 0)
+ )
+ );
+ }
+ });
+ }
+ });
+
+ // Spawn Painting
+ protocol.registerOutgoing(State.PLAY, 0x04, 0x04, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.VAR_INT); // 0 - Entity ID
+
+ // Track entity
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ addTrackedEntity(
+ wrapper.user(),
+ wrapper.get(Type.VAR_INT, 0),
+ true,
+ (short) 9
+ );
+ }
+ });
+ }
+ });
+
+ // Join game
+ protocol.registerOutgoing(State.PLAY, 0x23, 0x23, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.INT); // 0 - Entity ID
+ map(Type.UNSIGNED_BYTE); // 1 - Gamemode
+ map(Type.INT); // 2 - Dimension
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ addTrackedEntity(
+ wrapper.user(),
+ wrapper.get(Type.INT, 0),
+ false,
+ (short) -12
+ );
+ }
+ });
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
+ int dimensionId = wrapper.get(Type.INT, 1);
+ clientWorld.setEnvironment(dimensionId);
+ }
+ });
+ }
+ });
+
+ // Respawn Packet (save dimension id)
+ protocol.registerOutgoing(State.PLAY, 0x33, 0x33, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.INT); // 0 - Dimension ID
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
+ int dimensionId = wrapper.get(Type.INT, 0);
+ clientWorld.setEnvironment(dimensionId);
+ }
+ });
+ }
+ });
+
+ // Spawn Player
+ protocol.registerOutgoing(State.PLAY, 0x05, 0x05, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.VAR_INT); // 0 - Entity ID
+ map(Type.UUID); // 1 - Player UUID
+ map(Type.DOUBLE); // 2 - X
+ map(Type.DOUBLE); // 3 - Y
+ map(Type.DOUBLE); // 4 - Z
+ map(Type.BYTE); // 5 - Yaw
+ map(Type.BYTE); // 6 - Pitch
+ map(Types1_9.METADATA_LIST); // 7 - Metadata list
+
+ // Track Entity
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ addTrackedEntity(
+ wrapper.user(),
+ wrapper.get(Type.VAR_INT, 0),
+ false,
+ (short) -12
+ );
+ }
+ });
+
+ // Rewrite Metadata
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ wrapper.set(
+ Types1_9.METADATA_LIST,
+ 0,
+ handleMeta(
+ wrapper.user(),
+ wrapper.get(Type.VAR_INT, 0),
+ wrapper.get(Types1_9.METADATA_LIST, 0)
+ )
+ );
+ }
+ });
+ }
+ });
+
+ // Destroy entities
+ protocol.registerOutgoing(State.PLAY, 0x30, 0x30, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.VAR_INT_ARRAY); // 0 - Entity IDS
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ for (int entity : wrapper.get(Type.VAR_INT_ARRAY, 0))
+ wrapper.user().get(EntityTracker.class).removeEntity(entity);
+ }
+ });
+ }
+ });
+
+ // Metadata packet
+ protocol.registerOutgoing(State.PLAY, 0x39, 0x39, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.VAR_INT); // 0 - Entity ID
+ map(Types1_9.METADATA_LIST); // 1 - Metadata list
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ wrapper.set(
+ Types1_9.METADATA_LIST,
+ 0,
+ handleMeta(
+ wrapper.user(),
+ wrapper.get(Type.VAR_INT, 0),
+ wrapper.get(Types1_9.METADATA_LIST, 0)
+ )
+ );
+ }
+ });
+ }
+ });
+ }
+
+ @Override
+ protected void registerRewrites() {
+ rewriteEntityId(102, 91); // Replace polar bear with sheep
+
+ registerMetaRewriter((isObject, entityType, data) -> { // Change the sheep color when the polar bear is stending up
+ if (!isObject && entityType != 102)
+ return data;
+
+ if (data.getId() == 13) { // is boolean
+ boolean b = (boolean) data.getValue();
+
+ data.setId(13);
+ data.setType(Type.BYTE);
+ data.setTypeID(NewType.Byte.getTypeID());
+ data.setValue(b ? (byte) (14 & 0x0F) : 0);
+ }
+ return data;
+ });
+
+ registerMetaRewriter((isObject, entityType, data) -> { // Change husk to normal zombie
+ if (isObject || entityType != 54)
+ return data;
+
+ if (data.getId() == 13 && data.getTypeID() == 1 && (int) data.getValue() == 6)
+ data.setValue(0);
+ return data;
+ });
+
+ registerMetaRewriter((isObject, entityType, data) -> { // Change stray- to normal skeleton
+ if (isObject || entityType != 51)
+ return data;
+
+ if (data.getId() == 12 && data.getTypeID() == 1 && (int) data.getValue() == 2)
+ data.setValue(0);
+ return data;
+ });
+
+ registerMetaRewriter((isObject, entityType, m) -> {
+ if (m.getId() == 5)
+ throw new RemovedValueException();
+ else if (m.getId() >= 5)
+ m.setId(m.getId() - 1);
+ return m;
+ });
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/SoundPackets.java b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/SoundPackets.java
new file mode 100644
index 00000000..2b071ce5
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/protocol/protocol1_9_4to1_10/packets/SoundPackets.java
@@ -0,0 +1,113 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.packets;
+
+import nl.matsv.viabackwards.api.rewriters.SoundIdRewriter;
+import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.Protocol1_9To1_10;
+import us.myles.ViaVersion.api.PacketWrapper;
+import us.myles.ViaVersion.api.remapper.PacketHandler;
+import us.myles.ViaVersion.api.remapper.PacketRemapper;
+import us.myles.ViaVersion.api.remapper.ValueTransformer;
+import us.myles.ViaVersion.api.type.Type;
+import us.myles.ViaVersion.packets.State;
+
+public class SoundPackets extends SoundIdRewriter {
+ protected static ValueTransformer toOldPitch = new ValueTransformer(Type.UNSIGNED_BYTE) {
+ public Short transform(PacketWrapper packetWrapper, Float inputValue) throws Exception {
+ return (short) Math.round(inputValue * 63.5F);
+ }
+ };
+
+ @Override
+ protected void registerPackets(Protocol1_9To1_10 protocol) {
+ // Named sound effect
+ protocol.registerOutgoing(State.PLAY, 0x19, 0x19, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.STRING); // 0 - Sound name
+ map(Type.VAR_INT); // 1 - Sound Category
+ map(Type.INT); // 2 - x
+ map(Type.INT); // 3 - y
+ map(Type.INT); // 4 - z
+ map(Type.FLOAT); // 5 - Volume
+ map(Type.FLOAT, toOldPitch); // 6 - Pitch
+ }
+ });
+
+ // Sound effect
+ protocol.registerOutgoing(State.PLAY, 0x46, 0x46, new PacketRemapper() {
+ @Override
+ public void registerMap() {
+ map(Type.VAR_INT); // 0 - Sound name
+ map(Type.VAR_INT); // 1 - Sound Category
+ map(Type.INT); // 2 - x
+ map(Type.INT); // 3 - y
+ map(Type.INT); // 4 - z
+ map(Type.FLOAT); // 5 - Volume
+ map(Type.FLOAT, toOldPitch); // 6 - Pitch
+
+ handler(new PacketHandler() {
+ @Override
+ public void handle(PacketWrapper wrapper) throws Exception {
+ int oldId = wrapper.get(Type.VAR_INT, 0);
+ int newId = handleSounds(oldId);
+ if (newId == -1)
+ wrapper.cancel();
+ else {
+ if (hasPitch(oldId))
+ wrapper.set(Type.UNSIGNED_BYTE, 0, (short) Math.round(handlePitch(oldId) * 63.5F));
+ wrapper.set(Type.VAR_INT, 0, newId);
+ }
+ }
+ });
+ }
+ });
+ }
+
+ @Override
+ protected void registerRewrites() {
+ rewriteSound(24, -1); // Enchantment table sound
+
+ // Husk
+ rewriteSound(249, 400); // Husk -> Zombie ambient
+ rewriteSound(250, 404); // Husk -> Zombie death
+ rewriteSound(251, 405); // Husk -> Zombie hurt
+ rewriteSound(252, 407); // Husk -> Zombie step
+
+ // Polar bear
+ rewriteSound(301, 400, .6F); // Polar bear ambient
+ rewriteSound(302, 400, 1.9F); // Polar baby bear ambient
+ rewriteSound(303, 404, .7F); // Polar bear death
+ rewriteSound(304, 320, .6F); // Polar bear hurt
+ rewriteSound(305, 241, .6F); // Polar bear step
+ rewriteSound(306, 393, 1.2F); // Polar bear warning
+
+ // Stray
+ rewriteSound(365, 331); // Stray -> Skeleton ambient
+ rewriteSound(366, 332); // Stray -> Skeleton death
+ rewriteSound(367, 333); // Stray -> Skeleton hurt
+ rewriteSound(368, 335); // Stray -> Skeleton step
+
+ // Wither skeleton
+ rewriteSound(387, 331); // Wither skeleton -> Skeleton ambient
+ rewriteSound(388, 332); // Wither skeleton -> Skeleton death
+ rewriteSound(389, 333); // Wither skeleton -> Skeleton hurt
+ rewriteSound(390, 335); // Wither skeleton -> Skeleton step
+ }
+}
diff --git a/src/main/java/nl/matsv/viabackwards/utils/Block.java b/src/main/java/nl/matsv/viabackwards/utils/Block.java
new file mode 100644
index 00000000..c95b827e
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/utils/Block.java
@@ -0,0 +1,31 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.utils;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@AllArgsConstructor
+@EqualsAndHashCode
+@Data
+public class Block {
+ private int id;
+ private int data;
+}
diff --git a/src/main/java/nl/matsv/viabackwards/utils/ItemUtil.java b/src/main/java/nl/matsv/viabackwards/utils/ItemUtil.java
new file mode 100644
index 00000000..a005de55
--- /dev/null
+++ b/src/main/java/nl/matsv/viabackwards/utils/ItemUtil.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * Copyright (C) 2016 Matsv
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package nl.matsv.viabackwards.utils;
+
+import us.myles.ViaVersion.api.minecraft.item.Item;
+
+public class ItemUtil {
+
+ public static Item copyItem(Item item) {
+ if (item == null) return null;
+ return new Item(item.getId(), item.getAmount(), item.getData(), item.getTag() != null ? item.getTag().clone() : null);
+ }
+}
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 00000000..e16bca99
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,10 @@
+name: ViaBackwards
+version: ${project.version}
+main: nl.matsv.viabackwards.ViaBackwards
+description: Allow
+
+authors: [Matsv]
+website: https://matsv.nl
+
+load: STARTUP
+depend: [ViaVersion]