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 + 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 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]