Compare commits
79 Commits
1.12.2-R0.
...
1.12.2-R0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e912befc0 | ||
|
|
45d6b0c072 | ||
|
|
d596840e83 | ||
|
|
9e06a9fe5c | ||
|
|
452dd1f3b5 | ||
|
|
8dbfbd2650 | ||
|
|
fc17d8fdc7 | ||
|
|
bbd1057666 | ||
|
|
671c5fbc49 | ||
|
|
405a299b36 | ||
|
|
8b6de7576a | ||
|
|
f6f2d1121c | ||
|
|
8a6c36ab2c | ||
|
|
4c622207e1 | ||
|
|
8db031c856 | ||
|
|
7c6627edc8 | ||
|
|
343666756c | ||
|
|
99b9880f0e | ||
|
|
022a6468d5 | ||
|
|
9d5d638670 | ||
|
|
4e920243d1 | ||
|
|
239f83e1d3 | ||
|
|
93588656d1 | ||
|
|
8a9ad35a57 | ||
|
|
e4ed177d7b | ||
|
|
fb7bf16869 | ||
|
|
1e93929534 | ||
|
|
30f6e3f56f | ||
|
|
c55568a01c | ||
|
|
04ff47a598 | ||
|
|
fdec006644 | ||
|
|
3eb2067ffa | ||
|
|
b89d955eb5 | ||
|
|
54205afb71 | ||
|
|
711fc08eeb | ||
|
|
e8dfb64f42 | ||
|
|
a78ae42d9c | ||
|
|
f7792c2510 | ||
|
|
9fedd2d94e | ||
|
|
cf62349837 | ||
|
|
1d9f3a0584 | ||
|
|
8925ac73d4 | ||
|
|
5c39b7eabd | ||
|
|
d8f0674b89 | ||
|
|
cda8c79514 | ||
|
|
080b080c15 | ||
|
|
19e1d0d927 | ||
|
|
974cf681d0 | ||
|
|
3e38351ce7 | ||
|
|
dc30e8c8d5 | ||
|
|
427a4152f3 | ||
|
|
68816a0b5a | ||
|
|
f6e54678bb | ||
|
|
aed67213c2 | ||
|
|
9038d2d2b6 | ||
|
|
eb96ab4f5b | ||
|
|
89ca2f2bc5 | ||
|
|
97798e18ce | ||
|
|
db54c87abd | ||
|
|
f45908ae38 | ||
|
|
2b49aba77c | ||
|
|
bc2a639c52 | ||
|
|
3938713380 | ||
|
|
dc10b10979 | ||
|
|
876bf4d7cd | ||
|
|
3ee0111f24 | ||
|
|
42a90440b9 | ||
|
|
b58e98e0de | ||
|
|
dc9c0655de | ||
|
|
c3e9767dbc | ||
|
|
01ecfef964 | ||
|
|
8a7ebe839c | ||
|
|
c11a88d1ba | ||
|
|
9626867217 | ||
|
|
55248e4deb | ||
|
|
095a6e4d0b | ||
|
|
559896e14b | ||
|
|
6855fbe294 | ||
|
|
41d97284be |
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
---
|
---
|
||||||
> Akarin is a powerful server software form the 'new dimension', formerly known as [Torch](https://github.com/Akarin-project/Torch).
|
> Akarin is a powerful server software form the 'new dimension', formerly known as Torch.
|
||||||
|
|
||||||
As a [Paper](https://github.com/PaperMC/Paper) fork, it supports almost all plugins that [Spigot](https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse) can use.
|
As a [Paper](https://github.com/PaperMC/Paper) fork, it supports almost all plugins that [Spigot](https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse) can use.
|
||||||
|
|
||||||
@@ -20,8 +20,8 @@ Get Akarin
|
|||||||
---
|
---
|
||||||
### Download
|
### Download
|
||||||
#### Recommended Sites
|
#### Recommended Sites
|
||||||
|
+ [**Jenkins**](http://ci.ilummc.com/job/Akarin/) - *Kudos to [Izzel_Aliz](https://github.com/IzzelAliz)*
|
||||||
+ [ **Circle CI**](https://circleci.com/gh/Akarin-project/Akarin/tree/master) - Checkout the 'Artifacts' tab of the latest build *Login required*
|
+ [ **Circle CI**](https://circleci.com/gh/Akarin-project/Akarin/tree/master) - Checkout the 'Artifacts' tab of the latest build *Login required*
|
||||||
+ [ **Jenkins**](http://ci.ilummc.com/job/Akarin/) - *Kudos to [Izzel_Aliz](https://github.com/IzzelAliz)*
|
|
||||||
|
|
||||||
*Contact me via the email below or open an [Issue](https://github.com/Akarin-project/akarin/issues) if you want to add your website here*
|
*Contact me via the email below or open an [Issue](https://github.com/Akarin-project/akarin/issues) if you want to add your website here*
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ Contributing
|
|||||||
---
|
---
|
||||||
* Feel free to open an [Issue](https://github.com/Akarin-project/akarin/issues) if you have any problem with Akarin.
|
* Feel free to open an [Issue](https://github.com/Akarin-project/akarin/issues) if you have any problem with Akarin.
|
||||||
* [Pull Request](https://github.com/Akarin-project/akarin/pulls) is welcomed, Akarin use [Mixin](https://github.com/SpongePowered/Mixin) to modify the code, you can checkout `sources` folder to see them. Moreover, add your name to the [LICENSE](https://github.com/Akarin-project/Akarin/blob/master/LICENSE.md) if you want to publish your code under the [MIT License](https://github.com/Akarin-project/Akarin/blob/master/licenses/MIT.md).
|
* [Pull Request](https://github.com/Akarin-project/akarin/pulls) is welcomed, Akarin use [Mixin](https://github.com/SpongePowered/Mixin) to modify the code, you can checkout `sources` folder to see them. Moreover, add your name to the [LICENSE](https://github.com/Akarin-project/Akarin/blob/master/LICENSE.md) if you want to publish your code under the [MIT License](https://github.com/Akarin-project/Akarin/blob/master/licenses/MIT.md).
|
||||||
* If you want to join the [Akarin-project](https://github.com/Akarin-project) team, you can send an email to `kira@kira.moe` with your experience and necessary information. Besides, welcome to join our [TIM Group](https://jq.qq.com/?_wv=1027&k=59q2kV4) to chat *(Chinese)*.
|
* If you want to join the [Akarin-project](https://github.com/Akarin-project) team, you can send an email to `kira@kira.moe` with your experience and necessary information. Besides, welcome to join our [Discord](https://discord.gg/D3Rsukh) to chat.
|
||||||
* Note that you must `--setup` at least once to deploy necessary dependency otherwise some imports cannot be organized.
|
* Note that you must `--setup` at least once to deploy necessary dependency otherwise some imports cannot be organized.
|
||||||
|
|
||||||

|

|
||||||
@@ -19,7 +19,7 @@ if [ "$2" == "--setup" ] || [ "$3" == "--setup" ] || [ "$4" == "--setup" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cd "$paperbasedir"
|
cd "$paperbasedir"
|
||||||
./paper patch
|
./paper jar
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
0
scripts/inst.sh
Normal file → Executable file
0
scripts/inst.sh
Normal file → Executable file
@@ -3,7 +3,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>akarin</artifactId>
|
<artifactId>akarin</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<version>1.12.2-R0.2.1-RELEASE</version>
|
<version>1.12.2-R0.3-SNAPSHOT</version>
|
||||||
<name>Akarin</name>
|
<name>Akarin</name>
|
||||||
<url>https://github.com/Akarin-project/Akarin</url>
|
<url>https://github.com/Akarin-project/Akarin</url>
|
||||||
|
|
||||||
@@ -126,17 +126,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.akarin</groupId>
|
<groupId>io.akarin</groupId>
|
||||||
<artifactId>legacylauncher</artifactId>
|
<artifactId>legacylauncher</artifactId>
|
||||||
<version>1.20</version>
|
<version>1.23</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spongepowered</groupId>
|
<groupId>org.spongepowered</groupId>
|
||||||
<artifactId>mixin</artifactId>
|
<artifactId>mixin</artifactId>
|
||||||
<version>0.7.8-SNAPSHOT</version>
|
<version>0.7.10-SNAPSHOT</version>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>me.nallar.whocalled</groupId>
|
|
||||||
<artifactId>WhoCalled</artifactId>
|
|
||||||
<version>1.1</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
@@ -177,7 +172,7 @@
|
|||||||
<version>1.3</version>
|
<version>1.3</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<outputPrefix>git-Akarin-</outputPrefix>
|
<outputPrefix>git-Akarin-</outputPrefix>
|
||||||
<scmDirectory>..</scmDirectory>
|
<scmDirectory>../..</scmDirectory> <!-- Akarin -->
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.akarin.api;
|
package io.akarin.api.internal;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@@ -8,47 +8,63 @@ import java.util.concurrent.Executors;
|
|||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.bukkit.entity.Minecart;
|
|
||||||
|
|
||||||
import com.google.common.collect.Queues;
|
import com.google.common.collect.Queues;
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
|
||||||
import co.aikar.timings.Timing;
|
import co.aikar.timings.Timing;
|
||||||
import co.aikar.timings.Timings;
|
import co.aikar.timings.Timings;
|
||||||
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
|
@SuppressWarnings("restriction")
|
||||||
public abstract class Akari {
|
public abstract class Akari {
|
||||||
/**
|
/**
|
||||||
* A common logger used by mixin classes
|
* A common logger used by mixin classes
|
||||||
*/
|
*/
|
||||||
public final static Logger logger = LogManager.getLogger("Akarin");
|
public final static Logger logger = LogManager.getLogger("Akarin");
|
||||||
|
|
||||||
/**
|
|
||||||
* Temporarily disable desync timings error, moreover it's worthless to trace async operation
|
|
||||||
*/
|
|
||||||
public static volatile boolean silentTiming;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A common thread pool factory
|
* A common thread pool factory
|
||||||
*/
|
*/
|
||||||
public static final ThreadFactory STAGE_FACTORY = new ThreadFactoryBuilder().setNameFormat("Akarin Schedule Thread - %1$d").build();
|
public static final ThreadFactory STAGE_FACTORY = new ThreadFactoryBuilder().setNameFormat("Akarin Parallel Registry Thread - %1$d").build();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main thread callback tasks
|
* Main thread callback tasks
|
||||||
*/
|
*/
|
||||||
public static final Queue<Runnable> callbackQueue = Queues.newConcurrentLinkedQueue();
|
public static final Queue<Runnable> callbackQueue = Queues.newConcurrentLinkedQueue();
|
||||||
|
|
||||||
|
public static class AssignableThread extends Thread {
|
||||||
|
public AssignableThread(Runnable run) {
|
||||||
|
super(run);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AssignableFactory implements ThreadFactory {
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable run) {
|
||||||
|
Thread thread = new AssignableThread(run);
|
||||||
|
thread.setName("Akarin Parallel Schedule Thread");
|
||||||
|
thread.setPriority(AkarinGlobalConfig.primaryThreadPriority); // Fair
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A common tick pool
|
* A common tick pool
|
||||||
*/
|
*/
|
||||||
public static final ExecutorCompletionService<?> STAGE_TICK = new ExecutorCompletionService<>(Executors.newSingleThreadExecutor(Akari.STAGE_FACTORY));
|
public static final ExecutorCompletionService<?> STAGE_TICK = new ExecutorCompletionService<>(Executors.newSingleThreadExecutor(new AssignableFactory()));
|
||||||
|
|
||||||
public static volatile boolean mayMock;
|
|
||||||
|
|
||||||
public static boolean isPrimaryThread() {
|
public static boolean isPrimaryThread() {
|
||||||
return Thread.currentThread().equals(MinecraftServer.getServer().primaryThread);
|
return isPrimaryThread(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isPrimaryThread(boolean assign) {
|
||||||
|
Thread current = Thread.currentThread();
|
||||||
|
return current == MinecraftServer.getServer().primaryThread || (assign ? current instanceof AssignableThread : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String EMPTY_STRING = "";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The unsafe
|
* The unsafe
|
||||||
*/
|
*/
|
||||||
@@ -65,10 +81,18 @@ public abstract class Akari {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String serverVersion = Akari.class.getPackage().getImplementationVersion();
|
||||||
|
|
||||||
|
public static String getServerVersion() {
|
||||||
|
return serverVersion + " (MC: " + MinecraftServer.getServer().getVersion() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Timings
|
* Timings
|
||||||
*/
|
*/
|
||||||
public final static Timing worldTiming = getTiming("Akarin - World");
|
public final static Timing worldTiming = getTiming("Akarin - Full World Tick");
|
||||||
|
|
||||||
|
public final static Timing entityCallbackTiming = getTiming("Akarin - Entity Callback");
|
||||||
|
|
||||||
public final static Timing callbackTiming = getTiming("Akarin - Callback");
|
public final static Timing callbackTiming = getTiming("Akarin - Callback");
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.akarin.api;
|
package io.akarin.api.internal;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
* at http://creativecommons.org/publicdomain/zero/1.0/
|
* at http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.akarin.api;
|
package io.akarin.api.internal.collections;
|
||||||
|
|
||||||
import java.util.AbstractQueue;
|
import java.util.AbstractQueue;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -45,6 +45,8 @@ import java.util.Spliterator;
|
|||||||
import java.util.Spliterators;
|
import java.util.Spliterators;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An unbounded thread-safe {@linkplain Queue queue} based on linked nodes.
|
* An unbounded thread-safe {@linkplain Queue queue} based on linked nodes.
|
||||||
* This queue orders elements FIFO (first-in-first-out).
|
* This queue orders elements FIFO (first-in-first-out).
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.akarin.api;
|
package io.akarin.api.internal.collections;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.akarin.api.mixin;
|
package io.akarin.api.internal.mixin;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package io.akarin.api.internal.mixin;
|
||||||
|
|
||||||
|
public interface IMixinLockProvider {
|
||||||
|
public Object lock();
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.api.internal.mixin;
|
||||||
|
|
||||||
|
public interface IMixinRealTimeTicking {
|
||||||
|
|
||||||
|
long getRealTimeTicks();
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.akarin.api.mixin;
|
package io.akarin.api.internal.mixin;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
@@ -3,6 +3,8 @@ package io.akarin.server.core;
|
|||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@@ -14,7 +16,6 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
import org.bukkit.configuration.InvalidConfigurationException;
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import io.akarin.api.Akari;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class AkarinGlobalConfig {
|
public class AkarinGlobalConfig {
|
||||||
@@ -169,39 +170,19 @@ public class AkarinGlobalConfig {
|
|||||||
legacyWorldTimings = getBoolean("alternative.legacy-world-timings-required", false);
|
legacyWorldTimings = getBoolean("alternative.legacy-world-timings-required", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int timeUpdateInterval;
|
public static long timeUpdateInterval;
|
||||||
private static void timeUpdateInterval() {
|
private static void timeUpdateInterval() {
|
||||||
timeUpdateInterval = getSeconds(getString("core.world-time-update-interval", "1s"));
|
timeUpdateInterval = getSeconds(getString("core.tick-rate.world-time-update-interval", "1s")) * 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int keepAliveSendInterval;
|
public static long keepAliveSendInterval;
|
||||||
private static void keepAliveSendInterval() {
|
private static void keepAliveSendInterval() {
|
||||||
keepAliveSendInterval = getSeconds(getString("core.keep-alive-packet-send-interval", "15s"));
|
keepAliveSendInterval = getSeconds(getString("core.tick-rate.keep-alive-packet-send-interval", "15s")) * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int keepAliveTimeout;
|
public static long keepAliveTimeout;
|
||||||
private static void keepAliveTimeout() {
|
private static void keepAliveTimeout() {
|
||||||
keepAliveTimeout = getSeconds(getString("core.keep-alive-response-timeout", "30s"));
|
keepAliveTimeout = getSeconds(getString("core.keep-alive-response-timeout", "30s")) * 1000;
|
||||||
}
|
|
||||||
|
|
||||||
public static int asyncLightingThreads;
|
|
||||||
private static void asyncLightingThreads() {
|
|
||||||
asyncLightingThreads = getInt("core.async-lighting.executor-threads", 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean enableMockPlugin;
|
|
||||||
private static void enableMockPlugin() {
|
|
||||||
enableMockPlugin = getBoolean("core.thread-safe.enable-mock-plugins", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> mockPackageList;
|
|
||||||
private static void mockPluginList() {
|
|
||||||
mockPackageList = getList("core.thread-safe.mock-package-name-contains", Lists.newArrayList("me.konsolas.aac"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean enableAsyncCatcher;
|
|
||||||
private static void enableAsyncCatcher() {
|
|
||||||
enableAsyncCatcher = getBoolean("core.thread-safe.async-catcher.enable", false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean throwOnAsyncCaught;
|
public static boolean throwOnAsyncCaught;
|
||||||
@@ -209,13 +190,93 @@ public class AkarinGlobalConfig {
|
|||||||
throwOnAsyncCaught = getBoolean("core.thread-safe.async-catcher.throw-on-caught", true);
|
throwOnAsyncCaught = getBoolean("core.thread-safe.async-catcher.throw-on-caught", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean asyncLightingWorkStealing;
|
|
||||||
private static void asyncLightingWorkStealing() {
|
|
||||||
asyncLightingWorkStealing = getBoolean("core.async-lighting.use-work-stealing", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean allowSpawnerModify;
|
public static boolean allowSpawnerModify;
|
||||||
private static void allowSpawnerModify() {
|
private static void allowSpawnerModify() {
|
||||||
allowSpawnerModify = getBoolean("alternative.allow-spawner-modify", true);
|
allowSpawnerModify = getBoolean("alternative.allow-spawner-modify", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean noResponseDoGC;
|
||||||
|
private static void noResponseDoGC() {
|
||||||
|
noResponseDoGC = getBoolean("alternative.gc-before-stuck-restart", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String messageKick;
|
||||||
|
private static void messageKick() {
|
||||||
|
messageKick = getString("messages.disconnect.kick-player", "Kicked by an operator.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String messageBan;
|
||||||
|
private static void messageBan() {
|
||||||
|
messageBan = getString("messages.disconnect.ban-player-name", "You are banned from this server! %s %s");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String messageBanReason;
|
||||||
|
private static void messageBanReason() {
|
||||||
|
messageBanReason = getString("messages.disconnect.ban-reason", "\nReason: ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String messageBanExpires;
|
||||||
|
private static void messageBanExpires() {
|
||||||
|
messageBanExpires = getString("messages.disconnect.ban-expires", "\nYour ban will be removed on ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String messageBanIp;
|
||||||
|
private static void messageBanIp() {
|
||||||
|
messageBanIp = getString("messages.disconnect.ban-player-ip", "Your IP address is banned from this server! %s %s");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String messageDupLogin;
|
||||||
|
private static void messageDupLogin() {
|
||||||
|
messageDupLogin = getString("messages.disconnect.kick-player-duplicate-login", "You logged in from another location");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String messageJoin;
|
||||||
|
private static void messageJoin() {
|
||||||
|
messageJoin = getString("messages.connect.player-join-server", "§e%s joined the game");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String messageJoinRenamed;
|
||||||
|
private static void messageJoinRenamed() {
|
||||||
|
messageJoinRenamed = getString("messages.connect.renamed-player-join-server", "§e%s (formerly known as %s) joined the game");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String messageKickKeepAlive;
|
||||||
|
private static void messagekickKeepAlive() {
|
||||||
|
messageKickKeepAlive = getString("messages.disconnect.kick-player-timeout-keep-alive", "Timed out");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String messagePlayerQuit;
|
||||||
|
private static void messagePlayerQuit() {
|
||||||
|
messagePlayerQuit = getString("messages.disconnect.player-quit-server", "§e%s left the game");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String serverBrandName;
|
||||||
|
private static void serverBrandName() {
|
||||||
|
serverBrandName = getString("alternative.modified-server-brand-name", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean disableEndPortalCreate;
|
||||||
|
private static void disableEndPortalCreate() {
|
||||||
|
disableEndPortalCreate = getBoolean("alternative.disable-end-portal-create", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int primaryThreadPriority;
|
||||||
|
private static void primaryThreadPriority() {
|
||||||
|
primaryThreadPriority = getInt("core.primary-thread-priority", 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long playersInfoUpdateInterval;
|
||||||
|
private static void playersInfoUpdateInterval() {
|
||||||
|
playersInfoUpdateInterval = getSeconds(getString("core.tick-rate.players-info-update-interval", "30s")) * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long versionUpdateInterval;
|
||||||
|
private static void versionUpdateInterval() {
|
||||||
|
versionUpdateInterval = getSeconds(getString("alternative.version-update-interval", "3600s")) * 1000; // 1 hour
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean sendLightOnlyChunkSection;
|
||||||
|
private static void sendLightOnlyChunkSection() {
|
||||||
|
sendLightOnlyChunkSection = getBoolean("core.send-light-only-chunk-sections", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
package io.akarin.server.core;
|
package io.akarin.server.core;
|
||||||
|
|
||||||
import io.akarin.api.Akari;
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
import net.minecraft.server.EntityPlayer;
|
import net.minecraft.server.EntityPlayer;
|
||||||
|
import net.minecraft.server.EnumDifficulty;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.PacketPlayOutKeepAlive;
|
import net.minecraft.server.PacketPlayOutKeepAlive;
|
||||||
|
import net.minecraft.server.PacketPlayOutPlayerInfo;
|
||||||
import net.minecraft.server.PacketPlayOutUpdateTime;
|
import net.minecraft.server.PacketPlayOutUpdateTime;
|
||||||
import net.minecraft.server.PlayerConnection;
|
import net.minecraft.server.PlayerConnection;
|
||||||
|
import net.minecraft.server.WorldServer;
|
||||||
|
|
||||||
public class AkarinSlackScheduler extends Thread {
|
public class AkarinSlackScheduler extends Thread {
|
||||||
public static AkarinSlackScheduler get() {
|
public static AkarinSlackScheduler get() {
|
||||||
@@ -24,49 +30,77 @@ public class AkarinSlackScheduler extends Thread {
|
|||||||
private static final AkarinSlackScheduler instance = new AkarinSlackScheduler();
|
private static final AkarinSlackScheduler instance = new AkarinSlackScheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timers
|
||||||
|
*/
|
||||||
private long updateTime;
|
private long updateTime;
|
||||||
|
private long resendPlayersInfo;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
MinecraftServer server = MinecraftServer.getServer();
|
MinecraftServer server = MinecraftServer.getServer();
|
||||||
|
|
||||||
// Send time updates to everyone, it will get the right time from the world the player is in.
|
while (server.isRunning()) {
|
||||||
if (++updateTime == AkarinGlobalConfig.timeUpdateInterval * 10) {
|
// Send time updates to everyone, it will get the right time from the world the player is in.
|
||||||
|
// Time update, from MinecraftServer#D
|
||||||
|
if (++updateTime >= AkarinGlobalConfig.timeUpdateInterval) {
|
||||||
|
for (EntityPlayer player : server.getPlayerList().players) {
|
||||||
|
player.playerConnection.sendPacket(new PacketPlayOutUpdateTime(player.world.getTime(), player.getPlayerTime(), player.world.getGameRules().getBoolean("doDaylightCycle"))); // Add support for per player time
|
||||||
|
}
|
||||||
|
updateTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep alive, from PlayerConnection#e
|
||||||
for (EntityPlayer player : server.getPlayerList().players) {
|
for (EntityPlayer player : server.getPlayerList().players) {
|
||||||
player.playerConnection.sendPacket(new PacketPlayOutUpdateTime(player.world.getTime(), player.getPlayerTime(), player.world.getGameRules().getBoolean("doDaylightCycle"))); // Add support for per player time
|
PlayerConnection conn = player.playerConnection;
|
||||||
}
|
// Paper - give clients a longer time to respond to pings as per pre 1.12.2 timings
|
||||||
updateTime = 0;
|
// This should effectively place the keepalive handling back to "as it was" before 1.12.2
|
||||||
}
|
long currentTime = System.nanoTime() / 1000000L;
|
||||||
|
long elapsedTime = currentTime - conn.getLastPing();
|
||||||
for (EntityPlayer player : server.getPlayerList().players) {
|
if (conn.isPendingPing()) {
|
||||||
PlayerConnection conn = player.playerConnection;
|
// We're pending a ping from the client
|
||||||
// Paper - give clients a longer time to respond to pings as per pre 1.12.2 timings
|
if (!conn.processedDisconnect && elapsedTime >= AkarinGlobalConfig.keepAliveTimeout) { // check keepalive limit, don't fire if already disconnected
|
||||||
// This should effectively place the keepalive handling back to "as it was" before 1.12.2
|
Akari.callbackQueue.add(() -> {
|
||||||
long currentTime = System.currentTimeMillis();
|
Akari.logger.warn("{} was kicked due to keepalive timeout!", conn.player.getName()); // more info
|
||||||
long elapsedTime = currentTime - conn.getLastPing();
|
conn.disconnect("disconnect.timeout");
|
||||||
if (conn.isPendingPing()) {
|
});
|
||||||
// We're pending a ping from the client
|
}
|
||||||
if (!conn.processedDisconnect && elapsedTime >= AkarinGlobalConfig.keepAliveTimeout * 1000L) { // check keepalive limit, don't fire if already disconnected
|
} else {
|
||||||
Akari.callbackQueue.add(() -> {
|
if (elapsedTime >= AkarinGlobalConfig.keepAliveSendInterval) { // 15 seconds default
|
||||||
Akari.logger.warn("{} was kicked due to keepalive timeout!", conn.player.getName()); // more info
|
conn.setPendingPing(true);
|
||||||
conn.disconnect("disconnect.timeout");
|
conn.setLastPing(currentTime);
|
||||||
});
|
conn.setKeepAliveID(currentTime);
|
||||||
}
|
conn.sendPacket(new PacketPlayOutKeepAlive(conn.getKeepAliveID()));
|
||||||
} else {
|
}
|
||||||
if (elapsedTime >= AkarinGlobalConfig.keepAliveSendInterval * 1000L) { // 15 seconds default
|
|
||||||
conn.setPendingPing(true);
|
|
||||||
conn.setLastPing(currentTime);
|
|
||||||
conn.setKeepAliveID(currentTime);
|
|
||||||
conn.sendPacket(new PacketPlayOutKeepAlive(conn.getKeepAliveID()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Force hardcore difficulty, from WorldServer#doTick
|
||||||
try {
|
for (WorldServer world : server.worlds) {
|
||||||
Thread.sleep(100);
|
if (world.getWorldData().isHardcore() && world.getDifficulty() != EnumDifficulty.HARD) {
|
||||||
} catch (InterruptedException ex) {
|
world.getWorldData().setDifficulty(EnumDifficulty.HARD);
|
||||||
Akari.logger.warn("Slack scheduler thread was interrupted unexpectly!");
|
}
|
||||||
ex.printStackTrace();
|
}
|
||||||
|
|
||||||
|
// Update player info, from PlayerList#tick
|
||||||
|
if (++resendPlayersInfo > AkarinGlobalConfig.playersInfoUpdateInterval) {
|
||||||
|
for (EntityPlayer target : server.getPlayerList().players) {
|
||||||
|
target.playerConnection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_LATENCY, Iterables.filter(server.getPlayerList().players, new Predicate<EntityPlayer>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(EntityPlayer input) {
|
||||||
|
return target.getBukkitEntity().canSee(input.getBukkitEntity());
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
resendPlayersInfo = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Akari.logger.warn("Slack scheduler thread was interrupted unexpectly!");
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
package io.akarin.server.core;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import io.netty.channel.Channel;
|
|
||||||
import io.netty.channel.ChannelException;
|
|
||||||
import io.netty.channel.ChannelInitializer;
|
|
||||||
import io.netty.channel.ChannelOption;
|
|
||||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
|
||||||
import net.minecraft.server.EnumProtocolDirection;
|
|
||||||
import net.minecraft.server.HandshakeListener;
|
|
||||||
import net.minecraft.server.LegacyPingHandler;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.NetworkManager;
|
|
||||||
import net.minecraft.server.PacketDecoder;
|
|
||||||
import net.minecraft.server.PacketEncoder;
|
|
||||||
import net.minecraft.server.PacketPrepender;
|
|
||||||
import net.minecraft.server.PacketSplitter;
|
|
||||||
|
|
||||||
public class ChannelAdapter extends ChannelInitializer<Channel> {
|
|
||||||
private final List<NetworkManager> managers;
|
|
||||||
|
|
||||||
public ChannelAdapter(List<NetworkManager> list) {
|
|
||||||
managers = list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ChannelAdapter create(List<NetworkManager> managers) {
|
|
||||||
return new ChannelAdapter(managers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void initChannel(Channel channel) {
|
|
||||||
try {
|
|
||||||
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
|
|
||||||
} catch (ChannelException ex) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30))
|
|
||||||
.addLast("legacy_query", new LegacyPingHandler(MinecraftServer.getServer().getServerConnection()))
|
|
||||||
.addLast("splitter", new PacketSplitter()).addLast("decoder", new PacketDecoder(EnumProtocolDirection.SERVERBOUND))
|
|
||||||
.addLast("prepender", new PacketPrepender()).addLast("encoder", new PacketEncoder(EnumProtocolDirection.CLIENTBOUND));
|
|
||||||
|
|
||||||
NetworkManager manager = new NetworkManager(EnumProtocolDirection.SERVERBOUND);
|
|
||||||
managers.add(manager);
|
|
||||||
|
|
||||||
channel.pipeline().addLast("packet_handler", manager);
|
|
||||||
manager.setPacketListener(new HandshakeListener(MinecraftServer.getServer(), manager));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,11 +10,11 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import io.akarin.api.Akari;
|
import io.akarin.api.internal.Akari;
|
||||||
import io.akarin.server.core.AkarinGlobalConfig;
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
|
|
||||||
@Mixin(value = Main.class, remap = false)
|
@Mixin(value = Main.class, remap = false)
|
||||||
public class Bootstrap {
|
public abstract class Bootstrap {
|
||||||
@Inject(method = "main([Ljava/lang/String;)V", at = @At("HEAD"))
|
@Inject(method = "main([Ljava/lang/String;)V", at = @At("HEAD"))
|
||||||
private static void premain(CallbackInfo info) {
|
private static void premain(CallbackInfo info) {
|
||||||
AkarinGlobalConfig.init(new File("akarin.yml"));
|
AkarinGlobalConfig.init(new File("akarin.yml"));
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.Overwrite;
|
|||||||
import net.minecraft.server.EULA;
|
import net.minecraft.server.EULA;
|
||||||
|
|
||||||
@Mixin(value = EULA.class, remap = false)
|
@Mixin(value = EULA.class, remap = false)
|
||||||
public class DummyEula {
|
public abstract class DummyEula {
|
||||||
/**
|
/**
|
||||||
* Read then check the EULA file <i>formerly</i>
|
* Read then check the EULA file <i>formerly</i>
|
||||||
* @param file
|
* @param file
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import com.destroystokyo.paper.Metrics;
|
|||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
@Mixin(targets = "com.destroystokyo.paper.Metrics$PaperMetrics", remap = false)
|
@Mixin(targets = "com.destroystokyo.paper.Metrics$PaperMetrics", remap = false)
|
||||||
public class MetricsBootstrap {
|
public abstract class MetricsBootstrap {
|
||||||
@Overwrite
|
@Overwrite
|
||||||
static void startMetrics() {
|
static void startMetrics() {
|
||||||
// Get the config file
|
// Get the config file
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import com.destroystokyo.paper.Metrics;
|
|||||||
import com.destroystokyo.paper.Metrics.CustomChart;
|
import com.destroystokyo.paper.Metrics.CustomChart;
|
||||||
|
|
||||||
@Mixin(value = Metrics.class, remap = false)
|
@Mixin(value = Metrics.class, remap = false)
|
||||||
public class MixinMetrics {
|
public abstract class MixinMetrics {
|
||||||
// The url to which the data is sent - bukkit/Torch (keep our old name)
|
// The url to which the data is sent - bukkit/Torch (keep our old name)
|
||||||
private final static String URL = "https://bStats.org/submitData/bukkit";
|
private final static String URL = "https://bStats.org/submitData/bukkit";
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package io.akarin.server.mixin.bootstrap;
|
||||||
|
|
||||||
|
import org.spigotmc.RestartCommand;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
|
|
||||||
|
@Mixin(value = RestartCommand.class, remap = false)
|
||||||
|
public abstract class MixinRestartCommand {
|
||||||
|
@Inject(method = "restart()V", at = @At("HEAD"))
|
||||||
|
private static void beforeRestart(CallbackInfo ci) {
|
||||||
|
if (AkarinGlobalConfig.noResponseDoGC) {
|
||||||
|
Akari.logger.warn("Attempting to garbage collect, may takes a few seconds");
|
||||||
|
System.runFinalization();
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import io.akarin.api.Akari;
|
import io.akarin.api.internal.Akari;
|
||||||
import net.minecraft.server.BiomeBase;
|
import net.minecraft.server.BiomeBase;
|
||||||
import net.minecraft.server.Block;
|
import net.minecraft.server.Block;
|
||||||
import net.minecraft.server.BlockFire;
|
import net.minecraft.server.BlockFire;
|
||||||
@@ -24,7 +24,7 @@ import net.minecraft.server.PotionRegistry;
|
|||||||
import net.minecraft.server.SoundEffect;
|
import net.minecraft.server.SoundEffect;
|
||||||
|
|
||||||
@Mixin(value = DispenserRegistry.class, remap = false)
|
@Mixin(value = DispenserRegistry.class, remap = false)
|
||||||
public class ParallelRegistry {
|
public abstract class ParallelRegistry {
|
||||||
/**
|
/**
|
||||||
* Registry order: SoundEffect -> Block
|
* Registry order: SoundEffect -> Block
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
@Mixin(value = WatchdogThread.class, remap = false)
|
@Mixin(value = WatchdogThread.class, remap = false)
|
||||||
public class Watchcat extends Thread {
|
public abstract class Watchcat extends Thread {
|
||||||
@Shadow private static WatchdogThread instance;
|
@Shadow private static WatchdogThread instance;
|
||||||
@Shadow private @Final long timeoutTime;
|
@Shadow private @Final long timeoutTime;
|
||||||
@Shadow private @Final boolean restart;
|
@Shadow private @Final boolean restart;
|
||||||
@@ -74,7 +74,7 @@ public class Watchcat extends Thread {
|
|||||||
}
|
}
|
||||||
log.log(Level.SEVERE, "------------------------------");
|
log.log(Level.SEVERE, "------------------------------");
|
||||||
|
|
||||||
if (restart) RestartCommand.restart();
|
if (restart) RestartCommand.restart(); // GC Inlined
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,22 +5,25 @@ import org.spongepowered.asm.mixin.Mixin;
|
|||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
import io.akarin.api.Akari;
|
import io.akarin.api.internal.Akari;
|
||||||
import io.akarin.server.core.AkarinGlobalConfig;
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.PersistentCollection;
|
||||||
|
|
||||||
@Mixin(value = AsyncCatcher.class, remap = false)
|
@Mixin(value = AsyncCatcher.class, remap = false)
|
||||||
public class MixinAsyncCatcher {
|
public abstract class MixinAsyncCatcher {
|
||||||
@Shadow public static boolean enabled;
|
@Shadow public static boolean enabled;
|
||||||
|
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public static void catchOp(String reason) {
|
public static void catchOp(String reason) {
|
||||||
if (AkarinGlobalConfig.enableAsyncCatcher && enabled && Thread.currentThread() != MinecraftServer.getServer().primaryThread) {
|
if (enabled) {
|
||||||
|
if (Akari.isPrimaryThread()) return;
|
||||||
|
|
||||||
if (AkarinGlobalConfig.throwOnAsyncCaught) {
|
if (AkarinGlobalConfig.throwOnAsyncCaught) {
|
||||||
throw new IllegalStateException("Asynchronous " + reason + "!");
|
throw new IllegalStateException("Asynchronous " + reason + "!");
|
||||||
} else {
|
} else {
|
||||||
Akari.logger.warn("Asynchronous " + reason + "!");
|
Akari.logger.warn("Asynchronous " + reason + "!");
|
||||||
Thread.dumpStack();
|
Thread.dumpStack();
|
||||||
|
PersistentCollection.class.getName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import io.akarin.server.core.AkarinGlobalConfig;
|
|||||||
import net.minecraft.server.Chunk;
|
import net.minecraft.server.Chunk;
|
||||||
|
|
||||||
@Mixin(value = ChunkIOExecutor.class, remap = false)
|
@Mixin(value = ChunkIOExecutor.class, remap = false)
|
||||||
public class MixinChunkIOExecutor {
|
public abstract class MixinChunkIOExecutor {
|
||||||
@Shadow @Final static int BASE_THREADS;
|
@Shadow @Final static int BASE_THREADS;
|
||||||
@Shadow @Mutable @Final static int PLAYERS_PER_THREAD;
|
@Shadow @Mutable @Final static int PLAYERS_PER_THREAD;
|
||||||
@Shadow @Final private static AsynchronousExecutor<?, Chunk, Runnable, RuntimeException> instance;
|
@Shadow @Final private static AsynchronousExecutor<?, Chunk, Runnable, RuntimeException> instance;
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package io.akarin.server.mixin.core;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
|
import net.minecraft.server.ChunkSection;
|
||||||
|
|
||||||
|
@Mixin(value = ChunkSection.class, remap = false)
|
||||||
|
public abstract class MixinChunkSection {
|
||||||
|
@Shadow private int nonEmptyBlockCount;
|
||||||
|
|
||||||
|
@Overwrite // PAIL: isEmpty
|
||||||
|
public boolean a() {
|
||||||
|
return AkarinGlobalConfig.sendLightOnlyChunkSection ? false : nonEmptyBlockCount == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package io.akarin.server.mixin.core;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
|
import net.minecraft.server.CommandAbstract;
|
||||||
|
import net.minecraft.server.CommandBan;
|
||||||
|
import net.minecraft.server.CommandException;
|
||||||
|
import net.minecraft.server.EntityPlayer;
|
||||||
|
import net.minecraft.server.ExceptionUsage;
|
||||||
|
import net.minecraft.server.GameProfileBanEntry;
|
||||||
|
import net.minecraft.server.ICommand;
|
||||||
|
import net.minecraft.server.ICommandListener;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
|
@Mixin(value = CommandBan.class, remap = false)
|
||||||
|
public abstract class MixinCommandBan {
|
||||||
|
@Overwrite
|
||||||
|
public void execute(MinecraftServer server, ICommandListener sender, String[] args) throws CommandException {
|
||||||
|
if (args.length >= 1 && args[0].length() > 1) {
|
||||||
|
GameProfile profile = server.getUserCache().getProfile(args[0]);
|
||||||
|
|
||||||
|
if (profile == null) {
|
||||||
|
throw new CommandException("commands.ban.failed", new Object[] {args[0]});
|
||||||
|
} else {
|
||||||
|
// Akarin start - use string
|
||||||
|
boolean hasReason = true; // Akarin
|
||||||
|
String message = null;
|
||||||
|
if (args.length >= 2) {
|
||||||
|
message = "";
|
||||||
|
for (int i = 2; i < args.length; i++) {
|
||||||
|
message = message + args[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hasReason = false; // Akarin
|
||||||
|
message = Akari.EMPTY_STRING; // Akarin - modify message
|
||||||
|
}
|
||||||
|
// Akarin end
|
||||||
|
|
||||||
|
GameProfileBanEntry entry = new GameProfileBanEntry(profile, (Date) null, sender.getName(), (Date) null, message);
|
||||||
|
|
||||||
|
server.getPlayerList().getProfileBans().add(entry);
|
||||||
|
EntityPlayer entityplayer = server.getPlayerList().getPlayer(args[0]);
|
||||||
|
|
||||||
|
if (entityplayer != null) {
|
||||||
|
entityplayer.playerConnection.disconnect(hasReason ? message : AkarinGlobalConfig.messageBan);
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandAbstract.a(sender, (ICommand) this, "commands.ban.success", args[0]); // PAIL: notifyCommandListener
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ExceptionUsage("commands.ban.usage");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package io.akarin.server.mixin.core;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
|
import net.minecraft.server.CommandAbstract;
|
||||||
|
import net.minecraft.server.CommandBanIp;
|
||||||
|
import net.minecraft.server.EntityPlayer;
|
||||||
|
import net.minecraft.server.ICommand;
|
||||||
|
import net.minecraft.server.ICommandListener;
|
||||||
|
import net.minecraft.server.IpBanEntry;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
|
@Mixin(value = CommandBanIp.class, remap = false)
|
||||||
|
public abstract class MixinCommandBanIp {
|
||||||
|
@Overwrite // PAIL: banIp
|
||||||
|
protected void a(MinecraftServer server, ICommandListener sender, String args, @Nullable String banReason) {
|
||||||
|
// Akarin start - modify message
|
||||||
|
boolean hasReason = true;
|
||||||
|
if (banReason == null) {
|
||||||
|
banReason = Akari.EMPTY_STRING;
|
||||||
|
hasReason = false;
|
||||||
|
}
|
||||||
|
// Akarin end
|
||||||
|
IpBanEntry ipbanentry = new IpBanEntry(args, (Date) null, sender.getName(), (Date) null, banReason);
|
||||||
|
|
||||||
|
server.getPlayerList().getIPBans().add(ipbanentry);
|
||||||
|
List<EntityPlayer> withIpPlayers = server.getPlayerList().b(args); // PAIL: getPlayersMatchingAddress
|
||||||
|
String[] banPlayerNames = new String[withIpPlayers.size()];
|
||||||
|
|
||||||
|
for (int i = 0; i < banPlayerNames.length; i++) {
|
||||||
|
EntityPlayer each = withIpPlayers.get(i);
|
||||||
|
banPlayerNames[i] = each.getName();
|
||||||
|
each.playerConnection.disconnect(hasReason ? banReason : AkarinGlobalConfig.messageBanIp); // Akarin
|
||||||
|
}
|
||||||
|
|
||||||
|
if (withIpPlayers.isEmpty()) {
|
||||||
|
CommandAbstract.a(sender, (ICommand) this, "commands.banip.success", args); // PAIL: notifyCommandListener
|
||||||
|
} else {
|
||||||
|
CommandAbstract.a(sender, (ICommand) this, "commands.banip.success.players", args, CommandAbstract.a(banPlayerNames)); // PAIL: notifyCommandListener - joinNiceString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package io.akarin.server.mixin.core;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
|
import net.minecraft.server.CommandAbstract;
|
||||||
|
import net.minecraft.server.CommandException;
|
||||||
|
import net.minecraft.server.CommandKick;
|
||||||
|
import net.minecraft.server.EntityPlayer;
|
||||||
|
import net.minecraft.server.ExceptionPlayerNotFound;
|
||||||
|
import net.minecraft.server.ExceptionUsage;
|
||||||
|
import net.minecraft.server.ICommand;
|
||||||
|
import net.minecraft.server.ICommandListener;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
|
@Mixin(value = CommandKick.class, remap = false)
|
||||||
|
public abstract class MixinCommandKick {
|
||||||
|
@Overwrite
|
||||||
|
public void execute(MinecraftServer server, ICommandListener sender, String[] args) throws CommandException {
|
||||||
|
if (args.length > 0 && args[0].length() > 1) {
|
||||||
|
EntityPlayer target = server.getPlayerList().getPlayer(args[0]);
|
||||||
|
|
||||||
|
if (target == null) {
|
||||||
|
throw new ExceptionPlayerNotFound("commands.generic.player.notFound", args[0]);
|
||||||
|
} else {
|
||||||
|
if (args.length >= 2) {
|
||||||
|
// Akarin start - use string
|
||||||
|
String message = "";
|
||||||
|
for (int i = 2; i < args.length; i++) {
|
||||||
|
message = message + args[i];
|
||||||
|
}
|
||||||
|
target.playerConnection.disconnect(message);
|
||||||
|
CommandAbstract.a(sender, (ICommand) this, "commands.kick.success.reason", target.getName(), message); // PAIL: notifyCommandListener
|
||||||
|
// Akarin end
|
||||||
|
} else {
|
||||||
|
target.playerConnection.disconnect(AkarinGlobalConfig.messageKick); // Akarin
|
||||||
|
CommandAbstract.a(sender, (ICommand) this, "commands.kick.success", target.getName()); // PAIL: notifyCommandListener
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ExceptionUsage("commands.kick.usage");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,38 +7,40 @@ import org.spongepowered.asm.mixin.Mutable;
|
|||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
import io.akarin.server.core.AkarinGlobalConfig;
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
import me.nallar.whocalled.WhoCalled;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
@Mixin(value = CraftServer.class, remap = false)
|
@Mixin(value = CraftServer.class, remap = false)
|
||||||
public class MixinCraftServer {
|
public abstract class MixinCraftServer {
|
||||||
@Shadow @Final @Mutable private String serverName;
|
@Shadow @Final @Mutable private String serverName;
|
||||||
|
@Shadow @Final @Mutable private String serverVersion;
|
||||||
@Shadow @Final protected MinecraftServer console;
|
@Shadow @Final protected MinecraftServer console;
|
||||||
private boolean needApplyServerName = true;
|
private boolean needApplyServerName = true;
|
||||||
|
private boolean needApplyServerVersion = true;
|
||||||
|
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public String getName() {
|
public String getName() {
|
||||||
// We cannot apply the name modification in <init> method,
|
// We cannot apply the name modification in <init> method,
|
||||||
// cause the initializer will be added to the tail
|
// cause the initializer will be added to the tail
|
||||||
if (needApplyServerName) {
|
if (needApplyServerName) {
|
||||||
serverName = "Akarin";
|
serverName = AkarinGlobalConfig.serverBrandName.equals(Akari.EMPTY_STRING) ? "Akarin" : AkarinGlobalConfig.serverBrandName;
|
||||||
needApplyServerName = false;
|
needApplyServerName = false;
|
||||||
}
|
}
|
||||||
return serverName;
|
return serverName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public boolean isPrimaryThread() {
|
public String getVersion() {
|
||||||
if (AkarinGlobalConfig.enableMockPlugin) {
|
if (needApplyServerVersion) {
|
||||||
// Mock forcely main thread plugins
|
serverVersion = AkarinGlobalConfig.serverBrandName.equals(Akari.EMPTY_STRING) ? serverVersion : serverVersion.replace("Akarin", AkarinGlobalConfig.serverBrandName);
|
||||||
String callerPackage = WhoCalled.$.getCallingClass().getPackage().getName();
|
needApplyServerVersion = false;
|
||||||
if (callerPackage.startsWith("net.minecraft") || callerPackage.startsWith("org.bukkit") ||
|
|
||||||
callerPackage.startsWith("co.aikar") || callerPackage.startsWith("io.akarin")) return Thread.currentThread().equals(console.primaryThread);
|
|
||||||
for (String contains : AkarinGlobalConfig.mockPackageList) {
|
|
||||||
if (callerPackage.contains(contains)) return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return Thread.currentThread().equals(console.primaryThread);
|
return serverVersion + " (MC: " + console.getVersion() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Overwrite
|
||||||
|
public boolean isPrimaryThread() {
|
||||||
|
return Akari.isPrimaryThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,38 @@
|
|||||||
package io.akarin.server.mixin.core;
|
package io.akarin.server.mixin.core;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.bukkit.craftbukkit.util.Waitable;
|
||||||
|
import org.spigotmc.AsyncCatcher;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
import net.minecraft.server.MCUtil;
|
import net.minecraft.server.MCUtil;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
@Mixin(value = MCUtil.class, remap = false)
|
@Mixin(value = MCUtil.class, remap = false)
|
||||||
public class MixinMCUtil {
|
public abstract class MixinMCUtil {
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public static <T> T ensureMain(String reason, Supplier<T> run) {
|
public static <T> T ensureMain(String reason, Supplier<T> run) {
|
||||||
|
if (AsyncCatcher.enabled && !Akari.isPrimaryThread()) {
|
||||||
|
new IllegalStateException("Asynchronous " + reason + "! Blocking thread until it returns ").printStackTrace();
|
||||||
|
Waitable<T> wait = new Waitable<T>() {
|
||||||
|
@Override
|
||||||
|
protected T evaluate() {
|
||||||
|
return run.get();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MinecraftServer.getServer().processQueue.add(wait);
|
||||||
|
try {
|
||||||
|
return wait.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return run.get();
|
return run.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ package io.akarin.server.mixin.core;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ExecutorCompletionService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.FutureTask;
|
import java.util.concurrent.FutureTask;
|
||||||
import org.bukkit.craftbukkit.CraftServer;
|
import org.bukkit.craftbukkit.CraftServer;
|
||||||
import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor;
|
import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor;
|
||||||
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
||||||
|
import org.bukkit.event.world.WorldLoadEvent;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Mutable;
|
import org.spongepowered.asm.mixin.Mutable;
|
||||||
@@ -16,9 +19,12 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import co.aikar.timings.MinecraftTimings;
|
import co.aikar.timings.MinecraftTimings;
|
||||||
import io.akarin.api.Akari;
|
import io.akarin.api.internal.Akari;
|
||||||
|
import io.akarin.api.internal.Akari.AssignableFactory;
|
||||||
|
import io.akarin.api.internal.mixin.IMixinLockProvider;
|
||||||
import io.akarin.server.core.AkarinGlobalConfig;
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
import io.akarin.server.core.AkarinSlackScheduler;
|
import io.akarin.server.core.AkarinSlackScheduler;
|
||||||
|
import net.minecraft.server.BlockPosition;
|
||||||
import net.minecraft.server.CrashReport;
|
import net.minecraft.server.CrashReport;
|
||||||
import net.minecraft.server.CustomFunctionData;
|
import net.minecraft.server.CustomFunctionData;
|
||||||
import net.minecraft.server.ITickable;
|
import net.minecraft.server.ITickable;
|
||||||
@@ -33,11 +39,35 @@ import net.minecraft.server.WorldServer;
|
|||||||
|
|
||||||
@Mixin(value = MinecraftServer.class, remap = false)
|
@Mixin(value = MinecraftServer.class, remap = false)
|
||||||
public abstract class MixinMinecraftServer {
|
public abstract class MixinMinecraftServer {
|
||||||
|
@Shadow @Final public Thread primaryThread;
|
||||||
|
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public String getServerModName() {
|
public String getServerModName() {
|
||||||
return "Akarin";
|
return "Akarin";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject(method = "run()V", at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "net/minecraft/server/MinecraftServer.aw()J",
|
||||||
|
shift = At.Shift.BEFORE
|
||||||
|
))
|
||||||
|
private void prerun(CallbackInfo info) {
|
||||||
|
primaryThread.setPriority(AkarinGlobalConfig.primaryThreadPriority < Thread.NORM_PRIORITY ? Thread.NORM_PRIORITY :
|
||||||
|
(AkarinGlobalConfig.primaryThreadPriority > Thread.MAX_PRIORITY ? 10 : AkarinGlobalConfig.primaryThreadPriority));
|
||||||
|
|
||||||
|
for (int i = 0; i < worlds.size(); ++i) {
|
||||||
|
WorldServer world = worlds.get(i);
|
||||||
|
TileEntityHopper.skipHopperEvents = world.paperConfig.disableHopperMoveEvents || InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0;
|
||||||
|
}
|
||||||
|
AkarinSlackScheduler.boot();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Overwrite
|
||||||
|
public boolean isMainThread() {
|
||||||
|
return Akari.isPrimaryThread();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Forcely disable snooper
|
* Forcely disable snooper
|
||||||
*/
|
*/
|
||||||
@@ -47,30 +77,69 @@ public abstract class MixinMinecraftServer {
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
public void b(MojangStatisticsGenerator generator) {}
|
public void b(MojangStatisticsGenerator generator) {}
|
||||||
|
|
||||||
@Inject(method = "run()V", at = @At(
|
/*
|
||||||
value = "INVOKE",
|
* Parallel spawn chunks generation
|
||||||
target = "net/minecraft/server/MinecraftServer.aw()J",
|
*/
|
||||||
shift = At.Shift.BEFORE
|
@Shadow public abstract boolean isRunning();
|
||||||
))
|
@Shadow(aliases = "a_") protected abstract void output(String s, int i);
|
||||||
private void prerun(CallbackInfo info) {
|
@Shadow(aliases = "t") protected abstract void enablePluginsPostWorld();
|
||||||
for (int i = 0; i < worlds.size(); ++i) {
|
|
||||||
WorldServer world = worlds.get(i);
|
private void prepareChunks(WorldServer world, int index) {
|
||||||
TileEntityHopper.skipHopperEvents = world.paperConfig.disableHopperMoveEvents || InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0;
|
MinecraftServer.LOGGER.info("Preparing start region for level " + index + " (Seed: " + world.getSeed() + ")");
|
||||||
|
BlockPosition spawnPos = world.getSpawn();
|
||||||
|
long lastRecord = System.currentTimeMillis();
|
||||||
|
|
||||||
|
int preparedChunks = 0;
|
||||||
|
short radius = world.paperConfig.keepLoadedRange;
|
||||||
|
for (int skipX = -radius; skipX <= radius && isRunning(); skipX += 16) {
|
||||||
|
for (int skipZ = -radius; skipZ <= radius && isRunning(); skipZ += 16) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
if (now - lastRecord > 1000L) {
|
||||||
|
output("Preparing spawn area (level " + index + ") ", preparedChunks * 100 / 625);
|
||||||
|
lastRecord = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
preparedChunks++;
|
||||||
|
world.getChunkProviderServer().getChunkAt(spawnPos.getX() + skipX >> 4, spawnPos.getZ() + skipZ >> 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
AkarinSlackScheduler.boot();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Overwrite
|
||||||
|
protected void l() throws InterruptedException {
|
||||||
|
ExecutorCompletionService<?> executor = new ExecutorCompletionService<>(Executors.newFixedThreadPool(worlds.size(), new AssignableFactory()));
|
||||||
|
|
||||||
|
for (int index = 0; index < worlds.size(); index++) {
|
||||||
|
WorldServer world = this.worlds.get(index);
|
||||||
|
if (!world.getWorld().getKeepSpawnInMemory()) continue;
|
||||||
|
|
||||||
|
int fIndex = index;
|
||||||
|
executor.submit(() -> prepareChunks(world, fIndex), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (WorldServer world : this.worlds) {
|
||||||
|
if (world.getWorld().getKeepSpawnInMemory()) executor.take();
|
||||||
|
this.server.getPluginManager().callEvent(new WorldLoadEvent(world.getWorld()));
|
||||||
|
}
|
||||||
|
|
||||||
|
enablePluginsPostWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parallel world ticking
|
||||||
|
*/
|
||||||
@Shadow public CraftServer server;
|
@Shadow public CraftServer server;
|
||||||
@Shadow @Mutable protected Queue<FutureTask<?>> j;
|
@Shadow @Mutable protected Queue<FutureTask<?>> j;
|
||||||
@Shadow public Queue<Runnable> processQueue;
|
@Shadow public Queue<Runnable> processQueue;
|
||||||
@Shadow private int ticks;
|
@Shadow private int ticks;
|
||||||
@Shadow public List<WorldServer> worlds;
|
@Shadow public List<WorldServer> worlds;
|
||||||
@Shadow private PlayerList v;
|
@Shadow(aliases = "v") private PlayerList playerList;
|
||||||
@Shadow @Final private List<ITickable> o;
|
@Shadow(aliases = "o") @Final private List<ITickable> tickables;
|
||||||
|
|
||||||
@Shadow public abstract PlayerList getPlayerList();
|
@Shadow public abstract PlayerList getPlayerList();
|
||||||
@Shadow public abstract ServerConnection an();
|
@Shadow(aliases = "an") public abstract ServerConnection serverConnection();
|
||||||
@Shadow public abstract CustomFunctionData aL();
|
@Shadow(aliases = "aL") public abstract CustomFunctionData functionManager();
|
||||||
|
|
||||||
private boolean tickEntities(WorldServer world) {
|
private boolean tickEntities(WorldServer world) {
|
||||||
try {
|
try {
|
||||||
@@ -106,10 +175,6 @@ public abstract class MixinMinecraftServer {
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
public void D() throws InterruptedException {
|
public void D() throws InterruptedException {
|
||||||
Runnable runnable;
|
Runnable runnable;
|
||||||
Akari.callbackTiming.startTiming();
|
|
||||||
while ((runnable = Akari.callbackQueue.poll()) != null) runnable.run();
|
|
||||||
Akari.callbackTiming.stopTiming();
|
|
||||||
|
|
||||||
MinecraftTimings.bukkitSchedulerTimer.startTiming();
|
MinecraftTimings.bukkitSchedulerTimer.startTiming();
|
||||||
this.server.getScheduler().mainThreadHeartbeat(this.ticks);
|
this.server.getScheduler().mainThreadHeartbeat(this.ticks);
|
||||||
MinecraftTimings.bukkitSchedulerTimer.stopTiming();
|
MinecraftTimings.bukkitSchedulerTimer.stopTiming();
|
||||||
@@ -137,13 +202,11 @@ public abstract class MixinMinecraftServer {
|
|||||||
worlds.get(i).timings.doTick.startTiming();
|
worlds.get(i).timings.doTick.startTiming();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Akari.silentTiming = true; // Disable timings
|
|
||||||
Akari.STAGE_TICK.submit(() -> {
|
Akari.STAGE_TICK.submit(() -> {
|
||||||
// Never tick one world concurrently!
|
// Never tick one world concurrently!
|
||||||
// TODO better treat world index
|
|
||||||
for (int i = 1; i <= worlds.size(); ++i) {
|
for (int i = 1; i <= worlds.size(); ++i) {
|
||||||
WorldServer world = worlds.get(i < worlds.size() ? i : 0);
|
WorldServer world = worlds.get(i < worlds.size() ? i : 0);
|
||||||
synchronized (world) {
|
synchronized (((IMixinLockProvider) world).lock()) {
|
||||||
tickEntities(world);
|
tickEntities(world);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,13 +214,15 @@ public abstract class MixinMinecraftServer {
|
|||||||
|
|
||||||
for (int i = 0; i < worlds.size(); ++i) {
|
for (int i = 0; i < worlds.size(); ++i) {
|
||||||
WorldServer world = worlds.get(i);
|
WorldServer world = worlds.get(i);
|
||||||
synchronized (world) {
|
synchronized (((IMixinLockProvider) world).lock()) {
|
||||||
tickWorld(world);
|
tickWorld(world);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Akari.entityCallbackTiming.startTiming();
|
||||||
Akari.STAGE_TICK.take();
|
Akari.STAGE_TICK.take();
|
||||||
Akari.silentTiming = false; // Enable timings
|
Akari.entityCallbackTiming.stopTiming();
|
||||||
|
|
||||||
Akari.worldTiming.stopTiming();
|
Akari.worldTiming.stopTiming();
|
||||||
if (AkarinGlobalConfig.legacyWorldTimings) {
|
if (AkarinGlobalConfig.legacyWorldTimings) {
|
||||||
for (int i = 0; i < worlds.size(); ++i) {
|
for (int i = 0; i < worlds.size(); ++i) {
|
||||||
@@ -172,33 +237,34 @@ public abstract class MixinMinecraftServer {
|
|||||||
|
|
||||||
for (int i = 0; i < worlds.size(); ++i) {
|
for (int i = 0; i < worlds.size(); ++i) {
|
||||||
WorldServer world = worlds.get(i);
|
WorldServer world = worlds.get(i);
|
||||||
tickConflictSync(world);
|
tickUnsafeSync(world);
|
||||||
|
|
||||||
world.getTracker().updatePlayers();
|
world.getTracker().updatePlayers();
|
||||||
world.explosionDensityCache.clear(); // Paper - Optimize explosions
|
world.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftTimings.connectionTimer.startTiming();
|
MinecraftTimings.connectionTimer.startTiming();
|
||||||
this.an().c();
|
serverConnection().c();
|
||||||
MinecraftTimings.connectionTimer.stopTiming();
|
MinecraftTimings.connectionTimer.stopTiming();
|
||||||
|
|
||||||
MinecraftTimings.playerListTimer.startTiming();
|
Akari.callbackTiming.startTiming();
|
||||||
this.v.tick();
|
while ((runnable = Akari.callbackQueue.poll()) != null) runnable.run();
|
||||||
MinecraftTimings.playerListTimer.stopTiming();
|
Akari.callbackTiming.stopTiming();
|
||||||
|
|
||||||
MinecraftTimings.commandFunctionsTimer.startTiming();
|
MinecraftTimings.commandFunctionsTimer.startTiming();
|
||||||
this.aL().e();
|
functionManager().e();
|
||||||
MinecraftTimings.commandFunctionsTimer.stopTiming();
|
MinecraftTimings.commandFunctionsTimer.stopTiming();
|
||||||
|
|
||||||
MinecraftTimings.tickablesTimer.startTiming();
|
MinecraftTimings.tickablesTimer.startTiming();
|
||||||
for (int i = 0; i < this.o.size(); ++i) {
|
for (int i = 0; i < this.tickables.size(); ++i) {
|
||||||
this.o.get(i).e();
|
tickables.get(i).e();
|
||||||
}
|
}
|
||||||
MinecraftTimings.tickablesTimer.stopTiming();
|
MinecraftTimings.tickablesTimer.stopTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tickConflictSync(WorldServer world) {
|
public void tickUnsafeSync(WorldServer world) {
|
||||||
;
|
world.timings.doChunkMap.startTiming();
|
||||||
|
world.manager.flush();
|
||||||
|
world.timings.doChunkMap.stopTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package io.akarin.server.mixin.core;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import co.aikar.timings.MinecraftTimings;
|
||||||
|
import co.aikar.timings.Timing;
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
|
import net.minecraft.server.CancelledPacketHandleException;
|
||||||
|
import net.minecraft.server.IAsyncTaskHandler;
|
||||||
|
import net.minecraft.server.Packet;
|
||||||
|
import net.minecraft.server.PacketListener;
|
||||||
|
import net.minecraft.server.PlayerConnectionUtils;
|
||||||
|
|
||||||
|
@Mixin(value = PlayerConnectionUtils.class, remap = false)
|
||||||
|
public abstract class MixinPlayerConnectionUtils {
|
||||||
|
@Overwrite
|
||||||
|
public static <T extends PacketListener> void ensureMainThread(final Packet<T> packet, final T listener, IAsyncTaskHandler iasynctaskhandler) throws CancelledPacketHandleException {
|
||||||
|
if (!iasynctaskhandler.isMainThread()) {
|
||||||
|
Timing timing = MinecraftTimings.getPacketTiming(packet);
|
||||||
|
// MinecraftServer#postToMainThread inlined thread check, no twice
|
||||||
|
Akari.callbackQueue.add(() -> {
|
||||||
|
try (Timing ignored = timing.startTiming()) {
|
||||||
|
packet.a(listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
throw CancelledPacketHandleException.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package io.akarin.server.mixin.core;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
|
||||||
|
import net.minecraft.server.PlayerList;
|
||||||
|
|
||||||
|
@Mixin(value = PlayerList.class, remap = false)
|
||||||
|
public abstract class MixinPlayerList {
|
||||||
|
@Overwrite
|
||||||
|
public void tick() {} // Migrated to slack service
|
||||||
|
}
|
||||||
@@ -7,20 +7,43 @@ import org.spongepowered.asm.mixin.Final;
|
|||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import io.akarin.api.Akari;
|
import co.aikar.timings.Timing;
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
|
import io.akarin.api.internal.Akari.AssignableThread;
|
||||||
import io.akarin.server.core.AkarinGlobalConfig;
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
@Mixin(targets = "co.aikar.timings.TimingHandler", remap = false)
|
@Mixin(targets = "co.aikar.timings.TimingHandler", remap = false)
|
||||||
public class MixinTimingHandler {
|
public abstract class MixinTimingHandler {
|
||||||
@Shadow @Final String name;
|
@Shadow @Final String name;
|
||||||
@Shadow private boolean enabled;
|
@Shadow private boolean enabled;
|
||||||
@Shadow private volatile long start;
|
@Shadow private volatile long start;
|
||||||
@Shadow private volatile int timingDepth;
|
@Shadow private volatile int timingDepth;
|
||||||
|
|
||||||
|
@Shadow abstract void addDiff(long diff);
|
||||||
|
@Shadow public abstract Timing startTiming();
|
||||||
|
|
||||||
|
@Overwrite
|
||||||
|
public Timing startTimingIfSync() {
|
||||||
|
if (Akari.isPrimaryThread(false)) {
|
||||||
|
startTiming();
|
||||||
|
}
|
||||||
|
return (Timing) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
@Inject(method = "startTiming", at = @At("HEAD"), cancellable = true)
|
||||||
|
public void onStartTiming(CallbackInfoReturnable ci) {
|
||||||
|
if (!Akari.isPrimaryThread(false)) ci.setReturnValue(this); // Avoid modify any field
|
||||||
|
}
|
||||||
|
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public void stopTimingIfSync() {
|
public void stopTimingIfSync() {
|
||||||
if (Akari.isPrimaryThread()) { // Akarin
|
if (Akari.isPrimaryThread(false)) {
|
||||||
stopTiming(true); // Avoid twice thread check
|
stopTiming(true); // Avoid twice thread check
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,23 +53,18 @@ public class MixinTimingHandler {
|
|||||||
stopTiming(false);
|
stopTiming(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Shadow void addDiff(long diff) {}
|
public void stopTiming(boolean alreadySync) {
|
||||||
|
Thread curThread = Thread.currentThread();
|
||||||
public void stopTiming(boolean sync) {
|
if (!enabled || curThread instanceof AssignableThread) return;
|
||||||
if (enabled && --timingDepth == 0 && start != 0) {
|
if (!alreadySync && curThread != MinecraftServer.getServer().primaryThread) {
|
||||||
if (Akari.silentTiming) { // It must be off-main thread now
|
if (AkarinGlobalConfig.silentAsyncTimings) return;
|
||||||
start = 0;
|
|
||||||
return;
|
Bukkit.getLogger().log(Level.SEVERE, "stopTiming called async for " + name);
|
||||||
} else {
|
Thread.dumpStack();
|
||||||
if (!sync && !Akari.isPrimaryThread()) { // Akarin
|
}
|
||||||
if (AkarinGlobalConfig.silentAsyncTimings) {
|
|
||||||
Bukkit.getLogger().log(Level.SEVERE, "stopTiming called async for " + name);
|
// Main thread ensured
|
||||||
new Throwable().printStackTrace();
|
if (--timingDepth == 0 && start != 0) {
|
||||||
}
|
|
||||||
start = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addDiff(System.nanoTime() - start);
|
addDiff(System.nanoTime() - start);
|
||||||
start = 0;
|
start = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import org.spongepowered.asm.mixin.Mixin;
|
|||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
import io.akarin.api.Akari;
|
import io.akarin.api.internal.Akari;
|
||||||
import io.akarin.server.core.AkarinGlobalConfig;
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
import net.minecraft.server.MCUtil;
|
import net.minecraft.server.MCUtil;
|
||||||
|
|
||||||
@Mixin(value = VersionCommand.class, remap = false)
|
@Mixin(value = VersionCommand.class, remap = false)
|
||||||
public class MixinVersionCommand {
|
public abstract class MixinVersionCommand {
|
||||||
@Shadow private static int getFromRepo(String repo, String hash) { return 0; }
|
@Shadow private static int getFromRepo(String repo, String hash) { return 0; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,7 +70,7 @@ public class MixinVersionCommand {
|
|||||||
|
|
||||||
if (hasVersion) {
|
if (hasVersion) {
|
||||||
long current = System.currentTimeMillis();
|
long current = System.currentTimeMillis();
|
||||||
if (current - lastCheckMillis > 7200000 /* 2 hours */) {
|
if (current - lastCheckMillis > AkarinGlobalConfig.versionUpdateInterval) {
|
||||||
lastCheckMillis = current;
|
lastCheckMillis = current;
|
||||||
hasVersion = false;
|
hasVersion = false;
|
||||||
} else {
|
} else {
|
||||||
@@ -104,7 +104,7 @@ public class MixinVersionCommand {
|
|||||||
versionWaiters.add(sender);
|
versionWaiters.add(sender);
|
||||||
sender.sendMessage("Checking version, please wait...");
|
sender.sendMessage("Checking version, please wait...");
|
||||||
|
|
||||||
String version = Bukkit.getVersion();
|
String version = Akari.getServerVersion();
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
version = "Unique"; // Custom - > Unique
|
version = "Unique"; // Custom - > Unique
|
||||||
customVersion = true;
|
customVersion = true;
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package io.akarin.server.mixin.core;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
|
import net.minecraft.server.AxisAlignedBB;
|
||||||
|
import net.minecraft.server.Entity;
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixes MC-103516(https://bugs.mojang.com/browse/MC-103516)
|
||||||
|
*/
|
||||||
|
@Mixin(value = World.class, remap = false)
|
||||||
|
public abstract class MixinWorld {
|
||||||
|
@Shadow public abstract List<Entity> getEntities(@Nullable Entity entity, AxisAlignedBB box);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if there are no solid, live entities in the specified AxisAlignedBB, excluding the given entity
|
||||||
|
*/
|
||||||
|
public boolean a(AxisAlignedBB box, @Nullable Entity target) { // PAIL: checkNoEntityCollision
|
||||||
|
List<Entity> list = this.getEntities(null, box);
|
||||||
|
|
||||||
|
for (Entity each : list) {
|
||||||
|
if (!each.dead && each.i && each != target && (target == null || !each.x(target))) { // PAIL: preventEntitySpawning - isRidingSameEntity
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package io.akarin.server.mixin.core;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinLockProvider;
|
||||||
|
import net.minecraft.server.WorldServer;
|
||||||
|
|
||||||
|
@Mixin(value = WorldServer.class, remap = false)
|
||||||
|
public abstract class MixinWorldServer implements IMixinLockProvider {
|
||||||
|
@Redirect(method = "doTick", at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "net/minecraft/server/PlayerChunkMap.flush()V"
|
||||||
|
))
|
||||||
|
public void onFlush() {} // Migrated to main thread
|
||||||
|
|
||||||
|
private final Object tickLock = new Object();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object lock() {
|
||||||
|
return tickLock;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,8 +11,7 @@ import net.minecraft.server.Blocks;
|
|||||||
import net.minecraft.server.ItemMonsterEgg;
|
import net.minecraft.server.ItemMonsterEgg;
|
||||||
|
|
||||||
@Mixin(value = ItemMonsterEgg.class, remap = false)
|
@Mixin(value = ItemMonsterEgg.class, remap = false)
|
||||||
public class MonsterEggGuardian {
|
public abstract class MonsterEggGuardian {
|
||||||
|
|
||||||
@Redirect(method = "a", at = @At(
|
@Redirect(method = "a", at = @At(
|
||||||
value = "FIELD",
|
value = "FIELD",
|
||||||
target = "net/minecraft/server/Blocks.MOB_SPAWNER:Lnet/minecraft/server/Block;",
|
target = "net/minecraft/server/Blocks.MOB_SPAWNER:Lnet/minecraft/server/Block;",
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.akarin.api.mixin.IMixinChunk;
|
import io.akarin.api.internal.mixin.IMixinChunk;
|
||||||
|
import net.minecraft.server.BlockPosition;
|
||||||
import net.minecraft.server.Chunk;
|
import net.minecraft.server.Chunk;
|
||||||
import net.minecraft.server.EnumDirection;
|
import net.minecraft.server.EnumDirection;
|
||||||
import net.minecraft.server.MCUtil;
|
import net.minecraft.server.MCUtil;
|
||||||
@@ -99,8 +100,10 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
|
|
||||||
@Inject(method = "addEntities", at = @At("RETURN"))
|
@Inject(method = "addEntities", at = @At("RETURN"))
|
||||||
public void onLoadReturn(CallbackInfo ci) {
|
public void onLoadReturn(CallbackInfo ci) {
|
||||||
|
BlockPosition origin = new BlockPosition(locX, 0, locZ);
|
||||||
for (EnumDirection direction : CARDINAL_DIRECTIONS) {
|
for (EnumDirection direction : CARDINAL_DIRECTIONS) {
|
||||||
Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(world.getChunkProvider(), locX, locZ);
|
BlockPosition shift = origin.shift(direction);
|
||||||
|
Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(world.getChunkProvider(), shift.getX(), shift.getZ());
|
||||||
if (neighbor != null) {
|
if (neighbor != null) {
|
||||||
int neighborIndex = directionToIndex(direction);
|
int neighborIndex = directionToIndex(direction);
|
||||||
int oppositeNeighborIndex = directionToIndex(direction.opposite());
|
int oppositeNeighborIndex = directionToIndex(direction.opposite());
|
||||||
@@ -112,8 +115,10 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
|
|
||||||
@Inject(method = "removeEntities", at = @At("RETURN"))
|
@Inject(method = "removeEntities", at = @At("RETURN"))
|
||||||
public void onUnload(CallbackInfo ci) {
|
public void onUnload(CallbackInfo ci) {
|
||||||
|
BlockPosition origin = new BlockPosition(locX, 0, locZ);
|
||||||
for (EnumDirection direction : CARDINAL_DIRECTIONS) {
|
for (EnumDirection direction : CARDINAL_DIRECTIONS) {
|
||||||
Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(world.getChunkProvider(), locX, locZ);
|
BlockPosition shift = origin.shift(direction);
|
||||||
|
Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(world.getChunkProvider(), shift.getX(), shift.getZ());
|
||||||
if (neighbor != null) {
|
if (neighbor != null) {
|
||||||
int neighborIndex = directionToIndex(direction);
|
int neighborIndex = directionToIndex(direction);
|
||||||
int oppositeNeighborIndex = directionToIndex(direction.opposite());
|
int oppositeNeighborIndex = directionToIndex(direction.opposite());
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
package io.akarin.server.mixin.cps;
|
package io.akarin.server.mixin.cps;
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import org.spigotmc.SlackActivityAccountant;
|
import org.spigotmc.SlackActivityAccountant;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||||
import net.minecraft.server.Chunk;
|
import net.minecraft.server.Chunk;
|
||||||
import net.minecraft.server.ChunkProviderServer;
|
import net.minecraft.server.ChunkProviderServer;
|
||||||
import net.minecraft.server.IChunkLoader;
|
import net.minecraft.server.IChunkLoader;
|
||||||
@@ -19,13 +21,10 @@ public abstract class MixinChunkProviderServer {
|
|||||||
@Shadow @Final public WorldServer world;
|
@Shadow @Final public WorldServer world;
|
||||||
@Shadow public Long2ObjectOpenHashMap<Chunk> chunks;
|
@Shadow public Long2ObjectOpenHashMap<Chunk> chunks;
|
||||||
|
|
||||||
public int pendingUnloadChunks; // For keeping unload target-size feature
|
|
||||||
|
|
||||||
public void unload(Chunk chunk) {
|
public void unload(Chunk chunk) {
|
||||||
if (this.world.worldProvider.c(chunk.locX, chunk.locZ)) {
|
if (this.world.worldProvider.c(chunk.locX, chunk.locZ)) {
|
||||||
// Akarin - avoid using the queue and simply check the unloaded flag during unloads
|
// Akarin - avoid using the queue and simply check the unloaded flag during unloads
|
||||||
// this.unloadQueue.add(Long.valueOf(ChunkCoordIntPair.a(chunk.locX, chunk.locZ)));
|
// this.unloadQueue.add(Long.valueOf(ChunkCoordIntPair.a(chunk.locX, chunk.locZ)));
|
||||||
pendingUnloadChunks++;
|
|
||||||
chunk.setShouldUnload(true);
|
chunk.setShouldUnload(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,33 +36,34 @@ public abstract class MixinChunkProviderServer {
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
public boolean unloadChunks() {
|
public boolean unloadChunks() {
|
||||||
if (!this.world.savingDisabled) {
|
if (!this.world.savingDisabled) {
|
||||||
SlackActivityAccountant activityAccountant = world.getMinecraftServer().slackActivityAccountant;
|
|
||||||
activityAccountant.startActivity(0.5);
|
|
||||||
|
|
||||||
Iterator<Chunk> it = chunks.values().iterator();
|
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
long unloadAfter = world.paperConfig.delayChunkUnloadsBy;
|
long unloadAfter = world.paperConfig.delayChunkUnloadsBy;
|
||||||
int targetSize = Math.min(pendingUnloadChunks - 100, (int) (pendingUnloadChunks * UNLOAD_QUEUE_RESIZE_FACTOR)); // Paper - Make more aggressive
|
SlackActivityAccountant activityAccountant = world.getMinecraftServer().slackActivityAccountant;
|
||||||
|
activityAccountant.startActivity(0.5);
|
||||||
|
ObjectIterator<Entry<Chunk>> it = chunks.long2ObjectEntrySet().fastIterator();
|
||||||
|
int remainingChunks = chunks.size();
|
||||||
|
int targetSize = Math.min(remainingChunks - 100, (int) (remainingChunks * UNLOAD_QUEUE_RESIZE_FACTOR)); // Paper - Make more aggressive
|
||||||
|
|
||||||
for (int i = 0; i < chunks.size() && pendingUnloadChunks > targetSize; i++) { // CraftBukkit removes unload logic to its method, we must check index
|
while (it.hasNext()) {
|
||||||
Chunk chunk = it.next();
|
Entry<Chunk> entry = it.next();
|
||||||
|
Chunk chunk = entry.getValue();
|
||||||
|
if (chunk == null) continue;
|
||||||
|
|
||||||
if (chunk != null && chunk.isUnloading()) {
|
if (chunk.isUnloading()) {
|
||||||
if (unloadAfter > 0) {
|
if (chunk.scheduledForUnload != null) {
|
||||||
// We changed Paper's delay unload logic, the original behavior is just mark as unloading
|
if (now - chunk.scheduledForUnload > unloadAfter) {
|
||||||
if (chunk.scheduledForUnload == null || now - chunk.scheduledForUnload < unloadAfter) {
|
chunk.scheduledForUnload = null;
|
||||||
continue;
|
} else continue;
|
||||||
}
|
|
||||||
chunk.scheduledForUnload = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a plugin cancelled it, we shouldn't trying unload it for a while
|
if (!unloadChunk(chunk, true)) { // Event cancelled
|
||||||
chunk.setShouldUnload(false); // Paper
|
// If a plugin cancelled it, we shouldn't trying unload it for a while
|
||||||
|
chunk.setShouldUnload(false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!unloadChunk(chunk, true)) continue; // Event cancelled
|
it.remove();
|
||||||
pendingUnloadChunks--;
|
if (--remainingChunks <= targetSize || activityAccountant.activityTimeIsExhausted()) break; // more slack since the target size not work as intended
|
||||||
|
|
||||||
if (activityAccountant.activityTimeIsExhausted()) break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
activityAccountant.endActivity();
|
activityAccountant.endActivity();
|
||||||
@@ -72,8 +72,16 @@ public abstract class MixinChunkProviderServer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "unloadChunk", at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "it/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap.remove(J)Ljava/lang/Object;"
|
||||||
|
))
|
||||||
|
private Object remove(Long2ObjectOpenHashMap<Chunk> chunks, long chunkHash) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "ServerChunkCache: " + chunks.size(); // Akarin - remove unload queue
|
return "ServerChunkCache: " + chunks.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,24 +4,18 @@ import java.util.Set;
|
|||||||
|
|
||||||
import org.bukkit.craftbukkit.CraftWorld;
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
import org.spongepowered.asm.lib.Opcodes;
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
|
|
||||||
import net.minecraft.server.Chunk;
|
import net.minecraft.server.Chunk;
|
||||||
import net.minecraft.server.PlayerChunk;
|
import net.minecraft.server.WorldServer;
|
||||||
|
|
||||||
@Mixin(value = CraftWorld.class, remap = false)
|
@Mixin(value = CraftWorld.class, remap = false)
|
||||||
public class MixinCraftWorld {
|
public abstract class MixinCraftWorld {
|
||||||
@Inject(method = "processChunkGC()V", at = @At(
|
@Shadow @Final private WorldServer world;
|
||||||
value = "INVOKE",
|
|
||||||
target = "net/minecraft/server/ChunkProviderServer.unload(Lnet/minecraft/server/Chunk;)V"
|
|
||||||
))
|
|
||||||
public void cancelUnloading(Chunk chunk, CallbackInfo ci) {
|
|
||||||
if (chunk.isUnloading()) ci.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "processChunkGC()V", at = @At(
|
@Redirect(method = "processChunkGC()V", at = @At(
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
@@ -38,15 +32,8 @@ public class MixinCraftWorld {
|
|||||||
opcode = Opcodes.INVOKEINTERFACE
|
opcode = Opcodes.INVOKEINTERFACE
|
||||||
))
|
))
|
||||||
public boolean regenChunk(Set<Long> set, Object chunkHash) {
|
public boolean regenChunk(Set<Long> set, Object chunkHash) {
|
||||||
return false;
|
Chunk chunk = world.getChunkProviderServer().chunks.get(chunkHash);
|
||||||
}
|
if (chunk != null) chunk.setShouldUnload(false);
|
||||||
|
return true;
|
||||||
@Inject(method = "processChunkGC()V", at = @At(
|
|
||||||
value = "FIELD",
|
|
||||||
target = "net/minecraft/server/PlayerChunk.chunk:Lnet/minecraft/server/Chunk;",
|
|
||||||
opcode = Opcodes.PUTFIELD
|
|
||||||
))
|
|
||||||
public void noUnload(PlayerChunk playerChunk, Chunk chunk, CallbackInfo ci) {
|
|
||||||
chunk.setShouldUnload(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
@@ -45,9 +44,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.akarin.api.Akari;
|
import io.akarin.api.internal.Akari;
|
||||||
import io.akarin.api.mixin.IMixinChunk;
|
import io.akarin.api.internal.mixin.IMixinChunk;
|
||||||
import io.akarin.api.mixin.IMixinWorldServer;
|
import io.akarin.api.internal.mixin.IMixinWorldServer;
|
||||||
import net.minecraft.server.BlockPosition;
|
import net.minecraft.server.BlockPosition;
|
||||||
import net.minecraft.server.Blocks;
|
import net.minecraft.server.Blocks;
|
||||||
import net.minecraft.server.Chunk;
|
import net.minecraft.server.Chunk;
|
||||||
@@ -103,7 +102,7 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
@Inject(method = "<init>", at = @At("RETURN"))
|
||||||
public void onConstruct(World worldIn, int x, int z, CallbackInfo ci) {
|
public void onConstruct(World worldIn, int x, int z, CallbackInfo ci) {
|
||||||
this.lightExecutorService = ((IMixinWorldServer) worldIn).getLightingExecutor();
|
lightExecutorService = ((IMixinWorldServer) worldIn).getLightingExecutor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -124,8 +123,8 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
@Inject(method = "b(Z)V", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "b(Z)V", at = @At("HEAD"), cancellable = true)
|
||||||
private void onTickHead(boolean skipRecheckGaps, CallbackInfo ci) {
|
private void onTickHead(boolean skipRecheckGaps, CallbackInfo ci) {
|
||||||
final List<Chunk> neighbors = this.getSurroundingChunks();
|
final List<Chunk> neighbors = this.getSurroundingChunks();
|
||||||
if (this.isGapLightingUpdated && this.world.worldProvider.m() && !skipRecheckGaps && !neighbors.isEmpty()) { // PAIL: isGapLightingUpdated - hasSkyLight
|
if (this.isGapLightingUpdated && this.world.worldProvider.m() && !skipRecheckGaps && !neighbors.isEmpty()) { // PAIL: hasSkyLight
|
||||||
this.lightExecutorService.execute(() -> {
|
lightExecutorService.execute(() -> {
|
||||||
this.recheckGapsAsync(neighbors);
|
this.recheckGapsAsync(neighbors);
|
||||||
});
|
});
|
||||||
this.isGapLightingUpdated = false;
|
this.isGapLightingUpdated = false;
|
||||||
@@ -134,7 +133,7 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
this.ticked = true;
|
this.ticked = true;
|
||||||
|
|
||||||
if (!this.isLightPopulated && this.isTerrainPopulated && !neighbors.isEmpty()) {
|
if (!this.isLightPopulated && this.isTerrainPopulated && !neighbors.isEmpty()) {
|
||||||
this.lightExecutorService.execute(() -> {
|
lightExecutorService.execute(() -> {
|
||||||
this.checkLightAsync(neighbors);
|
this.checkLightAsync(neighbors);
|
||||||
});
|
});
|
||||||
// set to true to avoid requeuing the same task when not finished
|
// set to true to avoid requeuing the same task when not finished
|
||||||
@@ -233,7 +232,7 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
|
|
||||||
@Inject(method = "o()V", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "o()V", at = @At("HEAD"), cancellable = true)
|
||||||
private void checkLightHead(CallbackInfo ci) {
|
private void checkLightHead(CallbackInfo ci) {
|
||||||
if (this.world.getMinecraftServer().isStopped() || this.lightExecutorService.isShutdown()) {
|
if (this.world.getMinecraftServer().isStopped() || lightExecutorService.isShutdown()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,15 +245,15 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Akari.isPrimaryThread()) { // Akarin
|
if (Akari.isPrimaryThread(false)) {
|
||||||
try {
|
try {
|
||||||
this.lightExecutorService.execute(() -> {
|
lightExecutorService.execute(() -> {
|
||||||
this.checkLightAsync(neighborChunks);
|
this.checkLightAsync(neighborChunks);
|
||||||
});
|
});
|
||||||
} catch (RejectedExecutionException ex) {
|
} catch (RejectedExecutionException ex) {
|
||||||
// This could happen if ServerHangWatchdog kills the server
|
// This could happen if ServerHangWatchdog kills the server
|
||||||
// between the start of the method and the execute() call.
|
// between the start of the method and the execute() call.
|
||||||
if (!this.world.getMinecraftServer().isStopped() && !this.lightExecutorService.isShutdown()) {
|
if (!this.world.getMinecraftServer().isStopped() && !lightExecutorService.isShutdown()) {
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,13 +274,13 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
BlockPosition blockpos = new BlockPosition(this.locX << 4, 0, this.locZ << 4);
|
BlockPosition blockpos = new BlockPosition(this.locX << 4, 0, this.locZ << 4);
|
||||||
|
|
||||||
if (this.world.worldProvider.m()) { // PAIL: hasSkyLight
|
if (this.world.worldProvider.m()) { // PAIL: hasSkyLight
|
||||||
label44:
|
reCheckLight:
|
||||||
|
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
for (int j = 0; j < 16; ++j) {
|
for (int j = 0; j < 16; ++j) {
|
||||||
if (!this.checkLightAsync(i, j, neighbors)) {
|
if (!this.checkLightAsync(i, j, neighbors)) {
|
||||||
this.isLightPopulated = false;
|
this.isLightPopulated = false;
|
||||||
break label44;
|
break reCheckLight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,7 +293,7 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
chunk.a(enumfacing.opposite()); // PAIL: checkLightSide
|
chunk.checkLightSide(enumfacing.opposite());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setSkylightUpdated();
|
this.setSkylightUpdated();
|
||||||
@@ -452,7 +451,7 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
|
|
||||||
@Inject(method = "c(III)V", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "c(III)V", at = @At("HEAD"), cancellable = true)
|
||||||
private void onRelightBlock(int x, int y, int z, CallbackInfo ci) {
|
private void onRelightBlock(int x, int y, int z, CallbackInfo ci) {
|
||||||
this.lightExecutorService.execute(() -> {
|
lightExecutorService.execute(() -> {
|
||||||
this.relightBlockAsync(x, y, z);
|
this.relightBlockAsync(x, y, z);
|
||||||
});
|
});
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
@@ -473,7 +472,7 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
j = y;
|
j = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (j > 0 && this.getBlockData(x, j - 1, z).c() == 0) {
|
while (j > 0 && this.getBlockData(x, j - 1, z).c() == 0) { // PAIL: getLightOpacity
|
||||||
--j;
|
--j;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,7 +489,7 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
|
|
||||||
if (extendedblockstorage2 != Chunk.EMPTY_CHUNK_SECTION) {
|
if (extendedblockstorage2 != Chunk.EMPTY_CHUNK_SECTION) {
|
||||||
extendedblockstorage2.a(x, j1 & 15, z, 15); // PAIL: setSkyLight
|
extendedblockstorage2.a(x, j1 & 15, z, 15); // PAIL: setSkyLight
|
||||||
this.world.m(new BlockPosition((this.locX << 4) + x, j1, (this.locZ << 4) + z)); // PAIL: notifyLightSet
|
// this.world.m(new BlockPosition((this.locX << 4) + x, j1, (this.locZ << 4) + z)); // PAIL: notifyLightSet - client side
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -499,7 +498,7 @@ public abstract class MixinChunk implements IMixinChunk {
|
|||||||
|
|
||||||
if (extendedblockstorage != Chunk.EMPTY_CHUNK_SECTION) {
|
if (extendedblockstorage != Chunk.EMPTY_CHUNK_SECTION) {
|
||||||
extendedblockstorage.a(x, i1 & 15, z, 0); // PAIL: setSkyLight
|
extendedblockstorage.a(x, i1 & 15, z, 0); // PAIL: setSkyLight
|
||||||
this.world.m(new BlockPosition((this.locX << 4) + x, i1, (this.locZ << 4) + z)); // PAIL: notifyLightSet
|
// this.world.m(new BlockPosition((this.locX << 4) + x, i1, (this.locZ << 4) + z)); // PAIL: notifyLightSet - client side
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,12 +30,12 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
import io.akarin.api.mixin.IMixinChunk;
|
import io.akarin.api.internal.mixin.IMixinChunk;
|
||||||
import net.minecraft.server.ChunkProviderServer;
|
import net.minecraft.server.ChunkProviderServer;
|
||||||
import net.minecraft.server.WorldServer;
|
import net.minecraft.server.WorldServer;
|
||||||
|
|
||||||
@Mixin(value = ChunkProviderServer.class, remap = false, priority = 1001)
|
@Mixin(value = ChunkProviderServer.class, remap = false, priority = 1001)
|
||||||
public class MixinChunkProviderServer {
|
public abstract class MixinChunkProviderServer {
|
||||||
@Shadow @Final public WorldServer world;
|
@Shadow @Final public WorldServer world;
|
||||||
|
|
||||||
@Redirect(method = "unloadChunks", at = @At(
|
@Redirect(method = "unloadChunks", at = @At(
|
||||||
|
|||||||
@@ -28,12 +28,13 @@ import org.spongepowered.asm.mixin.Mixin;
|
|||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
import net.minecraft.server.BlockPosition;
|
import net.minecraft.server.BlockPosition;
|
||||||
|
import net.minecraft.server.Chunk;
|
||||||
import net.minecraft.server.EnumSkyBlock;
|
import net.minecraft.server.EnumSkyBlock;
|
||||||
import net.minecraft.server.IChunkProvider;
|
import net.minecraft.server.IChunkProvider;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.World;
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
@Mixin(value = World.class, remap = false)
|
@Mixin(value = World.class, remap = false, priority = 1001)
|
||||||
public abstract class MixinWorld {
|
public abstract class MixinWorld {
|
||||||
@Shadow protected IChunkProvider chunkProvider;
|
@Shadow protected IChunkProvider chunkProvider;
|
||||||
@Shadow int[] J; // PAIL: lightUpdateBlockList
|
@Shadow int[] J; // PAIL: lightUpdateBlockList
|
||||||
@@ -41,5 +42,5 @@ public abstract class MixinWorld {
|
|||||||
@Shadow(aliases = "c") public abstract boolean checkLightFor(EnumSkyBlock lightType, BlockPosition pos);
|
@Shadow(aliases = "c") public abstract boolean checkLightFor(EnumSkyBlock lightType, BlockPosition pos);
|
||||||
@Shadow public abstract MinecraftServer getMinecraftServer();
|
@Shadow public abstract MinecraftServer getMinecraftServer();
|
||||||
@Shadow public abstract boolean areChunksLoaded(BlockPosition center, int radius, boolean allowEmpty);
|
@Shadow public abstract boolean areChunksLoaded(BlockPosition center, int radius, boolean allowEmpty);
|
||||||
@Shadow(aliases = "m") public abstract void notifyLightSet(BlockPosition pos);
|
@Shadow public abstract Chunk getChunkIfLoaded(int x, int z);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,21 +27,23 @@ package io.akarin.server.mixin.lighting;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
|
||||||
import io.akarin.api.Akari;
|
import io.akarin.api.internal.Akari;
|
||||||
import io.akarin.api.mixin.IMixinChunk;
|
import io.akarin.api.internal.mixin.IMixinChunk;
|
||||||
import io.akarin.api.mixin.IMixinWorldServer;
|
import io.akarin.api.internal.mixin.IMixinWorldServer;
|
||||||
import io.akarin.server.core.AkarinGlobalConfig;
|
|
||||||
import net.minecraft.server.BlockPosition;
|
import net.minecraft.server.BlockPosition;
|
||||||
import net.minecraft.server.Chunk;
|
import net.minecraft.server.Chunk;
|
||||||
import net.minecraft.server.EnumDirection;
|
import net.minecraft.server.EnumDirection;
|
||||||
import net.minecraft.server.EnumSkyBlock;
|
import net.minecraft.server.EnumSkyBlock;
|
||||||
import net.minecraft.server.IBlockData;
|
import net.minecraft.server.IBlockData;
|
||||||
import net.minecraft.server.MCUtil;
|
import net.minecraft.server.MCUtil;
|
||||||
|
import net.minecraft.server.MathHelper;
|
||||||
import net.minecraft.server.WorldServer;
|
import net.minecraft.server.WorldServer;
|
||||||
import net.minecraft.server.BlockPosition.PooledBlockPosition;
|
import net.minecraft.server.BlockPosition.PooledBlockPosition;
|
||||||
|
|
||||||
@@ -53,11 +55,11 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld
|
|||||||
private static final short XZ_MASK = 0xF;
|
private static final short XZ_MASK = 0xF;
|
||||||
private static final short Y_SHORT_MASK = 0xFF;
|
private static final short Y_SHORT_MASK = 0xFF;
|
||||||
|
|
||||||
private final ExecutorService lightExecutorService = preparExecutorService();;
|
private final static ThreadFactory SERVICE_FACTORY = new ThreadFactoryBuilder().setNameFormat("Akarin Async Lighting Thread - %1$d").build();
|
||||||
|
private final ExecutorService lightExecutorService = getExecutorService();
|
||||||
|
|
||||||
private ExecutorService preparExecutorService() {
|
private ExecutorService getExecutorService() {
|
||||||
return AkarinGlobalConfig.asyncLightingWorkStealing ?
|
return Executors.newFixedThreadPool(1, SERVICE_FACTORY);
|
||||||
Executors.newFixedThreadPool(AkarinGlobalConfig.asyncLightingThreads, new ThreadFactoryBuilder().setNameFormat("Akarin Async Light Thread").build()) : Executors.newWorkStealingPool(AkarinGlobalConfig.asyncLightingThreads);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -73,114 +75,114 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld
|
|||||||
final IMixinChunk spongeChunk = (IMixinChunk) currentChunk;
|
final IMixinChunk spongeChunk = (IMixinChunk) currentChunk;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
int k = this.getLightForAsync(lightType, pos, currentChunk, neighbors); // Sponge - use thread safe method
|
int current = this.getLightForAsync(lightType, pos, currentChunk, neighbors); // Sponge - use thread safe method
|
||||||
int l = this.getRawBlockLightAsync(lightType, pos, currentChunk, neighbors); // Sponge - use thread safe method
|
int rawLight = this.getRawBlockLightAsync(lightType, pos, currentChunk, neighbors); // Sponge - use thread safe method
|
||||||
int i1 = pos.getX();
|
int x = pos.getX();
|
||||||
int j1 = pos.getY();
|
int y = pos.getY();
|
||||||
int k1 = pos.getZ();
|
int z = pos.getZ();
|
||||||
|
|
||||||
if (l > k) {
|
if (rawLight > current) {
|
||||||
this.J[j++] = 133152; // PAIL: lightUpdateBlockList
|
this.J[j++] = 133152; // PAIL: lightUpdateBlockList
|
||||||
} else if (l < k) {
|
} else if (rawLight < current) {
|
||||||
this.J[j++] = 133152 | k << 18; // PAIL: lightUpdateBlockList
|
this.J[j++] = 133152 | current << 18; // PAIL: lightUpdateBlockList
|
||||||
|
|
||||||
while (i < j) {
|
while (i < j) {
|
||||||
int l1 = this.J[i++]; // PAIL: lightUpdateBlockList
|
int l1 = this.J[i++]; // PAIL: lightUpdateBlockList
|
||||||
int i2 = (l1 & 63) - 32 + i1;
|
int i2 = (l1 & 63) - 32 + x;
|
||||||
int j2 = (l1 >> 6 & 63) - 32 + j1;
|
int j2 = (l1 >> 6 & 63) - 32 + y;
|
||||||
int k2 = (l1 >> 12 & 63) - 32 + k1;
|
int k2 = (l1 >> 12 & 63) - 32 + z;
|
||||||
int l2 = l1 >> 18 & 15;
|
int l2 = l1 >> 18 & 15;
|
||||||
BlockPosition blockpos = new BlockPosition(i2, j2, k2);
|
BlockPosition blockpos = new BlockPosition(i2, j2, k2);
|
||||||
int i3 = this.getLightForAsync(lightType, blockpos, currentChunk, neighbors); // Sponge - use thread safe method
|
int lightLevel = this.getLightForAsync(lightType, blockpos, currentChunk, neighbors); // Sponge - use thread safe method
|
||||||
|
|
||||||
if (i3 == l2) {
|
if (lightLevel == l2) {
|
||||||
this.setLightForAsync(lightType, blockpos, 0, currentChunk, neighbors); // Sponge - use thread safe method
|
this.setLightForAsync(lightType, blockpos, 0, currentChunk, neighbors); // Sponge - use thread safe method
|
||||||
|
|
||||||
if (l2 > 0) {
|
if (l2 > 0) {
|
||||||
int j3 = Math.abs(i2 - i1); // TODO MathHelper
|
int j3 = MathHelper.a(i2 - x); // abs
|
||||||
int k3 = Math.abs(j2 - j1);
|
int k3 = MathHelper.a(j2 - y);
|
||||||
int l3 = Math.abs(k2 - k1);
|
int l3 = MathHelper.a(k2 - z);
|
||||||
|
|
||||||
if (j3 + k3 + l3 < 17) {
|
if (j3 + k3 + l3 < 17) {
|
||||||
PooledBlockPosition blockpos$pooledmutableblockpos = PooledBlockPosition.aquire();
|
PooledBlockPosition mutableBlockpos = PooledBlockPosition.aquire();
|
||||||
|
|
||||||
for (EnumDirection enumfacing : EnumDirection.values()) {
|
for (EnumDirection enumfacing : EnumDirection.values()) {
|
||||||
int i4 = i2 + enumfacing.getAdjacentX();
|
int i4 = i2 + enumfacing.getAdjacentX();
|
||||||
int j4 = j2 + enumfacing.getAdjacentX();
|
int j4 = j2 + enumfacing.getAdjacentX();
|
||||||
int k4 = k2 + enumfacing.getAdjacentX();
|
int k4 = k2 + enumfacing.getAdjacentX();
|
||||||
blockpos$pooledmutableblockpos.setValues(i4, j4, k4);
|
mutableBlockpos.setValues(i4, j4, k4);
|
||||||
// Sponge start - get chunk safely
|
// Sponge start - get chunk safely
|
||||||
final Chunk pooledChunk = this.getLightChunk(blockpos$pooledmutableblockpos, currentChunk, neighbors);
|
final Chunk pooledChunk = this.getLightChunk(mutableBlockpos, currentChunk, neighbors);
|
||||||
if (pooledChunk == null) {
|
if (pooledChunk == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int l4 = Math.max(1, pooledChunk.getBlockData(blockpos$pooledmutableblockpos).c()); // PAIL: getLightOpacity
|
int opacity = Math.max(1, pooledChunk.getBlockData(mutableBlockpos).c()); // PAIL: getLightOpacity
|
||||||
i3 = this.getLightForAsync(lightType, blockpos$pooledmutableblockpos, currentChunk, neighbors);
|
lightLevel = this.getLightForAsync(lightType, mutableBlockpos, currentChunk, neighbors);
|
||||||
// Sponge end
|
// Sponge end
|
||||||
|
|
||||||
if (i3 == l2 - l4 && j < this.J.length) { // PAIL: lightUpdateBlockList
|
if (lightLevel == l2 - opacity && j < this.J.length) { // PAIL: lightUpdateBlockList
|
||||||
this.J[j++] = i4 - i1 + 32 | j4 - j1 + 32 << 6 | k4 - k1 + 32 << 12 | l2 - l4 << 18; // PAIL: lightUpdateBlockList
|
this.J[j++] = i4 - x + 32 | j4 - y + 32 << 6 | k4 - z + 32 << 12 | l2 - opacity << 18; // PAIL: lightUpdateBlockList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blockpos$pooledmutableblockpos.free();
|
mutableBlockpos.free();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i < j) {
|
while (i < j) {
|
||||||
int i5 = this.J[i++]; // PAIL: lightUpdateBlockList
|
int i5 = this.J[i++]; // PAIL: lightUpdateBlockList
|
||||||
int j5 = (i5 & 63) - 32 + i1;
|
int j5 = (i5 & 63) - 32 + x;
|
||||||
int k5 = (i5 >> 6 & 63) - 32 + j1;
|
int k5 = (i5 >> 6 & 63) - 32 + y;
|
||||||
int l5 = (i5 >> 12 & 63) - 32 + k1;
|
int l5 = (i5 >> 12 & 63) - 32 + z;
|
||||||
BlockPosition blockpos1 = new BlockPosition(j5, k5, l5);
|
BlockPosition blockpos1 = new BlockPosition(j5, k5, l5);
|
||||||
int i6 = this.getLightForAsync(lightType, blockpos1, currentChunk, neighbors); // Sponge - use thread safe method
|
int i6 = this.getLightForAsync(lightType, blockpos1, currentChunk, neighbors); // Sponge - use thread safe method
|
||||||
int j6 = this.getRawBlockLightAsync(lightType, blockpos1, currentChunk, neighbors); // Sponge - use thread safe method
|
int j6 = this.getRawBlockLightAsync(lightType, blockpos1, currentChunk, neighbors); // Sponge - use thread safe method
|
||||||
|
|
||||||
if (j6 != i6) {
|
if (j6 != i6) {
|
||||||
this.setLightForAsync(lightType, blockpos1, j6, currentChunk, neighbors); // Sponge - use thread safe method
|
this.setLightForAsync(lightType, blockpos1, j6, currentChunk, neighbors); // Sponge - use thread safe method
|
||||||
|
|
||||||
if (j6 > i6) {
|
if (j6 > i6) {
|
||||||
int k6 = Math.abs(j5 - i1);
|
int k6 = Math.abs(j5 - x);
|
||||||
int l6 = Math.abs(k5 - j1);
|
int l6 = Math.abs(k5 - y);
|
||||||
int i7 = Math.abs(l5 - k1);
|
int i7 = Math.abs(l5 - z);
|
||||||
boolean flag = j < this.J.length - 6; // PAIL: lightUpdateBlockList
|
boolean flag = j < this.J.length - 6; // PAIL: lightUpdateBlockList
|
||||||
|
|
||||||
if (k6 + l6 + i7 < 17 && flag) {
|
if (k6 + l6 + i7 < 17 && flag) {
|
||||||
// Sponge start - use thread safe method getLightForAsync
|
// Sponge start - use thread safe method getLightForAsync
|
||||||
if (this.getLightForAsync(lightType, blockpos1.west(), currentChunk, neighbors) < j6) {
|
if (this.getLightForAsync(lightType, blockpos1.west(), currentChunk, neighbors) < j6) {
|
||||||
this.J[j++] = j5 - 1 - i1 + 32 + (k5 - j1 + 32 << 6) + (l5 - k1 + 32 << 12); // PAIL: lightUpdateBlockList
|
this.J[j++] = j5 - 1 - x + 32 + (k5 - y + 32 << 6) + (l5 - z + 32 << 12); // PAIL: lightUpdateBlockList
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getLightForAsync(lightType, blockpos1.east(), currentChunk, neighbors) < j6) {
|
if (this.getLightForAsync(lightType, blockpos1.east(), currentChunk, neighbors) < j6) {
|
||||||
this.J[j++] = j5 + 1 - i1 + 32 + (k5 - j1 + 32 << 6) + (l5 - k1 + 32 << 12); // PAIL: lightUpdateBlockList
|
this.J[j++] = j5 + 1 - x + 32 + (k5 - y + 32 << 6) + (l5 - z + 32 << 12); // PAIL: lightUpdateBlockList
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getLightForAsync(lightType, blockpos1.down(), currentChunk, neighbors) < j6) {
|
if (this.getLightForAsync(lightType, blockpos1.down(), currentChunk, neighbors) < j6) {
|
||||||
this.J[j++] = j5 - i1 + 32 + (k5 - 1 - j1 + 32 << 6) + (l5 - k1 + 32 << 12); // PAIL: lightUpdateBlockList
|
this.J[j++] = j5 - x + 32 + (k5 - 1 - y + 32 << 6) + (l5 - z + 32 << 12); // PAIL: lightUpdateBlockList
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getLightForAsync(lightType, blockpos1.up(), currentChunk, neighbors) < j6) {
|
if (this.getLightForAsync(lightType, blockpos1.up(), currentChunk, neighbors) < j6) {
|
||||||
this.J[j++] = j5 - i1 + 32 + (k5 + 1 - j1 + 32 << 6) + (l5 - k1 + 32 << 12); // PAIL: lightUpdateBlockList
|
this.J[j++] = j5 - x + 32 + (k5 + 1 - y + 32 << 6) + (l5 - z + 32 << 12); // PAIL: lightUpdateBlockList
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getLightForAsync(lightType, blockpos1.north(), currentChunk, neighbors) < j6) {
|
if (this.getLightForAsync(lightType, blockpos1.north(), currentChunk, neighbors) < j6) {
|
||||||
this.J[j++] = j5 - i1 + 32 + (k5 - j1 + 32 << 6) + (l5 - 1 - k1 + 32 << 12); // PAIL: lightUpdateBlockList
|
this.J[j++] = j5 - x + 32 + (k5 - y + 32 << 6) + (l5 - 1 - z + 32 << 12); // PAIL: lightUpdateBlockList
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getLightForAsync(lightType, blockpos1.south(), currentChunk, neighbors) < j6) {
|
if (this.getLightForAsync(lightType, blockpos1.south(), currentChunk, neighbors) < j6) {
|
||||||
this.J[j++] = j5 - i1 + 32 + (k5 - j1 + 32 << 6) + (l5 + 1 - k1 + 32 << 12); // PAIL: lightUpdateBlockList
|
this.J[j++] = j5 - x + 32 + (k5 - y + 32 << 6) + (l5 + 1 - z + 32 << 12); // PAIL: lightUpdateBlockList
|
||||||
}
|
}
|
||||||
// Sponge end
|
// Sponge end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sponge start - Asynchronous light updates
|
// Sponge start - Asynchronous light updates
|
||||||
spongeChunk.getQueuedLightingUpdates(lightType).remove((Short) this.blockPosToShort(pos));
|
spongeChunk.getQueuedLightingUpdates(lightType).remove((Short) this.blockPosToShort(pos));
|
||||||
spongeChunk.getPendingLightUpdates().decrementAndGet();
|
spongeChunk.getPendingLightUpdates().decrementAndGet();
|
||||||
@@ -188,7 +190,6 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld
|
|||||||
final IMixinChunk neighbor = (IMixinChunk) neighborChunk;
|
final IMixinChunk neighbor = (IMixinChunk) neighborChunk;
|
||||||
neighbor.getPendingLightUpdates().decrementAndGet();
|
neighbor.getPendingLightUpdates().decrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sponge end
|
// Sponge end
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -203,22 +204,22 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld
|
|||||||
if (currentChunk == null) {
|
if (currentChunk == null) {
|
||||||
currentChunk = MCUtil.getLoadedChunkWithoutMarkingActive(chunkProvider, pos.getX() >> 4, pos.getZ() >> 4);
|
currentChunk = MCUtil.getLoadedChunkWithoutMarkingActive(chunkProvider, pos.getX() >> 4, pos.getZ() >> 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
final IMixinChunk spongeChunk = (IMixinChunk) currentChunk;
|
final IMixinChunk spongeChunk = (IMixinChunk) currentChunk;
|
||||||
if (currentChunk == null || currentChunk.isUnloading() || !spongeChunk.areNeighborsLoaded()) {
|
if (currentChunk == null || currentChunk.isUnloading() || !spongeChunk.areNeighborsLoaded()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final short shortPos = this.blockPosToShort(pos);
|
final short shortPos = this.blockPosToShort(pos);
|
||||||
if (spongeChunk.getQueuedLightingUpdates(lightType).contains(shortPos)) {
|
if (spongeChunk.getQueuedLightingUpdates(lightType).contains(shortPos)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Chunk chunk = currentChunk;
|
final Chunk chunk = currentChunk;
|
||||||
spongeChunk.getQueuedLightingUpdates(lightType).add(shortPos);
|
spongeChunk.getQueuedLightingUpdates(lightType).add(shortPos);
|
||||||
spongeChunk.getPendingLightUpdates().incrementAndGet();
|
spongeChunk.getPendingLightUpdates().incrementAndGet();
|
||||||
spongeChunk.setLightUpdateTime(chunk.getWorld().getTime());
|
spongeChunk.setLightUpdateTime(chunk.getWorld().getTime());
|
||||||
|
|
||||||
List<Chunk> neighbors = spongeChunk.getNeighbors();
|
List<Chunk> neighbors = spongeChunk.getNeighbors();
|
||||||
// add diagonal chunks
|
// add diagonal chunks
|
||||||
Chunk southEastChunk = ((IMixinChunk) spongeChunk.getNeighborChunk(0)).getNeighborChunk(2);
|
Chunk southEastChunk = ((IMixinChunk) spongeChunk.getNeighborChunk(0)).getNeighborChunk(2);
|
||||||
@@ -237,13 +238,13 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld
|
|||||||
if (northWestChunk != null) {
|
if (northWestChunk != null) {
|
||||||
neighbors.add(northWestChunk);
|
neighbors.add(northWestChunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Chunk neighborChunk : neighbors) {
|
for (Chunk neighborChunk : neighbors) {
|
||||||
final IMixinChunk neighbor = (IMixinChunk) neighborChunk;
|
final IMixinChunk neighbor = (IMixinChunk) neighborChunk;
|
||||||
neighbor.getPendingLightUpdates().incrementAndGet();
|
neighbor.getPendingLightUpdates().incrementAndGet();
|
||||||
neighbor.setLightUpdateTime(chunk.getWorld().getTime());
|
neighbor.setLightUpdateTime(chunk.getWorld().getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Akari.isPrimaryThread()) { // Akarin
|
if (Akari.isPrimaryThread()) { // Akarin
|
||||||
this.lightExecutorService.execute(() -> {
|
this.lightExecutorService.execute(() -> {
|
||||||
this.checkLightAsync(lightType, pos, chunk, neighbors);
|
this.checkLightAsync(lightType, pos, chunk, neighbors);
|
||||||
@@ -280,23 +281,23 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getLightForAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk currentChunk, List<Chunk> neighbors) {
|
private int getLightForAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk currentChunk, List<Chunk> neighbors) {
|
||||||
if (pos.getY() < 0) {
|
if (pos.getY() < 0) {
|
||||||
pos = new BlockPosition(pos.getX(), 0, pos.getZ());
|
pos = new BlockPosition(pos.getX(), 0, pos.getZ());
|
||||||
}
|
}
|
||||||
if (!(pos.isValidLocation())) {
|
if (!pos.isValidLocation()) {
|
||||||
return lightType.c; // PAIL: defaultLightValue
|
return lightType.c; // PAIL: defaultLightValue
|
||||||
}
|
}
|
||||||
|
|
||||||
final Chunk chunk = this.getLightChunk(pos, currentChunk, neighbors);
|
final Chunk chunk = this.getLightChunk(pos, currentChunk, neighbors);
|
||||||
if (chunk == null || chunk.isUnloading()) {
|
if (chunk == null || chunk.isUnloading()) {
|
||||||
return lightType.c; // PAIL: defaultLightValue
|
return lightType.c; // PAIL: defaultLightValue
|
||||||
}
|
}
|
||||||
|
|
||||||
return chunk.getBrightness(lightType, pos);
|
return chunk.getBrightness(lightType, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getRawBlockLightAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk currentChunk, List<Chunk> neighbors) {
|
private int getRawBlockLightAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk currentChunk, List<Chunk> neighbors) {
|
||||||
final Chunk chunk = getLightChunk(pos, currentChunk, neighbors);
|
final Chunk chunk = getLightChunk(pos, currentChunk, neighbors);
|
||||||
if (chunk == null || chunk.isUnloading()) {
|
if (chunk == null || chunk.isUnloading()) {
|
||||||
@@ -305,38 +306,38 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld
|
|||||||
if (lightType == EnumSkyBlock.SKY && chunk.c(pos)) { // PAIL: canSeeSky
|
if (lightType == EnumSkyBlock.SKY && chunk.c(pos)) { // PAIL: canSeeSky
|
||||||
return 15;
|
return 15;
|
||||||
} else {
|
} else {
|
||||||
IBlockData blockState = chunk.getBlockData(pos);
|
IBlockData blockData = chunk.getBlockData(pos);
|
||||||
int blockLight = blockState.d(); // getLightValue
|
int blockLight = blockData.d(); // getLightValue
|
||||||
int i = lightType == EnumSkyBlock.SKY ? 0 : blockLight;
|
int rawLight = lightType == EnumSkyBlock.SKY ? 0 : blockLight;
|
||||||
int j = blockState.c(); // PAIL: getLightOpacity
|
int opacity = blockData.c(); // PAIL: getLightOpacity
|
||||||
|
|
||||||
if (j >= 15 && blockLight > 0) {
|
if (opacity >= 15 && blockLight > 0) {
|
||||||
j = 1;
|
opacity = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j < 1) {
|
if (opacity < 1) {
|
||||||
j = 1;
|
opacity = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j >= 15) {
|
if (opacity >= 15) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (i >= 14) {
|
} else if (rawLight >= 14) {
|
||||||
return i;
|
return rawLight;
|
||||||
} else {
|
} else {
|
||||||
for (EnumDirection facing : EnumDirection.values()) {
|
for (EnumDirection facing : EnumDirection.values()) {
|
||||||
BlockPosition blockpos = pos.shift(facing);
|
BlockPosition blockpos = pos.shift(facing);
|
||||||
int k = this.getLightForAsync(lightType, blockpos, currentChunk, neighbors) - j;
|
int current = this.getLightForAsync(lightType, blockpos, currentChunk, neighbors) - opacity;
|
||||||
|
|
||||||
if (k > i) {
|
if (current > rawLight) {
|
||||||
i = k;
|
rawLight = current;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i >= 14) {
|
if (rawLight >= 14) {
|
||||||
return i;
|
return rawLight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return rawLight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -345,12 +346,12 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld
|
|||||||
if (pos.isValidLocation()) {
|
if (pos.isValidLocation()) {
|
||||||
final Chunk chunk = this.getLightChunk(pos, currentChunk, neighbors);
|
final Chunk chunk = this.getLightChunk(pos, currentChunk, neighbors);
|
||||||
if (chunk != null && !chunk.isUnloading()) {
|
if (chunk != null && !chunk.isUnloading()) {
|
||||||
chunk.a(type, pos, lightValue); // PAIL: setBrightness
|
chunk.a(type, pos, lightValue); // PAIL: setLightFor
|
||||||
this.notifyLightSet(pos);
|
// this.notifyLightSet(pos); // client side
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private short blockPosToShort(BlockPosition pos) {
|
private short blockPosToShort(BlockPosition pos) {
|
||||||
short serialized = (short) setNibble(0, pos.getX() & XZ_MASK, 0, NUM_XZ_BITS);
|
short serialized = (short) setNibble(0, pos.getX() & XZ_MASK, 0, NUM_XZ_BITS);
|
||||||
serialized = (short) setNibble(serialized, pos.getY() & Y_SHORT_MASK, 1, NUM_SHORT_Y_BITS);
|
serialized = (short) setNibble(serialized, pos.getY() & Y_SHORT_MASK, 1, NUM_SHORT_Y_BITS);
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
package io.akarin.server.mixin.nsc;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
|
|
||||||
import net.minecraft.server.PlayerConnection;
|
|
||||||
|
|
||||||
@Mixin(value = PlayerConnection.class, remap = false)
|
|
||||||
public class MixinPlayerConnection {
|
|
||||||
@Overwrite
|
|
||||||
private long d() {
|
|
||||||
return System.currentTimeMillis(); // nanoTime() / 1000000L
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,6 +7,7 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.spigotmc.SpigotConfig;
|
import org.spigotmc.SpigotConfig;
|
||||||
@@ -17,26 +18,37 @@ import org.spongepowered.asm.mixin.Overwrite;
|
|||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.akarin.api.LocalAddress;
|
import io.akarin.api.internal.LocalAddress;
|
||||||
import io.akarin.server.core.AkarinGlobalConfig;
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
import io.akarin.server.core.ChannelAdapter;
|
|
||||||
import io.netty.bootstrap.ServerBootstrap;
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelException;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.ServerChannel;
|
import io.netty.channel.ServerChannel;
|
||||||
import io.netty.channel.epoll.Epoll;
|
import io.netty.channel.epoll.Epoll;
|
||||||
import io.netty.channel.epoll.EpollServerSocketChannel;
|
import io.netty.channel.epoll.EpollServerSocketChannel;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||||
import io.netty.util.concurrent.Future;
|
import io.netty.util.concurrent.Future;
|
||||||
import io.netty.util.concurrent.GenericFutureListener;
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
import net.minecraft.server.ChatComponentText;
|
import net.minecraft.server.ChatComponentText;
|
||||||
|
import net.minecraft.server.EnumProtocolDirection;
|
||||||
|
import net.minecraft.server.HandshakeListener;
|
||||||
|
import net.minecraft.server.LegacyPingHandler;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.NetworkManager;
|
import net.minecraft.server.NetworkManager;
|
||||||
|
import net.minecraft.server.PacketDecoder;
|
||||||
|
import net.minecraft.server.PacketEncoder;
|
||||||
import net.minecraft.server.PacketPlayOutKickDisconnect;
|
import net.minecraft.server.PacketPlayOutKickDisconnect;
|
||||||
|
import net.minecraft.server.PacketPrepender;
|
||||||
|
import net.minecraft.server.PacketSplitter;
|
||||||
import net.minecraft.server.ServerConnection;
|
import net.minecraft.server.ServerConnection;
|
||||||
|
|
||||||
@Mixin(value = ServerConnection.class, remap = false)
|
@Mixin(value = ServerConnection.class, remap = false)
|
||||||
public class NonblockingServerConnection {
|
public abstract class NonblockingServerConnection {
|
||||||
private final static Logger logger = LogManager.getLogger("NSC");
|
private final static Logger logger = LogManager.getLogger("NSC");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,7 +87,26 @@ public class NonblockingServerConnection {
|
|||||||
logger.info("Using nio channel type");
|
logger.info("Using nio channel type");
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerBootstrap bootstrap = new ServerBootstrap().channel(channelClass).childHandler(ChannelAdapter.create(networkManagers)).group(loopGroup);
|
ServerBootstrap bootstrap = new ServerBootstrap().channel(channelClass).childHandler(new ChannelInitializer<Channel>() {
|
||||||
|
@Override
|
||||||
|
protected void initChannel(Channel channel) throws Exception {
|
||||||
|
try {
|
||||||
|
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
|
||||||
|
} catch (ChannelException ex) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30))
|
||||||
|
.addLast("legacy_query", new LegacyPingHandler(MinecraftServer.getServer().getServerConnection()))
|
||||||
|
.addLast("splitter", new PacketSplitter()).addLast("decoder", new PacketDecoder(EnumProtocolDirection.SERVERBOUND))
|
||||||
|
.addLast("prepender", new PacketPrepender()).addLast("encoder", new PacketEncoder(EnumProtocolDirection.CLIENTBOUND));
|
||||||
|
|
||||||
|
NetworkManager manager = new NetworkManager(EnumProtocolDirection.SERVERBOUND);
|
||||||
|
networkManagers.add(manager);
|
||||||
|
|
||||||
|
channel.pipeline().addLast("packet_handler", manager);
|
||||||
|
manager.setPacketListener(new HandshakeListener(MinecraftServer.getServer(), manager));
|
||||||
|
}
|
||||||
|
}).group(loopGroup);
|
||||||
synchronized (endPoints) {
|
synchronized (endPoints) {
|
||||||
data.addAll(Lists.transform(AkarinGlobalConfig.extraAddress, s -> {
|
data.addAll(Lists.transform(AkarinGlobalConfig.extraAddress, s -> {
|
||||||
String[] info = s.split(":");
|
String[] info = s.split(":");
|
||||||
@@ -110,13 +141,13 @@ public class NonblockingServerConnection {
|
|||||||
try {
|
try {
|
||||||
manager.a(); // PAIL: NetworkManager::processReceivedPackets
|
manager.a(); // PAIL: NetworkManager::processReceivedPackets
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.warn("Failed to handle packet for {}", new Object[] { manager.getSocketAddress(), ex });
|
logger.warn("Failed to handle packet for {}", manager.getSocketAddress(), ex);
|
||||||
final ChatComponentText kick = new ChatComponentText("Internal server error");
|
final ChatComponentText message = new ChatComponentText("Internal server error");
|
||||||
|
|
||||||
manager.sendPacket(new PacketPlayOutKickDisconnect(kick), new GenericFutureListener<Future<? super Void>>() {
|
manager.sendPacket(new PacketPlayOutKickDisconnect(message), new GenericFutureListener<Future<? super Void>>() {
|
||||||
@Override
|
@Override
|
||||||
public void operationComplete(Future<? super Void> future) throws Exception {
|
public void operationComplete(Future<? super Void> future) throws Exception {
|
||||||
manager.close(kick);
|
manager.close(message);
|
||||||
}
|
}
|
||||||
}, new GenericFutureListener[0]);
|
}, new GenericFutureListener[0]);
|
||||||
manager.stopReading();
|
manager.stopReading();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import org.spongepowered.asm.mixin.Mixin;
|
|||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
import io.akarin.api.CheckedConcurrentLinkedQueue;
|
import io.akarin.api.internal.collections.CheckedConcurrentLinkedQueue;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.util.concurrent.Future;
|
import io.netty.util.concurrent.Future;
|
||||||
import io.netty.util.concurrent.GenericFutureListener;
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
@@ -28,7 +28,7 @@ public abstract class OptimisticNetworkManager {
|
|||||||
|
|
||||||
private static final QueuedPacket SIGNAL_PACKET = new QueuedPacket(null, null);
|
private static final QueuedPacket SIGNAL_PACKET = new QueuedPacket(null, null);
|
||||||
|
|
||||||
@Overwrite
|
@Overwrite // PAIL: trySendQueue
|
||||||
private boolean m() {
|
private boolean m() {
|
||||||
if (this.channel != null && this.channel.isOpen()) {
|
if (this.channel != null && this.channel.isOpen()) {
|
||||||
if (this.packets.isEmpty()) { // return if the packet queue is empty so that the write lock by Anti-Xray doesn't affect the vanilla performance at all
|
if (this.packets.isEmpty()) { // return if the packet queue is empty so that the write lock by Anti-Xray doesn't affect the vanilla performance at all
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package io.akarin.server.mixin.optimization;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
|
import com.destroystokyo.paper.exception.ServerInternalException;
|
||||||
|
|
||||||
|
import net.minecraft.server.IDataManager;
|
||||||
|
import net.minecraft.server.MCUtil;
|
||||||
|
import net.minecraft.server.NBTCompressedStreamTools;
|
||||||
|
import net.minecraft.server.NBTTagCompound;
|
||||||
|
import net.minecraft.server.PersistentBase;
|
||||||
|
import net.minecraft.server.PersistentCollection;
|
||||||
|
|
||||||
|
@Mixin(value = PersistentCollection.class, remap = false)
|
||||||
|
public abstract class MixinPersistentCollection {
|
||||||
|
@Shadow(aliases = "b") @Final private IDataManager dataManager;
|
||||||
|
|
||||||
|
@Overwrite
|
||||||
|
private void a(PersistentBase persistentbase) {
|
||||||
|
if (this.dataManager == null) return;
|
||||||
|
|
||||||
|
File file = this.dataManager.getDataFile(persistentbase.id);
|
||||||
|
if (file == null) return;
|
||||||
|
|
||||||
|
NBTTagCompound nbttagcompound = new NBTTagCompound();
|
||||||
|
nbttagcompound.set("data", persistentbase.b(new NBTTagCompound()));
|
||||||
|
|
||||||
|
// Akarin start
|
||||||
|
MCUtil.scheduleAsyncTask(() -> {
|
||||||
|
try {
|
||||||
|
FileOutputStream fileoutputstream = new FileOutputStream(file);
|
||||||
|
|
||||||
|
NBTCompressedStreamTools.a(nbttagcompound, fileoutputstream);
|
||||||
|
fileoutputstream.close();
|
||||||
|
} catch (Exception exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
ServerInternalException.reportInternalException(exception); // Paper
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Akarin end
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import org.spongepowered.asm.mixin.Overwrite;
|
|||||||
import net.minecraft.server.TileEntityEnchantTable;
|
import net.minecraft.server.TileEntityEnchantTable;
|
||||||
|
|
||||||
@Mixin(value = TileEntityEnchantTable.class, remap = false)
|
@Mixin(value = TileEntityEnchantTable.class, remap = false)
|
||||||
public class MixinTileEntityEnchantTable {
|
public abstract class MixinTileEntityEnchantTable {
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public void e() {} // No tickable
|
public void e() {} // No tickable
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,509 @@
|
|||||||
|
package io.akarin.server.mixin.optimization;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
import org.bukkit.event.block.BlockRedstoneEvent;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
|
import net.minecraft.server.BaseBlockPosition;
|
||||||
|
import net.minecraft.server.Block;
|
||||||
|
import net.minecraft.server.BlockDiodeAbstract;
|
||||||
|
import net.minecraft.server.BlockObserver;
|
||||||
|
import net.minecraft.server.BlockPiston;
|
||||||
|
import net.minecraft.server.BlockPosition;
|
||||||
|
import net.minecraft.server.BlockRedstoneComparator;
|
||||||
|
import net.minecraft.server.BlockRedstoneTorch;
|
||||||
|
import net.minecraft.server.BlockRedstoneWire;
|
||||||
|
import net.minecraft.server.BlockRepeater;
|
||||||
|
import net.minecraft.server.Blocks;
|
||||||
|
import net.minecraft.server.EnumDirection;
|
||||||
|
import net.minecraft.server.IBlockAccess;
|
||||||
|
import net.minecraft.server.IBlockData;
|
||||||
|
import net.minecraft.server.Material;
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
|
@Mixin(value = BlockRedstoneWire.class, remap = false)
|
||||||
|
public abstract class PandaRedstoneWire extends Block {
|
||||||
|
|
||||||
|
protected PandaRedstoneWire(Material material) {
|
||||||
|
super(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Positions that need to be turned off **/
|
||||||
|
private List<BlockPosition> turnOff = Lists.newArrayList();
|
||||||
|
/** Positions that need to be checked to be turned on **/
|
||||||
|
private List<BlockPosition> turnOn = Lists.newArrayList();
|
||||||
|
/** Positions of wire that was updated already (Ordering determines update order and is therefore required!) **/
|
||||||
|
private final Set<BlockPosition> updatedRedstoneWire = Sets.newLinkedHashSet();
|
||||||
|
|
||||||
|
/** Ordered arrays of the facings; Needed for the update order.
|
||||||
|
* I went with a vertical-first order here, but vertical last would work to.
|
||||||
|
* However it should be avoided to update the vertical axis between the horizontal ones as this would cause unneeded directional behavior. **/
|
||||||
|
private static final EnumDirection[] facingsHorizontal = {EnumDirection.WEST, EnumDirection.EAST, EnumDirection.NORTH, EnumDirection.SOUTH};
|
||||||
|
private static final EnumDirection[] facingsVertical = {EnumDirection.DOWN, EnumDirection.UP};
|
||||||
|
private static final EnumDirection[] facings = ArrayUtils.addAll(facingsVertical, facingsHorizontal);
|
||||||
|
|
||||||
|
/** Offsets for all surrounding blocks that need to receive updates **/
|
||||||
|
private static final BaseBlockPosition[] surroundingBlocksOffset;
|
||||||
|
static {
|
||||||
|
Set<BaseBlockPosition> set = Sets.newLinkedHashSet();
|
||||||
|
for (EnumDirection facing : facings) {
|
||||||
|
set.add(facing.getDirectionPosition());
|
||||||
|
}
|
||||||
|
for (EnumDirection facing1 : facings) {
|
||||||
|
BaseBlockPosition v1 = facing1.getDirectionPosition();
|
||||||
|
for (EnumDirection facing2 : facings) {
|
||||||
|
BaseBlockPosition v2 = facing2.getDirectionPosition();
|
||||||
|
set.add(new BaseBlockPosition(v1.getX() + v2.getX(), v1.getY() + v2.getY(), v1.getZ() + v2.getZ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set.remove(BaseBlockPosition.ZERO);
|
||||||
|
surroundingBlocksOffset = set.toArray(new BaseBlockPosition[set.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Shadow(aliases = "g") private boolean canProvidePower;
|
||||||
|
@Shadow public abstract int getPower(World world, BlockPosition pos, int strength);
|
||||||
|
@Shadow(aliases = "b") public abstract boolean isPowerSourceAt(IBlockAccess worldIn, BlockPosition pos, EnumDirection side);
|
||||||
|
|
||||||
|
@Inject(method = "e", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void onUpdateSurroundingRedstone(World worldIn, BlockPosition pos, IBlockData state, CallbackInfoReturnable<IBlockData> cir) {
|
||||||
|
this.updateSurroundingRedstone(worldIn, pos);
|
||||||
|
cir.setReturnValue(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "a*", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void onCalculateCurrentChanges(World worldIn, BlockPosition pos1, BlockPosition pos2, IBlockData state, CallbackInfoReturnable<IBlockData> cir) {
|
||||||
|
this.calculateCurrentChanges(worldIn, pos1);
|
||||||
|
cir.setReturnValue(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculates all surrounding wires and causes all needed updates
|
||||||
|
*
|
||||||
|
* @author panda
|
||||||
|
*
|
||||||
|
* @param world World
|
||||||
|
* @param pos Position that needs updating
|
||||||
|
*/
|
||||||
|
private void updateSurroundingRedstone(World world, BlockPosition pos) {
|
||||||
|
// Recalculate the connected wires
|
||||||
|
this.calculateCurrentChanges(world, pos);
|
||||||
|
|
||||||
|
// Set to collect all the updates, to only execute them once. Ordering required.
|
||||||
|
Set<BlockPosition> blocksNeedingUpdate = Sets.newLinkedHashSet();
|
||||||
|
|
||||||
|
// Add the needed updates
|
||||||
|
for (BlockPosition posi : this.updatedRedstoneWire) {
|
||||||
|
this.addBlocksNeedingUpdate(world, posi, blocksNeedingUpdate);
|
||||||
|
}
|
||||||
|
// Add all other updates to keep known behaviors
|
||||||
|
// They are added in a backwards order because it preserves a commonly used behavior with the update order
|
||||||
|
Iterator<BlockPosition> it = Lists.newLinkedList(this.updatedRedstoneWire).descendingIterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
this.addAllSurroundingBlocks(it.next(), blocksNeedingUpdate);
|
||||||
|
}
|
||||||
|
// Remove updates on the wires as they just were updated
|
||||||
|
blocksNeedingUpdate.removeAll(this.updatedRedstoneWire);
|
||||||
|
/*
|
||||||
|
* Avoid unnecessary updates on the just updated wires A huge scale test
|
||||||
|
* showed about 40% more ticks per second It's probably less in normal
|
||||||
|
* usage but likely still worth it
|
||||||
|
*/
|
||||||
|
this.updatedRedstoneWire.clear();
|
||||||
|
|
||||||
|
// Execute updates
|
||||||
|
for (BlockPosition posi : blocksNeedingUpdate) {
|
||||||
|
world.applyPhysics(posi, (BlockRedstoneWire) (Object) this, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns on or off all connected wires
|
||||||
|
*
|
||||||
|
* @param worldIn World
|
||||||
|
* @param position Position of the wire that received the update
|
||||||
|
*/
|
||||||
|
private void calculateCurrentChanges(World worldIn, BlockPosition position) {
|
||||||
|
// Turn off all connected wires first if needed
|
||||||
|
if (worldIn.getType(position).getBlock() == (BlockRedstoneWire) (Object) this) {
|
||||||
|
turnOff.add(position);
|
||||||
|
} else {
|
||||||
|
// In case this wire was removed, check the surrounding wires
|
||||||
|
this.checkSurroundingWires(worldIn, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!turnOff.isEmpty()) {
|
||||||
|
BlockPosition pos = turnOff.remove(0);
|
||||||
|
IBlockData state = worldIn.getType(pos);
|
||||||
|
int oldPower = state.get(BlockRedstoneWire.POWER).intValue();
|
||||||
|
this.canProvidePower = false;
|
||||||
|
int blockPower = worldIn.z(pos); // PAIL: isBlockIndirectlyGettingPowered
|
||||||
|
this.canProvidePower = true;
|
||||||
|
int wirePower = this.getSurroundingWirePower(worldIn, pos);
|
||||||
|
|
||||||
|
// Lower the strength as it moved a block
|
||||||
|
wirePower--;
|
||||||
|
int newPower = Math.max(blockPower, wirePower);
|
||||||
|
|
||||||
|
// Akarin start - BlockRedstoneEvent
|
||||||
|
if (oldPower != newPower) {
|
||||||
|
BlockRedstoneEvent event = new BlockRedstoneEvent(worldIn.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()), oldPower, newPower);
|
||||||
|
worldIn.getServer().getPluginManager().callEvent(event);
|
||||||
|
newPower = event.getNewCurrent();
|
||||||
|
}
|
||||||
|
// Akarin end
|
||||||
|
|
||||||
|
// Power lowered?
|
||||||
|
if (newPower < oldPower) {
|
||||||
|
// If it's still powered by a direct source (but weaker) mark for turn on
|
||||||
|
if (blockPower > 0 && !this.turnOn.contains(pos)) {
|
||||||
|
this.turnOn.add(pos);
|
||||||
|
}
|
||||||
|
// Set all the way to off for now, because wires that were powered by this need to update first
|
||||||
|
setWireState(worldIn, pos, state, 0);
|
||||||
|
// Power rose?
|
||||||
|
} else if (newPower > oldPower) {
|
||||||
|
// Set new Power
|
||||||
|
this.setWireState(worldIn, pos, state, newPower);
|
||||||
|
}
|
||||||
|
// Check if surrounding wires need to change based on the current/new state and add them to the lists
|
||||||
|
this.checkSurroundingWires(worldIn, pos);
|
||||||
|
}
|
||||||
|
// Now all needed wires are turned off. Time to turn them on again if there is a power source.
|
||||||
|
while (!this.turnOn.isEmpty()) {
|
||||||
|
BlockPosition pos = this.turnOn.remove(0);
|
||||||
|
IBlockData state = worldIn.getType(pos);
|
||||||
|
int oldPower = state.get(BlockRedstoneWire.POWER).intValue();
|
||||||
|
this.canProvidePower = false;
|
||||||
|
int blockPower = worldIn.z(pos); // PAIL: isBlockIndirectlyGettingPowered
|
||||||
|
this.canProvidePower = true;
|
||||||
|
int wirePower = this.getSurroundingWirePower(worldIn, pos);
|
||||||
|
// Lower the strength as it moved a block
|
||||||
|
wirePower--;
|
||||||
|
int newPower = Math.max(blockPower, wirePower);
|
||||||
|
|
||||||
|
// Akarin start - BlockRedstoneEvent
|
||||||
|
BlockRedstoneEvent event = new BlockRedstoneEvent(worldIn.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()), oldPower, newPower);
|
||||||
|
worldIn.getServer().getPluginManager().callEvent(event);
|
||||||
|
newPower = event.getNewCurrent();
|
||||||
|
// Akarin end
|
||||||
|
|
||||||
|
if (newPower > oldPower) {
|
||||||
|
setWireState(worldIn, pos, state, newPower);
|
||||||
|
} else if (newPower < oldPower) {
|
||||||
|
// Add warning
|
||||||
|
}
|
||||||
|
// Check if surrounding wires need to change based on the current/new state and add them to the lists
|
||||||
|
this.checkSurroundingWires(worldIn, pos);
|
||||||
|
}
|
||||||
|
this.turnOff.clear();
|
||||||
|
this.turnOn.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an wire needs to be marked for update depending on the power next to it
|
||||||
|
*
|
||||||
|
* @author panda
|
||||||
|
*
|
||||||
|
* @param worldIn World
|
||||||
|
* @param pos Position of the wire that might need to change
|
||||||
|
* @param otherPower Power of the wire next to it
|
||||||
|
*/
|
||||||
|
private void addWireToList(World worldIn, BlockPosition pos, int otherPower) {
|
||||||
|
IBlockData state = worldIn.getType(pos);
|
||||||
|
if (state.getBlock() == (BlockRedstoneWire) (Object) this) {
|
||||||
|
int power = state.get(BlockRedstoneWire.POWER).intValue();
|
||||||
|
// Could get powered stronger by the neighbor?
|
||||||
|
if (power < (otherPower - 1) && !this.turnOn.contains(pos)) {
|
||||||
|
// Mark for turn on check.
|
||||||
|
this.turnOn.add(pos);
|
||||||
|
}
|
||||||
|
// Should have powered the neighbor? Probably was powered by it and is in turn off phase.
|
||||||
|
if (power > otherPower && !this.turnOff.contains(pos)) {
|
||||||
|
// Mark for turn off check.
|
||||||
|
this.turnOff.add(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the wires around need to get updated depending on this wires state.
|
||||||
|
* Checks all wires below before the same layer before on top to keep
|
||||||
|
* some more rotational symmetry around the y-axis.
|
||||||
|
*
|
||||||
|
* @author panda
|
||||||
|
*
|
||||||
|
* @param worldIn World
|
||||||
|
* @param pos Position of the wire
|
||||||
|
*/
|
||||||
|
private void checkSurroundingWires(World worldIn, BlockPosition pos) {
|
||||||
|
IBlockData state = worldIn.getType(pos);
|
||||||
|
int ownPower = 0;
|
||||||
|
if (state.getBlock() == (BlockRedstoneWire) (Object) this) {
|
||||||
|
ownPower = state.get(BlockRedstoneWire.POWER).intValue();
|
||||||
|
}
|
||||||
|
// Check wires on the same layer first as they appear closer to the wire
|
||||||
|
for (EnumDirection facing : facingsHorizontal) {
|
||||||
|
BlockPosition offsetPos = pos.shift(facing);
|
||||||
|
if (facing.getAxis().isHorizontal()) {
|
||||||
|
this.addWireToList(worldIn, offsetPos, ownPower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (EnumDirection facingVertical : facingsVertical) {
|
||||||
|
BlockPosition offsetPos = pos.shift(facingVertical);
|
||||||
|
boolean solidBlock = worldIn.getType(offsetPos).k(); // PAIL: isBlockNormalCube
|
||||||
|
for (EnumDirection facingHorizontal : facingsHorizontal) {
|
||||||
|
// wire can travel upwards if the block on top doesn't cut the wire (is non-solid)
|
||||||
|
// it can travel down if the block below is solid and the block "diagonal" doesn't cut off the wire (is non-solid)
|
||||||
|
if ((facingVertical == EnumDirection.UP && !solidBlock) || (facingVertical == EnumDirection.DOWN && solidBlock && !worldIn.getType(offsetPos.shift(facingHorizontal)).k())) { // PAIL: isBlockNormalCube
|
||||||
|
this.addWireToList(worldIn, offsetPos.shift(facingHorizontal), ownPower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum power of the surrounding wires
|
||||||
|
*
|
||||||
|
* @author panda
|
||||||
|
*
|
||||||
|
* @param worldIn World
|
||||||
|
* @param pos Position of the asking wire
|
||||||
|
* @return The maximum power of the wires that could power the wire at pos
|
||||||
|
*/
|
||||||
|
private int getSurroundingWirePower(World worldIn, BlockPosition pos) {
|
||||||
|
int wirePower = 0;
|
||||||
|
for (EnumDirection enumfacing : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
|
||||||
|
BlockPosition offsetPos = pos.shift(enumfacing);
|
||||||
|
// Wires on the same layer
|
||||||
|
wirePower = this.getPower(worldIn, offsetPos, wirePower);
|
||||||
|
|
||||||
|
// Block below the wire need to be solid (Upwards diode of slabs/stairs/glowstone) and no block should cut the wire
|
||||||
|
if(worldIn.getType(offsetPos).l() && !worldIn.getType(pos.up()).l()) { // PAIL: isNormalCube
|
||||||
|
wirePower = this.getPower(worldIn, offsetPos.up(), wirePower);
|
||||||
|
// Only get from power below if no block is cutting the wire
|
||||||
|
} else if (!worldIn.getType(offsetPos).l()) { // PAIL: isNormalCube
|
||||||
|
wirePower = this.getPower(worldIn, offsetPos.down(), wirePower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wirePower;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds all blocks that need to receive an update from a redstone change in this position.
|
||||||
|
* This means only blocks that actually could change.
|
||||||
|
*
|
||||||
|
* @author panda
|
||||||
|
*
|
||||||
|
* @param worldIn World
|
||||||
|
* @param pos Position of the wire
|
||||||
|
* @param set Set to add the update positions too
|
||||||
|
*/
|
||||||
|
private void addBlocksNeedingUpdate(World worldIn, BlockPosition pos, Set<BlockPosition> set) {
|
||||||
|
List<EnumDirection> connectedSides = this.getSidesToPower(worldIn, pos);
|
||||||
|
// Add the blocks next to the wire first (closest first order)
|
||||||
|
for (EnumDirection facing : facings) {
|
||||||
|
BlockPosition offsetPos = pos.shift(facing);
|
||||||
|
// canConnectTo() is not the nicest solution here as it returns true for e.g. the front of a repeater
|
||||||
|
// canBlockBePowereFromSide catches these cases
|
||||||
|
if (!connectedSides.contains(facing.opposite()) && facing != EnumDirection.DOWN
|
||||||
|
&& (!facing.getAxis().isHorizontal() || canConnectToBlock(worldIn.getType(offsetPos), facing))) continue;
|
||||||
|
if (this.canBlockBePoweredFromSide(worldIn.getType(offsetPos), facing, true))
|
||||||
|
set.add(offsetPos);
|
||||||
|
}
|
||||||
|
// Later add blocks around the surrounding blocks that get powered
|
||||||
|
for (EnumDirection facing : facings) {
|
||||||
|
BlockPosition offsetPos = pos.shift(facing);
|
||||||
|
if (!connectedSides.contains(facing.opposite()) && facing != EnumDirection.DOWN || !worldIn.getType(offsetPos).l()) continue; // PAIL: isNormalCube
|
||||||
|
for (EnumDirection facing1 : facings) {
|
||||||
|
if (this.canBlockBePoweredFromSide(worldIn.getType(offsetPos.shift(facing1)), facing1, false))
|
||||||
|
set.add(offsetPos.shift(facing1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a block can get powered from a side.
|
||||||
|
* This behavior would better be implemented per block type as follows:
|
||||||
|
* - return false as default. (blocks that are not affected by redstone don't need to be updated, it doesn't really hurt if they are either)
|
||||||
|
* - return true for all blocks that can get powered from all side and change based on it (doors, fence gates, trap doors, note blocks, lamps, dropper, hopper, TNT, rails, possibly more)
|
||||||
|
* - implement own logic for pistons, repeaters, comparators and redstone torches
|
||||||
|
* The current implementation was chosen to keep everything in one class.
|
||||||
|
*
|
||||||
|
* Why is this extra check needed?
|
||||||
|
* 1. It makes sure that many old behaviors still work (QC + Pistons).
|
||||||
|
* 2. It prevents updates from "jumping".
|
||||||
|
* Or rather it prevents this wire to update a block that would get powered by the next one of the same line.
|
||||||
|
* This is to prefer as it makes understanding the update order of the wire really easy. The signal "travels" from the power source.
|
||||||
|
*
|
||||||
|
* @author panda
|
||||||
|
*
|
||||||
|
* @param state State of the block
|
||||||
|
* @param side Side from which it gets powered
|
||||||
|
* @param isWire True if it's powered by a wire directly, False if through a block
|
||||||
|
* @return True if the block can change based on the power level it gets on the given side, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean canBlockBePoweredFromSide(IBlockData state, EnumDirection side, boolean isWire) {
|
||||||
|
if (state.getBlock() instanceof BlockPiston && state.get(BlockPiston.FACING) == side.opposite()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (state.getBlock() instanceof BlockDiodeAbstract && state.get(BlockDiodeAbstract.FACING) != side.opposite()) {
|
||||||
|
if (isWire && state.getBlock() instanceof BlockRedstoneComparator
|
||||||
|
&& state.get(BlockRedstoneComparator.FACING).k() != side.getAxis() && side.getAxis().isHorizontal()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (state.getBlock() instanceof BlockRedstoneTorch) {
|
||||||
|
if (isWire || state.get(BlockRedstoneTorch.FACING) != side) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a list of all horizontal sides that can get powered by a wire.
|
||||||
|
* The list is ordered the same as the facingsHorizontal.
|
||||||
|
*
|
||||||
|
* @param worldIn World
|
||||||
|
* @param pos Position of the wire
|
||||||
|
* @return List of all facings that can get powered by this wire
|
||||||
|
*/
|
||||||
|
private List<EnumDirection> getSidesToPower(World worldIn, BlockPosition pos) {
|
||||||
|
List<EnumDirection> retval = Lists.newArrayList();
|
||||||
|
for (EnumDirection facing : facingsHorizontal) {
|
||||||
|
if (isPowerSourceAt(worldIn, pos, facing))
|
||||||
|
retval.add(facing);
|
||||||
|
}
|
||||||
|
if (retval.isEmpty()) return Lists.newArrayList(facingsHorizontal);
|
||||||
|
boolean northsouth = retval.contains(EnumDirection.NORTH) || retval.contains(EnumDirection.SOUTH);
|
||||||
|
boolean eastwest = retval.contains(EnumDirection.EAST) || retval.contains(EnumDirection.WEST);
|
||||||
|
if (northsouth) {
|
||||||
|
retval.remove(EnumDirection.EAST);
|
||||||
|
retval.remove(EnumDirection.WEST);
|
||||||
|
}
|
||||||
|
if (eastwest) {
|
||||||
|
retval.remove(EnumDirection.NORTH);
|
||||||
|
retval.remove(EnumDirection.SOUTH);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds all surrounding positions to a set.
|
||||||
|
* This is the neighbor blocks, as well as their neighbors
|
||||||
|
*
|
||||||
|
* @param pos
|
||||||
|
* @param set
|
||||||
|
*/
|
||||||
|
private void addAllSurroundingBlocks(BlockPosition pos, Set<BlockPosition> set) {
|
||||||
|
for (BaseBlockPosition vect : surroundingBlocksOffset) {
|
||||||
|
set.add(pos.a(vect)); // PAIL: add
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the block state of a wire with a new power level and marks for updates
|
||||||
|
*
|
||||||
|
* @author panda
|
||||||
|
*
|
||||||
|
* @param worldIn World
|
||||||
|
* @param pos Position at which the state needs to be set
|
||||||
|
* @param state Old state
|
||||||
|
* @param power Power it should get set to
|
||||||
|
*/
|
||||||
|
private void setWireState(World worldIn, BlockPosition pos, IBlockData state, int power) {
|
||||||
|
state = state.set(BlockRedstoneWire.POWER, Integer.valueOf(power));
|
||||||
|
worldIn.setTypeAndData(pos, state, 2);
|
||||||
|
updatedRedstoneWire.add(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author panda
|
||||||
|
* @reason Uses local surrounding block offset list for notifications.
|
||||||
|
*
|
||||||
|
* @param world The world
|
||||||
|
* @param pos The position
|
||||||
|
* @param state The block state
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Overwrite
|
||||||
|
public void onPlace(World world, BlockPosition pos, IBlockData state) {
|
||||||
|
this.updateSurroundingRedstone(world, pos);
|
||||||
|
for (BaseBlockPosition vec : surroundingBlocksOffset) {
|
||||||
|
world.applyPhysics(pos.a(vec), this, false); // PAIL: add
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author panda
|
||||||
|
* @reason Uses local surrounding block offset list for notifications.
|
||||||
|
*
|
||||||
|
* @param world The world
|
||||||
|
* @param pos The position
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Overwrite
|
||||||
|
public void remove(World world, BlockPosition pos, IBlockData state) {
|
||||||
|
super.remove(world, pos, state);
|
||||||
|
this.updateSurroundingRedstone(world, pos);
|
||||||
|
for (BaseBlockPosition vec : surroundingBlocksOffset) {
|
||||||
|
world.applyPhysics(pos.a(vec), this, false); // PAIL: add
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author panda
|
||||||
|
* @reason Changed to use getSidesToPower() to avoid duplicate implementation.
|
||||||
|
*
|
||||||
|
* @param blockState The block state
|
||||||
|
* @param blockAccess The block access
|
||||||
|
* @param pos The position
|
||||||
|
* @param side The side
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Overwrite
|
||||||
|
public int b(IBlockData blockState, IBlockAccess blockAccess, BlockPosition pos, EnumDirection side) { // PAIL: getWeakPower
|
||||||
|
if (!this.canProvidePower) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if (side == EnumDirection.UP || this.getSidesToPower((World) blockAccess, pos).contains(side)) {
|
||||||
|
return blockState.get(BlockRedstoneWire.POWER).intValue();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean canConnectToBlock(IBlockData blockState, @Nullable EnumDirection side) {
|
||||||
|
Block block = blockState.getBlock();
|
||||||
|
|
||||||
|
if (block == Blocks.REDSTONE_WIRE) {
|
||||||
|
return true;
|
||||||
|
} else if (Blocks.UNPOWERED_REPEATER.D(blockState)) { // PAIL: isSameDiode
|
||||||
|
EnumDirection enumdirection1 = blockState.get(BlockRepeater.FACING);
|
||||||
|
|
||||||
|
return enumdirection1 == side || enumdirection1.opposite() == side;
|
||||||
|
} else if (Blocks.dk == blockState.getBlock()) {
|
||||||
|
return side == blockState.get(BlockObserver.FACING); // PAIL: OBSERVER
|
||||||
|
} else {
|
||||||
|
return blockState.m() && side != null; // PAIL: canProvidePower
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ import net.minecraft.server.WorldGenBigTree;
|
|||||||
* Fixes MC-128547(https://bugs.mojang.com/browse/MC-128547)
|
* Fixes MC-128547(https://bugs.mojang.com/browse/MC-128547)
|
||||||
*/
|
*/
|
||||||
@Mixin(value = WorldGenBigTree.class, remap = false)
|
@Mixin(value = WorldGenBigTree.class, remap = false)
|
||||||
public class WeakBigTree {
|
public abstract class WeakBigTree {
|
||||||
@Shadow(aliases = "l") private World worldReference;
|
@Shadow(aliases = "l") private World worldReference;
|
||||||
|
|
||||||
@Inject(method = "generate", at = @At("RETURN"))
|
@Inject(method = "generate", at = @At("RETURN"))
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import net.minecraft.server.ItemStack;
|
|||||||
* Fixes MC-128547(https://bugs.mojang.com/browse/MC-128547)
|
* Fixes MC-128547(https://bugs.mojang.com/browse/MC-128547)
|
||||||
*/
|
*/
|
||||||
@Mixin(value = EnchantmentManager.class, remap = false)
|
@Mixin(value = EnchantmentManager.class, remap = false)
|
||||||
public class WeakEnchantmentManager {
|
public abstract class WeakEnchantmentManager {
|
||||||
@Shadow(aliases = "a") @Final private static EnchantmentManager.EnchantmentModifierProtection protection;
|
@Shadow(aliases = "a") @Final private static EnchantmentManager.EnchantmentModifierProtection protection;
|
||||||
@Shadow(aliases = "c") @Final private static EnchantmentManager.EnchantmentModifierThorns thorns;
|
@Shadow(aliases = "c") @Final private static EnchantmentManager.EnchantmentModifierThorns thorns;
|
||||||
@Shadow(aliases = "d") @Final private static EnchantmentManager.EnchantmentModifierArthropods arthropods;
|
@Shadow(aliases = "d") @Final private static EnchantmentManager.EnchantmentModifierArthropods arthropods;
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.Entity;
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
|
@Mixin(value = Entity.class, remap = false)
|
||||||
|
public abstract class MixinEntity {
|
||||||
|
private static final String ENTITY_RIDABLE_COOLDOWN_FIELD = "Lnet/minecraft/entity/Entity;j:I"; // PUTFIELD: rideCooldown
|
||||||
|
private static final String ENTITY_PORTAL_COUNTER_FIELD = "Lnet/minecraft/entity/Entity;al:I"; // PUTFIELD: portalCounter
|
||||||
|
@Shadow protected int j;
|
||||||
|
@Shadow protected int al;
|
||||||
|
@Shadow public World world;
|
||||||
|
|
||||||
|
// PAIL: onEntityUpdate
|
||||||
|
@Redirect(method = "Y()V", at = @At(value = "FIELD", target = ENTITY_RIDABLE_COOLDOWN_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupEntityCooldown(Entity self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) this.world).getRealTimeTicks();
|
||||||
|
this.j = Math.max(0, this.j - ticks); // PAIL: rideCooldown
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "Y()V", at = @At(value = "FIELD", target = ENTITY_PORTAL_COUNTER_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupPortalCounter(Entity self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) this.world).getRealTimeTicks();
|
||||||
|
this.al += ticks; // PAIL: portalCounter
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.EntityAgeable;
|
||||||
|
|
||||||
|
@Mixin(value = EntityAgeable.class, remap = false)
|
||||||
|
public abstract class MixinEntityAgeable {
|
||||||
|
private static final String ENTITY_AGEABLE_SET_GROWING_AGE_METHOD = "Lnet/minecraft/entity/EntityAgeable;setAgeRaw(I)V";
|
||||||
|
|
||||||
|
// PAIL: onLivingUpdate
|
||||||
|
@Redirect(method = "n()V", at = @At(value = "INVOKE", target = ENTITY_AGEABLE_SET_GROWING_AGE_METHOD, ordinal = 0))
|
||||||
|
public void fixupGrowingUp(EntityAgeable self, int age) {
|
||||||
|
// Subtract the one the original update method added
|
||||||
|
int diff = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks() - 1;
|
||||||
|
self.setAgeRaw(Math.min(0, age + diff));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "n()V", at = @At(value = "INVOKE", target = ENTITY_AGEABLE_SET_GROWING_AGE_METHOD, ordinal = 1))
|
||||||
|
public void fixupBreedingCooldown(EntityAgeable self, int age) {
|
||||||
|
// Subtract the one the original update method added
|
||||||
|
int diff = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks() - 1;
|
||||||
|
self.setAgeRaw(Math.max(0, age - diff));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.EntityExperienceOrb;
|
||||||
|
|
||||||
|
@Mixin(value = EntityExperienceOrb.class, remap = false)
|
||||||
|
public abstract class MixinEntityExperienceOrb {
|
||||||
|
private static final String ENTITY_XP_DELAY_PICKUP_FIELD = "Lnet/minecraft/entity/item/EntityExperienceOrb;c:I"; // PUTFIELD: delayBeforeCanPickup
|
||||||
|
private static final String ENTITY_XP_AGE_FIELD = "Lnet/minecraft/entity/item/EntityExperienceOrb;b:I"; // PUTFIELD: xpOrbAge
|
||||||
|
@Shadow public int c; // PAIL: delayBeforeCanPickup
|
||||||
|
@Shadow public int b; // PAIL: xpOrbAge
|
||||||
|
|
||||||
|
// PAIL: onUpdate
|
||||||
|
@Redirect(method = "B_()V", at = @At(value = "FIELD", target = ENTITY_XP_DELAY_PICKUP_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupPickupDelay(EntityExperienceOrb self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks();
|
||||||
|
this.c = Math.max(0, this.c - ticks); // PAIL: delayBeforeCanPickup
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "B_()V", at = @At(value = "FIELD", target = ENTITY_XP_AGE_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupAge(EntityExperienceOrb self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks();
|
||||||
|
this.b += ticks; // PAIL: xpOrbAge
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.EntityHuman;
|
||||||
|
|
||||||
|
@Mixin(value = EntityHuman.class, remap = false)
|
||||||
|
public abstract class MixinEntityHuman {
|
||||||
|
private static final String ENTITY_PLAYER_XP_COOLDOWN_FIELD = "Lnet/minecraft/entity/player/EntityHuman;bD:I"; // PUTFIELD: xpCooldown
|
||||||
|
private static final String ENTITY_PLAYER_SLEEP_TIMER_FIELD = "Lnet/minecraft/entity/player/EntityHuman;sleepTicks:I";
|
||||||
|
@Shadow public int bD;
|
||||||
|
@Shadow private int sleepTicks;
|
||||||
|
|
||||||
|
// PAIL: onUpdate
|
||||||
|
@Redirect(method = "B_()V", at = @At(value = "FIELD", target = ENTITY_PLAYER_XP_COOLDOWN_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupXpCooldown(EntityHuman self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks();
|
||||||
|
this.bD = Math.max(0, this.bD - ticks); // PAIL: xpCooldown
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "B_()V", at = @At(value = "FIELD", target = ENTITY_PLAYER_SLEEP_TIMER_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupSleepTimer(EntityHuman self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks();
|
||||||
|
this.sleepTicks += ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "B_()V", at = @At(value = "FIELD", target = ENTITY_PLAYER_SLEEP_TIMER_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 2))
|
||||||
|
public void fixupWakeTimer(EntityHuman self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks();
|
||||||
|
this.sleepTicks += ticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.EntityInsentient;
|
||||||
|
import net.minecraft.server.EntityLiving;
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
|
@Mixin(value = EntityInsentient.class, remap = false)
|
||||||
|
public abstract class MixinEntityInsentient extends EntityLiving {
|
||||||
|
private static final String ENTITY_LIVING_AGE_FIELD = "Lnet/minecraft/entity/EntityInsentient;ticksFarFromPlayer:I";
|
||||||
|
|
||||||
|
public MixinEntityInsentient(World world) {
|
||||||
|
super(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "doTick", at = @At(value = "FIELD", target = ENTITY_LIVING_AGE_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupEntityDespawnAge(EntityInsentient self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks();
|
||||||
|
this.ticksFarFromPlayer += ticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.EntityItem;
|
||||||
|
|
||||||
|
@Mixin(value = EntityItem.class, remap = false)
|
||||||
|
public abstract class MixinEntityItem {
|
||||||
|
private static final String ENTITY_ITEM_DELAY_PICKUP_FIELD = "Lnet/minecraft/entity/item/EntityItem;pickupDelay:I";
|
||||||
|
private static final String ENTITY_ITEM_AGE_FIELD = "Lnet/minecraft/entity/item/EntityItem;age:I";
|
||||||
|
@Shadow public int age;
|
||||||
|
@Shadow private int pickupDelay;
|
||||||
|
|
||||||
|
// PAIL: onUpdate
|
||||||
|
@Redirect(method = "B_()V", at = @At(value = "FIELD", target = ENTITY_ITEM_DELAY_PICKUP_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupPickupDelay(EntityItem self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks();
|
||||||
|
this.pickupDelay = Math.max(0, this.pickupDelay - ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "B_()V", at = @At(value = "FIELD", target = ENTITY_ITEM_AGE_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupAge(EntityItem self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks();
|
||||||
|
this.age += ticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.Entity;
|
||||||
|
import net.minecraft.server.EntityPlayer;
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
|
@Mixin(value = EntityPlayer.class, remap = false)
|
||||||
|
public abstract class MixinEntityPlayer extends Entity {
|
||||||
|
private static final String ENTITY_PLAYER_MP_PORTAL_COOLDOWN_FIELD = "Lnet/minecraft/entity/player/EntityPlayer;portalCooldown:I";
|
||||||
|
|
||||||
|
public MixinEntityPlayer(World worldIn) {
|
||||||
|
super(worldIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PAIL: decrementTimeUntilPortal
|
||||||
|
@Redirect(method = "I()V", at = @At(value = "FIELD", target = ENTITY_PLAYER_MP_PORTAL_COOLDOWN_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupPortalCooldown(EntityPlayer self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks();
|
||||||
|
this.portalCooldown = Math.max(0, this.portalCooldown - ticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.EntityZombieVillager;
|
||||||
|
|
||||||
|
@Mixin(value = EntityZombieVillager.class, remap = false)
|
||||||
|
public abstract class MixinEntityZombieVillager {
|
||||||
|
private static final String ENTITY_ZOMBIE_GET_CONVERSION_BOOST_METHOD = "Lnet/minecraft/entity/monster/EntityZombieVillager;du()I"; // INVOKE: getConversionProgress
|
||||||
|
|
||||||
|
@Shadow(aliases = "du") protected abstract int getConversionProgress();
|
||||||
|
|
||||||
|
// PAIL: onUpdate
|
||||||
|
@Redirect(method = "B_()V", at = @At(value = "INVOKE", target = ENTITY_ZOMBIE_GET_CONVERSION_BOOST_METHOD, ordinal = 0))
|
||||||
|
public int fixupConversionTimeBoost(EntityZombieVillager self) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) self.getWorld()).getRealTimeTicks();
|
||||||
|
return this.getConversionProgress() * ticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
|
@Mixin(value = MinecraftServer.class, remap = false, priority = 1001)
|
||||||
|
public abstract class MixinMinecraftServer implements IMixinRealTimeTicking {
|
||||||
|
private static long lastTickNanos = System.nanoTime();
|
||||||
|
private static long realTimeTicks = 1;
|
||||||
|
|
||||||
|
@Inject(method = "C()V", at = @At("HEAD")) // PAIL: fullTick
|
||||||
|
public void onTickUpdateRealTimeTicks(CallbackInfo ci) {
|
||||||
|
long currentNanos = System.nanoTime();
|
||||||
|
realTimeTicks = (currentNanos - lastTickNanos) / 50000000;
|
||||||
|
if (realTimeTicks < 1) {
|
||||||
|
realTimeTicks = 1;
|
||||||
|
}
|
||||||
|
lastTickNanos = currentNanos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRealTimeTicks() {
|
||||||
|
return realTimeTicks;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.PlayerConnection;
|
||||||
|
|
||||||
|
@Mixin(value = PlayerConnection.class, remap = false)
|
||||||
|
public abstract class MixinPlayerConnection {
|
||||||
|
private static final String NET_HANDLER_PLAY_CHAT_SPAM_FIELD = "Lnet/minecraft/network/PlayerConnection;chatThrottle:I";
|
||||||
|
private static final String NET_HANDLER_PLAY_DROP_SPAM_FIELD = "Lnet/minecraft/network/PlayerConnection;itemDropThreshold:I";
|
||||||
|
@Shadow private volatile int chatThrottle;
|
||||||
|
@Shadow(aliases = "j") private int itemDropThreshold;
|
||||||
|
@Shadow @Final private MinecraftServer minecraftServer;
|
||||||
|
|
||||||
|
// PAIL: update
|
||||||
|
@Redirect(method = "e()V", at = @At(value = "FIELD", target = NET_HANDLER_PLAY_CHAT_SPAM_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupChatSpamCheck(PlayerConnection self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) this.minecraftServer).getRealTimeTicks();
|
||||||
|
this.chatThrottle = Math.max(0, this.chatThrottle - ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "e()V", at = @At(value = "FIELD", target = NET_HANDLER_PLAY_DROP_SPAM_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupDropSpamCheck(PlayerConnection self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) this.minecraftServer).getRealTimeTicks();
|
||||||
|
this.itemDropThreshold = Math.max(0, this.itemDropThreshold - ticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.PlayerInteractManager;
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
|
@Mixin(value = PlayerInteractManager.class, remap = false)
|
||||||
|
public abstract class MixinPlayerInteractManager {
|
||||||
|
private static final String PLAYER_INTERACTION_BLOCK_DAMAGE_FIELD = "Lnet/minecraft/server/management/PlayerInteractManager;currentTick:I";
|
||||||
|
@Shadow public World world;
|
||||||
|
@Shadow private int currentTick;
|
||||||
|
|
||||||
|
// PAIL: updateBlockRemoving
|
||||||
|
@Redirect(method = "a()V", at = @At(value = "FIELD", target = PLAYER_INTERACTION_BLOCK_DAMAGE_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupDiggingTime(PlayerInteractManager self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) this.world.getMinecraftServer()).getRealTimeTicks();
|
||||||
|
this.currentTick += ticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.TileEntity;
|
||||||
|
import net.minecraft.server.TileEntityBrewingStand;
|
||||||
|
|
||||||
|
@Mixin(value = TileEntityBrewingStand.class, remap = false)
|
||||||
|
public abstract class MixinTileEntityBrewingStand extends TileEntity {
|
||||||
|
private static final String BREWING_STAND_BREW_TIME_FIELD = "Lnet/minecraft/tileentity/TileEntityBrewingStand;brewTime:I";
|
||||||
|
@Shadow private int brewTime;
|
||||||
|
|
||||||
|
// PAIL: update
|
||||||
|
@Redirect(method = "e()V", at = @At(value = "FIELD", target = BREWING_STAND_BREW_TIME_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupBrewTime(TileEntityBrewingStand self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) this.getWorld()).getRealTimeTicks();
|
||||||
|
this.brewTime = Math.max(0, this.brewTime - ticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.MathHelper;
|
||||||
|
import net.minecraft.server.TileEntity;
|
||||||
|
import net.minecraft.server.TileEntityFurnace;
|
||||||
|
|
||||||
|
@Mixin(value = TileEntityFurnace.class, remap = false)
|
||||||
|
public abstract class MixinTileEntityFurnace extends TileEntity {
|
||||||
|
private static final String FURNACE_BURN_TIME_FIELD = "Lnet/minecraft/tileentity/TileEntityFurnace;burnTime:I";
|
||||||
|
private static final String FURNACE_COOK_TIME_FIELD = "Lnet/minecraft/tileentity/TileEntityFurnace;cookTime:I";
|
||||||
|
@Shadow private int burnTime;
|
||||||
|
@Shadow private int cookTime;
|
||||||
|
@Shadow private int cookTimeTotal;
|
||||||
|
|
||||||
|
// PAIL: update
|
||||||
|
@Redirect(method = "e()V", at = @At(value = "FIELD", target = FURNACE_BURN_TIME_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupBurnTime(TileEntityFurnace self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) this.getWorld()).getRealTimeTicks();
|
||||||
|
this.burnTime = Math.max(0, this.burnTime - ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "e()V", at = @At(value = "FIELD", target = FURNACE_COOK_TIME_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
|
||||||
|
public void fixupCookTime(TileEntityFurnace self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) this.getWorld()).getRealTimeTicks();
|
||||||
|
this.cookTime = Math.min(this.cookTimeTotal, this.cookTime + ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "e()V", at = @At(value = "FIELD", target = FURNACE_COOK_TIME_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 3))
|
||||||
|
public void fixupCookTimeCooldown(TileEntityFurnace self, int modifier) {
|
||||||
|
int ticks = (int) ((IMixinRealTimeTicking) this.getWorld()).getRealTimeTicks();
|
||||||
|
this.cookTime = MathHelper.clamp(this.cookTime - (2 * ticks), 0, this.cookTimeTotal);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
|
@Mixin(value = World.class, remap = false, priority = 1002)
|
||||||
|
public abstract class MixinWorld implements IMixinRealTimeTicking {
|
||||||
|
@Shadow @Nullable public abstract MinecraftServer getMinecraftServer();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRealTimeTicks() {
|
||||||
|
if (this.getMinecraftServer() != null) {
|
||||||
|
return ((IMixinRealTimeTicking) this.getMinecraftServer()).getRealTimeTicks();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Sponge, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.akarin.server.mixin.realtime;
|
||||||
|
|
||||||
|
import org.bukkit.World.Environment;
|
||||||
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import io.akarin.api.internal.mixin.IMixinRealTimeTicking;
|
||||||
|
import net.minecraft.server.IDataManager;
|
||||||
|
import net.minecraft.server.MethodProfiler;
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
import net.minecraft.server.WorldData;
|
||||||
|
import net.minecraft.server.WorldProvider;
|
||||||
|
import net.minecraft.server.WorldServer;
|
||||||
|
|
||||||
|
@Mixin(value = WorldServer.class, remap = false, priority = 1001)
|
||||||
|
public abstract class MixinWorldServer extends World implements IMixinRealTimeTicking {
|
||||||
|
|
||||||
|
protected MixinWorldServer(IDataManager idatamanager, WorldData worlddata, WorldProvider worldprovider, MethodProfiler methodprofiler, boolean flag, ChunkGenerator gen, Environment env) {
|
||||||
|
super(idatamanager, worlddata, worldprovider, methodprofiler, flag, gen, env);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "doTick()V", at = @At("HEAD"))
|
||||||
|
public void fixTimeOfDay(CallbackInfo ci) {
|
||||||
|
if (this.getGameRules().getBoolean("doDaylightCycle")) {
|
||||||
|
// Subtract the one the original tick method is going to add
|
||||||
|
long diff = this.getRealTimeTicks() - 1;
|
||||||
|
// Don't set if we're not changing it as other mods might be listening for changes
|
||||||
|
if (diff > 0) {
|
||||||
|
this.worldData.setDayTime(this.worldData.getDayTime() + diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import com.google.common.base.Predicate;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Queues;
|
import com.google.common.collect.Queues;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -18,6 +19,13 @@ import com.google.common.collect.Lists; // CraftBukkit
|
|||||||
import org.bukkit.Server; // CraftBukkit
|
import org.bukkit.Server; // CraftBukkit
|
||||||
import org.bukkit.craftbukkit.util.CraftMagicNumbers; // Paper
|
import org.bukkit.craftbukkit.util.CraftMagicNumbers; // Paper
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>Akarin Changes Note</b><br>
|
||||||
|
* <br>
|
||||||
|
* 1) Add volatile to fields<br>
|
||||||
|
* 2) Add OBFHELPER<br>
|
||||||
|
* @author cakoyo
|
||||||
|
*/
|
||||||
public class Chunk {
|
public class Chunk {
|
||||||
|
|
||||||
private static final Logger e = LogManager.getLogger();
|
private static final Logger e = LogManager.getLogger();
|
||||||
@@ -26,7 +34,7 @@ public class Chunk {
|
|||||||
private final byte[] g;
|
private final byte[] g;
|
||||||
private final int[] h;
|
private final int[] h;
|
||||||
private final boolean[] i;
|
private final boolean[] i;
|
||||||
private boolean j;
|
private boolean j; public boolean isLoaded() { return j; } // Paper - OBFHELPER
|
||||||
public final World world;
|
public final World world;
|
||||||
public final int[] heightMap;
|
public final int[] heightMap;
|
||||||
public Long scheduledForUnload; // Paper - delay chunk unloads
|
public Long scheduledForUnload; // Paper - delay chunk unloads
|
||||||
@@ -35,10 +43,39 @@ public class Chunk {
|
|||||||
private boolean m;
|
private boolean m;
|
||||||
public final Map<BlockPosition, TileEntity> tileEntities;
|
public final Map<BlockPosition, TileEntity> tileEntities;
|
||||||
public final List<Entity>[] entitySlices; // Spigot
|
public final List<Entity>[] entitySlices; // Spigot
|
||||||
final PaperLightingQueue.LightingQueue lightingQueue = new PaperLightingQueue.LightingQueue(this); // Paper
|
// Paper start
|
||||||
private boolean done;
|
public final co.aikar.util.Counter<String> entityCounts = new co.aikar.util.Counter<>();
|
||||||
private boolean lit;
|
public final co.aikar.util.Counter<String> tileEntityCounts = new co.aikar.util.Counter<>();
|
||||||
private boolean r; private boolean isTicked() { return r; }; // Paper - OBFHELPER
|
private class TileEntityHashMap extends java.util.HashMap<BlockPosition, TileEntity> {
|
||||||
|
@Override
|
||||||
|
public TileEntity put(BlockPosition key, TileEntity value) {
|
||||||
|
TileEntity replaced = super.put(key, value);
|
||||||
|
if (replaced != null) {
|
||||||
|
replaced.setCurrentChunk(null);
|
||||||
|
tileEntityCounts.decrement(replaced.tileEntityKeyString);
|
||||||
|
}
|
||||||
|
if (value != null) {
|
||||||
|
value.setCurrentChunk(Chunk.this);
|
||||||
|
tileEntityCounts.increment(value.tileEntityKeyString);
|
||||||
|
}
|
||||||
|
return replaced;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileEntity remove(Object key) {
|
||||||
|
TileEntity removed = super.remove(key);
|
||||||
|
if (removed != null) {
|
||||||
|
removed.setCurrentChunk(null);
|
||||||
|
tileEntityCounts.decrement(removed.tileEntityKeyString);
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public final PaperLightingQueue.LightingQueue lightingQueue = new PaperLightingQueue.LightingQueue(this); // Akarin - public
|
||||||
|
// Paper end
|
||||||
|
private volatile boolean done; // Akarin - volatile
|
||||||
|
private volatile boolean lit; // Akarin - volatile
|
||||||
|
private volatile boolean r; private boolean isTicked() { return r; }; // Paper - OBFHELPER // Akarin - volatile
|
||||||
private boolean s;
|
private boolean s;
|
||||||
private boolean t;
|
private boolean t;
|
||||||
private long lastSaved;
|
private long lastSaved;
|
||||||
@@ -90,10 +127,10 @@ public class Chunk {
|
|||||||
this.g = new byte[256];
|
this.g = new byte[256];
|
||||||
this.h = new int[256];
|
this.h = new int[256];
|
||||||
this.i = new boolean[256];
|
this.i = new boolean[256];
|
||||||
this.tileEntities = Maps.newHashMap();
|
this.tileEntities = new TileEntityHashMap(); // Paper
|
||||||
this.x = 4096;
|
this.x = 4096;
|
||||||
this.y = Queues.newConcurrentLinkedQueue();
|
this.y = Queues.newConcurrentLinkedQueue();
|
||||||
this.entitySlices = (new List[16]); // Spigot
|
this.entitySlices = (List[]) (new List[16]); // Spigot
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.locX = i;
|
this.locX = i;
|
||||||
this.locZ = j;
|
this.locZ = j;
|
||||||
@@ -459,7 +496,6 @@ public class Chunk {
|
|||||||
return CrashReportSystemDetails.a(i, j, k);
|
return CrashReportSystemDetails.a(i, j, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object call() throws Exception {
|
public Object call() throws Exception {
|
||||||
return this.a();
|
return this.a();
|
||||||
}
|
}
|
||||||
@@ -668,9 +704,14 @@ public class Chunk {
|
|||||||
this.entityCount.adjustOrPutValue( creatureType.a(), 1, 1 );
|
this.entityCount.adjustOrPutValue( creatureType.a(), 1, 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Paper start
|
||||||
|
entity.setCurrentChunk(this);
|
||||||
|
entityCounts.increment(entity.entityKeyString);
|
||||||
|
// Paper end
|
||||||
// Spigot end
|
// Spigot end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeEntity(Entity entity) { b(entity); } // Paper - OBFHELPER
|
||||||
public void b(Entity entity) {
|
public void b(Entity entity) {
|
||||||
this.a(entity, entity.ac);
|
this.a(entity, entity.ac);
|
||||||
}
|
}
|
||||||
@@ -707,6 +748,10 @@ public class Chunk {
|
|||||||
this.entityCount.adjustValue( creatureType.a(), -1 );
|
this.entityCount.adjustValue( creatureType.a(), -1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Paper start
|
||||||
|
entity.setCurrentChunk(null);
|
||||||
|
entityCounts.decrement(entity.entityKeyString);
|
||||||
|
// Paper end
|
||||||
// Spigot end
|
// Spigot end
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,7 +780,7 @@ public class Chunk {
|
|||||||
tileentity = world.capturedTileEntities.get(blockposition);
|
tileentity = world.capturedTileEntities.get(blockposition);
|
||||||
}
|
}
|
||||||
if (tileentity == null) {
|
if (tileentity == null) {
|
||||||
tileentity = this.tileEntities.get(blockposition);
|
tileentity = (TileEntity) this.tileEntities.get(blockposition);
|
||||||
}
|
}
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
|
|
||||||
@@ -767,7 +812,7 @@ public class Chunk {
|
|||||||
tileentity.setPosition(blockposition);
|
tileentity.setPosition(blockposition);
|
||||||
if (this.getBlockData(blockposition).getBlock() instanceof ITileEntity) {
|
if (this.getBlockData(blockposition).getBlock() instanceof ITileEntity) {
|
||||||
if (this.tileEntities.containsKey(blockposition)) {
|
if (this.tileEntities.containsKey(blockposition)) {
|
||||||
this.tileEntities.get(blockposition).z();
|
((TileEntity) this.tileEntities.get(blockposition)).z();
|
||||||
}
|
}
|
||||||
|
|
||||||
tileentity.A();
|
tileentity.A();
|
||||||
@@ -789,6 +834,7 @@ public class Chunk {
|
|||||||
|
|
||||||
if (this.world.paperConfig.removeCorruptTEs) {
|
if (this.world.paperConfig.removeCorruptTEs) {
|
||||||
this.removeTileEntity(tileentity.getPosition());
|
this.removeTileEntity(tileentity.getPosition());
|
||||||
|
this.markDirty();
|
||||||
org.bukkit.Bukkit.getLogger().info("Removing corrupt tile entity");
|
org.bukkit.Bukkit.getLogger().info("Removing corrupt tile entity");
|
||||||
}
|
}
|
||||||
// Paper end
|
// Paper end
|
||||||
@@ -799,7 +845,7 @@ public class Chunk {
|
|||||||
public void removeTileEntity(BlockPosition blockposition) { this.d(blockposition); } // Paper - OBFHELPER
|
public void removeTileEntity(BlockPosition blockposition) { this.d(blockposition); } // Paper - OBFHELPER
|
||||||
public void d(BlockPosition blockposition) {
|
public void d(BlockPosition blockposition) {
|
||||||
if (this.j) {
|
if (this.j) {
|
||||||
TileEntity tileentity = this.tileEntities.remove(blockposition);
|
TileEntity tileentity = (TileEntity) this.tileEntities.remove(blockposition);
|
||||||
|
|
||||||
if (tileentity != null) {
|
if (tileentity != null) {
|
||||||
tileentity.z();
|
tileentity.z();
|
||||||
@@ -817,7 +863,7 @@ public class Chunk {
|
|||||||
for (int j = 0; j < i; ++j) {
|
for (int j = 0; j < i; ++j) {
|
||||||
List entityslice = aentityslice[j]; // Spigot
|
List entityslice = aentityslice[j]; // Spigot
|
||||||
|
|
||||||
this.world.a(entityslice);
|
this.world.a((Collection) entityslice);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -831,11 +877,11 @@ public class Chunk {
|
|||||||
// Spigot Start
|
// Spigot Start
|
||||||
if ( tileentity instanceof IInventory )
|
if ( tileentity instanceof IInventory )
|
||||||
{
|
{
|
||||||
for ( org.bukkit.entity.HumanEntity h : Lists.<org.bukkit.entity.HumanEntity>newArrayList(( (IInventory) tileentity ).getViewers() ) )
|
for ( org.bukkit.entity.HumanEntity h : Lists.<org.bukkit.entity.HumanEntity>newArrayList((List<org.bukkit.entity.HumanEntity>) ( (IInventory) tileentity ).getViewers() ) )
|
||||||
{
|
{
|
||||||
if ( h instanceof org.bukkit.craftbukkit.entity.CraftHumanEntity )
|
if ( h instanceof org.bukkit.craftbukkit.entity.CraftHumanEntity )
|
||||||
{
|
{
|
||||||
( (org.bukkit.craftbukkit.entity.CraftHumanEntity) h).getHandle().closeInventory();
|
( (org.bukkit.craftbukkit.entity.CraftHumanEntity) h).getHandle().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -856,11 +902,11 @@ public class Chunk {
|
|||||||
// Spigot Start
|
// Spigot Start
|
||||||
if ( entity instanceof IInventory )
|
if ( entity instanceof IInventory )
|
||||||
{
|
{
|
||||||
for ( org.bukkit.entity.HumanEntity h : Lists.<org.bukkit.entity.HumanEntity>newArrayList( ( (IInventory) entity ).getViewers() ) )
|
for ( org.bukkit.entity.HumanEntity h : Lists.<org.bukkit.entity.HumanEntity>newArrayList( (List<org.bukkit.entity.HumanEntity>) ( (IInventory) entity ).getViewers() ) )
|
||||||
{
|
{
|
||||||
if ( h instanceof org.bukkit.craftbukkit.entity.CraftHumanEntity )
|
if ( h instanceof org.bukkit.craftbukkit.entity.CraftHumanEntity )
|
||||||
{
|
{
|
||||||
( (org.bukkit.craftbukkit.entity.CraftHumanEntity) h).getHandle().closeInventory();
|
( (org.bukkit.craftbukkit.entity.CraftHumanEntity) h).getHandle().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -975,7 +1021,7 @@ public class Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Random a(long i) {
|
public Random a(long i) {
|
||||||
return new Random(this.world.getSeed() + this.locX * this.locX * 4987142 + this.locX * 5947611 + this.locZ * this.locZ * 4392871L + this.locZ * 389711 ^ i);
|
return new Random(this.world.getSeed() + (long) (this.locX * this.locX * 4987142) + (long) (this.locX * 5947611) + (long) (this.locZ * this.locZ) * 4392871L + (long) (this.locZ * 389711) ^ i);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
@@ -1055,7 +1101,7 @@ public class Chunk {
|
|||||||
random.setSeed(world.getSeed());
|
random.setSeed(world.getSeed());
|
||||||
long xRand = random.nextLong() / 2L * 2L + 1L;
|
long xRand = random.nextLong() / 2L * 2L + 1L;
|
||||||
long zRand = random.nextLong() / 2L * 2L + 1L;
|
long zRand = random.nextLong() / 2L * 2L + 1L;
|
||||||
random.setSeed(locX * xRand + locZ * zRand ^ world.getSeed());
|
random.setSeed((long) locX * xRand + (long) locZ * zRand ^ world.getSeed());
|
||||||
|
|
||||||
org.bukkit.World world = this.world.getWorld();
|
org.bukkit.World world = this.world.getWorld();
|
||||||
if (world != null) {
|
if (world != null) {
|
||||||
@@ -1116,7 +1162,7 @@ public class Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (!this.y.isEmpty()) {
|
while (!this.y.isEmpty()) {
|
||||||
BlockPosition blockposition = this.y.poll();
|
BlockPosition blockposition = (BlockPosition) this.y.poll();
|
||||||
|
|
||||||
if (this.a(blockposition, Chunk.EnumTileEntityState.CHECK) == null && this.getBlockData(blockposition).getBlock().isTileEntity()) {
|
if (this.a(blockposition, Chunk.EnumTileEntityState.CHECK) == null && this.getBlockData(blockposition).getBlock().isTileEntity()) {
|
||||||
TileEntity tileentity = this.g(blockposition);
|
TileEntity tileentity = this.g(blockposition);
|
||||||
@@ -1137,7 +1183,7 @@ public class Chunk {
|
|||||||
* For now at least we will simply send all chunks, in accordance with pre 1.7 behaviour.
|
* For now at least we will simply send all chunks, in accordance with pre 1.7 behaviour.
|
||||||
*/
|
*/
|
||||||
// Paper Start
|
// Paper Start
|
||||||
// if randomLightUpdates are enabled, we should always return true, otherwise chunks may never send
|
// if randomLightUpdates are disabled, we should always return true, otherwise chunks may never send
|
||||||
// to the client due to not being lit, otherwise retain standard behavior and only send properly lit chunks.
|
// to the client due to not being lit, otherwise retain standard behavior and only send properly lit chunks.
|
||||||
return !this.world.spigotConfig.randomLightUpdates || (this.isTicked() && this.done && this.lit);
|
return !this.world.spigotConfig.randomLightUpdates || (this.isTicked() && this.done && this.lit);
|
||||||
// Paper End
|
// Paper End
|
||||||
@@ -1298,7 +1344,8 @@ public class Chunk {
|
|||||||
this.h(false);
|
this.h(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void a(EnumDirection enumdirection) { // Akarin - private -> public - PAIL: checkLightSide
|
public void checkLightSide(EnumDirection direction) { a(direction); } // Akarin - OBFHELPER
|
||||||
|
private void a(EnumDirection enumdirection) {
|
||||||
if (this.done) {
|
if (this.done) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -1333,7 +1380,7 @@ public class Chunk {
|
|||||||
|
|
||||||
for (l = k + 16 - 1; l > this.world.getSeaLevel() || l > 0 && !flag1; --l) {
|
for (l = k + 16 - 1; l > this.world.getSeaLevel() || l > 0 && !flag1; --l) {
|
||||||
blockposition_mutableblockposition.c(blockposition_mutableblockposition.getX(), l, blockposition_mutableblockposition.getZ());
|
blockposition_mutableblockposition.c(blockposition_mutableblockposition.getX(), l, blockposition_mutableblockposition.getZ());
|
||||||
int i1 = this.b(blockposition_mutableblockposition);
|
int i1 = this.b((BlockPosition) blockposition_mutableblockposition);
|
||||||
|
|
||||||
if (i1 == 255 && blockposition_mutableblockposition.getY() < this.world.getSeaLevel()) {
|
if (i1 == 255 && blockposition_mutableblockposition.getY() < this.world.getSeaLevel()) {
|
||||||
flag1 = true;
|
flag1 = true;
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
if (worldserver.worldProvider.m() && worldserver.getWorldData().getGameType() != EnumGamemode.ADVENTURE) {
|
if (worldserver.worldProvider.m() && worldserver.getWorldData().getGameType() != EnumGamemode.ADVENTURE) {
|
||||||
int i = Math.max(0, minecraftserver.a(worldserver));
|
int i = Math.max(0, minecraftserver.a(worldserver));
|
||||||
int j = MathHelper.floor(worldserver.getWorldBorder().b(blockposition.getX(), blockposition.getZ()));
|
int j = MathHelper.floor(worldserver.getWorldBorder().b((double) blockposition.getX(), (double) blockposition.getZ()));
|
||||||
|
|
||||||
if (j < i) {
|
if (j < i) {
|
||||||
i = j;
|
i = j;
|
||||||
@@ -146,7 +146,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(NBTTagCompound nbttagcompound) {
|
public void a(NBTTagCompound nbttagcompound) {
|
||||||
super.a(nbttagcompound);
|
super.a(nbttagcompound);
|
||||||
if (this.locY > 300) this.locY = 257; // Paper - bring down to a saner Y level if out of world
|
if (this.locY > 300) this.locY = 257; // Paper - bring down to a saner Y level if out of world
|
||||||
@@ -174,7 +173,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
public static void a(DataConverterManager dataconvertermanager) {
|
public static void a(DataConverterManager dataconvertermanager) {
|
||||||
dataconvertermanager.a(DataConverterTypes.PLAYER, new DataInspector() {
|
dataconvertermanager.a(DataConverterTypes.PLAYER, new DataInspector() {
|
||||||
@Override
|
|
||||||
public NBTTagCompound a(DataConverter dataconverter, NBTTagCompound nbttagcompound, int i) {
|
public NBTTagCompound a(DataConverter dataconverter, NBTTagCompound nbttagcompound, int i) {
|
||||||
if (nbttagcompound.hasKeyOfType("RootVehicle", 10)) {
|
if (nbttagcompound.hasKeyOfType("RootVehicle", 10)) {
|
||||||
NBTTagCompound nbttagcompound1 = nbttagcompound.getCompound("RootVehicle");
|
NBTTagCompound nbttagcompound1 = nbttagcompound.getCompound("RootVehicle");
|
||||||
@@ -189,7 +187,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void b(NBTTagCompound nbttagcompound) {
|
public void b(NBTTagCompound nbttagcompound) {
|
||||||
super.b(nbttagcompound);
|
super.b(nbttagcompound);
|
||||||
nbttagcompound.setInt("playerGameType", this.playerInteractManager.getGameMode().getId());
|
nbttagcompound.setInt("playerGameType", this.playerInteractManager.getGameMode().getId());
|
||||||
@@ -221,7 +218,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CraftBukkit start - World fallback code, either respawn location or global spawn
|
// CraftBukkit start - World fallback code, either respawn location or global spawn
|
||||||
@Override
|
|
||||||
public void spawnIn(World world) {
|
public void spawnIn(World world) {
|
||||||
super.spawnIn(world);
|
super.spawnIn(world);
|
||||||
if (world == null) {
|
if (world == null) {
|
||||||
@@ -246,13 +242,11 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
|
|
||||||
@Override
|
|
||||||
public void levelDown(int i) {
|
public void levelDown(int i) {
|
||||||
super.levelDown(i);
|
super.levelDown(i);
|
||||||
this.lastSentExp = -1;
|
this.lastSentExp = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enchantDone(ItemStack itemstack, int i) {
|
public void enchantDone(ItemStack itemstack, int i) {
|
||||||
super.enchantDone(itemstack, i);
|
super.enchantDone(itemstack, i);
|
||||||
this.lastSentExp = -1;
|
this.lastSentExp = -1;
|
||||||
@@ -262,29 +256,24 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.activeContainer.addSlotListener(this);
|
this.activeContainer.addSlotListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enterCombat() {
|
public void enterCombat() {
|
||||||
super.enterCombat();
|
super.enterCombat();
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutCombatEvent(this.getCombatTracker(), PacketPlayOutCombatEvent.EnumCombatEventType.ENTER_COMBAT));
|
this.playerConnection.sendPacket(new PacketPlayOutCombatEvent(this.getCombatTracker(), PacketPlayOutCombatEvent.EnumCombatEventType.ENTER_COMBAT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exitCombat() {
|
public void exitCombat() {
|
||||||
super.exitCombat();
|
super.exitCombat();
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutCombatEvent(this.getCombatTracker(), PacketPlayOutCombatEvent.EnumCombatEventType.END_COMBAT));
|
this.playerConnection.sendPacket(new PacketPlayOutCombatEvent(this.getCombatTracker(), PacketPlayOutCombatEvent.EnumCombatEventType.END_COMBAT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void a(IBlockData iblockdata) {
|
protected void a(IBlockData iblockdata) {
|
||||||
CriterionTriggers.d.a(this, iblockdata);
|
CriterionTriggers.d.a(this, iblockdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ItemCooldown l() {
|
protected ItemCooldown l() {
|
||||||
return new ItemCooldownPlayer(this);
|
return new ItemCooldownPlayer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void B_() {
|
public void B_() {
|
||||||
// CraftBukkit start
|
// CraftBukkit start
|
||||||
if (this.joining) {
|
if (this.joining) {
|
||||||
@@ -304,7 +293,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
// Paper end
|
// Paper end
|
||||||
if (!this.world.isClientSide && !this.activeContainer.canUse(this)) {
|
if (!this.world.isClientSide && !this.activeContainer.canUse(this)) {
|
||||||
this.closeInventory();
|
this.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper
|
||||||
this.activeContainer = this.defaultContainer;
|
this.activeContainer = this.defaultContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +348,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
ItemStack itemstack = this.inventory.getItem(i);
|
ItemStack itemstack = this.inventory.getItem(i);
|
||||||
|
|
||||||
if (!itemstack.isEmpty() && itemstack.getItem().f()) {
|
if (!itemstack.isEmpty() && itemstack.getItem().f()) {
|
||||||
Packet packet = ((ItemWorldMapBase) itemstack.getItem()).a(itemstack, this.world, this);
|
Packet packet = ((ItemWorldMapBase) itemstack.getItem()).a(itemstack, this.world, (EntityHuman) this);
|
||||||
|
|
||||||
if (packet != null) {
|
if (packet != null) {
|
||||||
this.playerConnection.sendPacket(packet);
|
this.playerConnection.sendPacket(packet);
|
||||||
@@ -425,7 +414,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.oldLevel != this.expLevel) {
|
if (this.oldLevel != this.expLevel) {
|
||||||
CraftEventFactory.callPlayerLevelChangeEvent(this.world.getServer().getPlayer(this), this.oldLevel, this.expLevel);
|
CraftEventFactory.callPlayerLevelChangeEvent(this.world.getServer().getPlayer((EntityPlayer) this), this.oldLevel, this.expLevel);
|
||||||
this.oldLevel = this.expLevel;
|
this.oldLevel = this.expLevel;
|
||||||
}
|
}
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
@@ -450,7 +439,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void die(DamageSource damagesource) {
|
public void die(DamageSource damagesource) {
|
||||||
boolean flag = this.world.getGameRules().getBoolean("showDeathMessages");
|
boolean flag = this.world.getGameRules().getBoolean("showDeathMessages");
|
||||||
|
|
||||||
@@ -483,9 +471,9 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
if (scoreboardteambase != null && scoreboardteambase.getDeathMessageVisibility() != ScoreboardTeamBase.EnumNameTagVisibility.ALWAYS) {
|
if (scoreboardteambase != null && scoreboardteambase.getDeathMessageVisibility() != ScoreboardTeamBase.EnumNameTagVisibility.ALWAYS) {
|
||||||
if (scoreboardteambase.getDeathMessageVisibility() == ScoreboardTeamBase.EnumNameTagVisibility.HIDE_FOR_OTHER_TEAMS) {
|
if (scoreboardteambase.getDeathMessageVisibility() == ScoreboardTeamBase.EnumNameTagVisibility.HIDE_FOR_OTHER_TEAMS) {
|
||||||
this.server.getPlayerList().a(this, chatmessage);
|
this.server.getPlayerList().a((EntityHuman) this, chatmessage);
|
||||||
} else if (scoreboardteambase.getDeathMessageVisibility() == ScoreboardTeamBase.EnumNameTagVisibility.HIDE_FOR_OWN_TEAM) {
|
} else if (scoreboardteambase.getDeathMessageVisibility() == ScoreboardTeamBase.EnumNameTagVisibility.HIDE_FOR_OWN_TEAM) {
|
||||||
this.server.getPlayerList().b(this, chatmessage);
|
this.server.getPlayerList().b((EntityHuman) this, chatmessage);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.server.getPlayerList().sendMessage(chatmessage);
|
this.server.getPlayerList().sendMessage(chatmessage);
|
||||||
@@ -501,7 +489,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.inventory.clear();
|
this.inventory.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.closeInventory();
|
this.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DEATH); // Paper
|
||||||
this.setSpectatorTarget(this); // Remove spectated target
|
this.setSpectatorTarget(this); // Remove spectated target
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
|
|
||||||
@@ -518,7 +506,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
EntityLiving entityliving = this.ci();
|
EntityLiving entityliving = this.ci();
|
||||||
|
|
||||||
if (entityliving != null) {
|
if (entityliving != null) {
|
||||||
EntityTypes.MonsterEggInfo entitytypes_monsteregginfo = EntityTypes.eggInfo.get(EntityTypes.a(entityliving));
|
EntityTypes.MonsterEggInfo entitytypes_monsteregginfo = (EntityTypes.MonsterEggInfo) EntityTypes.eggInfo.get(EntityTypes.a((Entity) entityliving));
|
||||||
|
|
||||||
if (entitytypes_monsteregginfo != null) {
|
if (entitytypes_monsteregginfo != null) {
|
||||||
this.b(entitytypes_monsteregginfo.killedByEntityStatistic);
|
this.b(entitytypes_monsteregginfo.killedByEntityStatistic);
|
||||||
@@ -534,7 +522,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.getCombatTracker().g();
|
this.getCombatTracker().g();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(Entity entity, int i, DamageSource damagesource) {
|
public void a(Entity entity, int i, DamageSource damagesource) {
|
||||||
if (entity != this) {
|
if (entity != this) {
|
||||||
super.a(entity, i, damagesource);
|
super.a(entity, i, damagesource);
|
||||||
@@ -603,7 +590,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
return Lists.newArrayList();
|
return Lists.newArrayList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean damageEntity(DamageSource damagesource, float f) {
|
public boolean damageEntity(DamageSource damagesource, float f) {
|
||||||
if (this.isInvulnerable(damagesource)) {
|
if (this.isInvulnerable(damagesource)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -634,7 +620,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean a(EntityHuman entityhuman) {
|
public boolean a(EntityHuman entityhuman) {
|
||||||
return !this.canPvP() ? false : super.a(entityhuman);
|
return !this.canPvP() ? false : super.a(entityhuman);
|
||||||
}
|
}
|
||||||
@@ -644,7 +629,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
return this.world.pvpMode;
|
return this.world.pvpMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Entity b(int i) {
|
public Entity b(int i) {
|
||||||
if (this.isSleeping()) return this; // CraftBukkit - SPIGOT-3154
|
if (this.isSleeping()) return this; // CraftBukkit - SPIGOT-3154
|
||||||
@@ -683,7 +667,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean a(EntityPlayer entityplayer) {
|
public boolean a(EntityPlayer entityplayer) {
|
||||||
return entityplayer.isSpectator() ? this.getSpecatorTarget() == this : (this.isSpectator() ? false : super.a(entityplayer));
|
return entityplayer.isSpectator() ? this.getSpecatorTarget() == this : (this.isSpectator() ? false : super.a(entityplayer));
|
||||||
}
|
}
|
||||||
@@ -699,13 +682,11 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void receive(Entity entity, int i) {
|
public void receive(Entity entity, int i) {
|
||||||
super.receive(entity, i);
|
super.receive(entity, i);
|
||||||
this.activeContainer.b();
|
this.activeContainer.b();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public EntityHuman.EnumBedResult a(BlockPosition blockposition) {
|
public EntityHuman.EnumBedResult a(BlockPosition blockposition) {
|
||||||
EntityHuman.EnumBedResult entityhuman_enumbedresult = super.a(blockposition);
|
EntityHuman.EnumBedResult entityhuman_enumbedresult = super.a(blockposition);
|
||||||
|
|
||||||
@@ -713,7 +694,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.b(StatisticList.ab);
|
this.b(StatisticList.ab);
|
||||||
PacketPlayOutBed packetplayoutbed = new PacketPlayOutBed(this, blockposition);
|
PacketPlayOutBed packetplayoutbed = new PacketPlayOutBed(this, blockposition);
|
||||||
|
|
||||||
this.x().getTracker().a(this, packetplayoutbed);
|
this.x().getTracker().a((Entity) this, (Packet) packetplayoutbed);
|
||||||
this.playerConnection.a(this.locX, this.locY, this.locZ, this.yaw, this.pitch);
|
this.playerConnection.a(this.locX, this.locY, this.locZ, this.yaw, this.pitch);
|
||||||
this.playerConnection.sendPacket(packetplayoutbed);
|
this.playerConnection.sendPacket(packetplayoutbed);
|
||||||
CriterionTriggers.p.a(this);
|
CriterionTriggers.p.a(this);
|
||||||
@@ -722,7 +703,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
return entityhuman_enumbedresult;
|
return entityhuman_enumbedresult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(boolean flag, boolean flag1, boolean flag2) {
|
public void a(boolean flag, boolean flag1, boolean flag2) {
|
||||||
if (!this.sleeping) return; // CraftBukkit - Can't leave bed if not in one!
|
if (!this.sleeping) return; // CraftBukkit - Can't leave bed if not in one!
|
||||||
if (this.isSleeping()) {
|
if (this.isSleeping()) {
|
||||||
@@ -736,7 +716,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean a(Entity entity, boolean flag) {
|
public boolean a(Entity entity, boolean flag) {
|
||||||
Entity entity1 = this.bJ();
|
Entity entity1 = this.bJ();
|
||||||
|
|
||||||
@@ -753,7 +732,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stopRiding() {
|
public void stopRiding() {
|
||||||
Entity entity = this.bJ();
|
Entity entity = this.bJ();
|
||||||
|
|
||||||
@@ -773,15 +751,12 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isInvulnerable(DamageSource damagesource) {
|
public boolean isInvulnerable(DamageSource damagesource) {
|
||||||
return super.isInvulnerable(damagesource) || this.L();
|
return super.isInvulnerable(damagesource) || this.L();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void a(double d0, boolean flag, IBlockData iblockdata, BlockPosition blockposition) {}
|
protected void a(double d0, boolean flag, IBlockData iblockdata, BlockPosition blockposition) {}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void b(BlockPosition blockposition) {
|
protected void b(BlockPosition blockposition) {
|
||||||
if (!this.isSpectator()) {
|
if (!this.isSpectator()) {
|
||||||
super.b(blockposition);
|
super.b(blockposition);
|
||||||
@@ -810,9 +785,8 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
super.a(d0, flag, iblockdata, blockposition);
|
super.a(d0, flag, iblockdata, blockposition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void openSign(TileEntitySign tileentitysign) {
|
public void openSign(TileEntitySign tileentitysign) {
|
||||||
tileentitysign.a(this);
|
tileentitysign.a((EntityHuman) this);
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutOpenSignEditor(tileentitysign.getPosition()));
|
this.playerConnection.sendPacket(new PacketPlayOutOpenSignEditor(tileentitysign.getPosition()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -821,7 +795,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
return containerCounter; // CraftBukkit
|
return containerCounter; // CraftBukkit
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void openTileEntity(ITileEntityContainer itileentitycontainer) {
|
public void openTileEntity(ITileEntityContainer itileentitycontainer) {
|
||||||
// CraftBukkit start - Inventory open hook
|
// CraftBukkit start - Inventory open hook
|
||||||
if (false && itileentitycontainer instanceof ILootable && ((ILootable) itileentitycontainer).b() != null && this.isSpectator()) {
|
if (false && itileentitycontainer instanceof ILootable && ((ILootable) itileentitycontainer).b() != null && this.isSpectator()) {
|
||||||
@@ -841,7 +814,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void openContainer(IInventory iinventory) {
|
public void openContainer(IInventory iinventory) {
|
||||||
// CraftBukkit start - Inventory open hook
|
// CraftBukkit start - Inventory open hook
|
||||||
// Copied from below
|
// Copied from below
|
||||||
@@ -871,7 +843,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.a((new ChatMessage("container.spectatorCantOpen", new Object[0])).setChatModifier((new ChatModifier()).setColor(EnumChatFormat.RED)), true);
|
this.a((new ChatMessage("container.spectatorCantOpen", new Object[0])).setChatModifier((new ChatModifier()).setColor(EnumChatFormat.RED)), true);
|
||||||
} else {
|
} else {
|
||||||
if (this.activeContainer != this.defaultContainer) {
|
if (this.activeContainer != this.defaultContainer) {
|
||||||
this.closeInventory();
|
this.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.OPEN_NEW); // Paper
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iinventory instanceof ITileInventory) {
|
if (iinventory instanceof ITileInventory) {
|
||||||
@@ -901,7 +873,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void openTrade(IMerchant imerchant) {
|
public void openTrade(IMerchant imerchant) {
|
||||||
// CraftBukkit start - Inventory open hook
|
// CraftBukkit start - Inventory open hook
|
||||||
Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerMerchant(this.inventory, imerchant, this.world));
|
Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerMerchant(this.inventory, imerchant, this.world));
|
||||||
@@ -929,7 +900,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void openHorseInventory(EntityHorseAbstract entityhorseabstract, IInventory iinventory) {
|
public void openHorseInventory(EntityHorseAbstract entityhorseabstract, IInventory iinventory) {
|
||||||
// CraftBukkit start - Inventory open hook
|
// CraftBukkit start - Inventory open hook
|
||||||
Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerHorse(this.inventory, iinventory, entityhorseabstract, this));
|
Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerHorse(this.inventory, iinventory, entityhorseabstract, this));
|
||||||
@@ -939,7 +909,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
if (this.activeContainer != this.defaultContainer) {
|
if (this.activeContainer != this.defaultContainer) {
|
||||||
this.closeInventory();
|
this.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.OPEN_NEW); // Paper
|
||||||
}
|
}
|
||||||
|
|
||||||
this.nextContainerCounter();
|
this.nextContainerCounter();
|
||||||
@@ -949,26 +919,23 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.activeContainer.addSlotListener(this);
|
this.activeContainer.addSlotListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(ItemStack itemstack, EnumHand enumhand) {
|
public void a(ItemStack itemstack, EnumHand enumhand) {
|
||||||
Item item = itemstack.getItem();
|
Item item = itemstack.getItem();
|
||||||
|
|
||||||
if (item == Items.WRITTEN_BOOK) {
|
if (item == Items.WRITTEN_BOOK) {
|
||||||
PacketDataSerializer packetdataserializer = new PacketDataSerializer(Unpooled.buffer());
|
PacketDataSerializer packetdataserializer = new PacketDataSerializer(Unpooled.buffer());
|
||||||
|
|
||||||
packetdataserializer.a(enumhand);
|
packetdataserializer.a((Enum) enumhand);
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutCustomPayload("MC|BOpen", packetdataserializer));
|
this.playerConnection.sendPacket(new PacketPlayOutCustomPayload("MC|BOpen", packetdataserializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(TileEntityCommand tileentitycommand) {
|
public void a(TileEntityCommand tileentitycommand) {
|
||||||
tileentitycommand.c(true);
|
tileentitycommand.c(true);
|
||||||
this.a((TileEntity) tileentitycommand);
|
this.a((TileEntity) tileentitycommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(Container container, int i, ItemStack itemstack) {
|
public void a(Container container, int i, ItemStack itemstack) {
|
||||||
if (!(container.getSlot(i) instanceof SlotResult)) {
|
if (!(container.getSlot(i) instanceof SlotResult)) {
|
||||||
if (container == this.defaultContainer) {
|
if (container == this.defaultContainer) {
|
||||||
@@ -985,7 +952,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.a(container, container.a());
|
this.a(container, container.a());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(Container container, NonNullList<ItemStack> nonnulllist) {
|
public void a(Container container, NonNullList<ItemStack> nonnulllist) {
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutWindowItems(container.windowId, nonnulllist));
|
this.playerConnection.sendPacket(new PacketPlayOutWindowItems(container.windowId, nonnulllist));
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, this.inventory.getCarried()));
|
this.playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, this.inventory.getCarried()));
|
||||||
@@ -996,12 +962,10 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setContainerData(Container container, int i, int j) {
|
public void setContainerData(Container container, int i, int j) {
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutWindowData(container.windowId, i, j));
|
this.playerConnection.sendPacket(new PacketPlayOutWindowData(container.windowId, i, j));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setContainerData(Container container, IInventory iinventory) {
|
public void setContainerData(Container container, IInventory iinventory) {
|
||||||
for (int i = 0; i < iinventory.h(); ++i) {
|
for (int i = 0; i < iinventory.h(); ++i) {
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutWindowData(container.windowId, i, iinventory.getProperty(i)));
|
this.playerConnection.sendPacket(new PacketPlayOutWindowData(container.windowId, i, iinventory.getProperty(i)));
|
||||||
@@ -1009,9 +973,13 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void closeInventory() {
|
public void closeInventory() {
|
||||||
CraftEventFactory.handleInventoryCloseEvent(this); // CraftBukkit
|
// Paper start
|
||||||
|
closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNKNOWN);
|
||||||
|
}
|
||||||
|
public void closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
|
||||||
|
CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit
|
||||||
|
// Paper end
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutCloseWindow(this.activeContainer.windowId));
|
this.playerConnection.sendPacket(new PacketPlayOutCloseWindow(this.activeContainer.windowId));
|
||||||
this.r();
|
this.r();
|
||||||
}
|
}
|
||||||
@@ -1023,7 +991,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void r() {
|
public void r() {
|
||||||
this.activeContainer.b(this);
|
this.activeContainer.b((EntityHuman) this);
|
||||||
this.activeContainer = this.defaultContainer;
|
this.activeContainer = this.defaultContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1043,7 +1011,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(Statistic statistic, int i) {
|
public void a(Statistic statistic, int i) {
|
||||||
if (statistic != null) {
|
if (statistic != null) {
|
||||||
this.bZ.b(this, statistic, i);
|
this.bZ.b(this, statistic, i);
|
||||||
@@ -1058,7 +1025,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(Statistic statistic) {
|
public void a(Statistic statistic) {
|
||||||
if (statistic != null) {
|
if (statistic != null) {
|
||||||
this.bZ.setStatistic(this, statistic, 0);
|
this.bZ.setStatistic(this, statistic, 0);
|
||||||
@@ -1073,12 +1039,10 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(List<IRecipe> list) {
|
public void a(List<IRecipe> list) {
|
||||||
this.cr.a(list, this);
|
this.cr.a(list, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(MinecraftKey[] aminecraftkey) {
|
public void a(MinecraftKey[] aminecraftkey) {
|
||||||
ArrayList arraylist = Lists.newArrayList();
|
ArrayList arraylist = Lists.newArrayList();
|
||||||
MinecraftKey[] aminecraftkey1 = aminecraftkey;
|
MinecraftKey[] aminecraftkey1 = aminecraftkey;
|
||||||
@@ -1099,7 +1063,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.a((List<IRecipe>) arraylist); // CraftBukkit - decompile error
|
this.a((List<IRecipe>) arraylist); // CraftBukkit - decompile error
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void b(List<IRecipe> list) {
|
public void b(List<IRecipe> list) {
|
||||||
this.cr.b(list, this);
|
this.cr.b(list, this);
|
||||||
}
|
}
|
||||||
@@ -1130,12 +1093,10 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(IChatBaseComponent ichatbasecomponent, boolean flag) {
|
public void a(IChatBaseComponent ichatbasecomponent, boolean flag) {
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutChat(ichatbasecomponent, flag ? ChatMessageType.GAME_INFO : ChatMessageType.CHAT));
|
this.playerConnection.sendPacket(new PacketPlayOutChat(ichatbasecomponent, flag ? ChatMessageType.GAME_INFO : ChatMessageType.CHAT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void v() {
|
protected void v() {
|
||||||
if (!this.activeItem.isEmpty() && this.isHandRaised()) {
|
if (!this.activeItem.isEmpty() && this.isHandRaised()) {
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutEntityStatus(this, (byte) 9));
|
this.playerConnection.sendPacket(new PacketPlayOutEntityStatus(this, (byte) 9));
|
||||||
@@ -1182,7 +1143,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.setShoulderEntityRight(entityplayer.getShoulderEntityRight());
|
this.setShoulderEntityRight(entityplayer.getShoulderEntityRight());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void a(MobEffect mobeffect) {
|
protected void a(MobEffect mobeffect) {
|
||||||
super.a(mobeffect);
|
super.a(mobeffect);
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutEntityEffect(this.getId(), mobeffect));
|
this.playerConnection.sendPacket(new PacketPlayOutEntityEffect(this.getId(), mobeffect));
|
||||||
@@ -1194,14 +1154,12 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
CriterionTriggers.z.a(this);
|
CriterionTriggers.z.a(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void a(MobEffect mobeffect, boolean flag) {
|
protected void a(MobEffect mobeffect, boolean flag) {
|
||||||
super.a(mobeffect, flag);
|
super.a(mobeffect, flag);
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutEntityEffect(this.getId(), mobeffect));
|
this.playerConnection.sendPacket(new PacketPlayOutEntityEffect(this.getId(), mobeffect));
|
||||||
CriterionTriggers.z.a(this);
|
CriterionTriggers.z.a(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void b(MobEffect mobeffect) {
|
protected void b(MobEffect mobeffect) {
|
||||||
super.b(mobeffect);
|
super.b(mobeffect);
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutRemoveEntityEffect(this.getId(), mobeffect.getMobEffect()));
|
this.playerConnection.sendPacket(new PacketPlayOutRemoveEntityEffect(this.getId(), mobeffect.getMobEffect()));
|
||||||
@@ -1212,22 +1170,18 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
CriterionTriggers.z.a(this);
|
CriterionTriggers.z.a(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enderTeleportTo(double d0, double d1, double d2) {
|
public void enderTeleportTo(double d0, double d1, double d2) {
|
||||||
this.playerConnection.a(d0, d1, d2, this.yaw, this.pitch);
|
this.playerConnection.a(d0, d1, d2, this.yaw, this.pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(Entity entity) {
|
public void a(Entity entity) {
|
||||||
this.x().getTracker().sendPacketToEntity(this, new PacketPlayOutAnimation(entity, 4));
|
this.x().getTracker().sendPacketToEntity(this, new PacketPlayOutAnimation(entity, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void b(Entity entity) {
|
public void b(Entity entity) {
|
||||||
this.x().getTracker().sendPacketToEntity(this, new PacketPlayOutAnimation(entity, 5));
|
this.x().getTracker().sendPacketToEntity(this, new PacketPlayOutAnimation(entity, 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateAbilities() {
|
public void updateAbilities() {
|
||||||
if (this.playerConnection != null) {
|
if (this.playerConnection != null) {
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutAbilities(this.abilities));
|
this.playerConnection.sendPacket(new PacketPlayOutAbilities(this.abilities));
|
||||||
@@ -1239,7 +1193,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
return (WorldServer) this.world;
|
return (WorldServer) this.world;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(EnumGamemode enumgamemode) {
|
public void a(EnumGamemode enumgamemode) {
|
||||||
// CraftBukkit start
|
// CraftBukkit start
|
||||||
if (enumgamemode == this.playerInteractManager.getGameMode()) {
|
if (enumgamemode == this.playerInteractManager.getGameMode()) {
|
||||||
@@ -1254,7 +1207,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
|
|
||||||
this.playerInteractManager.setGameMode(enumgamemode);
|
this.playerInteractManager.setGameMode(enumgamemode);
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(3, enumgamemode.getId()));
|
this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(3, (float) enumgamemode.getId()));
|
||||||
if (enumgamemode == EnumGamemode.SPECTATOR) {
|
if (enumgamemode == EnumGamemode.SPECTATOR) {
|
||||||
this.releaseShoulderEntities();
|
this.releaseShoulderEntities();
|
||||||
this.stopRiding();
|
this.stopRiding();
|
||||||
@@ -1266,22 +1219,18 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.cE();
|
this.cE();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSpectator() {
|
public boolean isSpectator() {
|
||||||
return this.playerInteractManager.getGameMode() == EnumGamemode.SPECTATOR;
|
return this.playerInteractManager.getGameMode() == EnumGamemode.SPECTATOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean z() {
|
public boolean z() {
|
||||||
return this.playerInteractManager.getGameMode() == EnumGamemode.CREATIVE;
|
return this.playerInteractManager.getGameMode() == EnumGamemode.CREATIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendMessage(IChatBaseComponent ichatbasecomponent) {
|
public void sendMessage(IChatBaseComponent ichatbasecomponent) {
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutChat(ichatbasecomponent));
|
this.playerConnection.sendPacket(new PacketPlayOutChat(ichatbasecomponent));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean a(int i, String s) {
|
public boolean a(int i, String s) {
|
||||||
/* CraftBukkit start
|
/* CraftBukkit start
|
||||||
if ("seed".equals(s) && !this.server.aa()) {
|
if ("seed".equals(s) && !this.server.aa()) {
|
||||||
@@ -1354,7 +1303,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.playerConnection.sendPacket(new PacketPlayOutResourcePackSend(s, s1));
|
this.playerConnection.sendPacket(new PacketPlayOutResourcePackSend(s, s1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockPosition getChunkCoordinates() {
|
public BlockPosition getChunkCoordinates() {
|
||||||
return new BlockPosition(this.locX, this.locY + 0.5D, this.locZ);
|
return new BlockPosition(this.locX, this.locY + 0.5D, this.locZ);
|
||||||
}
|
}
|
||||||
@@ -1384,7 +1332,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
this.removeQueue.remove(Integer.valueOf(entity.getId()));
|
this.removeQueue.remove(Integer.valueOf(entity.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void G() {
|
protected void G() {
|
||||||
if (this.isSpectator()) {
|
if (this.isSpectator()) {
|
||||||
this.bY();
|
this.bY();
|
||||||
@@ -1397,13 +1344,13 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Entity getSpecatorTarget() {
|
public Entity getSpecatorTarget() {
|
||||||
return this.co == null ? this : this.co;
|
return (Entity) (this.co == null ? this : this.co);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSpectatorTarget(Entity entity) {
|
public void setSpectatorTarget(Entity entity) {
|
||||||
Entity entity1 = this.getSpecatorTarget();
|
Entity entity1 = this.getSpecatorTarget();
|
||||||
|
|
||||||
this.co = entity == null ? this : entity;
|
this.co = (Entity) (entity == null ? this : entity);
|
||||||
if (entity1 != this.co) {
|
if (entity1 != this.co) {
|
||||||
this.playerConnection.sendPacket(new PacketPlayOutCamera(this.co));
|
this.playerConnection.sendPacket(new PacketPlayOutCamera(this.co));
|
||||||
this.playerConnection.a(this.co.locX, this.co.locY, this.co.locZ, this.yaw, this.pitch, TeleportCause.SPECTATE); // CraftBukkit
|
this.playerConnection.a(this.co.locX, this.co.locY, this.co.locZ, this.yaw, this.pitch, TeleportCause.SPECTATE); // CraftBukkit
|
||||||
@@ -1411,7 +1358,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void I() {
|
protected void I() {
|
||||||
if (this.portalCooldown > 0 && !this.worldChangeInvuln) {
|
if (this.portalCooldown > 0 && !this.worldChangeInvuln) {
|
||||||
--this.portalCooldown;
|
--this.portalCooldown;
|
||||||
@@ -1419,7 +1365,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void attack(Entity entity) {
|
public void attack(Entity entity) {
|
||||||
if (this.playerInteractManager.getGameMode() == EnumGamemode.SPECTATOR) {
|
if (this.playerInteractManager.getGameMode() == EnumGamemode.SPECTATOR) {
|
||||||
this.setSpectatorTarget(entity);
|
this.setSpectatorTarget(entity);
|
||||||
@@ -1438,7 +1383,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|||||||
return listName; // CraftBukkit
|
return listName; // CraftBukkit
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(EnumHand enumhand) {
|
public void a(EnumHand enumhand) {
|
||||||
super.a(enumhand);
|
super.a(enumhand);
|
||||||
this.ds();
|
this.ds();
|
||||||
|
|||||||
319
sources/src/main/java/net/minecraft/server/EnumDirection.java
Normal file
319
sources/src/main/java/net/minecraft/server/EnumDirection.java
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
package net.minecraft.server;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterators;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>Akarin Changes Note</b><br>
|
||||||
|
* <br>
|
||||||
|
* 1) Add OBFHELPER<br>
|
||||||
|
* @author cakoyo
|
||||||
|
*/
|
||||||
|
public enum EnumDirection implements INamable {
|
||||||
|
|
||||||
|
DOWN(0, 1, -1, "down", EnumDirection.EnumAxisDirection.NEGATIVE, EnumDirection.EnumAxis.Y, new BaseBlockPosition(0, -1, 0)), UP(1, 0, -1, "up", EnumDirection.EnumAxisDirection.POSITIVE, EnumDirection.EnumAxis.Y, new BaseBlockPosition(0, 1, 0)), NORTH(2, 3, 2, "north", EnumDirection.EnumAxisDirection.NEGATIVE, EnumDirection.EnumAxis.Z, new BaseBlockPosition(0, 0, -1)), SOUTH(3, 2, 0, "south", EnumDirection.EnumAxisDirection.POSITIVE, EnumDirection.EnumAxis.Z, new BaseBlockPosition(0, 0, 1)), WEST(4, 5, 1, "west", EnumDirection.EnumAxisDirection.NEGATIVE, EnumDirection.EnumAxis.X, new BaseBlockPosition(-1, 0, 0)), EAST(5, 4, 3, "east", EnumDirection.EnumAxisDirection.POSITIVE, EnumDirection.EnumAxis.X, new BaseBlockPosition(1, 0, 0));
|
||||||
|
|
||||||
|
private final int g;
|
||||||
|
private final int h;
|
||||||
|
private final int i;
|
||||||
|
private final String j;
|
||||||
|
private final EnumDirection.EnumAxis k;
|
||||||
|
private final EnumDirection.EnumAxisDirection l;
|
||||||
|
private final BaseBlockPosition m; public BaseBlockPosition getDirectionPosition() { return m; } // Akarin - OBFHELPER
|
||||||
|
private static final EnumDirection[] n = new EnumDirection[6];
|
||||||
|
private static final EnumDirection[] o = new EnumDirection[4];
|
||||||
|
private static final Map<String, EnumDirection> p = Maps.newHashMap();
|
||||||
|
|
||||||
|
private EnumDirection(int i, int j, int k, String s, EnumDirection.EnumAxisDirection enumdirection_enumaxisdirection, EnumDirection.EnumAxis enumdirection_enumaxis, BaseBlockPosition baseblockposition) {
|
||||||
|
this.g = i;
|
||||||
|
this.i = k;
|
||||||
|
this.h = j;
|
||||||
|
this.j = s;
|
||||||
|
this.k = enumdirection_enumaxis;
|
||||||
|
this.l = enumdirection_enumaxisdirection;
|
||||||
|
this.m = baseblockposition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int a() {
|
||||||
|
return this.g;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int get2DRotationValue() {
|
||||||
|
return this.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnumDirection.EnumAxisDirection c() {
|
||||||
|
return this.l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnumDirection opposite() {
|
||||||
|
return fromType1(this.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnumDirection e() {
|
||||||
|
switch (this) {
|
||||||
|
case NORTH:
|
||||||
|
return EnumDirection.EAST;
|
||||||
|
|
||||||
|
case EAST:
|
||||||
|
return EnumDirection.SOUTH;
|
||||||
|
|
||||||
|
case SOUTH:
|
||||||
|
return EnumDirection.WEST;
|
||||||
|
|
||||||
|
case WEST:
|
||||||
|
return EnumDirection.NORTH;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unable to get Y-rotated facing of " + this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnumDirection f() {
|
||||||
|
switch (this) {
|
||||||
|
case NORTH:
|
||||||
|
return EnumDirection.WEST;
|
||||||
|
|
||||||
|
case EAST:
|
||||||
|
return EnumDirection.NORTH;
|
||||||
|
|
||||||
|
case SOUTH:
|
||||||
|
return EnumDirection.EAST;
|
||||||
|
|
||||||
|
case WEST:
|
||||||
|
return EnumDirection.SOUTH;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unable to get CCW facing of " + this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAdjacentX() {
|
||||||
|
return this.k == EnumDirection.EnumAxis.X ? this.l.a() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAdjacentY() {
|
||||||
|
return this.k == EnumDirection.EnumAxis.Y ? this.l.a() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAdjacentZ() {
|
||||||
|
return this.k == EnumDirection.EnumAxis.Z ? this.l.a() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String j() {
|
||||||
|
return this.j;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnumDirection.EnumAxis getAxis() { return k(); } // Akarin - OBFHELPER
|
||||||
|
public EnumDirection.EnumAxis k() {
|
||||||
|
return this.k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EnumDirection fromType1(int i) {
|
||||||
|
return EnumDirection.n[MathHelper.a(i % EnumDirection.n.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EnumDirection fromType2(int i) {
|
||||||
|
return EnumDirection.o[MathHelper.a(i % EnumDirection.o.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EnumDirection fromAngle(double d0) {
|
||||||
|
return fromType2(MathHelper.floor(d0 / 90.0D + 0.5D) & 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float l() {
|
||||||
|
return (this.i & 3) * 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EnumDirection a(Random random) {
|
||||||
|
return values()[random.nextInt(values().length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.j;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return this.j;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EnumDirection a(EnumDirection.EnumAxisDirection enumdirection_enumaxisdirection, EnumDirection.EnumAxis enumdirection_enumaxis) {
|
||||||
|
EnumDirection[] aenumdirection = values();
|
||||||
|
int i = aenumdirection.length;
|
||||||
|
|
||||||
|
for (int j = 0; j < i; ++j) {
|
||||||
|
EnumDirection enumdirection = aenumdirection[j];
|
||||||
|
|
||||||
|
if (enumdirection.c() == enumdirection_enumaxisdirection && enumdirection.k() == enumdirection_enumaxis) {
|
||||||
|
return enumdirection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("No such direction: " + enumdirection_enumaxisdirection + " " + enumdirection_enumaxis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EnumDirection a(BlockPosition blockposition, EntityLiving entityliving) {
|
||||||
|
if (Math.abs(entityliving.locX - (blockposition.getX() + 0.5F)) < 2.0D && Math.abs(entityliving.locZ - (blockposition.getZ() + 0.5F)) < 2.0D) {
|
||||||
|
double d0 = entityliving.locY + entityliving.getHeadHeight();
|
||||||
|
|
||||||
|
if (d0 - blockposition.getY() > 2.0D) {
|
||||||
|
return EnumDirection.UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockposition.getY() - d0 > 0.0D) {
|
||||||
|
return EnumDirection.DOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entityliving.getDirection().opposite();
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
EnumDirection[] aenumdirection = values();
|
||||||
|
int i = aenumdirection.length;
|
||||||
|
|
||||||
|
for (int j = 0; j < i; ++j) {
|
||||||
|
EnumDirection enumdirection = aenumdirection[j];
|
||||||
|
|
||||||
|
EnumDirection.n[enumdirection.g] = enumdirection;
|
||||||
|
if (enumdirection.k().c()) {
|
||||||
|
EnumDirection.o[enumdirection.i] = enumdirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnumDirection.p.put(enumdirection.j().toLowerCase(Locale.ROOT), enumdirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum EnumDirectionLimit implements Predicate<EnumDirection>, Iterable<EnumDirection> {
|
||||||
|
|
||||||
|
HORIZONTAL, VERTICAL;
|
||||||
|
|
||||||
|
private EnumDirectionLimit() {}
|
||||||
|
|
||||||
|
public EnumDirection[] a() {
|
||||||
|
switch (this) {
|
||||||
|
case HORIZONTAL:
|
||||||
|
return new EnumDirection[] { EnumDirection.NORTH, EnumDirection.EAST, EnumDirection.SOUTH, EnumDirection.WEST};
|
||||||
|
|
||||||
|
case VERTICAL:
|
||||||
|
return new EnumDirection[] { EnumDirection.UP, EnumDirection.DOWN};
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error("Someone\'s been tampering with the universe!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnumDirection a(Random random) {
|
||||||
|
EnumDirection[] aenumdirection = this.a();
|
||||||
|
|
||||||
|
return aenumdirection[random.nextInt(aenumdirection.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean a(@Nullable EnumDirection enumdirection) {
|
||||||
|
return enumdirection != null && enumdirection.k().d() == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<EnumDirection> iterator() {
|
||||||
|
return Iterators.forArray(this.a());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(@Nullable EnumDirection object) {
|
||||||
|
return this.a(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum EnumAxisDirection {
|
||||||
|
|
||||||
|
POSITIVE(1, "Towards positive"), NEGATIVE(-1, "Towards negative");
|
||||||
|
|
||||||
|
private final int c;
|
||||||
|
private final String d;
|
||||||
|
|
||||||
|
private EnumAxisDirection(int i, String s) {
|
||||||
|
this.c = i;
|
||||||
|
this.d = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int a() {
|
||||||
|
return this.c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum EnumAxis implements Predicate<EnumDirection>, INamable {
|
||||||
|
|
||||||
|
X("x", EnumDirection.EnumDirectionLimit.HORIZONTAL), Y("y", EnumDirection.EnumDirectionLimit.VERTICAL), Z("z", EnumDirection.EnumDirectionLimit.HORIZONTAL);
|
||||||
|
|
||||||
|
private static final Map<String, EnumDirection.EnumAxis> d = Maps.newHashMap();
|
||||||
|
private final String e;
|
||||||
|
private final EnumDirection.EnumDirectionLimit f;
|
||||||
|
|
||||||
|
private EnumAxis(String s, EnumDirection.EnumDirectionLimit enumdirection_enumdirectionlimit) {
|
||||||
|
this.e = s;
|
||||||
|
this.f = enumdirection_enumdirectionlimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String a() {
|
||||||
|
return this.e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean b() {
|
||||||
|
return this.f == EnumDirection.EnumDirectionLimit.VERTICAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHorizontal() { return c(); } // Akarin - OBFHELPER
|
||||||
|
public boolean c() {
|
||||||
|
return this.f == EnumDirection.EnumDirectionLimit.HORIZONTAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean a(@Nullable EnumDirection enumdirection) {
|
||||||
|
return enumdirection != null && enumdirection.k() == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnumDirection.EnumDirectionLimit d() {
|
||||||
|
return this.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return this.e;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(@Nullable EnumDirection object) {
|
||||||
|
return this.a(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
EnumDirection.EnumAxis[] aenumdirection_enumaxis = values();
|
||||||
|
int i = aenumdirection_enumaxis.length;
|
||||||
|
|
||||||
|
for (int j = 0; j < i; ++j) {
|
||||||
|
EnumDirection.EnumAxis enumdirection_enumaxis = aenumdirection_enumaxis[j];
|
||||||
|
|
||||||
|
EnumDirection.EnumAxis.d.put(enumdirection_enumaxis.a().toLowerCase(Locale.ROOT), enumdirection_enumaxis);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
99
sources/src/main/java/net/minecraft/server/ItemEnderEye.java
Normal file
99
sources/src/main/java/net/minecraft/server/ItemEnderEye.java
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
package net.minecraft.server;
|
||||||
|
|
||||||
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>Akarin Changes Note</b><br>
|
||||||
|
* <br>
|
||||||
|
* 1) Add end portal disable feature<br>
|
||||||
|
* @author cakoyo
|
||||||
|
*/
|
||||||
|
public class ItemEnderEye extends Item {
|
||||||
|
|
||||||
|
public ItemEnderEye() {
|
||||||
|
this.b(CreativeModeTab.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumInteractionResult a(EntityHuman entityhuman, World world, BlockPosition blockposition, EnumHand enumhand, EnumDirection enumdirection, float f, float f1, float f2) {
|
||||||
|
IBlockData iblockdata = world.getType(blockposition);
|
||||||
|
ItemStack itemstack = entityhuman.b(enumhand);
|
||||||
|
|
||||||
|
if (entityhuman.a(blockposition.shift(enumdirection), enumdirection, itemstack) && iblockdata.getBlock() == Blocks.END_PORTAL_FRAME && !iblockdata.get(BlockEnderPortalFrame.EYE).booleanValue()) {
|
||||||
|
if (world.isClientSide) {
|
||||||
|
return EnumInteractionResult.SUCCESS;
|
||||||
|
} else {
|
||||||
|
world.setTypeAndData(blockposition, iblockdata.set(BlockEnderPortalFrame.EYE, Boolean.valueOf(true)), 2);
|
||||||
|
world.updateAdjacentComparators(blockposition, Blocks.END_PORTAL_FRAME);
|
||||||
|
itemstack.subtract(1);
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; ++i) {
|
||||||
|
double d0 = blockposition.getX() + (5.0F + ItemEnderEye.j.nextFloat() * 6.0F) / 16.0F;
|
||||||
|
double d1 = blockposition.getY() + 0.8125F;
|
||||||
|
double d2 = blockposition.getZ() + (5.0F + ItemEnderEye.j.nextFloat() * 6.0F) / 16.0F;
|
||||||
|
double d3 = 0.0D;
|
||||||
|
double d4 = 0.0D;
|
||||||
|
double d5 = 0.0D;
|
||||||
|
|
||||||
|
world.addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0.0D, 0.0D, 0.0D, new int[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
world.a((EntityHuman) null, blockposition, SoundEffects.bp, SoundCategory.BLOCKS, 1.0F, 1.0F);
|
||||||
|
if (AkarinGlobalConfig.disableEndPortalCreate) return EnumInteractionResult.SUCCESS; // Akarin
|
||||||
|
ShapeDetector.ShapeDetectorCollection shapedetector_shapedetectorcollection = BlockEnderPortalFrame.e().a(world, blockposition);
|
||||||
|
|
||||||
|
if (shapedetector_shapedetectorcollection != null) {
|
||||||
|
BlockPosition blockposition1 = shapedetector_shapedetectorcollection.a().a(-3, 0, -3);
|
||||||
|
|
||||||
|
for (int j = 0; j < 3; ++j) {
|
||||||
|
for (int k = 0; k < 3; ++k) {
|
||||||
|
world.setTypeAndData(blockposition1.a(j, 0, k), Blocks.END_PORTAL.getBlockData(), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
world.a(1038, blockposition1.a(1, 0, 1), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EnumInteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return EnumInteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InteractionResultWrapper<ItemStack> a(World world, EntityHuman entityhuman, EnumHand enumhand) {
|
||||||
|
ItemStack itemstack = entityhuman.b(enumhand);
|
||||||
|
MovingObjectPosition movingobjectposition = this.a(world, entityhuman, false);
|
||||||
|
|
||||||
|
if (movingobjectposition != null && movingobjectposition.type == MovingObjectPosition.EnumMovingObjectType.BLOCK && world.getType(movingobjectposition.a()).getBlock() == Blocks.END_PORTAL_FRAME) {
|
||||||
|
return new InteractionResultWrapper(EnumInteractionResult.PASS, itemstack);
|
||||||
|
} else {
|
||||||
|
entityhuman.c(enumhand);
|
||||||
|
if (!world.isClientSide) {
|
||||||
|
BlockPosition blockposition = ((WorldServer) world).getChunkProviderServer().a(world, "Stronghold", new BlockPosition(entityhuman), false);
|
||||||
|
|
||||||
|
if (blockposition != null) {
|
||||||
|
EntityEnderSignal entityendersignal = new EntityEnderSignal(world, entityhuman.locX, entityhuman.locY + entityhuman.length / 2.0F, entityhuman.locZ);
|
||||||
|
|
||||||
|
entityendersignal.a(blockposition);
|
||||||
|
world.addEntity(entityendersignal);
|
||||||
|
if (entityhuman instanceof EntityPlayer) {
|
||||||
|
CriterionTriggers.l.a((EntityPlayer) entityhuman, blockposition);
|
||||||
|
}
|
||||||
|
|
||||||
|
world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.bc, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemEnderEye.j.nextFloat() * 0.4F + 0.8F));
|
||||||
|
world.a((EntityHuman) null, 1003, new BlockPosition(entityhuman), 0);
|
||||||
|
if (!entityhuman.abilities.canInstantlyBuild) {
|
||||||
|
itemstack.subtract(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
entityhuman.b(StatisticList.b(this));
|
||||||
|
return new InteractionResultWrapper(EnumInteractionResult.SUCCESS, itemstack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new InteractionResultWrapper(EnumInteractionResult.SUCCESS, itemstack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1688
sources/src/main/java/net/minecraft/server/MinecraftServer.java
Normal file
1688
sources/src/main/java/net/minecraft/server/MinecraftServer.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@ package net.minecraft.server;
|
|||||||
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
|
||||||
import io.akarin.api.CheckedConcurrentLinkedQueue;
|
import io.akarin.api.internal.collections.CheckedConcurrentLinkedQueue;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package net.minecraft.server;
|
||||||
|
|
||||||
|
import co.aikar.timings.Timing;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectCollection;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>Akarin Changes Note</b><br>
|
||||||
|
* <br>
|
||||||
|
* 1) Expose private members<br>
|
||||||
|
* @author cakoyo
|
||||||
|
*/
|
||||||
|
class PaperLightingQueue {
|
||||||
|
private static final long MAX_TIME = (long) (1000000000 / 20 * .95);
|
||||||
|
private static int updatesThisTick;
|
||||||
|
|
||||||
|
|
||||||
|
static void processQueue(long curTime) {
|
||||||
|
updatesThisTick = 0;
|
||||||
|
|
||||||
|
final long startTime = System.nanoTime();
|
||||||
|
final long maxTickTime = MAX_TIME - (startTime - curTime);
|
||||||
|
|
||||||
|
START:
|
||||||
|
for (World world : MinecraftServer.getServer().worlds) {
|
||||||
|
if (!world.paperConfig.queueLightUpdates) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectCollection<Chunk> loadedChunks = ((WorldServer) world).getChunkProviderServer().chunks.values();
|
||||||
|
for (Chunk chunk : loadedChunks.toArray(new Chunk[loadedChunks.size()])) {
|
||||||
|
if (chunk.lightingQueue.processQueue(startTime, maxTickTime)) {
|
||||||
|
break START;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LightingQueue extends ArrayDeque<Runnable> { // Akarin - public
|
||||||
|
final private Chunk chunk;
|
||||||
|
|
||||||
|
LightingQueue(Chunk chunk) {
|
||||||
|
super();
|
||||||
|
this.chunk = chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the lighting queue for this chunk
|
||||||
|
*
|
||||||
|
* @param startTime If start Time is 0, we will not limit execution time
|
||||||
|
* @param maxTickTime Maximum time to spend processing lighting updates
|
||||||
|
* @return true to abort processing furthur lighting updates
|
||||||
|
*/
|
||||||
|
private boolean processQueue(long startTime, long maxTickTime) {
|
||||||
|
if (this.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try (Timing ignored = chunk.world.timings.lightingQueueTimer.startTiming()) {
|
||||||
|
Runnable lightUpdate;
|
||||||
|
while ((lightUpdate = this.poll()) != null) {
|
||||||
|
lightUpdate.run();
|
||||||
|
if (startTime > 0 && ++PaperLightingQueue.updatesThisTick % 10 == 0 && PaperLightingQueue.updatesThisTick > 10) {
|
||||||
|
if (System.nanoTime() - startTime > maxTickTime) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes lighting updates to unload the chunk
|
||||||
|
*/
|
||||||
|
public void processUnload() { // Akarin - public
|
||||||
|
if (!chunk.world.paperConfig.queueLightUpdates) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
processQueue(0, 0); // No timeout
|
||||||
|
|
||||||
|
final int radius = 1; // TODO: bitflip, why should this ever be 2?
|
||||||
|
for (int x = chunk.locX - radius; x <= chunk.locX + radius; ++x) {
|
||||||
|
for (int z = chunk.locZ - radius; z <= chunk.locZ + radius; ++z) {
|
||||||
|
if (x == chunk.locX && z == chunk.locZ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(chunk.world, x, z);
|
||||||
|
if (neighbor != null) {
|
||||||
|
neighbor.lightingQueue.processQueue(0, 0); // No timeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
316
sources/src/main/java/net/minecraft/server/PlayerChunk.java
Normal file
316
sources/src/main/java/net/minecraft/server/PlayerChunk.java
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
package net.minecraft.server;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
// CraftBukkit Start
|
||||||
|
import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor;
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>Akarin Changes Note</b><br>
|
||||||
|
* <br>
|
||||||
|
* 1) Check player list empty<br>
|
||||||
|
* @author cakoyo
|
||||||
|
*/
|
||||||
|
public class PlayerChunk {
|
||||||
|
|
||||||
|
private static final Logger a = LogManager.getLogger();
|
||||||
|
private final PlayerChunkMap playerChunkMap;
|
||||||
|
public final List<EntityPlayer> c = Lists.newArrayList(); // CraftBukkit - public
|
||||||
|
private final ChunkCoordIntPair location;
|
||||||
|
private final short[] dirtyBlocks = new short[64];
|
||||||
|
@Nullable
|
||||||
|
public Chunk chunk; // CraftBukkit - public
|
||||||
|
private int dirtyCount;
|
||||||
|
private int h;
|
||||||
|
private long i;
|
||||||
|
private boolean done;
|
||||||
|
|
||||||
|
// CraftBukkit start - add fields
|
||||||
|
boolean chunkExists; // Paper
|
||||||
|
private boolean loadInProgress = false;
|
||||||
|
private Runnable loadedRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
loadInProgress = false;
|
||||||
|
PlayerChunk.this.chunk = PlayerChunk.this.playerChunkMap.getWorld().getChunkProviderServer().getOrLoadChunkAt(location.x, location.z);
|
||||||
|
markChunkUsed(); // Paper - delay chunk unloads
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Paper start - delay chunk unloads
|
||||||
|
public final void markChunkUsed() {
|
||||||
|
if (chunk != null && chunk.scheduledForUnload != null) {
|
||||||
|
chunk.scheduledForUnload = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
public PlayerChunk(PlayerChunkMap playerchunkmap, int i, int j) {
|
||||||
|
this.playerChunkMap = playerchunkmap;
|
||||||
|
this.location = new ChunkCoordIntPair(i, j);
|
||||||
|
// CraftBukkit start
|
||||||
|
loadInProgress = true;
|
||||||
|
this.chunk = playerchunkmap.getWorld().getChunkProviderServer().getChunkAt(i, j, loadedRunnable, false);
|
||||||
|
this.chunkExists = this.chunk != null || ChunkIOExecutor.hasQueuedChunkLoad(playerChunkMap.getWorld(), i, j); // Paper
|
||||||
|
markChunkUsed(); // Paper - delay chunk unloads
|
||||||
|
// CraftBukkit end
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChunkCoordIntPair a() {
|
||||||
|
return this.location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void a(final EntityPlayer entityplayer) { // CraftBukkit - added final to argument
|
||||||
|
if (this.c.contains(entityplayer)) {
|
||||||
|
PlayerChunk.a.debug("Failed to add player. {} already is in chunk {}, {}", entityplayer, Integer.valueOf(this.location.x), Integer.valueOf(this.location.z));
|
||||||
|
} else {
|
||||||
|
if (this.c.isEmpty()) {
|
||||||
|
this.i = this.playerChunkMap.getWorld().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.c.add(entityplayer);
|
||||||
|
// CraftBukkit start - use async chunk io
|
||||||
|
// if (this.done) {
|
||||||
|
// this.sendChunk(entityplayer);
|
||||||
|
// }
|
||||||
|
if (this.done) {
|
||||||
|
this.sendChunk(entityplayer);
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void b(EntityPlayer entityplayer) {
|
||||||
|
if (this.c.contains(entityplayer)) {
|
||||||
|
// CraftBukkit start - If we haven't loaded yet don't load the chunk just so we can clean it up
|
||||||
|
if (!this.done) {
|
||||||
|
this.c.remove(entityplayer);
|
||||||
|
|
||||||
|
if (this.c.isEmpty()) {
|
||||||
|
ChunkIOExecutor.dropQueuedChunkLoad(this.playerChunkMap.getWorld(), this.location.x, this.location.z, this.loadedRunnable);
|
||||||
|
this.playerChunkMap.b(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
if (this.done) {
|
||||||
|
entityplayer.playerConnection.sendPacket(new PacketPlayOutUnloadChunk(this.location.x, this.location.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.c.remove(entityplayer);
|
||||||
|
if (this.c.isEmpty()) {
|
||||||
|
this.playerChunkMap.b(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean a(boolean flag) {
|
||||||
|
if (this.chunk != null) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
/* CraftBukkit start
|
||||||
|
if (flag) {
|
||||||
|
this.chunk = this.playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z);
|
||||||
|
} else {
|
||||||
|
this.chunk = this.playerChunkMap.getWorld().getChunkProviderServer().getOrLoadChunkAt(this.location.x, this.location.z);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (!loadInProgress) {
|
||||||
|
loadInProgress = true;
|
||||||
|
this.chunk = playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z, loadedRunnable, flag);
|
||||||
|
markChunkUsed(); // Paper - delay chunk unloads
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
return this.chunk != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean b() {
|
||||||
|
if (this.done) {
|
||||||
|
return true;
|
||||||
|
} else if (this.chunk == null) {
|
||||||
|
return false;
|
||||||
|
} else if (!this.chunk.isReady()) {
|
||||||
|
return false;
|
||||||
|
} else if (!this.chunk.world.chunkPacketBlockController.onChunkPacketCreate(this.chunk, '\uffff', false)) { // Paper - Anti-Xray - Load nearby chunks if necessary
|
||||||
|
return false; // Paper - Anti-Xray - Wait and try again later
|
||||||
|
} else {
|
||||||
|
this.dirtyCount = 0;
|
||||||
|
this.h = 0;
|
||||||
|
this.done = true;
|
||||||
|
if (c.isEmpty()) return true; // Akarin - Fixes MC-120780
|
||||||
|
PacketPlayOutMapChunk packetplayoutmapchunk = new PacketPlayOutMapChunk(this.chunk, '\uffff');
|
||||||
|
Iterator iterator = this.c.iterator();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
|
||||||
|
|
||||||
|
entityplayer.playerConnection.sendPacket(packetplayoutmapchunk);
|
||||||
|
this.playerChunkMap.getWorld().getTracker().a(entityplayer, this.chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendChunk(EntityPlayer entityplayer) {
|
||||||
|
if (this.done) {
|
||||||
|
this.chunk.world.chunkPacketBlockController.onChunkPacketCreate(this.chunk, '\uffff', true); // Paper - Anti-Xray - Load nearby chunks if necessary
|
||||||
|
entityplayer.playerConnection.sendPacket(new PacketPlayOutMapChunk(this.chunk, '\uffff'));
|
||||||
|
this.playerChunkMap.getWorld().getTracker().a(entityplayer, this.chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void c() {
|
||||||
|
long i = this.playerChunkMap.getWorld().getTime();
|
||||||
|
|
||||||
|
if (this.chunk != null) {
|
||||||
|
this.chunk.c(this.chunk.x() + i - this.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.i = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void a(int i, int j, int k) {
|
||||||
|
if (this.done) {
|
||||||
|
if (this.dirtyCount == 0) {
|
||||||
|
this.playerChunkMap.a(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.h |= 1 << (j >> 4);
|
||||||
|
if (this.dirtyCount < 64) {
|
||||||
|
short short0 = (short) (i << 12 | k << 8 | j);
|
||||||
|
|
||||||
|
for (int l = 0; l < this.dirtyCount; ++l) {
|
||||||
|
if (this.dirtyBlocks[l] == short0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dirtyBlocks[this.dirtyCount++] = short0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void a(Packet<?> packet) {
|
||||||
|
if (this.done) {
|
||||||
|
for (int i = 0; i < this.c.size(); ++i) {
|
||||||
|
this.c.get(i).playerConnection.sendPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void d() {
|
||||||
|
if (this.done && this.chunk != null) {
|
||||||
|
if (this.dirtyCount != 0) {
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
int k;
|
||||||
|
|
||||||
|
if (this.dirtyCount == 1) {
|
||||||
|
i = (this.dirtyBlocks[0] >> 12 & 15) + this.location.x * 16;
|
||||||
|
j = this.dirtyBlocks[0] & 255;
|
||||||
|
k = (this.dirtyBlocks[0] >> 8 & 15) + this.location.z * 16;
|
||||||
|
BlockPosition blockposition = new BlockPosition(i, j, k);
|
||||||
|
|
||||||
|
this.a((new PacketPlayOutBlockChange(this.playerChunkMap.getWorld(), blockposition)));
|
||||||
|
if (this.playerChunkMap.getWorld().getType(blockposition).getBlock().isTileEntity()) {
|
||||||
|
this.a(this.playerChunkMap.getWorld().getTileEntity(blockposition));
|
||||||
|
}
|
||||||
|
} else if (this.dirtyCount == 64) {
|
||||||
|
// Paper - Anti-Xray - Loading chunks here could cause a ConcurrentModificationException #1104
|
||||||
|
//this.chunk.world.chunkPacketBlockController.onChunkPacketCreate(this.chunk, this.h, true); // Paper - Anti-Xray - Load nearby chunks if necessary
|
||||||
|
this.a((new PacketPlayOutMapChunk(this.chunk, this.h)));
|
||||||
|
} else {
|
||||||
|
this.a((new PacketPlayOutMultiBlockChange(this.dirtyCount, this.dirtyBlocks, this.chunk)));
|
||||||
|
|
||||||
|
for (i = 0; i < this.dirtyCount; ++i) {
|
||||||
|
j = (this.dirtyBlocks[i] >> 12 & 15) + this.location.x * 16;
|
||||||
|
k = this.dirtyBlocks[i] & 255;
|
||||||
|
int l = (this.dirtyBlocks[i] >> 8 & 15) + this.location.z * 16;
|
||||||
|
BlockPosition blockposition1 = new BlockPosition(j, k, l);
|
||||||
|
|
||||||
|
if (this.playerChunkMap.getWorld().getType(blockposition1).getBlock().isTileEntity()) {
|
||||||
|
this.a(this.playerChunkMap.getWorld().getTileEntity(blockposition1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dirtyCount = 0;
|
||||||
|
this.h = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void a(@Nullable TileEntity tileentity) {
|
||||||
|
if (tileentity != null) {
|
||||||
|
PacketPlayOutTileEntityData packetplayouttileentitydata = tileentity.getUpdatePacket();
|
||||||
|
|
||||||
|
if (packetplayouttileentitydata != null) {
|
||||||
|
this.a(packetplayouttileentitydata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean d(EntityPlayer entityplayer) {
|
||||||
|
return this.c.contains(entityplayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean a(Predicate<EntityPlayer> predicate) {
|
||||||
|
return Iterables.tryFind(this.c, predicate).isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean a(double d0, Predicate<EntityPlayer> predicate) {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (int j = this.c.size(); i < j; ++i) {
|
||||||
|
EntityPlayer entityplayer = this.c.get(i);
|
||||||
|
|
||||||
|
if (predicate.apply(entityplayer) && this.location.a(entityplayer) < d0 * d0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean e() {
|
||||||
|
return this.done;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Chunk f() {
|
||||||
|
return this.chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double g() {
|
||||||
|
double d0 = Double.MAX_VALUE;
|
||||||
|
Iterator iterator = this.c.iterator();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
|
||||||
|
double d1 = this.location.a(entityplayer);
|
||||||
|
|
||||||
|
if (d1 < d0) {
|
||||||
|
d0 = d1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return d0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ package net.minecraft.server;
|
|||||||
import com.google.common.primitives.Doubles;
|
import com.google.common.primitives.Doubles;
|
||||||
import com.google.common.primitives.Floats;
|
import com.google.common.primitives.Floats;
|
||||||
|
|
||||||
import io.akarin.api.Akari;
|
import io.akarin.api.internal.Akari;
|
||||||
import io.akarin.server.core.AkarinGlobalConfig;
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
import io.netty.util.concurrent.Future;
|
import io.netty.util.concurrent.Future;
|
||||||
import io.netty.util.concurrent.GenericFutureListener;
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
@@ -146,7 +146,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
private final static HashSet<Integer> invalidItems = new HashSet<Integer>(java.util.Arrays.asList(8, 9, 10, 11, 26, 34, 36, 43, 51, 55, 59, 62, 63, 64, 68, 71, 74, 75, 83, 90, 92, 93, 94, 104, 105, 115, 117, 118, 119, 125, 127, 132, 140, 141, 142, 144)); // TODO: Check after every update.
|
private final static HashSet<Integer> invalidItems = new HashSet<Integer>(java.util.Arrays.asList(8, 9, 10, 11, 26, 34, 36, 43, 51, 55, 59, 62, 63, 64, 68, 71, 74, 75, 83, 90, 92, 93, 94, 104, 105, 115, 117, 118, 119, 125, 127, 132, 140, 141, 142, 144)); // TODO: Check after every update.
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
|
|
||||||
@Override
|
|
||||||
public void e() {
|
public void e() {
|
||||||
this.syncPosition();
|
this.syncPosition();
|
||||||
this.player.playerTick();
|
this.player.playerTick();
|
||||||
@@ -189,7 +188,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.minecraftServer.methodProfiler.a("keepAlive");
|
this.minecraftServer.methodProfiler.a("keepAlive");
|
||||||
/* // Akarin start
|
/* // Akarin
|
||||||
// Paper Start - give clients a longer time to respond to pings as per pre 1.12.2 timings
|
// Paper Start - give clients a longer time to respond to pings as per pre 1.12.2 timings
|
||||||
// This should effectively place the keepalive handling back to "as it was" before 1.12.2
|
// This should effectively place the keepalive handling back to "as it was" before 1.12.2
|
||||||
long currentTime = this.getCurrentMillis();
|
long currentTime = this.getCurrentMillis();
|
||||||
@@ -209,7 +208,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Paper end
|
// Paper end
|
||||||
*/ // Akarin end
|
*/ // Akarin
|
||||||
|
|
||||||
this.minecraftServer.methodProfiler.b();
|
this.minecraftServer.methodProfiler.b();
|
||||||
// CraftBukkit start
|
// CraftBukkit start
|
||||||
@@ -225,7 +224,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
--this.j;
|
--this.j;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.player.J() > 0L && this.minecraftServer.getIdleTimeout() > 0 && MinecraftServer.aw() - this.player.J() > this.minecraftServer.getIdleTimeout() * 1000 * 60) {
|
if (this.player.J() > 0L && this.minecraftServer.getIdleTimeout() > 0 && MinecraftServer.aw() - this.player.J() > (long) (this.minecraftServer.getIdleTimeout() * 1000 * 60)) {
|
||||||
this.player.resetIdleTimer(); // CraftBukkit - SPIGOT-854
|
this.player.resetIdleTimer(); // CraftBukkit - SPIGOT-854
|
||||||
this.disconnect(new ChatMessage("multiplayer.disconnect.idling", new Object[0]));
|
this.disconnect(new ChatMessage("multiplayer.disconnect.idling", new Object[0]));
|
||||||
}
|
}
|
||||||
@@ -275,7 +274,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
final ChatComponentText chatcomponenttext = new ChatComponentText(s);
|
final ChatComponentText chatcomponenttext = new ChatComponentText(s);
|
||||||
|
|
||||||
this.networkManager.sendPacket(new PacketPlayOutKickDisconnect(chatcomponenttext), new GenericFutureListener() {
|
this.networkManager.sendPacket(new PacketPlayOutKickDisconnect(chatcomponenttext), new GenericFutureListener() {
|
||||||
@Override
|
|
||||||
public void operationComplete(Future future) throws Exception { // CraftBukkit - decompile error
|
public void operationComplete(Future future) throws Exception { // CraftBukkit - decompile error
|
||||||
PlayerConnection.this.networkManager.close(chatcomponenttext);
|
PlayerConnection.this.networkManager.close(chatcomponenttext);
|
||||||
}
|
}
|
||||||
@@ -284,14 +282,12 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
this.networkManager.stopReading();
|
this.networkManager.stopReading();
|
||||||
// CraftBukkit - Don't wait
|
// CraftBukkit - Don't wait
|
||||||
this.minecraftServer.postToMainThread(new Runnable() {
|
this.minecraftServer.postToMainThread(new Runnable() {
|
||||||
@Override
|
|
||||||
public void run() {
|
public void run() {
|
||||||
PlayerConnection.this.networkManager.handleDisconnection();
|
PlayerConnection.this.networkManager.handleDisconnection();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInSteerVehicle packetplayinsteervehicle) {
|
public void a(PacketPlayInSteerVehicle packetplayinsteervehicle) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinsteervehicle, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinsteervehicle, this, this.player.x());
|
||||||
this.player.a(packetplayinsteervehicle.a(), packetplayinsteervehicle.b(), packetplayinsteervehicle.c(), packetplayinsteervehicle.d());
|
this.player.a(packetplayinsteervehicle.a(), packetplayinsteervehicle.b(), packetplayinsteervehicle.c(), packetplayinsteervehicle.d());
|
||||||
@@ -305,7 +301,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
return !Doubles.isFinite(packetplayinvehiclemove.getX()) || !Doubles.isFinite(packetplayinvehiclemove.getY()) || !Doubles.isFinite(packetplayinvehiclemove.getZ()) || !Floats.isFinite(packetplayinvehiclemove.getPitch()) || !Floats.isFinite(packetplayinvehiclemove.getYaw());
|
return !Doubles.isFinite(packetplayinvehiclemove.getX()) || !Doubles.isFinite(packetplayinvehiclemove.getY()) || !Doubles.isFinite(packetplayinvehiclemove.getZ()) || !Floats.isFinite(packetplayinvehiclemove.getPitch()) || !Floats.isFinite(packetplayinvehiclemove.getYaw());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInVehicleMove packetplayinvehiclemove) {
|
public void a(PacketPlayInVehicleMove packetplayinvehiclemove) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinvehiclemove, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinvehiclemove, this, this.player.x());
|
||||||
if (b(packetplayinvehiclemove)) {
|
if (b(packetplayinvehiclemove)) {
|
||||||
@@ -355,7 +350,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
speed *= 2f; // TODO: Get the speed of the vehicle instead of the player
|
speed *= 2f; // TODO: Get the speed of the vehicle instead of the player
|
||||||
|
|
||||||
if (d10 - d9 > Math.max(100.0D, Math.pow(org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * i * speed, 2)) && (!this.minecraftServer.R() || !this.minecraftServer.Q().equals(entity.getName()))) { // Spigot
|
if (d10 - d9 > Math.max(100.0D, Math.pow((double) (org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed), 2)) && (!this.minecraftServer.R() || !this.minecraftServer.Q().equals(entity.getName()))) { // Spigot
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
PlayerConnection.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", entity.getName(), this.player.getName(), Double.valueOf(d6), Double.valueOf(d7), Double.valueOf(d8));
|
PlayerConnection.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", entity.getName(), this.player.getName(), Double.valueOf(d6), Double.valueOf(d7), Double.valueOf(d8));
|
||||||
this.networkManager.sendPacket(new PacketPlayOutVehicleMove(entity));
|
this.networkManager.sendPacket(new PacketPlayOutVehicleMove(entity));
|
||||||
@@ -473,7 +468,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInTeleportAccept packetplayinteleportaccept) {
|
public void a(PacketPlayInTeleportAccept packetplayinteleportaccept) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinteleportaccept, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinteleportaccept, this, this.player.x());
|
||||||
if (packetplayinteleportaccept.a() == this.teleportAwait && this.teleportPos != null) { // CraftBukkit
|
if (packetplayinteleportaccept.a() == this.teleportAwait && this.teleportPos != null) { // CraftBukkit
|
||||||
@@ -490,7 +484,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInRecipeDisplayed packetplayinrecipedisplayed) {
|
public void a(PacketPlayInRecipeDisplayed packetplayinrecipedisplayed) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinrecipedisplayed, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinrecipedisplayed, this, this.player.x());
|
||||||
if (packetplayinrecipedisplayed.a() == PacketPlayInRecipeDisplayed.Status.SHOWN) {
|
if (packetplayinrecipedisplayed.a() == PacketPlayInRecipeDisplayed.Status.SHOWN) {
|
||||||
@@ -502,7 +495,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInAdvancements packetplayinadvancements) {
|
public void a(PacketPlayInAdvancements packetplayinadvancements) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinadvancements, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinadvancements, this, this.player.x());
|
||||||
if (packetplayinadvancements.b() == PacketPlayInAdvancements.Status.OPENED_TAB) {
|
if (packetplayinadvancements.b() == PacketPlayInAdvancements.Status.OPENED_TAB) {
|
||||||
@@ -516,7 +508,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInFlying packetplayinflying) {
|
public void a(PacketPlayInFlying packetplayinflying) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinflying, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinflying, this, this.player.x());
|
||||||
if (b(packetplayinflying)) {
|
if (b(packetplayinflying)) {
|
||||||
@@ -598,7 +589,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
if (!this.player.L() && (!this.player.x().getGameRules().getBoolean("disableElytraMovementCheck") || !this.player.cP())) {
|
if (!this.player.L() && (!this.player.x().getGameRules().getBoolean("disableElytraMovementCheck") || !this.player.cP())) {
|
||||||
float f2 = this.player.cP() ? 300.0F : 100.0F;
|
float f2 = this.player.cP() ? 300.0F : 100.0F;
|
||||||
|
|
||||||
if (d11 - d10 > Math.max(f2, Math.pow(org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * i * speed, 2)) && (!this.minecraftServer.R() || !this.minecraftServer.Q().equals(this.player.getName()))) { // Spigot
|
if (d11 - d10 > Math.max(f2, Math.pow((double) (org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed), 2)) && (!this.minecraftServer.R() || !this.minecraftServer.Q().equals(this.player.getName()))) { // Spigot
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
PlayerConnection.LOGGER.warn("{} moved too quickly! {},{},{}", this.player.getName(), Double.valueOf(d7), Double.valueOf(d8), Double.valueOf(d9));
|
PlayerConnection.LOGGER.warn("{} moved too quickly! {},{},{}", this.player.getName(), Double.valueOf(d7), Double.valueOf(d8), Double.valueOf(d9));
|
||||||
this.a(this.player.locX, this.player.locY, this.player.locZ, this.player.yaw, this.player.pitch);
|
this.a(this.player.locX, this.player.locY, this.player.locZ, this.player.yaw, this.player.pitch);
|
||||||
@@ -855,7 +846,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
this.player.playerConnection.sendPacket(new PacketPlayOutPosition(d0, d1, d2, f, f1, set, this.teleportAwait));
|
this.player.playerConnection.sendPacket(new PacketPlayOutPosition(d0, d1, d2, f, f1, set, this.teleportAwait));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInBlockDig packetplayinblockdig) {
|
public void a(PacketPlayInBlockDig packetplayinblockdig) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinblockdig, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinblockdig, this, this.player.x());
|
||||||
if (this.player.isFrozen()) return; // CraftBukkit
|
if (this.player.isFrozen()) return; // CraftBukkit
|
||||||
@@ -918,9 +908,9 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
case START_DESTROY_BLOCK:
|
case START_DESTROY_BLOCK:
|
||||||
case ABORT_DESTROY_BLOCK:
|
case ABORT_DESTROY_BLOCK:
|
||||||
case STOP_DESTROY_BLOCK:
|
case STOP_DESTROY_BLOCK:
|
||||||
double d0 = this.player.locX - (blockposition.getX() + 0.5D);
|
double d0 = this.player.locX - ((double) blockposition.getX() + 0.5D);
|
||||||
double d1 = this.player.locY - (blockposition.getY() + 0.5D) + 1.5D;
|
double d1 = this.player.locY - ((double) blockposition.getY() + 0.5D) + 1.5D;
|
||||||
double d2 = this.player.locZ - (blockposition.getZ() + 0.5D);
|
double d2 = this.player.locZ - ((double) blockposition.getZ() + 0.5D);
|
||||||
double d3 = d0 * d0 + d1 * d1 + d2 * d2;
|
double d3 = d0 * d0 + d1 * d1 + d2 * d2;
|
||||||
|
|
||||||
if (d3 > 36.0D) {
|
if (d3 > 36.0D) {
|
||||||
@@ -984,7 +974,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
// Spigot end
|
// Spigot end
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInUseItem packetplayinuseitem) {
|
public void a(PacketPlayInUseItem packetplayinuseitem) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinuseitem, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinuseitem, this, this.player.x());
|
||||||
if (this.player.isFrozen()) return; // CraftBukkit
|
if (this.player.isFrozen()) return; // CraftBukkit
|
||||||
@@ -1001,7 +990,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
chatmessage.getChatModifier().setColor(EnumChatFormat.RED);
|
chatmessage.getChatModifier().setColor(EnumChatFormat.RED);
|
||||||
this.player.playerConnection.sendPacket(new PacketPlayOutChat(chatmessage, ChatMessageType.GAME_INFO));
|
this.player.playerConnection.sendPacket(new PacketPlayOutChat(chatmessage, ChatMessageType.GAME_INFO));
|
||||||
} else if (this.teleportPos == null && this.player.d(blockposition.getX() + 0.5D, blockposition.getY() + 0.5D, blockposition.getZ() + 0.5D) < 64.0D && !this.minecraftServer.a(worldserver, blockposition, this.player) && worldserver.getWorldBorder().a(blockposition)) {
|
} else if (this.teleportPos == null && this.player.d((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D) < 64.0D && !this.minecraftServer.a(worldserver, blockposition, this.player) && worldserver.getWorldBorder().a(blockposition)) {
|
||||||
// CraftBukkit start - Check if we can actually do something over this large a distance
|
// CraftBukkit start - Check if we can actually do something over this large a distance
|
||||||
Location eyeLoc = this.getPlayer().getEyeLocation();
|
Location eyeLoc = this.getPlayer().getEyeLocation();
|
||||||
double reachDistance = NumberConversions.square(eyeLoc.getX() - blockposition.getX()) + NumberConversions.square(eyeLoc.getY() - blockposition.getY()) + NumberConversions.square(eyeLoc.getZ() - blockposition.getZ());
|
double reachDistance = NumberConversions.square(eyeLoc.getX() - blockposition.getX()) + NumberConversions.square(eyeLoc.getY() - blockposition.getY()) + NumberConversions.square(eyeLoc.getZ() - blockposition.getZ());
|
||||||
@@ -1016,7 +1005,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(worldserver, blockposition.shift(enumdirection)));
|
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(worldserver, blockposition.shift(enumdirection)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInBlockPlace packetplayinblockplace) {
|
public void a(PacketPlayInBlockPlace packetplayinblockplace) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinblockplace, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinblockplace, this, this.player.x());
|
||||||
if (this.player.isFrozen()) return; // CraftBukkit
|
if (this.player.isFrozen()) return; // CraftBukkit
|
||||||
@@ -1032,7 +1020,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
float f1 = this.player.pitch;
|
float f1 = this.player.pitch;
|
||||||
float f2 = this.player.yaw;
|
float f2 = this.player.yaw;
|
||||||
double d0 = this.player.locX;
|
double d0 = this.player.locX;
|
||||||
double d1 = this.player.locY + this.player.getHeadHeight();
|
double d1 = this.player.locY + (double) this.player.getHeadHeight();
|
||||||
double d2 = this.player.locZ;
|
double d2 = this.player.locZ;
|
||||||
Vec3D vec3d = new Vec3D(d0, d1, d2);
|
Vec3D vec3d = new Vec3D(d0, d1, d2);
|
||||||
|
|
||||||
@@ -1043,7 +1031,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
float f7 = f4 * f5;
|
float f7 = f4 * f5;
|
||||||
float f8 = f3 * f5;
|
float f8 = f3 * f5;
|
||||||
double d3 = player.playerInteractManager.getGameMode()== EnumGamemode.CREATIVE ? 5.0D : 4.5D;
|
double d3 = player.playerInteractManager.getGameMode()== EnumGamemode.CREATIVE ? 5.0D : 4.5D;
|
||||||
Vec3D vec3d1 = vec3d.add(f7 * d3, f6 * d3, f8 * d3);
|
Vec3D vec3d1 = vec3d.add((double) f7 * d3, (double) f6 * d3, (double) f8 * d3);
|
||||||
MovingObjectPosition movingobjectposition = this.player.world.rayTrace(vec3d, vec3d1, false);
|
MovingObjectPosition movingobjectposition = this.player.world.rayTrace(vec3d, vec3d1, false);
|
||||||
|
|
||||||
boolean cancelled;
|
boolean cancelled;
|
||||||
@@ -1069,7 +1057,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInSpectate packetplayinspectate) {
|
public void a(PacketPlayInSpectate packetplayinspectate) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinspectate, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinspectate, this, this.player.x());
|
||||||
if (this.player.isSpectator()) {
|
if (this.player.isSpectator()) {
|
||||||
@@ -1127,7 +1114,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CraftBukkit start
|
// CraftBukkit start
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInResourcePackStatus packetplayinresourcepackstatus) {
|
public void a(PacketPlayInResourcePackStatus packetplayinresourcepackstatus) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinresourcepackstatus, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinresourcepackstatus, this, this.player.x());
|
||||||
// Paper start
|
// Paper start
|
||||||
@@ -1139,7 +1125,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInBoatMove packetplayinboatmove) {
|
public void a(PacketPlayInBoatMove packetplayinboatmove) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinboatmove, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinboatmove, this, this.player.x());
|
||||||
Entity entity = this.player.bJ();
|
Entity entity = this.player.bJ();
|
||||||
@@ -1150,7 +1135,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(IChatBaseComponent ichatbasecomponent) {
|
public void a(IChatBaseComponent ichatbasecomponent) {
|
||||||
// CraftBukkit start - Rarely it would send a disconnect line twice
|
// CraftBukkit start - Rarely it would send a disconnect line twice
|
||||||
if (this.processedDisconnect) {
|
if (this.processedDisconnect) {
|
||||||
@@ -1216,7 +1200,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
return packet.getClass().getCanonicalName();
|
return packet.getClass().getCanonicalName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object call() throws Exception {
|
public Object call() throws Exception {
|
||||||
return this.a();
|
return this.a();
|
||||||
}
|
}
|
||||||
@@ -1225,7 +1208,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInHeldItemSlot packetplayinhelditemslot) {
|
public void a(PacketPlayInHeldItemSlot packetplayinhelditemslot) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinhelditemslot, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinhelditemslot, this, this.player.x());
|
||||||
if (this.player.isFrozen()) return; // CraftBukkit
|
if (this.player.isFrozen()) return; // CraftBukkit
|
||||||
@@ -1246,7 +1228,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInChat packetplayinchat) {
|
public void a(PacketPlayInChat packetplayinchat) {
|
||||||
// CraftBukkit start - async chat
|
// CraftBukkit start - async chat
|
||||||
// SPIGOT-3638
|
// SPIGOT-3638
|
||||||
@@ -1387,6 +1368,8 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
// Paper Start
|
// Paper Start
|
||||||
if (!org.spigotmc.AsyncCatcher.shuttingDown && !Akari.isPrimaryThread()) { // Akarin
|
if (!org.spigotmc.AsyncCatcher.shuttingDown && !Akari.isPrimaryThread()) { // Akarin
|
||||||
final String fCommandLine = s;
|
final String fCommandLine = s;
|
||||||
|
Akari.callbackQueue.add(() -> chat(fCommandLine, false)); // Akarin
|
||||||
|
/* // Akarin
|
||||||
MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Command Dispatched Async: " + fCommandLine);
|
MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Command Dispatched Async: " + fCommandLine);
|
||||||
MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());
|
MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());
|
||||||
Waitable wait = new Waitable() {
|
Waitable wait = new Waitable() {
|
||||||
@@ -1405,6 +1388,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Exception processing chat command", e.getCause());
|
throw new RuntimeException("Exception processing chat command", e.getCause());
|
||||||
}
|
}
|
||||||
|
*/ // Akarin
|
||||||
}
|
}
|
||||||
// Paper End
|
// Paper End
|
||||||
this.handleCommand(s);
|
this.handleCommand(s);
|
||||||
@@ -1513,7 +1497,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInArmAnimation packetplayinarmanimation) {
|
public void a(PacketPlayInArmAnimation packetplayinarmanimation) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinarmanimation, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinarmanimation, this, this.player.x());
|
||||||
if (this.player.isFrozen()) return; // CraftBukkit
|
if (this.player.isFrozen()) return; // CraftBukkit
|
||||||
@@ -1522,7 +1505,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
float f1 = this.player.pitch;
|
float f1 = this.player.pitch;
|
||||||
float f2 = this.player.yaw;
|
float f2 = this.player.yaw;
|
||||||
double d0 = this.player.locX;
|
double d0 = this.player.locX;
|
||||||
double d1 = this.player.locY + this.player.getHeadHeight();
|
double d1 = this.player.locY + (double) this.player.getHeadHeight();
|
||||||
double d2 = this.player.locZ;
|
double d2 = this.player.locZ;
|
||||||
Vec3D vec3d = new Vec3D(d0, d1, d2);
|
Vec3D vec3d = new Vec3D(d0, d1, d2);
|
||||||
|
|
||||||
@@ -1533,7 +1516,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
float f7 = f4 * f5;
|
float f7 = f4 * f5;
|
||||||
float f8 = f3 * f5;
|
float f8 = f3 * f5;
|
||||||
double d3 = player.playerInteractManager.getGameMode()== EnumGamemode.CREATIVE ? 5.0D : 4.5D;
|
double d3 = player.playerInteractManager.getGameMode()== EnumGamemode.CREATIVE ? 5.0D : 4.5D;
|
||||||
Vec3D vec3d1 = vec3d.add(f7 * d3, f6 * d3, f8 * d3);
|
Vec3D vec3d1 = vec3d.add((double) f7 * d3, (double) f6 * d3, (double) f8 * d3);
|
||||||
MovingObjectPosition movingobjectposition = this.player.world.rayTrace(vec3d, vec3d1, false);
|
MovingObjectPosition movingobjectposition = this.player.world.rayTrace(vec3d, vec3d1, false);
|
||||||
|
|
||||||
if (movingobjectposition == null || movingobjectposition.type != MovingObjectPosition.EnumMovingObjectType.BLOCK) {
|
if (movingobjectposition == null || movingobjectposition.type != MovingObjectPosition.EnumMovingObjectType.BLOCK) {
|
||||||
@@ -1549,7 +1532,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
this.player.a(packetplayinarmanimation.a());
|
this.player.a(packetplayinarmanimation.a());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInEntityAction packetplayinentityaction) {
|
public void a(PacketPlayInEntityAction packetplayinentityaction) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinentityaction, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinentityaction, this, this.player.x());
|
||||||
// CraftBukkit start
|
// CraftBukkit start
|
||||||
@@ -1651,12 +1633,11 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInUseEntity packetplayinuseentity) {
|
public void a(PacketPlayInUseEntity packetplayinuseentity) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinuseentity, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinuseentity, this, this.player.x());
|
||||||
if (this.player.isFrozen()) return; // CraftBukkit
|
if (this.player.isFrozen()) return; // CraftBukkit
|
||||||
WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension);
|
WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension);
|
||||||
Entity entity = packetplayinuseentity.a(worldserver);
|
Entity entity = packetplayinuseentity.a((World) worldserver);
|
||||||
// Spigot Start
|
// Spigot Start
|
||||||
if ( entity == player && !player.isSpectator() )
|
if ( entity == player && !player.isSpectator() )
|
||||||
{
|
{
|
||||||
@@ -1686,10 +1667,10 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
Item origItem = this.player.inventory.getItemInHand() == null ? null : this.player.inventory.getItemInHand().getItem();
|
Item origItem = this.player.inventory.getItemInHand() == null ? null : this.player.inventory.getItemInHand().getItem();
|
||||||
PlayerInteractEntityEvent event;
|
PlayerInteractEntityEvent event;
|
||||||
if (packetplayinuseentity.a() == PacketPlayInUseEntity.EnumEntityUseAction.INTERACT) {
|
if (packetplayinuseentity.a() == PacketPlayInUseEntity.EnumEntityUseAction.INTERACT) {
|
||||||
event = new PlayerInteractEntityEvent(this.getPlayer(), entity.getBukkitEntity(), (packetplayinuseentity.b() == EnumHand.OFF_HAND) ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND);
|
event = new PlayerInteractEntityEvent((Player) this.getPlayer(), entity.getBukkitEntity(), (packetplayinuseentity.b() == EnumHand.OFF_HAND) ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND);
|
||||||
} else {
|
} else {
|
||||||
Vec3D target = packetplayinuseentity.c();
|
Vec3D target = packetplayinuseentity.c();
|
||||||
event = new PlayerInteractAtEntityEvent(this.getPlayer(), entity.getBukkitEntity(), new org.bukkit.util.Vector(target.x, target.y, target.z), (packetplayinuseentity.b() == EnumHand.OFF_HAND) ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND);
|
event = new PlayerInteractAtEntityEvent((Player) this.getPlayer(), entity.getBukkitEntity(), new org.bukkit.util.Vector(target.x, target.y, target.z), (packetplayinuseentity.b() == EnumHand.OFF_HAND) ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND);
|
||||||
}
|
}
|
||||||
this.server.getPluginManager().callEvent(event);
|
this.server.getPluginManager().callEvent(event);
|
||||||
|
|
||||||
@@ -1755,7 +1736,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInClientCommand packetplayinclientcommand) {
|
public void a(PacketPlayInClientCommand packetplayinclientcommand) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinclientcommand, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinclientcommand, this, this.player.x());
|
||||||
this.player.resetIdleTimer();
|
this.player.resetIdleTimer();
|
||||||
@@ -1787,17 +1767,15 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInCloseWindow packetplayinclosewindow) {
|
public void a(PacketPlayInCloseWindow packetplayinclosewindow) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinclosewindow, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinclosewindow, this, this.player.x());
|
||||||
|
|
||||||
if (this.player.isFrozen()) return; // CraftBukkit
|
if (this.player.isFrozen()) return; // CraftBukkit
|
||||||
CraftEventFactory.handleInventoryCloseEvent(this.player); // CraftBukkit
|
CraftEventFactory.handleInventoryCloseEvent(this.player, org.bukkit.event.inventory.InventoryCloseEvent.Reason.PLAYER); // CraftBukkit // Paper
|
||||||
|
|
||||||
this.player.r();
|
this.player.r();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInWindowClick packetplayinwindowclick) {
|
public void a(PacketPlayInWindowClick packetplayinwindowclick) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinwindowclick, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinwindowclick, this, this.player.x());
|
||||||
if (this.player.isFrozen()) return; // CraftBukkit
|
if (this.player.isFrozen()) return; // CraftBukkit
|
||||||
@@ -1808,7 +1786,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
NonNullList nonnulllist = NonNullList.a();
|
NonNullList nonnulllist = NonNullList.a();
|
||||||
|
|
||||||
for (int i = 0; i < this.player.activeContainer.slots.size(); ++i) {
|
for (int i = 0; i < this.player.activeContainer.slots.size(); ++i) {
|
||||||
nonnulllist.add(this.player.activeContainer.slots.get(i).getItem());
|
nonnulllist.add(((Slot) this.player.activeContainer.slots.get(i)).getItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.player.a(this.player.activeContainer, nonnulllist);
|
this.player.a(this.player.activeContainer, nonnulllist);
|
||||||
@@ -2094,7 +2072,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
NonNullList nonnulllist1 = NonNullList.a();
|
NonNullList nonnulllist1 = NonNullList.a();
|
||||||
|
|
||||||
for (int j = 0; j < this.player.activeContainer.slots.size(); ++j) {
|
for (int j = 0; j < this.player.activeContainer.slots.size(); ++j) {
|
||||||
ItemStack itemstack1 = this.player.activeContainer.slots.get(j).getItem();
|
ItemStack itemstack1 = ((Slot) this.player.activeContainer.slots.get(j)).getItem();
|
||||||
ItemStack itemstack2 = itemstack1.isEmpty() ? ItemStack.a : itemstack1;
|
ItemStack itemstack2 = itemstack1.isEmpty() ? ItemStack.a : itemstack1;
|
||||||
|
|
||||||
nonnulllist1.add(itemstack2);
|
nonnulllist1.add(itemstack2);
|
||||||
@@ -2107,7 +2085,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInAutoRecipe packetplayinautorecipe) {
|
public void a(PacketPlayInAutoRecipe packetplayinautorecipe) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinautorecipe, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinautorecipe, this, this.player.x());
|
||||||
this.player.resetIdleTimer();
|
this.player.resetIdleTimer();
|
||||||
@@ -2116,7 +2093,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInEnchantItem packetplayinenchantitem) {
|
public void a(PacketPlayInEnchantItem packetplayinenchantitem) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinenchantitem, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinenchantitem, this, this.player.x());
|
||||||
if (this.player.isFrozen()) return; // CraftBukkit
|
if (this.player.isFrozen()) return; // CraftBukkit
|
||||||
@@ -2128,7 +2104,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInSetCreativeSlot packetplayinsetcreativeslot) {
|
public void a(PacketPlayInSetCreativeSlot packetplayinsetcreativeslot) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinsetcreativeslot, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinsetcreativeslot, this, this.player.x());
|
||||||
if (this.player.playerInteractManager.isCreative()) {
|
if (this.player.playerInteractManager.isCreative()) {
|
||||||
@@ -2148,7 +2123,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
nbttagcompound1.remove("x");
|
nbttagcompound1.remove("x");
|
||||||
nbttagcompound1.remove("y");
|
nbttagcompound1.remove("y");
|
||||||
nbttagcompound1.remove("z");
|
nbttagcompound1.remove("z");
|
||||||
itemstack.a("BlockEntityTag", nbttagcompound1);
|
itemstack.a("BlockEntityTag", (NBTBase) nbttagcompound1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2214,11 +2189,10 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInTransaction packetplayintransaction) {
|
public void a(PacketPlayInTransaction packetplayintransaction) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayintransaction, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayintransaction, this, this.player.x());
|
||||||
if (this.player.isFrozen()) return; // CraftBukkit
|
if (this.player.isFrozen()) return; // CraftBukkit
|
||||||
Short oshort = this.k.get(this.player.activeContainer.windowId);
|
Short oshort = (Short) this.k.get(this.player.activeContainer.windowId);
|
||||||
|
|
||||||
if (oshort != null && packetplayintransaction.b() == oshort.shortValue() && this.player.activeContainer.windowId == packetplayintransaction.a() && !this.player.activeContainer.c(this.player) && !this.player.isSpectator()) {
|
if (oshort != null && packetplayintransaction.b() == oshort.shortValue() && this.player.activeContainer.windowId == packetplayintransaction.a() && !this.player.activeContainer.c(this.player) && !this.player.isSpectator()) {
|
||||||
this.player.activeContainer.a(this.player, true);
|
this.player.activeContainer.a(this.player, true);
|
||||||
@@ -2226,7 +2200,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInUpdateSign packetplayinupdatesign) {
|
public void a(PacketPlayInUpdateSign packetplayinupdatesign) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinupdatesign, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinupdatesign, this, this.player.x());
|
||||||
if (this.player.isFrozen()) return; // CraftBukkit
|
if (this.player.isFrozen()) return; // CraftBukkit
|
||||||
@@ -2262,7 +2235,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
for (int i = 0; i < astring.length; ++i) {
|
for (int i = 0; i < astring.length; ++i) {
|
||||||
lines[i] = SharedConstants.a(astring[i]); //Paper - Replaced with anvil color stripping method to stop exploits that allow colored signs to be created.
|
lines[i] = SharedConstants.a(astring[i]); //Paper - Replaced with anvil color stripping method to stop exploits that allow colored signs to be created.
|
||||||
}
|
}
|
||||||
SignChangeEvent event = new SignChangeEvent(player.getWorld().getBlockAt(x, y, z), this.server.getPlayer(this.player), lines);
|
SignChangeEvent event = new SignChangeEvent((org.bukkit.craftbukkit.block.CraftBlock) player.getWorld().getBlockAt(x, y, z), this.server.getPlayer(this.player), lines);
|
||||||
this.server.getPluginManager().callEvent(event);
|
this.server.getPluginManager().callEvent(event);
|
||||||
|
|
||||||
if (!event.isCancelled()) {
|
if (!event.isCancelled()) {
|
||||||
@@ -2277,7 +2250,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInKeepAlive packetplayinkeepalive) {
|
public void a(PacketPlayInKeepAlive packetplayinkeepalive) {
|
||||||
//PlayerConnectionUtils.ensureMainThread(packetplayinkeepalive, this, this.player.x()); // CraftBukkit // Paper - This shouldn't be on the main thread
|
//PlayerConnectionUtils.ensureMainThread(packetplayinkeepalive, this, this.player.x()); // CraftBukkit // Paper - This shouldn't be on the main thread
|
||||||
if (this.g && packetplayinkeepalive.a() == this.h) {
|
if (this.g && packetplayinkeepalive.a() == this.h) {
|
||||||
@@ -2302,7 +2274,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
return System.nanoTime() / 1000000L;
|
return System.nanoTime() / 1000000L;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInAbilities packetplayinabilities) {
|
public void a(PacketPlayInAbilities packetplayinabilities) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinabilities, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinabilities, this, this.player.x());
|
||||||
// CraftBukkit start
|
// CraftBukkit start
|
||||||
@@ -2319,7 +2290,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Paper start - async tab completion
|
// Paper start - async tab completion
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInTabComplete packet) {
|
public void a(PacketPlayInTabComplete packet) {
|
||||||
// CraftBukkit start
|
// CraftBukkit start
|
||||||
if (chatSpamField.addAndGet(this, 10) > 500 && !this.minecraftServer.getPlayerList().isOp(this.player.getProfile())) {
|
if (chatSpamField.addAndGet(this, 10) > 500 && !this.minecraftServer.getPlayerList().isOp(this.player.getProfile())) {
|
||||||
@@ -2366,13 +2336,11 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
// Paper end
|
// Paper end
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInSettings packetplayinsettings) {
|
public void a(PacketPlayInSettings packetplayinsettings) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayinsettings, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayinsettings, this, this.player.x());
|
||||||
this.player.a(packetplayinsettings);
|
this.player.a(packetplayinsettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(PacketPlayInCustomPayload packetplayincustompayload) {
|
public void a(PacketPlayInCustomPayload packetplayincustompayload) {
|
||||||
PlayerConnectionUtils.ensureMainThread(packetplayincustompayload, this, this.player.x());
|
PlayerConnectionUtils.ensureMainThread(packetplayincustompayload, this, this.player.x());
|
||||||
String s = packetplayincustompayload.a();
|
String s = packetplayincustompayload.a();
|
||||||
@@ -2407,7 +2375,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
if (itemstack.getItem() == Items.WRITABLE_BOOK && itemstack.getItem() == itemstack1.getItem()) {
|
if (itemstack.getItem() == Items.WRITABLE_BOOK && itemstack.getItem() == itemstack1.getItem()) {
|
||||||
itemstack1 = new ItemStack(Items.WRITABLE_BOOK); // CraftBukkit
|
itemstack1 = new ItemStack(Items.WRITABLE_BOOK); // CraftBukkit
|
||||||
itemstack1.a("pages", itemstack.getTag().getList("pages", 8));
|
itemstack1.a("pages", (NBTBase) itemstack.getTag().getList("pages", 8));
|
||||||
CraftEventFactory.handleEditBookEvent(player, itemstack1); // CraftBukkit
|
CraftEventFactory.handleEditBookEvent(player, itemstack1); // CraftBukkit
|
||||||
}
|
}
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
@@ -2444,19 +2412,19 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
if (itemstack.getItem() == Items.WRITABLE_BOOK && itemstack1.getItem() == Items.WRITABLE_BOOK) {
|
if (itemstack.getItem() == Items.WRITABLE_BOOK && itemstack1.getItem() == Items.WRITABLE_BOOK) {
|
||||||
ItemStack itemstack2 = new ItemStack(Items.WRITTEN_BOOK);
|
ItemStack itemstack2 = new ItemStack(Items.WRITTEN_BOOK);
|
||||||
|
|
||||||
itemstack2.a("author", (new NBTTagString(this.player.getName())));
|
itemstack2.a("author", (NBTBase) (new NBTTagString(this.player.getName())));
|
||||||
itemstack2.a("title", (new NBTTagString(itemstack.getTag().getString("title"))));
|
itemstack2.a("title", (NBTBase) (new NBTTagString(itemstack.getTag().getString("title"))));
|
||||||
NBTTagList nbttaglist = itemstack.getTag().getList("pages", 8);
|
NBTTagList nbttaglist = itemstack.getTag().getList("pages", 8);
|
||||||
|
|
||||||
for (int i = 0; i < nbttaglist.size(); ++i) {
|
for (int i = 0; i < nbttaglist.size(); ++i) {
|
||||||
s1 = nbttaglist.getString(i);
|
s1 = nbttaglist.getString(i);
|
||||||
ChatComponentText chatcomponenttext = new ChatComponentText(s1);
|
ChatComponentText chatcomponenttext = new ChatComponentText(s1);
|
||||||
|
|
||||||
s1 = IChatBaseComponent.ChatSerializer.a(chatcomponenttext);
|
s1 = IChatBaseComponent.ChatSerializer.a((IChatBaseComponent) chatcomponenttext);
|
||||||
nbttaglist.a(i, new NBTTagString(s1));
|
nbttaglist.a(i, new NBTTagString(s1));
|
||||||
}
|
}
|
||||||
|
|
||||||
itemstack2.a("pages", nbttaglist);
|
itemstack2.a("pages", (NBTBase) nbttaglist);
|
||||||
CraftEventFactory.handleEditBookEvent(player, itemstack2); // CraftBukkit
|
CraftEventFactory.handleEditBookEvent(player, itemstack2); // CraftBukkit
|
||||||
}
|
}
|
||||||
} catch (Exception exception1) {
|
} catch (Exception exception1) {
|
||||||
@@ -2554,7 +2522,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
boolean flag3 = packetdataserializer.readBoolean();
|
boolean flag3 = packetdataserializer.readBoolean();
|
||||||
|
|
||||||
if (commandblocklistenerabstract1 != null) {
|
if (commandblocklistenerabstract1 != null) {
|
||||||
EnumDirection enumdirection = this.player.world.getType(blockposition).get(BlockCommand.a);
|
EnumDirection enumdirection = (EnumDirection) this.player.world.getType(blockposition).get(BlockCommand.a);
|
||||||
IBlockData iblockdata;
|
IBlockData iblockdata;
|
||||||
|
|
||||||
switch (tileentitycommand_type) {
|
switch (tileentitycommand_type) {
|
||||||
@@ -2674,23 +2642,23 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
|||||||
|
|
||||||
if (b1 == 2) {
|
if (b1 == 2) {
|
||||||
if (tileentitystructure.q()) {
|
if (tileentitystructure.q()) {
|
||||||
this.player.a((new ChatMessage("structure_block.save_success", new Object[] { s7})), false);
|
this.player.a((IChatBaseComponent) (new ChatMessage("structure_block.save_success", new Object[] { s7})), false);
|
||||||
} else {
|
} else {
|
||||||
this.player.a((new ChatMessage("structure_block.save_failure", new Object[] { s7})), false);
|
this.player.a((IChatBaseComponent) (new ChatMessage("structure_block.save_failure", new Object[] { s7})), false);
|
||||||
}
|
}
|
||||||
} else if (b1 == 3) {
|
} else if (b1 == 3) {
|
||||||
if (!tileentitystructure.E()) {
|
if (!tileentitystructure.E()) {
|
||||||
this.player.a((new ChatMessage("structure_block.load_not_found", new Object[] { s7})), false);
|
this.player.a((IChatBaseComponent) (new ChatMessage("structure_block.load_not_found", new Object[] { s7})), false);
|
||||||
} else if (tileentitystructure.r()) {
|
} else if (tileentitystructure.r()) {
|
||||||
this.player.a((new ChatMessage("structure_block.load_success", new Object[] { s7})), false);
|
this.player.a((IChatBaseComponent) (new ChatMessage("structure_block.load_success", new Object[] { s7})), false);
|
||||||
} else {
|
} else {
|
||||||
this.player.a((new ChatMessage("structure_block.load_prepare", new Object[] { s7})), false);
|
this.player.a((IChatBaseComponent) (new ChatMessage("structure_block.load_prepare", new Object[] { s7})), false);
|
||||||
}
|
}
|
||||||
} else if (b1 == 4) {
|
} else if (b1 == 4) {
|
||||||
if (tileentitystructure.p()) {
|
if (tileentitystructure.p()) {
|
||||||
this.player.a((new ChatMessage("structure_block.size_success", new Object[] { s7})), false);
|
this.player.a((IChatBaseComponent) (new ChatMessage("structure_block.size_success", new Object[] { s7})), false);
|
||||||
} else {
|
} else {
|
||||||
this.player.a((new ChatMessage("structure_block.size_failure", new Object[0])), false);
|
this.player.a((IChatBaseComponent) (new ChatMessage("structure_block.size_failure", new Object[0])), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1543
sources/src/main/java/net/minecraft/server/PlayerList.java
Normal file
1543
sources/src/main/java/net/minecraft/server/PlayerList.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,7 @@ public class WorldData {
|
|||||||
private boolean z;
|
private boolean z;
|
||||||
private boolean A;
|
private boolean A;
|
||||||
private boolean B;
|
private boolean B;
|
||||||
private EnumDifficulty C;
|
private volatile EnumDifficulty C; // Akarin - volatile
|
||||||
private boolean D;
|
private boolean D;
|
||||||
private double E;
|
private double E;
|
||||||
private double F;
|
private double F;
|
||||||
|
|||||||
1512
sources/src/main/java/net/minecraft/server/WorldServer.java
Normal file
1512
sources/src/main/java/net/minecraft/server/WorldServer.java
Normal file
File diff suppressed because it is too large
Load Diff
1940
sources/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
Normal file
1940
sources/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
Normal file
File diff suppressed because it is too large
Load Diff
37
sources/src/main/resources/configurations/bukkit.yml
Normal file
37
sources/src/main/resources/configurations/bukkit.yml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# This is the main configuration file for Bukkit.
|
||||||
|
# As you can see, there's actually not that much to configure without any plugins.
|
||||||
|
# For a reference for any variable inside this file, check out the Bukkit Wiki at
|
||||||
|
# http://wiki.bukkit.org/Bukkit.yml
|
||||||
|
#
|
||||||
|
# If you need help on this file, feel free to join us on irc or leave a message
|
||||||
|
# on the forums asking for advice.
|
||||||
|
#
|
||||||
|
# IRC: #spigot @ irc.spi.gt
|
||||||
|
# (If this means nothing to you, just go to http://www.spigotmc.org/pages/irc/ )
|
||||||
|
# Forums: http://www.spigotmc.org/
|
||||||
|
# Bug tracker: http://www.spigotmc.org/go/bugs
|
||||||
|
|
||||||
|
|
||||||
|
settings:
|
||||||
|
allow-end: true
|
||||||
|
warn-on-overload: true
|
||||||
|
permissions-file: permissions.yml
|
||||||
|
update-folder: update
|
||||||
|
plugin-profiling: false
|
||||||
|
connection-throttle: 4000
|
||||||
|
query-plugins: false
|
||||||
|
deprecated-verbose: default
|
||||||
|
shutdown-message: "Server closed"
|
||||||
|
spawn-limits:
|
||||||
|
monsters: 70
|
||||||
|
animals: 15
|
||||||
|
water-animals: 5
|
||||||
|
ambient: 15
|
||||||
|
chunk-gc:
|
||||||
|
period-in-ticks: 600
|
||||||
|
load-threshold: 0
|
||||||
|
ticks-per:
|
||||||
|
animal-spawns: 400
|
||||||
|
monster-spawns: 1
|
||||||
|
autosave: 6000
|
||||||
|
aliases: now-in-commands.yml
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"minVersion": "0.7.8",
|
"minVersion": "0.7.10",
|
||||||
"package": "io.akarin.server.mixin",
|
"package": "io.akarin.server.mixin",
|
||||||
"target": "@env(DEFAULT)",
|
"target": "@env(DEFAULT)",
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
@@ -11,33 +11,36 @@
|
|||||||
"bootstrap.MixinMetrics",
|
"bootstrap.MixinMetrics",
|
||||||
"bootstrap.ParallelRegistry",
|
"bootstrap.ParallelRegistry",
|
||||||
"bootstrap.MetricsBootstrap",
|
"bootstrap.MetricsBootstrap",
|
||||||
|
"bootstrap.MixinRestartCommand",
|
||||||
|
|
||||||
|
"core.MixinWorld",
|
||||||
"core.MixinMCUtil",
|
"core.MixinMCUtil",
|
||||||
|
"core.MixinPlayerList",
|
||||||
|
"core.MixinCommandBan",
|
||||||
|
"core.MixinCommandKick",
|
||||||
"core.MixinCraftServer",
|
"core.MixinCraftServer",
|
||||||
|
"core.MixinWorldServer",
|
||||||
|
"core.MixinCommandBanIp",
|
||||||
|
"core.MixinChunkSection",
|
||||||
"core.MixinAsyncCatcher",
|
"core.MixinAsyncCatcher",
|
||||||
"core.MixinTimingHandler",
|
"core.MixinTimingHandler",
|
||||||
"core.MonsterEggGuardian",
|
"core.MonsterEggGuardian",
|
||||||
"core.MixinVersionCommand",
|
"core.MixinVersionCommand",
|
||||||
"core.MixinMinecraftServer",
|
"core.MixinMinecraftServer",
|
||||||
"core.MixinChunkIOExecutor",
|
"core.MixinChunkIOExecutor",
|
||||||
|
"core.MixinPlayerConnectionUtils",
|
||||||
|
|
||||||
"cps.MixinChunk",
|
|
||||||
"cps.MixinCraftWorld",
|
"cps.MixinCraftWorld",
|
||||||
"cps.MixinChunkProviderServer",
|
"cps.MixinChunkProviderServer",
|
||||||
|
|
||||||
"nsc.MixinPlayerConnection",
|
|
||||||
"nsc.OptimisticNetworkManager",
|
"nsc.OptimisticNetworkManager",
|
||||||
"nsc.NonblockingServerConnection",
|
"nsc.NonblockingServerConnection",
|
||||||
|
|
||||||
"lighting.MixinChunk",
|
|
||||||
"lighting.MixinWorld",
|
|
||||||
"lighting.MixinWorldServer",
|
|
||||||
"lighting.MixinChunkProviderServer",
|
|
||||||
|
|
||||||
"optimization.WeakBigTree",
|
"optimization.WeakBigTree",
|
||||||
"optimization.WeakEnchantmentManager",
|
"optimization.WeakEnchantmentManager",
|
||||||
"optimization.MixinEntityHorseAbstract",
|
"optimization.MixinEntityHorseAbstract",
|
||||||
"optimization.MixinEntityTameableAnimal",
|
"optimization.MixinEntityTameableAnimal",
|
||||||
|
"optimization.MixinPersistentCollection",
|
||||||
"optimization.MixinTileEntityEnchantTable"
|
"optimization.MixinTileEntityEnchantTable"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"minVersion": "0.7.10",
|
||||||
|
"package": "io.akarin.server.mixin",
|
||||||
|
"target": "@env(DEFAULT)",
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"server": [
|
||||||
|
"cps.MixinChunk",
|
||||||
|
|
||||||
|
"lighting.MixinChunk",
|
||||||
|
"lighting.MixinWorld",
|
||||||
|
"lighting.MixinWorldServer",
|
||||||
|
"lighting.MixinChunkProviderServer",
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"minVersion": "0.7.10",
|
||||||
|
"package": "io.akarin.server.mixin",
|
||||||
|
"target": "@env(DEFAULT)",
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"server": [
|
||||||
|
"optimization.PandaRedstoneWire",
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"minVersion": "0.7.10",
|
||||||
|
"package": "io.akarin.server.mixin",
|
||||||
|
"target": "@env(DEFAULT)",
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"server": [
|
||||||
|
"realtime.MixinWorld",
|
||||||
|
"realtime.MixinEntity",
|
||||||
|
"realtime.MixinEntityItem",
|
||||||
|
"realtime.MixinWorldServer",
|
||||||
|
"realtime.MixinEntityHuman",
|
||||||
|
"realtime.MixinEntityPlayer",
|
||||||
|
"realtime.MixinEntityAgeable",
|
||||||
|
"realtime.MixinMinecraftServer",
|
||||||
|
"realtime.MixinEntityInsentient",
|
||||||
|
"realtime.MixinPlayerConnection",
|
||||||
|
"realtime.MixinTileEntityFurnace",
|
||||||
|
"realtime.MixinEntityExperienceOrb",
|
||||||
|
"realtime.MixinEntityZombieVillager",
|
||||||
|
"realtime.MixinPlayerInteractManager",
|
||||||
|
"realtime.MixinTileEntityBrewingStand",
|
||||||
|
]
|
||||||
|
}
|
||||||
Submodule work/Paper updated: 15bd1f642b...8f4c8d86bf
Reference in New Issue
Block a user