Merge branch 'master' into refactor/1.15
# Conflicts: # arclight-common/src/main/java/io/izzel/arclight/common/bridge/server/management/PlayerListBridge.java # arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/item/ItemStackMixin.java # arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/server/management/PlayerListMixin.java # arclight-common/src/main/java/io/izzel/arclight/common/mod/ArclightConnector.java # arclight-common/src/main/resources/META-INF/accesstransformer.cfg # arclight-common/src/main/resources/mixins.arclight.core.json # arclight-forge-1.14/build.gradle # arclight-forge-1.14/src/main/java/io/izzel/arclight/server/Main.java # settings.gradle
This commit is contained in:
commit
c538046c1a
15
README.md
15
README.md
@ -9,7 +9,7 @@ A Bukkit server implementation utilizing Mixin.
|
|||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
1. Download the jar from [release page](https://github.com/IzzelAliz/Arclight/releases) or [build server](https://ci.appveyor.com/project/IzzelAliz/arclight/build/artifacts).
|
1. Download the jar from [release page](https://github.com/IzzelAliz/Arclight/releases) or [build server](https://ci.appveyor.com/project/IzzelAliz/arclight/build/artifacts).
|
||||||
2. Launch with command `java -jar arclight-coremod-xxx.jar`
|
2. Launch with command `java -jar arclight-forge-mcversion-xxx.jar nogui`. The `nogui` argument will disable the server control panel.
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
@ -19,7 +19,18 @@ QQ Group chat 3556966
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
To setup development workspace, clone this repository and import the project.
|
This project uses Gradle 4.9 as build tool with [arclight-gradle-plugin](https://github.com/IzzelAliz/arclight-gradle-plugin).
|
||||||
|
|
||||||
|
To setup development workspace, clone this repository first, and type
|
||||||
|
```
|
||||||
|
./gradlew remapSpigotJar idea
|
||||||
|
```
|
||||||
|
|
||||||
|
This will generate proper spigot sources and srg mappings.
|
||||||
|
|
||||||
|
Finally, import the project. IntelliJ IDEA is the recommended IDE.
|
||||||
|
|
||||||
|
Due to a [MixinGradle bug](https://github.com/SpongePowered/MixinGradle/issues/9), you may build the project twice or the mixin shadows won't get reobfuscated.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@ -60,6 +60,7 @@ dependencies {
|
|||||||
compile 'mysql:mysql-connector-java:5.1.47'
|
compile 'mysql:mysql-connector-java:5.1.47'
|
||||||
compile 'org.yaml:snakeyaml:1.23'
|
compile 'org.yaml:snakeyaml:1.23'
|
||||||
compile project(':arclight-api')
|
compile project(':arclight-api')
|
||||||
|
compile project(':i18n-config')
|
||||||
}
|
}
|
||||||
|
|
||||||
remapSpigotJar {
|
remapSpigotJar {
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
package io.izzel.arclight.common.bridge.network;
|
||||||
|
|
||||||
|
import com.mojang.authlib.properties.Property;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface NetworkManagerBridge {
|
||||||
|
|
||||||
|
UUID bridge$getSpoofedUUID();
|
||||||
|
|
||||||
|
void bridge$setSpoofedUUID(UUID spoofedUUID);
|
||||||
|
|
||||||
|
Property[] bridge$getSpoofedProfile();
|
||||||
|
|
||||||
|
void bridge$setSpoofedProfile(Property[] spoofedProfile);
|
||||||
|
|
||||||
|
SocketAddress bridge$getRawAddress();
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package io.izzel.arclight.common.bridge.network.login;
|
||||||
|
|
||||||
|
public interface ServerLoginNetHandlerBridge {
|
||||||
|
|
||||||
|
String bridge$getHostname();
|
||||||
|
|
||||||
|
void bridge$setHostname(String hostname);
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package io.izzel.arclight.common.bridge.server.management;
|
package io.izzel.arclight.common.bridge.server.management;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
import net.minecraft.network.play.server.SRespawnPacket;
|
import net.minecraft.network.play.server.SRespawnPacket;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
@ -8,8 +9,10 @@ import net.minecraft.world.GameType;
|
|||||||
import net.minecraft.world.WorldType;
|
import net.minecraft.world.WorldType;
|
||||||
import net.minecraft.world.dimension.DimensionType;
|
import net.minecraft.world.dimension.DimensionType;
|
||||||
import net.minecraft.world.server.ServerWorld;
|
import net.minecraft.world.server.ServerWorld;
|
||||||
|
import net.minecraft.network.login.ServerLoginNetHandler;
|
||||||
import org.bukkit.craftbukkit.v.CraftServer;
|
import org.bukkit.craftbukkit.v.CraftServer;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface PlayerListBridge {
|
public interface PlayerListBridge {
|
||||||
@ -20,6 +23,8 @@ public interface PlayerListBridge {
|
|||||||
|
|
||||||
CraftServer bridge$getCraftServer();
|
CraftServer bridge$getCraftServer();
|
||||||
|
|
||||||
|
ServerPlayerEntity bridge$canPlayerLogin(SocketAddress socketAddress, GameProfile gameProfile, ServerLoginNetHandler handler);
|
||||||
|
|
||||||
boolean bridge$worldNoCollision(ServerWorld world, Entity entity);
|
boolean bridge$worldNoCollision(ServerWorld world, Entity entity);
|
||||||
|
|
||||||
void bridge$setSpawnPoint(ServerPlayerEntity player, BlockPos pos, boolean flag, DimensionType type, boolean flag1);
|
void bridge$setSpawnPoint(ServerPlayerEntity player, BlockPos pos, boolean flag, DimensionType type, boolean flag1);
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
package io.izzel.arclight.common.mixin.bukkit;
|
package io.izzel.arclight.common.mixin.bukkit;
|
||||||
|
|
||||||
|
import io.izzel.arclight.common.mod.util.log.ArclightPluginLogger;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.PluginLogger;
|
import org.bukkit.plugin.PluginLogger;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
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 io.izzel.arclight.common.mod.util.ArclightPluginLogger;
|
|
||||||
|
|
||||||
@Mixin(JavaPlugin.class)
|
@Mixin(JavaPlugin.class)
|
||||||
public class JavaPluginMixin {
|
public class JavaPluginMixin {
|
||||||
|
|||||||
@ -591,9 +591,11 @@ public abstract class LivingEntityMixin extends EntityMixin implements LivingEnt
|
|||||||
|
|
||||||
@Redirect(method = "heal", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;setHealth(F)V"))
|
@Redirect(method = "heal", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;setHealth(F)V"))
|
||||||
public void arclight$healEvent(LivingEntity livingEntity, float health) {
|
public void arclight$healEvent(LivingEntity livingEntity, float health) {
|
||||||
|
EntityRegainHealthEvent.RegainReason regainReason = arclight$regainReason == null ? EntityRegainHealthEvent.RegainReason.CUSTOM : arclight$regainReason;
|
||||||
|
arclight$regainReason = null;
|
||||||
float f = this.getHealth();
|
float f = this.getHealth();
|
||||||
float amount = health - f;
|
float amount = health - f;
|
||||||
EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), amount, arclight$regainReason == null ? EntityRegainHealthEvent.RegainReason.CUSTOM : arclight$regainReason);
|
EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), amount, regainReason);
|
||||||
if (this.valid) {
|
if (this.valid) {
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,48 @@
|
|||||||
|
package io.izzel.arclight.common.mixin.core.network;
|
||||||
|
|
||||||
|
import com.mojang.authlib.properties.Property;
|
||||||
|
import io.izzel.arclight.common.bridge.network.NetworkManagerBridge;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import net.minecraft.network.NetworkManager;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Mixin(NetworkManager.class)
|
||||||
|
public class NetworkManagerMixin implements NetworkManagerBridge {
|
||||||
|
|
||||||
|
@Shadow public Channel channel;
|
||||||
|
public java.util.UUID spoofedUUID;
|
||||||
|
public com.mojang.authlib.properties.Property[] spoofedProfile;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID bridge$getSpoofedUUID() {
|
||||||
|
return spoofedUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridge$setSpoofedUUID(UUID spoofedUUID) {
|
||||||
|
this.spoofedUUID = spoofedUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Property[] bridge$getSpoofedProfile() {
|
||||||
|
return spoofedProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridge$setSpoofedProfile(Property[] spoofedProfile) {
|
||||||
|
this.spoofedProfile = spoofedProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketAddress getRawAddress() {
|
||||||
|
return this.channel.remoteAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SocketAddress bridge$getRawAddress() {
|
||||||
|
return getRawAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,124 @@
|
|||||||
|
package io.izzel.arclight.common.mixin.core.network.handshake;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.mojang.authlib.properties.Property;
|
||||||
|
import com.mojang.util.UUIDTypeAdapter;
|
||||||
|
import io.izzel.arclight.common.bridge.network.NetworkManagerBridge;
|
||||||
|
import io.izzel.arclight.common.bridge.network.login.ServerLoginNetHandlerBridge;
|
||||||
|
import net.minecraft.network.NetworkManager;
|
||||||
|
import net.minecraft.network.ProtocolType;
|
||||||
|
import net.minecraft.network.handshake.ServerHandshakeNetHandler;
|
||||||
|
import net.minecraft.network.handshake.client.CHandshakePacket;
|
||||||
|
import net.minecraft.network.login.ServerLoginNetHandler;
|
||||||
|
import net.minecraft.network.login.server.SDisconnectLoginPacket;
|
||||||
|
import net.minecraft.network.status.ServerStatusNetHandler;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.util.SharedConstants;
|
||||||
|
import net.minecraft.util.text.TranslationTextComponent;
|
||||||
|
import net.minecraftforge.fml.server.ServerLifecycleHooks;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.spigotmc.SpigotConfig;
|
||||||
|
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 java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@Mixin(ServerHandshakeNetHandler.class)
|
||||||
|
public class ServerHandshakeNetHandlerMixin {
|
||||||
|
|
||||||
|
private static final Gson gson = new Gson();
|
||||||
|
private static final HashMap<InetAddress, Long> throttleTracker = new HashMap<>();
|
||||||
|
private static int throttleCounter = 0;
|
||||||
|
|
||||||
|
@Shadow @Final private NetworkManager networkManager;
|
||||||
|
@Shadow @Final private MinecraftServer server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author IzzelAliz
|
||||||
|
* @reason
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public void processHandshake(CHandshakePacket packetIn) {
|
||||||
|
if (!ServerLifecycleHooks.handleServerLogin(packetIn, this.networkManager)) return;
|
||||||
|
switch (packetIn.getRequestedState()) {
|
||||||
|
case LOGIN: {
|
||||||
|
this.networkManager.setConnectionState(ProtocolType.LOGIN);
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
long connectionThrottle = Bukkit.getServer().getConnectionThrottle();
|
||||||
|
InetAddress address = ((InetSocketAddress) this.networkManager.getRemoteAddress()).getAddress();
|
||||||
|
synchronized (throttleTracker) {
|
||||||
|
if (throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - throttleTracker.get(address) < connectionThrottle) {
|
||||||
|
throttleTracker.put(address, currentTime);
|
||||||
|
TranslationTextComponent component = new TranslationTextComponent("Connection throttled! Please wait before reconnecting.");
|
||||||
|
this.networkManager.sendPacket(new SDisconnectLoginPacket(component));
|
||||||
|
this.networkManager.closeChannel(component);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throttleTracker.put(address, currentTime);
|
||||||
|
++throttleCounter;
|
||||||
|
if (throttleCounter > 200) {
|
||||||
|
throttleCounter = 0;
|
||||||
|
throttleTracker.entrySet().removeIf(entry -> entry.getValue() > connectionThrottle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
LogManager.getLogger().debug("Failed to check connection throttle", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (packetIn.getProtocolVersion() > SharedConstants.getVersion().getProtocolVersion()) {
|
||||||
|
TranslationTextComponent component = new TranslationTextComponent(MessageFormat.format(SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getVersion().getName()));
|
||||||
|
this.networkManager.sendPacket(new SDisconnectLoginPacket(component));
|
||||||
|
this.networkManager.closeChannel(component);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (packetIn.getProtocolVersion() < SharedConstants.getVersion().getProtocolVersion()) {
|
||||||
|
TranslationTextComponent component = new TranslationTextComponent(MessageFormat.format(SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getVersion().getName()));
|
||||||
|
this.networkManager.sendPacket(new SDisconnectLoginPacket(component));
|
||||||
|
this.networkManager.closeChannel(component);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.networkManager.setNetHandler(new ServerLoginNetHandler(this.server, this.networkManager));
|
||||||
|
|
||||||
|
|
||||||
|
if (SpigotConfig.bungee) {
|
||||||
|
String[] split = packetIn.ip.split("\00");
|
||||||
|
if (split.length == 3 || split.length == 4) {
|
||||||
|
packetIn.ip = split[0];
|
||||||
|
this.networkManager.socketAddress = new InetSocketAddress(split[1], ((InetSocketAddress) this.networkManager.getRemoteAddress()).getPort());
|
||||||
|
((NetworkManagerBridge) this.networkManager).bridge$setSpoofedUUID(UUIDTypeAdapter.fromString(split[2]));
|
||||||
|
} else {
|
||||||
|
TranslationTextComponent component = new TranslationTextComponent("If you wish to use IP forwarding, please enable it in your BungeeCord config as well!");
|
||||||
|
this.networkManager.sendPacket(new SDisconnectLoginPacket(component));
|
||||||
|
this.networkManager.closeChannel(component);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (split.length == 4) {
|
||||||
|
((NetworkManagerBridge) this.networkManager).bridge$setSpoofedProfile(gson.fromJson(split[3], Property[].class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
((ServerLoginNetHandlerBridge) this.networkManager.getNetHandler()).bridge$setHostname(packetIn.ip + ":" + packetIn.port);
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STATUS: {
|
||||||
|
this.networkManager.setConnectionState(ProtocolType.STATUS);
|
||||||
|
this.networkManager.setNetHandler(new ServerStatusNetHandler(this.server, this.networkManager));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new UnsupportedOperationException("Invalid intention " + packetIn.getRequestedState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package io.izzel.arclight.common.mixin.core.network.handshake.client;
|
||||||
|
|
||||||
|
import net.minecraft.network.PacketBuffer;
|
||||||
|
import net.minecraft.network.handshake.client.CHandshakePacket;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
@Mixin(CHandshakePacket.class)
|
||||||
|
public class CHandshakePacketMixin {
|
||||||
|
|
||||||
|
@Redirect(method = "readPacketData", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/PacketBuffer;readString(I)Ljava/lang/String;"))
|
||||||
|
private String arclight$bungeeHostname(PacketBuffer packetBuffer, int maxLength) {
|
||||||
|
return packetBuffer.readString(Short.MAX_VALUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,21 @@
|
|||||||
package io.izzel.arclight.common.mixin.core.network.login;
|
package io.izzel.arclight.common.mixin.core.network.login;
|
||||||
|
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.authlib.properties.Property;
|
||||||
|
import io.izzel.arclight.common.bridge.network.NetworkManagerBridge;
|
||||||
|
import io.izzel.arclight.common.bridge.network.login.ServerLoginNetHandlerBridge;
|
||||||
import io.izzel.arclight.common.bridge.server.MinecraftServerBridge;
|
import io.izzel.arclight.common.bridge.server.MinecraftServerBridge;
|
||||||
|
import io.izzel.arclight.common.bridge.server.management.PlayerListBridge;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
import net.minecraft.network.NetworkManager;
|
import net.minecraft.network.NetworkManager;
|
||||||
import net.minecraft.network.login.ServerLoginNetHandler;
|
import net.minecraft.network.login.ServerLoginNetHandler;
|
||||||
import net.minecraft.network.login.client.CEncryptionResponsePacket;
|
import net.minecraft.network.login.client.CEncryptionResponsePacket;
|
||||||
import net.minecraft.network.login.client.CLoginStartPacket;
|
import net.minecraft.network.login.client.CLoginStartPacket;
|
||||||
import net.minecraft.network.login.server.SDisconnectLoginPacket;
|
import net.minecraft.network.login.server.SDisconnectLoginPacket;
|
||||||
|
import net.minecraft.network.login.server.SEnableCompressionPacket;
|
||||||
import net.minecraft.network.login.server.SEncryptionRequestPacket;
|
import net.minecraft.network.login.server.SEncryptionRequestPacket;
|
||||||
|
import net.minecraft.network.login.server.SLoginSuccessPacket;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.util.CryptManager;
|
import net.minecraft.util.CryptManager;
|
||||||
import net.minecraft.util.DefaultUncaughtExceptionHandler;
|
import net.minecraft.util.DefaultUncaughtExceptionHandler;
|
||||||
@ -40,7 +47,7 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
@Mixin(ServerLoginNetHandler.class)
|
@Mixin(ServerLoginNetHandler.class)
|
||||||
public abstract class ServerLoginNetHandler1Mixin {
|
public abstract class ServerLoginNetHandlerMixin implements ServerLoginNetHandlerBridge {
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@Shadow private ServerLoginNetHandler.State currentLoginState;
|
@Shadow private ServerLoginNetHandler.State currentLoginState;
|
||||||
@ -54,8 +61,21 @@ public abstract class ServerLoginNetHandler1Mixin {
|
|||||||
@Shadow protected abstract GameProfile getOfflineProfile(GameProfile original);
|
@Shadow protected abstract GameProfile getOfflineProfile(GameProfile original);
|
||||||
@Shadow public abstract void disconnect(ITextComponent reason);
|
@Shadow public abstract void disconnect(ITextComponent reason);
|
||||||
@Shadow public abstract String getConnectionInfo();
|
@Shadow public abstract String getConnectionInfo();
|
||||||
|
@Shadow private ServerPlayerEntity player;
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
|
public String hostname;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bridge$getHostname() {
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridge$setHostname(String hostname) {
|
||||||
|
this.hostname = hostname;
|
||||||
|
}
|
||||||
|
|
||||||
public void disconnect(final String s) {
|
public void disconnect(final String s) {
|
||||||
try {
|
try {
|
||||||
final ITextComponent ichatbasecomponent = new StringTextComponent(s);
|
final ITextComponent ichatbasecomponent = new StringTextComponent(s);
|
||||||
@ -67,6 +87,40 @@ public abstract class ServerLoginNetHandler1Mixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author IzzelAliz
|
||||||
|
* @reason
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public void tryAcceptPlayer() {
|
||||||
|
/*
|
||||||
|
if (!this.loginGameProfile.isComplete()) {
|
||||||
|
this.loginGameProfile = this.getOfflineProfile(this.loginGameProfile);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
ServerPlayerEntity entity = ((PlayerListBridge) this.server.getPlayerList()).bridge$canPlayerLogin(this.networkManager.getRemoteAddress(), this.loginGameProfile, (ServerLoginNetHandler) (Object) this);
|
||||||
|
if (entity == null) {
|
||||||
|
// this.disconnect(itextcomponent);
|
||||||
|
} else {
|
||||||
|
this.currentLoginState = ServerLoginNetHandler.State.ACCEPTED;
|
||||||
|
if (this.server.getNetworkCompressionThreshold() >= 0 && !this.networkManager.isLocalChannel()) {
|
||||||
|
this.networkManager.sendPacket(new SEnableCompressionPacket(this.server.getNetworkCompressionThreshold()), (p_210149_1_) -> {
|
||||||
|
this.networkManager.setCompressionThreshold(this.server.getNetworkCompressionThreshold());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.networkManager.sendPacket(new SLoginSuccessPacket(this.loginGameProfile));
|
||||||
|
ServerPlayerEntity serverplayerentity = this.server.getPlayerList().getPlayerByUUID(this.loginGameProfile.getId());
|
||||||
|
if (serverplayerentity != null) {
|
||||||
|
this.currentLoginState = ServerLoginNetHandler.State.DELAY_ACCEPT;
|
||||||
|
this.player = entity;
|
||||||
|
} else {
|
||||||
|
this.server.getPlayerList().initializeConnectionToPlayer(this.networkManager, entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author IzzelAliz
|
* @author IzzelAliz
|
||||||
* @reason
|
* @reason
|
||||||
@ -102,8 +156,20 @@ public abstract class ServerLoginNetHandler1Mixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void initUUID() {
|
public void initUUID() {
|
||||||
UUID uuid = PlayerEntity.getOfflineUUID(this.loginGameProfile.getName());
|
UUID uuid;
|
||||||
|
if (((NetworkManagerBridge) this.networkManager).bridge$getSpoofedUUID() != null) {
|
||||||
|
uuid = ((NetworkManagerBridge) this.networkManager).bridge$getSpoofedUUID();
|
||||||
|
} else {
|
||||||
|
uuid = PlayerEntity.getOfflineUUID(this.loginGameProfile.getName());
|
||||||
|
}
|
||||||
this.loginGameProfile = new GameProfile(uuid, this.loginGameProfile.getName());
|
this.loginGameProfile = new GameProfile(uuid, this.loginGameProfile.getName());
|
||||||
|
if (((NetworkManagerBridge) this.networkManager).bridge$getSpoofedProfile() != null) {
|
||||||
|
Property[] spoofedProfile;
|
||||||
|
for (int length = (spoofedProfile = ((NetworkManagerBridge) this.networkManager).bridge$getSpoofedProfile()).length, i = 0; i < length; ++i) {
|
||||||
|
final Property property = spoofedProfile[i];
|
||||||
|
this.loginGameProfile.getProperties().put(property.getName(), property);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,7 +197,7 @@ public abstract class ServerLoginNetHandler1Mixin {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
String s = (new BigInteger(CryptManager.getServerIdHash("", server.getKeyPair().getPublic(), secretKey))).toString(16);
|
String s = (new BigInteger(CryptManager.getServerIdHash("", server.getKeyPair().getPublic(), secretKey))).toString(16);
|
||||||
loginGameProfile = server.getMinecraftSessionService().hasJoinedServer(new GameProfile((UUID) null, gameprofile.getName()), s, this.getAddress());
|
loginGameProfile = server.getMinecraftSessionService().hasJoinedServer(new GameProfile(null, gameprofile.getName()), s, this.getAddress());
|
||||||
if (loginGameProfile != null) {
|
if (loginGameProfile != null) {
|
||||||
if (!networkManager.isChannelOpen()) {
|
if (!networkManager.isChannelOpen()) {
|
||||||
return;
|
return;
|
||||||
@ -143,7 +209,7 @@ public abstract class ServerLoginNetHandler1Mixin {
|
|||||||
currentLoginState = ServerLoginNetHandler.State.NEGOTIATING;
|
currentLoginState = ServerLoginNetHandler.State.NEGOTIATING;
|
||||||
} else {
|
} else {
|
||||||
disconnect(new TranslationTextComponent("multiplayer.disconnect.unverified_username"));
|
disconnect(new TranslationTextComponent("multiplayer.disconnect.unverified_username"));
|
||||||
LOGGER.error("Username '{}' tried to join with an invalid session", (Object) gameprofile.getName());
|
LOGGER.error("Username '{}' tried to join with an invalid session", gameprofile.getName());
|
||||||
}
|
}
|
||||||
} catch (Exception var3) {
|
} catch (Exception var3) {
|
||||||
if (server.isSinglePlayer()) {
|
if (server.isSinglePlayer()) {
|
||||||
@ -5,21 +5,20 @@ import com.mojang.authlib.GameProfile;
|
|||||||
import io.izzel.arclight.api.ArclightVersion;
|
import io.izzel.arclight.api.ArclightVersion;
|
||||||
import io.izzel.arclight.common.bridge.entity.player.PlayerEntityBridge;
|
import io.izzel.arclight.common.bridge.entity.player.PlayerEntityBridge;
|
||||||
import io.izzel.arclight.common.bridge.entity.player.ServerPlayerEntityBridge;
|
import io.izzel.arclight.common.bridge.entity.player.ServerPlayerEntityBridge;
|
||||||
import io.izzel.arclight.common.bridge.network.play.ServerPlayNetHandlerBridge;
|
|
||||||
import io.izzel.arclight.common.bridge.server.MinecraftServerBridge;
|
import io.izzel.arclight.common.bridge.server.MinecraftServerBridge;
|
||||||
import io.izzel.arclight.common.bridge.server.management.PlayerListBridge;
|
import io.izzel.arclight.common.bridge.server.management.PlayerListBridge;
|
||||||
import io.izzel.arclight.common.bridge.world.WorldBridge;
|
import io.izzel.arclight.common.bridge.world.WorldBridge;
|
||||||
import io.izzel.arclight.common.bridge.world.dimension.DimensionTypeBridge;
|
|
||||||
import io.izzel.arclight.common.mod.ArclightMod;
|
|
||||||
import io.izzel.arclight.common.mod.server.BukkitRegistry;
|
import io.izzel.arclight.common.mod.server.BukkitRegistry;
|
||||||
import io.izzel.arclight.common.mod.util.ArclightCaptures;
|
import io.izzel.arclight.common.mod.util.ArclightCaptures;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
import net.minecraft.network.IPacket;
|
import net.minecraft.network.IPacket;
|
||||||
import net.minecraft.network.NetworkManager;
|
import net.minecraft.network.NetworkManager;
|
||||||
|
import net.minecraft.network.login.ServerLoginNetHandler;
|
||||||
import net.minecraft.network.play.server.SChangeGameStatePacket;
|
import net.minecraft.network.play.server.SChangeGameStatePacket;
|
||||||
import net.minecraft.network.play.server.SChatPacket;
|
import net.minecraft.network.play.server.SChatPacket;
|
||||||
import net.minecraft.network.play.server.SEntityStatusPacket;
|
import net.minecraft.network.play.server.SEntityStatusPacket;
|
||||||
|
import net.minecraft.network.play.server.SRespawnPacket;
|
||||||
import net.minecraft.network.play.server.SServerDifficultyPacket;
|
import net.minecraft.network.play.server.SServerDifficultyPacket;
|
||||||
import net.minecraft.network.play.server.SSetExperiencePacket;
|
import net.minecraft.network.play.server.SSetExperiencePacket;
|
||||||
import net.minecraft.network.play.server.SSpawnPositionPacket;
|
import net.minecraft.network.play.server.SSpawnPositionPacket;
|
||||||
@ -60,6 +59,7 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
|||||||
import org.bukkit.event.player.PlayerLoginEvent;
|
import org.bukkit.event.player.PlayerLoginEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||||
|
import org.spigotmc.SpigotConfig;
|
||||||
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;
|
||||||
@ -70,9 +70,12 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
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.izzel.arclight.common.mod.ArclightMod;
|
||||||
|
import io.izzel.arclight.common.mod.util.ArclightCaptures;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@ -128,10 +131,10 @@ public abstract class PlayerListMixin implements PlayerListBridge {
|
|||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ArclightMod.LOGGER.info("Registering for bukkit... ");
|
ArclightMod.LOGGER.info("registry.begin");
|
||||||
BukkitRegistry.registerAll();
|
BukkitRegistry.registerAll();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
ArclightMod.LOGGER.error("Error handling Forge registries ", t);
|
ArclightMod.LOGGER.error("registry.error", t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,16 +157,11 @@ public abstract class PlayerListMixin implements PlayerListBridge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @author IzzelAliz
|
public ServerPlayerEntity bridge$canPlayerLogin(SocketAddress socketAddress, GameProfile gameProfile, ServerLoginNetHandler handler) {
|
||||||
* @reason
|
UUID uuid = PlayerEntity.getUUID(gameProfile);
|
||||||
*/
|
List<ServerPlayerEntity> list = Lists.newArrayList();
|
||||||
@Overwrite
|
for (ServerPlayerEntity entityplayer : this.players) {
|
||||||
@Nullable
|
|
||||||
public ITextComponent canPlayerLogin(SocketAddress socketAddress, GameProfile gameProfile) {
|
|
||||||
final UUID uuid = PlayerEntity.getUUID(gameProfile);
|
|
||||||
final List<ServerPlayerEntity> list = Lists.newArrayList();
|
|
||||||
for (final ServerPlayerEntity entityplayer : this.players) {
|
|
||||||
if (entityplayer.getUniqueID().equals(uuid)) {
|
if (entityplayer.getUniqueID().equals(uuid)) {
|
||||||
list.add(entityplayer);
|
list.add(entityplayer);
|
||||||
}
|
}
|
||||||
@ -172,36 +170,40 @@ public abstract class PlayerListMixin implements PlayerListBridge {
|
|||||||
this.writePlayerData(entityplayer);
|
this.writePlayerData(entityplayer);
|
||||||
entityplayer.connection.disconnect(new TranslationTextComponent("multiplayer.disconnect.duplicate_login"));
|
entityplayer.connection.disconnect(new TranslationTextComponent("multiplayer.disconnect.duplicate_login"));
|
||||||
}
|
}
|
||||||
final ServerPlayerEntity entity = new ServerPlayerEntity(this.server, this.server.getWorld(DimensionType.OVERWORLD), gameProfile, new PlayerInteractionManager(this.server.getWorld(DimensionType.OVERWORLD)));
|
ServerPlayerEntity entity = new ServerPlayerEntity(this.server, this.server.getWorld(DimensionType.OVERWORLD), gameProfile, new PlayerInteractionManager(this.server.getWorld(DimensionType.OVERWORLD)));
|
||||||
final Player player = ((ServerPlayerEntityBridge) entity).bridge$getBukkitEntity();
|
Player player = ((ServerPlayerEntityBridge) entity).bridge$getBukkitEntity();
|
||||||
// todo hostname
|
|
||||||
final PlayerLoginEvent event = new PlayerLoginEvent(player, "", ((InetSocketAddress) socketAddress).getAddress());
|
String hostname = handler == null ? "" : ((ServerLoginNetHandlerBridge) handler).bridge$getHostname();
|
||||||
|
InetAddress realAddress = handler == null ? ((InetSocketAddress) socketAddress).getAddress() : ((InetSocketAddress) ((NetworkManagerBridge) handler.networkManager).bridge$getRawAddress()).getAddress();
|
||||||
|
|
||||||
|
PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((InetSocketAddress) socketAddress).getAddress(), realAddress);
|
||||||
if (this.getBannedPlayers().isBanned(gameProfile) && !this.getBannedPlayers().getEntry(gameProfile).hasBanExpired()) {
|
if (this.getBannedPlayers().isBanned(gameProfile) && !this.getBannedPlayers().getEntry(gameProfile).hasBanExpired()) {
|
||||||
final ProfileBanEntry gameprofilebanentry = this.bannedPlayers.getEntry(gameProfile);
|
ProfileBanEntry gameprofilebanentry = this.bannedPlayers.getEntry(gameProfile);
|
||||||
final TranslationTextComponent chatmessage = new TranslationTextComponent("multiplayer.disconnect.banned.reason", gameprofilebanentry.getBanReason());
|
TranslationTextComponent chatmessage = new TranslationTextComponent("multiplayer.disconnect.banned.reason", gameprofilebanentry.getBanReason());
|
||||||
if (gameprofilebanentry.getBanEndDate() != null) {
|
if (gameprofilebanentry.getBanEndDate() != null) {
|
||||||
chatmessage.appendSibling(new TranslationTextComponent("multiplayer.disconnect.banned.expiration", DATE_FORMAT.format(gameprofilebanentry.getBanEndDate())));
|
chatmessage.appendSibling(new TranslationTextComponent("multiplayer.disconnect.banned.expiration", DATE_FORMAT.format(gameprofilebanentry.getBanEndDate())));
|
||||||
}
|
}
|
||||||
event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CraftChatMessage.fromComponent(chatmessage));
|
event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CraftChatMessage.fromComponent(chatmessage));
|
||||||
} else if (!this.canJoin(gameProfile)) {
|
} else if (!this.canJoin(gameProfile)) {
|
||||||
final TranslationTextComponent chatmessage = new TranslationTextComponent("multiplayer.disconnect.not_whitelisted");
|
event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, SpigotConfig.whitelistMessage);
|
||||||
event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, CraftChatMessage.fromComponent(chatmessage));
|
|
||||||
} else if (this.getBannedIPs().isBanned(socketAddress) && !this.getBannedIPs().getBanEntry(socketAddress).hasBanExpired()) {
|
} else if (this.getBannedIPs().isBanned(socketAddress) && !this.getBannedIPs().getBanEntry(socketAddress).hasBanExpired()) {
|
||||||
final IPBanEntry ipbanentry = this.bannedIPs.getBanEntry(socketAddress);
|
IPBanEntry ipbanentry = this.bannedIPs.getBanEntry(socketAddress);
|
||||||
final TranslationTextComponent chatmessage = new TranslationTextComponent("multiplayer.disconnect.banned_ip.reason", ipbanentry.getBanReason());
|
TranslationTextComponent chatmessage = new TranslationTextComponent("multiplayer.disconnect.banned_ip.reason", ipbanentry.getBanReason());
|
||||||
if (ipbanentry.getBanEndDate() != null) {
|
if (ipbanentry.getBanEndDate() != null) {
|
||||||
chatmessage.appendSibling(new TranslationTextComponent("multiplayer.disconnect.banned_ip.expiration", DATE_FORMAT.format(ipbanentry.getBanEndDate())));
|
chatmessage.appendSibling(new TranslationTextComponent("multiplayer.disconnect.banned_ip.expiration", DATE_FORMAT.format(ipbanentry.getBanEndDate())));
|
||||||
}
|
}
|
||||||
event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CraftChatMessage.fromComponent(chatmessage));
|
event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CraftChatMessage.fromComponent(chatmessage));
|
||||||
} else if (this.players.size() >= this.maxPlayers && !this.bypassesPlayerLimit(gameProfile)) {
|
} else if (this.players.size() >= this.maxPlayers && !this.bypassesPlayerLimit(gameProfile)) {
|
||||||
event.disallow(PlayerLoginEvent.Result.KICK_FULL, "The server is full");
|
event.disallow(PlayerLoginEvent.Result.KICK_FULL, SpigotConfig.serverFullMessage);
|
||||||
}
|
}
|
||||||
this.cserver.getPluginManager().callEvent(event);
|
this.cserver.getPluginManager().callEvent(event);
|
||||||
if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
|
if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
|
||||||
return CraftChatMessage.fromStringOrNull(event.getKickMessage());
|
if (handler != null) {
|
||||||
} else {
|
handler.disconnect(CraftChatMessage.fromStringOrNull(event.getKickMessage()));
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServerPlayerEntity moveToWorld(ServerPlayerEntity playerIn, DimensionType dimension, boolean conqueredEnd, Location location, boolean avoidSuffocation) {
|
public ServerPlayerEntity moveToWorld(ServerPlayerEntity playerIn, DimensionType dimension, boolean conqueredEnd, Location location, boolean avoidSuffocation) {
|
||||||
@ -401,7 +403,7 @@ public abstract class PlayerListMixin implements PlayerListBridge {
|
|||||||
@Inject(method = "playerLoggedOut", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/management/PlayerList;writePlayerData(Lnet/minecraft/entity/player/ServerPlayerEntity;)V"))
|
@Inject(method = "playerLoggedOut", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/management/PlayerList;writePlayerData(Lnet/minecraft/entity/player/ServerPlayerEntity;)V"))
|
||||||
public void arclight$playerQuitPre(ServerPlayerEntity playerIn, CallbackInfo ci) {
|
public void arclight$playerQuitPre(ServerPlayerEntity playerIn, CallbackInfo ci) {
|
||||||
CraftEventFactory.handleInventoryCloseEvent(playerIn);
|
CraftEventFactory.handleInventoryCloseEvent(playerIn);
|
||||||
PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(cserver.getPlayer(playerIn), "\u00A7e" + playerIn.getName() + " left the game");
|
PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(cserver.getPlayer(playerIn), "\u00A7e" + playerIn.getName().getFormattedText() + " left the game");
|
||||||
cserver.getPluginManager().callEvent(playerQuitEvent);
|
cserver.getPluginManager().callEvent(playerQuitEvent);
|
||||||
((ServerPlayerEntityBridge) playerIn).bridge$getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
|
((ServerPlayerEntityBridge) playerIn).bridge$getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
|
||||||
playerIn.playerTick();
|
playerIn.playerTick();
|
||||||
|
|||||||
@ -1,41 +0,0 @@
|
|||||||
package io.izzel.arclight.common.mod;
|
|
||||||
|
|
||||||
import org.yaml.snakeyaml.Yaml;
|
|
||||||
import org.yaml.snakeyaml.constructor.Constructor;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
public class ArclightConfig {
|
|
||||||
|
|
||||||
public static ArclightConfig INSTANCE;
|
|
||||||
|
|
||||||
public Optimization optimizations;
|
|
||||||
|
|
||||||
static void init(Path path) {
|
|
||||||
ArclightConnector.LOGGER.info("Loading configurations from {}", path);
|
|
||||||
try {
|
|
||||||
if (!Files.exists(path)) {
|
|
||||||
InputStream stream = ArclightConfig.class.getResourceAsStream("/arclight.yml");
|
|
||||||
Files.copy(stream, path);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
ArclightConnector.LOGGER.error("Failed to save default configurations", e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Yaml yaml = new Yaml(new Constructor(ArclightConfig.class));
|
|
||||||
Object load = yaml.load(Files.newInputStream(path));
|
|
||||||
INSTANCE = (ArclightConfig) load;
|
|
||||||
} catch (IOException e) {
|
|
||||||
ArclightConnector.LOGGER.error("Failed to load configurations", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Optimization {
|
|
||||||
|
|
||||||
public boolean removeStreams = true;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,18 +2,19 @@ package io.izzel.arclight.common.mod;
|
|||||||
|
|
||||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||||
import io.izzel.arclight.api.ArclightVersion;
|
import io.izzel.arclight.api.ArclightVersion;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||||
|
import io.izzel.arclight.common.mod.util.log.ArclightI18nLogger;
|
||||||
|
import io.izzel.arclight.i18n.ArclightConfig;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.spongepowered.asm.mixin.Mixins;
|
import org.spongepowered.asm.mixin.Mixins;
|
||||||
import org.spongepowered.asm.mixin.connect.IMixinConnector;
|
import org.spongepowered.asm.mixin.connect.IMixinConnector;
|
||||||
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ArclightConnector implements IMixinConnector {
|
public class ArclightConnector implements IMixinConnector {
|
||||||
|
|
||||||
public static final Logger LOGGER = LogManager.getLogger("Arclight");
|
public static final Logger LOGGER = ArclightI18nLogger.getLogger("Arclight");
|
||||||
private static final List<String> FILTER_PACKAGE = Arrays.asList("com.google.common", "com.google.gson", "ninja.leaping.configurate", "io.izzel.arclight.api");
|
private static final List<String> FILTER_PACKAGE = Arrays.asList("com.google.common", "com.google.gson", "ninja.leaping.configurate", "io.izzel.arclight.api");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -27,7 +28,6 @@ public class ArclightConnector implements IMixinConnector {
|
|||||||
if (ArclightVersion.atLeast(ArclightVersion.v1_15)) {
|
if (ArclightVersion.atLeast(ArclightVersion.v1_15)) {
|
||||||
Mixins.addConfiguration("mixins.arclight.core.1_15.json");
|
Mixins.addConfiguration("mixins.arclight.core.1_15.json");
|
||||||
}
|
}
|
||||||
LOGGER.info("Arclight core mixin added.");
|
LOGGER.info("mixin-load.core");
|
||||||
ArclightConfig.init(Paths.get("arclight.yml"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,6 @@ import com.google.common.collect.ImmutableList;
|
|||||||
import net.minecraftforge.fml.loading.moddiscovery.AbstractJarFileLocator;
|
import net.minecraftforge.fml.loading.moddiscovery.AbstractJarFileLocator;
|
||||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||||
import net.minecraftforge.forgespi.locating.IModFile;
|
import net.minecraftforge.forgespi.locating.IModFile;
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
@ -14,8 +12,6 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class ArclightLocator extends AbstractJarFileLocator {
|
public class ArclightLocator extends AbstractJarFileLocator {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger("Arclight");
|
|
||||||
|
|
||||||
private final IModFile arclight;
|
private final IModFile arclight;
|
||||||
|
|
||||||
public ArclightLocator() {
|
public ArclightLocator() {
|
||||||
@ -39,6 +35,5 @@ public class ArclightLocator extends AbstractJarFileLocator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initArguments(Map<String, ?> arguments) {
|
public void initArguments(Map<String, ?> arguments) {
|
||||||
LOGGER.info("Arclight locator loaded.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,23 @@
|
|||||||
package io.izzel.arclight.common.mod;
|
package io.izzel.arclight.common.mod;
|
||||||
|
|
||||||
import io.izzel.arclight.common.mod.server.event.ArclightEventDispatcherRegistry;
|
import io.izzel.arclight.common.mod.server.event.ArclightEventDispatcherRegistry;
|
||||||
|
import io.izzel.arclight.common.mod.util.log.ArclightI18nLogger;
|
||||||
import net.minecraftforge.fml.CrashReportExtender;
|
import net.minecraftforge.fml.CrashReportExtender;
|
||||||
import net.minecraftforge.fml.ExtensionPoint;
|
import net.minecraftforge.fml.ExtensionPoint;
|
||||||
import net.minecraftforge.fml.ModLoadingContext;
|
import net.minecraftforge.fml.ModLoadingContext;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.network.FMLNetworkConstants;
|
import net.minecraftforge.fml.network.FMLNetworkConstants;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.bukkit.craftbukkit.v.CraftCrashReport;
|
import org.bukkit.craftbukkit.v.CraftCrashReport;
|
||||||
|
|
||||||
@Mod("arclight")
|
@Mod("arclight")
|
||||||
public class ArclightMod {
|
public class ArclightMod {
|
||||||
|
|
||||||
public static final Logger LOGGER = LogManager.getLogger("Arclight");
|
public static final Logger LOGGER = ArclightI18nLogger.getLogger("Arclight");
|
||||||
|
|
||||||
public ArclightMod() {
|
public ArclightMod() {
|
||||||
LOGGER.info("Arclight Mod loaded.");
|
LOGGER.info("mod-load");
|
||||||
ArclightEventDispatcherRegistry.registerAllEventDispatchers();
|
ArclightEventDispatcherRegistry.registerAllEventDispatchers();
|
||||||
CrashReportExtender.registerCrashCallable("Arclight", () -> new CraftCrashReport().call().toString());
|
CrashReportExtender.registerCrashCallable("Arclight", () -> new CraftCrashReport().call().toString());
|
||||||
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true));
|
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true));
|
||||||
|
|||||||
@ -2,6 +2,11 @@ package io.izzel.arclight.common.mod.server;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import io.izzel.arclight.api.EnumHelper;
|
||||||
|
import io.izzel.arclight.api.Unsafe;
|
||||||
|
import io.izzel.arclight.common.bridge.bukkit.MaterialBridge;
|
||||||
|
import io.izzel.arclight.common.mod.ArclightMod;
|
||||||
|
import io.izzel.arclight.common.mod.util.potion.ArclightPotionEffect;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.potion.Effect;
|
import net.minecraft.potion.Effect;
|
||||||
@ -15,11 +20,6 @@ import org.bukkit.craftbukkit.v.util.CraftMagicNumbers;
|
|||||||
import org.bukkit.craftbukkit.v.util.CraftNamespacedKey;
|
import org.bukkit.craftbukkit.v.util.CraftNamespacedKey;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.potion.PotionEffectType;
|
import org.bukkit.potion.PotionEffectType;
|
||||||
import io.izzel.arclight.common.bridge.bukkit.MaterialBridge;
|
|
||||||
import io.izzel.arclight.common.mod.ArclightMod;
|
|
||||||
import io.izzel.arclight.common.mod.util.potion.ArclightPotionEffect;
|
|
||||||
import io.izzel.arclight.api.EnumHelper;
|
|
||||||
import io.izzel.arclight.api.Unsafe;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -31,12 +31,12 @@ import java.util.Set;
|
|||||||
@SuppressWarnings({"unchecked", "ConstantConditions"})
|
@SuppressWarnings({"unchecked", "ConstantConditions"})
|
||||||
public class BukkitRegistry {
|
public class BukkitRegistry {
|
||||||
|
|
||||||
private static List<Class<?>> MAT_CTOR = ImmutableList.of(int.class, int.class, int.class);
|
private static final List<Class<?>> MAT_CTOR = ImmutableList.of(int.class, int.class, int.class);
|
||||||
private static Map<String, Material> BY_NAME = getStatic(Material.class, "BY_NAME");
|
private static final Map<String, Material> BY_NAME = getStatic(Material.class, "BY_NAME");
|
||||||
private static Map<Block, Material> BLOCK_MATERIAL = getStatic(CraftMagicNumbers.class, "BLOCK_MATERIAL");
|
private static final Map<Block, Material> BLOCK_MATERIAL = getStatic(CraftMagicNumbers.class, "BLOCK_MATERIAL");
|
||||||
private static Map<Item, Material> ITEM_MATERIAL = getStatic(CraftMagicNumbers.class, "ITEM_MATERIAL");
|
private static final Map<Item, Material> ITEM_MATERIAL = getStatic(CraftMagicNumbers.class, "ITEM_MATERIAL");
|
||||||
private static Map<Material, Item> MATERIAL_ITEM = getStatic(CraftMagicNumbers.class, "MATERIAL_ITEM");
|
private static final Map<Material, Item> MATERIAL_ITEM = getStatic(CraftMagicNumbers.class, "MATERIAL_ITEM");
|
||||||
private static Map<Material, Block> MATERIAL_BLOCK = getStatic(CraftMagicNumbers.class, "MATERIAL_BLOCK");
|
private static final Map<Material, Block> MATERIAL_BLOCK = getStatic(CraftMagicNumbers.class, "MATERIAL_BLOCK");
|
||||||
|
|
||||||
public static void registerAll() {
|
public static void registerAll() {
|
||||||
loadMaterials();
|
loadMaterials();
|
||||||
@ -52,7 +52,7 @@ public class BukkitRegistry {
|
|||||||
Enchantment.registerEnchantment(new CraftEnchantment(entry.getValue()));
|
Enchantment.registerEnchantment(new CraftEnchantment(entry.getValue()));
|
||||||
}
|
}
|
||||||
Enchantment.stopAcceptingRegistrations();
|
Enchantment.stopAcceptingRegistrations();
|
||||||
ArclightMod.LOGGER.info("Registered {} new enchantments", size - origin);
|
ArclightMod.LOGGER.info("registry.enchantment", size - origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadPotions() {
|
private static void loadPotions() {
|
||||||
@ -68,7 +68,7 @@ public class BukkitRegistry {
|
|||||||
ArclightMod.LOGGER.debug("Registered {}: {} as potion", entry.getKey(), effect);
|
ArclightMod.LOGGER.debug("Registered {}: {} as potion", entry.getKey(), effect);
|
||||||
}
|
}
|
||||||
PotionEffectType.stopAcceptingRegistrations();
|
PotionEffectType.stopAcceptingRegistrations();
|
||||||
ArclightMod.LOGGER.info("Registered {} new potion effect types", size - origin);
|
ArclightMod.LOGGER.info("registry.potion", size - origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadMaterials() {
|
private static void loadMaterials() {
|
||||||
@ -122,7 +122,7 @@ public class BukkitRegistry {
|
|||||||
ITEM_MATERIAL.put(item, material);
|
ITEM_MATERIAL.put(item, material);
|
||||||
MATERIAL_ITEM.put(material, item);
|
MATERIAL_ITEM.put(material, item);
|
||||||
}
|
}
|
||||||
ArclightMod.LOGGER.info("Registered {} new materials, with {} blocks and {} items", i - origin, blocks, items);
|
ArclightMod.LOGGER.info("registry.material", i - origin, blocks, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String toName(ResourceLocation location) {
|
private static String toName(ResourceLocation location) {
|
||||||
|
|||||||
@ -1,20 +1,20 @@
|
|||||||
package io.izzel.arclight.common.mod.server.event;
|
package io.izzel.arclight.common.mod.server.event;
|
||||||
|
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
|
||||||
import io.izzel.arclight.common.mod.ArclightMod;
|
import io.izzel.arclight.common.mod.ArclightMod;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
|
||||||
public abstract class ArclightEventDispatcherRegistry {
|
public abstract class ArclightEventDispatcherRegistry {
|
||||||
|
|
||||||
public static void registerAllEventDispatchers() {
|
public static void registerAllEventDispatchers() {
|
||||||
ArclightMod.LOGGER.info("Arclight register all event dispatchers.");
|
|
||||||
MinecraftForge.EVENT_BUS.register(new BlockBreakEventDispatcher());
|
MinecraftForge.EVENT_BUS.register(new BlockBreakEventDispatcher());
|
||||||
MinecraftForge.EVENT_BUS.register(new BlockPlaceEventDispatcher());
|
MinecraftForge.EVENT_BUS.register(new BlockPlaceEventDispatcher());
|
||||||
MinecraftForge.EVENT_BUS.register(new EntityPotionEffectEventDispatcher());
|
MinecraftForge.EVENT_BUS.register(new EntityPotionEffectEventDispatcher());
|
||||||
MinecraftForge.EVENT_BUS.register(new EntityRegainHealthEventDispatcher());
|
MinecraftForge.EVENT_BUS.register(new WorldEventDispatcher());
|
||||||
MinecraftForge.EVENT_BUS.register(new EntityEventDispatcher());
|
MinecraftForge.EVENT_BUS.register(new EntityEventDispatcher());
|
||||||
MinecraftForge.EVENT_BUS.register(new NetworkEventDispatcher());
|
MinecraftForge.EVENT_BUS.register(new NetworkEventDispatcher());
|
||||||
MinecraftForge.EVENT_BUS.register(new EntityTeleportEventDispatcher());
|
MinecraftForge.EVENT_BUS.register(new EntityTeleportEventDispatcher());
|
||||||
MinecraftForge.EVENT_BUS.register(new ItemEntityEventDispatcher());
|
MinecraftForge.EVENT_BUS.register(new ItemEntityEventDispatcher());
|
||||||
|
ArclightMod.LOGGER.info("registry.forge-event");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
package io.izzel.arclight.common.mod.server.event;
|
|
||||||
|
|
||||||
import io.izzel.arclight.common.bridge.entity.EntityBridge;
|
|
||||||
import io.izzel.arclight.common.bridge.world.WorldBridge;
|
|
||||||
import net.minecraftforge.event.entity.living.LivingHealEvent;
|
|
||||||
import net.minecraftforge.event.world.WorldEvent;
|
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.event.entity.EntityRegainHealthEvent;
|
|
||||||
import org.bukkit.event.world.WorldLoadEvent;
|
|
||||||
|
|
||||||
public class EntityRegainHealthEventDispatcher {
|
|
||||||
|
|
||||||
@SubscribeEvent(receiveCanceled = true)
|
|
||||||
public void onLivingHeal(LivingHealEvent event) {
|
|
||||||
EntityRegainHealthEvent bukkitEvent = ArclightEventFactory.callEntityRegainHealthEvent(((EntityBridge) event.getEntity()).bridge$getBukkitEntity(),
|
|
||||||
event.getAmount(), EntityRegainHealthEvent.RegainReason.CUSTOM);
|
|
||||||
event.setAmount((float) bukkitEvent.getAmount());
|
|
||||||
if (bukkitEvent.isCancelled()) {
|
|
||||||
event.setCanceled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void onWorldLoad(WorldEvent.Load event) {
|
|
||||||
Bukkit.getPluginManager().callEvent(new WorldLoadEvent(((WorldBridge) event.getWorld()).bridge$getWorld()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package io.izzel.arclight.common.mod.server.event;
|
||||||
|
|
||||||
|
import io.izzel.arclight.common.bridge.world.WorldBridge;
|
||||||
|
import net.minecraftforge.event.world.WorldEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.event.world.WorldLoadEvent;
|
||||||
|
|
||||||
|
public class WorldEventDispatcher {
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onWorldLoad(WorldEvent.Load event) {
|
||||||
|
Bukkit.getPluginManager().callEvent(new WorldLoadEvent(((WorldBridge) event.getWorld()).bridge$getWorld()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
package io.izzel.arclight.common.mod.util.log;
|
||||||
|
|
||||||
|
import io.izzel.arclight.i18n.ArclightLocale;
|
||||||
|
import org.apache.logging.log4j.Level;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.apache.logging.log4j.Marker;
|
||||||
|
import org.apache.logging.log4j.spi.ExtendedLogger;
|
||||||
|
import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;
|
||||||
|
import org.apache.logging.log4j.util.MessageSupplier;
|
||||||
|
import org.apache.logging.log4j.util.Supplier;
|
||||||
|
|
||||||
|
public class ArclightI18nLogger extends ExtendedLoggerWrapper {
|
||||||
|
|
||||||
|
public ArclightI18nLogger(ExtendedLogger logger) {
|
||||||
|
super(logger, logger.getName(), logger.getMessageFactory());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Logger getLogger(String name) {
|
||||||
|
return new ArclightI18nLogger((ExtendedLogger) LogManager.getLogger(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, CharSequence message, Throwable t) {
|
||||||
|
this.info("", "");
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message.toString()), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, Object message, Throwable t) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message.toString()), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, MessageSupplier msgSupplier, Throwable t) {
|
||||||
|
super.logMessage(fqcn, level, marker, msgSupplier, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, Supplier<?> msgSupplier, Throwable t) {
|
||||||
|
super.logMessage(fqcn, level, marker, msgSupplier, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Throwable t) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object... params) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4, p5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4, p5, p6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4, p5, p6, p7);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4, p5, p6, p7, p8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8, Object p9) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logMessage(String fqcn, Level level, Marker marker, String message, Supplier<?>... paramSuppliers) {
|
||||||
|
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), paramSuppliers);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package io.izzel.arclight.common.mod.util.log;
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.logging.LogManager;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class ArclightLazyLogManager extends LogManager {
|
||||||
|
|
||||||
|
private volatile LogManager delegate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addLogger(Logger logger) {
|
||||||
|
tryGet();
|
||||||
|
if (delegate != null) return delegate.addLogger(logger);
|
||||||
|
return super.addLogger(logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Logger getLogger(String name) {
|
||||||
|
tryGet();
|
||||||
|
if (delegate != null) return delegate.getLogger(name);
|
||||||
|
return super.getLogger(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<String> getLoggerNames() {
|
||||||
|
tryGet();
|
||||||
|
if (delegate != null) return delegate.getLoggerNames();
|
||||||
|
return super.getLoggerNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryGet() {
|
||||||
|
if (delegate != null) return;
|
||||||
|
try {
|
||||||
|
Class<?> name = Class.forName("org.apache.logging.log4j.jul.LogManager");
|
||||||
|
delegate = (LogManager) name.newInstance();
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package io.izzel.arclight.common.mod.util;
|
package io.izzel.arclight.common.mod.util.log;
|
||||||
|
|
||||||
import org.apache.logging.log4j.jul.ApiLogger;
|
import org.apache.logging.log4j.jul.ApiLogger;
|
||||||
import org.apache.logging.log4j.jul.CoreLoggerAdapter;
|
import org.apache.logging.log4j.jul.CoreLoggerAdapter;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package io.izzel.arclight.common.mod.util;
|
package io.izzel.arclight.common.mod.util.log;
|
||||||
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.PluginLogger;
|
import org.bukkit.plugin.PluginLogger;
|
||||||
@ -18,6 +18,7 @@ public net.minecraft.util.math.shapes.DoubleCubeMergingList <init>(II)V
|
|||||||
public net.minecraft.block.ComposterBlock$EmptyInventory
|
public net.minecraft.block.ComposterBlock$EmptyInventory
|
||||||
public net.minecraft.tileentity.SkullTileEntity field_184299_k #sessionService
|
public net.minecraft.tileentity.SkullTileEntity field_184299_k #sessionService
|
||||||
public net.minecraft.item.crafting.Ingredient <init>(Ljava/util/stream/Stream;)V
|
public net.minecraft.item.crafting.Ingredient <init>(Ljava/util/stream/Stream;)V
|
||||||
|
public net.minecraft.world.server.TicketManager field_219377_e #tickets
|
||||||
# Arclight 1.15
|
# Arclight 1.15
|
||||||
public net.minecraft.entity.Entity field_70165_t #posX
|
public net.minecraft.entity.Entity field_70165_t #posX
|
||||||
public net.minecraft.entity.Entity field_70163_u #posY
|
public net.minecraft.entity.Entity field_70163_u #posY
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
############################################################################
|
|
||||||
# Arclight configurations
|
|
||||||
#
|
|
||||||
# Repository https://github.com/IzzelAliz/Arclight
|
|
||||||
# Issue Tracker https://github.com/IzzelAliz/Arclight/issues
|
|
||||||
#
|
|
||||||
############################################################################
|
|
||||||
|
|
||||||
optimizations:
|
|
||||||
# The stream allocates useless garbage and hurts a lot of performance
|
|
||||||
# Arclight optimizes this by removing them
|
|
||||||
removeStreams: true
|
|
||||||
@ -21,10 +21,13 @@
|
|||||||
<TerminalConsole name="Console">
|
<TerminalConsole name="Console">
|
||||||
<PatternLayout>
|
<PatternLayout>
|
||||||
<!-- use white for info output -->
|
<!-- use white for info output -->
|
||||||
<LoggerNamePatternSelector noConsoleNoAnsi="true" defaultPattern="%highlight{[%d{HH:mm:ss}] [%t/%level] [%c{1.}/%markerSimpleName]: %minecraftFormatting{%msg}%n%tEx}{INFO=normal}">
|
<LoggerNamePatternSelector
|
||||||
|
defaultPattern="%highlight{[%d{HH:mm:ss}] [%t/%level] [%c{1.}/%markerSimpleName]: %minecraftFormatting{%msg}%n%tEx}{INFO=normal}">
|
||||||
<!-- don't include the full logger name for Mojang's logs since they use full class names and it's very verbose -->
|
<!-- don't include the full logger name for Mojang's logs since they use full class names and it's very verbose -->
|
||||||
<PatternMatch key="net.minecraft." pattern="%highlight{[%d{HH:mm:ss}] [%t/%level] [minecraft/%logger{1}]: %minecraftFormatting{%msg}%n%tEx}{INFO=normal}"/>
|
<PatternMatch key="net.minecraft."
|
||||||
<PatternMatch key="com.mojang." pattern="%highlight{[%d{HH:mm:ss}] [%t/%level] [mojang/%logger{1}]: %minecraftFormatting{%msg}%n%tEx}{INFO=normal}"/>
|
pattern="%highlight{[%d{HH:mm:ss}] [%t/%level] [minecraft/%logger{1}]: %minecraftFormatting{%msg}%n%tEx}{INFO=normal}"/>
|
||||||
|
<PatternMatch key="com.mojang."
|
||||||
|
pattern="%highlight{[%d{HH:mm:ss}] [%t/%level] [mojang/%logger{1}]: %minecraftFormatting{%msg}%n%tEx}{INFO=normal}"/>
|
||||||
</LoggerNamePatternSelector>
|
</LoggerNamePatternSelector>
|
||||||
</PatternLayout>
|
</PatternLayout>
|
||||||
</TerminalConsole>
|
</TerminalConsole>
|
||||||
|
|||||||
@ -284,9 +284,12 @@
|
|||||||
"item.crafting.StonecuttingRecipeMixin",
|
"item.crafting.StonecuttingRecipeMixin",
|
||||||
"item.crafting.SuspiciousStewRecipeMixin",
|
"item.crafting.SuspiciousStewRecipeMixin",
|
||||||
"item.crafting.TippedArrowRecipeMixin",
|
"item.crafting.TippedArrowRecipeMixin",
|
||||||
|
"network.NetworkManagerMixin",
|
||||||
"network.PacketThreadUtilMixin",
|
"network.PacketThreadUtilMixin",
|
||||||
"network.datasync.EntityDataManagerMixin",
|
"network.datasync.EntityDataManagerMixin",
|
||||||
"network.login.ServerLoginNetHandler1Mixin",
|
"network.handshake.ServerHandshakeNetHandlerMixin",
|
||||||
|
"network.handshake.client.CHandshakePacketMixin",
|
||||||
|
"network.login.ServerLoginNetHandlerMixin",
|
||||||
"network.play.ServerPlayNetHandlerMixin",
|
"network.play.ServerPlayNetHandlerMixin",
|
||||||
"network.play.client.CChatMessagePacketMixin",
|
"network.play.client.CChatMessagePacketMixin",
|
||||||
"network.play.client.CCloseWindowPacketMixin",
|
"network.play.client.CCloseWindowPacketMixin",
|
||||||
|
|||||||
@ -68,9 +68,11 @@ def embedLibs = ['org.spongepowered:mixin:0.8', 'org.ow2.asm:asm-util:6.2',
|
|||||||
dependencies {
|
dependencies {
|
||||||
minecraft "net.minecraftforge:forge:$minecraftVersion-$forgeVersion"
|
minecraft "net.minecraftforge:forge:$minecraftVersion-$forgeVersion"
|
||||||
compile group: 'org.jetbrains', name: 'annotations', version: '19.0.0'
|
compile group: 'org.jetbrains', name: 'annotations', version: '19.0.0'
|
||||||
|
compile project(':arclight-common')
|
||||||
compile(project(':arclight-common')) {
|
compile(project(':arclight-common')) {
|
||||||
exclude module: 'forge'
|
exclude module: 'forge'
|
||||||
}
|
}
|
||||||
|
embed project(':i18n-config')
|
||||||
embed project(':forge-installer')
|
embed project(':forge-installer')
|
||||||
for (def lib : embedLibs) {
|
for (def lib : embedLibs) {
|
||||||
arclight lib
|
arclight lib
|
||||||
@ -98,8 +100,9 @@ jar {
|
|||||||
manifest.attributes 'MixinConnector': 'io.izzel.arclight.impl.ArclightConnector_1_14'
|
manifest.attributes 'MixinConnector': 'io.izzel.arclight.impl.ArclightConnector_1_14'
|
||||||
manifest.attributes 'Main-Class': 'io.izzel.arclight.server.Main'
|
manifest.attributes 'Main-Class': 'io.izzel.arclight.server.Main'
|
||||||
manifest.attributes 'Implementation-Title': 'Arclight'
|
manifest.attributes 'Implementation-Title': 'Arclight'
|
||||||
manifest.attributes 'Implementation-Version': "arclight-${project.version}-${getGitHash()}"
|
manifest.attributes 'Implementation-Version': "arclight-$minecraftVersion-${project.version}-${getGitHash()}"
|
||||||
manifest.attributes 'Implementation-Vendor': 'Arclight Team'
|
manifest.attributes 'Implementation-Vendor': 'Arclight Team'
|
||||||
|
manifest.attributes 'Implementation-Timestamp': new Date().format("yyyy-MM-dd HH:mm:ss")
|
||||||
from(configurations.embed.collect { it.isDirectory() ? it : zipTree(it) }) {
|
from(configurations.embed.collect { it.isDirectory() ? it : zipTree(it) }) {
|
||||||
exclude "META-INF/MANIFEST.MF"
|
exclude "META-INF/MANIFEST.MF"
|
||||||
exclude "META-INF/*.SF"
|
exclude "META-INF/*.SF"
|
||||||
|
|||||||
@ -3,16 +3,22 @@ package io.izzel.arclight.server;
|
|||||||
import io.izzel.arclight.api.ArclightVersion;
|
import io.izzel.arclight.api.ArclightVersion;
|
||||||
import io.izzel.arclight.api.EnumHelper;
|
import io.izzel.arclight.api.EnumHelper;
|
||||||
import io.izzel.arclight.api.Unsafe;
|
import io.izzel.arclight.api.Unsafe;
|
||||||
import io.izzel.arclight.common.mod.util.remapper.ArclightRemapper;
|
|
||||||
import io.izzel.arclight.forgeinstaller.ForgeInstaller;
|
import io.izzel.arclight.forgeinstaller.ForgeInstaller;
|
||||||
|
import io.izzel.arclight.common.mod.util.remapper.ArclightRemapper;
|
||||||
import net.minecraftforge.server.ServerMain;
|
import net.minecraftforge.server.ServerMain;
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.jar.Attributes;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
public static void main(String[] args) throws Throwable {
|
public static void main(String[] args) throws Throwable {
|
||||||
|
System.setProperty("java.util.logging.manager", ArclightLazyLogManager.class.getCanonicalName());
|
||||||
|
System.setProperty("log4j.jul.LoggerAdapter", "io.izzel.arclight.common.mod.util.log.ArclightLoggerAdapter");
|
||||||
|
ArclightLocale.info("i18n.using-language", ArclightConfig.spec().getLocale().getCurrent(), ArclightConfig.spec().getLocale().getFallback());
|
||||||
|
ArclightVersion.setVersion(ArclightVersion.v1_14);
|
||||||
ForgeInstaller.install();
|
ForgeInstaller.install();
|
||||||
try { // Java 9 & Java 兼容性
|
try { // Java 9 & Java 兼容性
|
||||||
int javaVersion = (int) Float.parseFloat(System.getProperty("java.class.version"));
|
int javaVersion = (int) Float.parseFloat(System.getProperty("java.class.version"));
|
||||||
@ -26,10 +32,8 @@ public class Main {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
|
printLogo();
|
||||||
System.setProperty("log4j.jul.LoggerAdapter", "io.izzel.arclight.common.mod.util.ArclightLoggerAdapter");
|
ArclightI18nLogger.getLogger("Arclight").info("loading-mapping");
|
||||||
ArclightVersion.setVersion(ArclightVersion.v1_14);
|
|
||||||
LogManager.getLogger("Arclight").info("Loading mappings ...");
|
|
||||||
Objects.requireNonNull(ArclightRemapper.INSTANCE);
|
Objects.requireNonNull(ArclightRemapper.INSTANCE);
|
||||||
ServerMain.main(args);
|
ServerMain.main(args);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -37,4 +41,14 @@ public class Main {
|
|||||||
System.err.println("Fail to launch Arclight.");
|
System.err.println("Fail to launch Arclight.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void printLogo() throws Exception {
|
||||||
|
try (InputStream stream = Main.class.getResourceAsStream("/META-INF/MANIFEST.MF")) {
|
||||||
|
Manifest manifest = new Manifest(stream);
|
||||||
|
Attributes attributes = manifest.getMainAttributes();
|
||||||
|
String version = attributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
|
||||||
|
String buildTime = attributes.getValue("Implementation-Timestamp");
|
||||||
|
ArclightI18nLogger.getLogger("Arclight").info("logo", version, buildTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
i18n-config/build.gradle
Normal file
19
i18n-config/build.gradle
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
name = 'sponge'
|
||||||
|
url = 'https://repo.spongepowered.org/maven'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile 'org.spongepowered:configurate-hocon:3.6.1'
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) })
|
||||||
|
}
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
package io.izzel.arclight.i18n;
|
||||||
|
|
||||||
|
import com.google.common.reflect.TypeToken;
|
||||||
|
import io.izzel.arclight.i18n.conf.ConfigSpec;
|
||||||
|
import ninja.leaping.configurate.ConfigurationNode;
|
||||||
|
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
|
||||||
|
import ninja.leaping.configurate.hocon.HoconConfigurationLoader;
|
||||||
|
import ninja.leaping.configurate.objectmapping.ObjectMappingException;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
|
public class ArclightConfig {
|
||||||
|
|
||||||
|
private static ArclightConfig instance;
|
||||||
|
|
||||||
|
private final CommentedConfigurationNode node;
|
||||||
|
private final ConfigSpec spec;
|
||||||
|
|
||||||
|
public ArclightConfig(CommentedConfigurationNode node) throws ObjectMappingException {
|
||||||
|
this.node = node;
|
||||||
|
this.spec = this.node.getValue(TypeToken.of(ConfigSpec.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommentedConfigurationNode getNode() {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigSpec getSpec() {
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationNode get(String path) {
|
||||||
|
return this.node.getNode((Object[]) path.split("\\."));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfigSpec spec() {
|
||||||
|
return instance.spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void load() throws Exception {
|
||||||
|
Path path = Paths.get("arclight.conf");
|
||||||
|
CommentedConfigurationNode node = HoconConfigurationLoader.builder().setSource(
|
||||||
|
() -> new BufferedReader(new InputStreamReader(ArclightConfig.class.getResourceAsStream("/META-INF/arclight.conf"), StandardCharsets.UTF_8))
|
||||||
|
).build().load();
|
||||||
|
HoconConfigurationLoader loader = HoconConfigurationLoader.builder().setPath(path).build();
|
||||||
|
CommentedConfigurationNode cur = loader.load();
|
||||||
|
cur.mergeValuesFrom(node);
|
||||||
|
cur.getNode("locale", "current").setValue(ArclightLocale.getInstance().getCurrent());
|
||||||
|
fillComments(cur, ArclightLocale.getInstance());
|
||||||
|
instance = new ArclightConfig(cur);
|
||||||
|
loader.save(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void fillComments(CommentedConfigurationNode node, ArclightLocale locale) {
|
||||||
|
if (!node.getComment().isPresent()) {
|
||||||
|
String path = pathOf(node);
|
||||||
|
Optional<String> option = locale.getOption("comments." + path + ".comment");
|
||||||
|
option.ifPresent(node::setComment);
|
||||||
|
}
|
||||||
|
if (node.hasMapChildren()) {
|
||||||
|
for (CommentedConfigurationNode value : node.getChildrenMap().values()) {
|
||||||
|
fillComments(value, locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String pathOf(ConfigurationNode node) {
|
||||||
|
StringJoiner joiner = new StringJoiner(".");
|
||||||
|
for (Object o : node.getPath()) {
|
||||||
|
if (o != null) {
|
||||||
|
joiner.add(o.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String s = joiner.toString();
|
||||||
|
return s.isEmpty() ? "__root__" : s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
load();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,132 @@
|
|||||||
|
package io.izzel.arclight.i18n;
|
||||||
|
|
||||||
|
import ninja.leaping.configurate.ValueType;
|
||||||
|
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
|
||||||
|
import ninja.leaping.configurate.hocon.HoconConfigurationLoader;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
public class ArclightLocale {
|
||||||
|
|
||||||
|
private static ArclightLocale instance;
|
||||||
|
|
||||||
|
private final String current, fallback;
|
||||||
|
private final CommentedConfigurationNode node;
|
||||||
|
|
||||||
|
public ArclightLocale(String current, String fallback, CommentedConfigurationNode node) {
|
||||||
|
this.current = current;
|
||||||
|
this.fallback = fallback;
|
||||||
|
this.node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrent() {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFallback() {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommentedConfigurationNode getNode() {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String format(String node, Object... args) {
|
||||||
|
return MessageFormat.format(get(node), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String get(String path) {
|
||||||
|
return getOption(path).orElse(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> getOption(String path) {
|
||||||
|
CommentedConfigurationNode node = this.node.getNode((Object[]) path.split("\\."));
|
||||||
|
if (node.getValueType() == ValueType.LIST) {
|
||||||
|
StringJoiner joiner = new StringJoiner("\n");
|
||||||
|
for (CommentedConfigurationNode configurationNode : node.getChildrenList()) {
|
||||||
|
joiner.add(configurationNode.getString());
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(joiner.toString());
|
||||||
|
} else {
|
||||||
|
return Optional.ofNullable(node.getString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void info(String path, Object... args) {
|
||||||
|
System.out.println(instance.format(path, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void error(String path, Object... args) {
|
||||||
|
System.err.println(instance.format(path, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArclightLocale getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void init() throws Exception {
|
||||||
|
Map.Entry<String, String> entry = getLocale();
|
||||||
|
String current = entry.getKey();
|
||||||
|
String fallback = entry.getValue();
|
||||||
|
InputStream stream = ArclightLocale.class.getResourceAsStream("/META-INF/i18n/" + fallback + ".conf");
|
||||||
|
if (stream == null) throw new RuntimeException("Fallback locale is not found: " + fallback);
|
||||||
|
CommentedConfigurationNode node = HoconConfigurationLoader.builder().setSource(localeSource(fallback)).build().load();
|
||||||
|
instance = new ArclightLocale(current, fallback, node);
|
||||||
|
if (!current.equals(fallback)) {
|
||||||
|
try {
|
||||||
|
CommentedConfigurationNode curNode = HoconConfigurationLoader.builder().setSource(localeSource(current)).build().load();
|
||||||
|
curNode.mergeValuesFrom(node);
|
||||||
|
instance = new ArclightLocale(current, fallback, curNode);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(instance.format("i18n.current-not-available", current));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Callable<BufferedReader> localeSource(String path) {
|
||||||
|
return () -> new BufferedReader(new InputStreamReader(ArclightLocale.class.getResourceAsStream("/META-INF/i18n/" + path + ".conf"), StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map.Entry<String, String> getLocale() {
|
||||||
|
try {
|
||||||
|
Path path = Paths.get("arclight.conf");
|
||||||
|
if (!Files.exists(path)) {
|
||||||
|
throw new Exception();
|
||||||
|
} else {
|
||||||
|
CommentedConfigurationNode node = HoconConfigurationLoader.builder().setPath(path).build().load();
|
||||||
|
CommentedConfigurationNode locale = node.getNode("locale");
|
||||||
|
String current = locale.getNode("current").getString(currentLocale());
|
||||||
|
String fallback = locale.getNode("fallback").getString("zh_cn");
|
||||||
|
return new AbstractMap.SimpleImmutableEntry<>(current, fallback);
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return new AbstractMap.SimpleImmutableEntry<>(currentLocale(), "zh_cn");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String currentLocale() {
|
||||||
|
Locale locale = Locale.getDefault();
|
||||||
|
return locale.getLanguage().toLowerCase(Locale.ROOT) + "_" + locale.getCountry().toLowerCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
init();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package io.izzel.arclight.i18n.conf;
|
||||||
|
|
||||||
|
import ninja.leaping.configurate.objectmapping.Setting;
|
||||||
|
import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
|
||||||
|
|
||||||
|
@ConfigSerializable
|
||||||
|
public class ConfigSpec {
|
||||||
|
|
||||||
|
@Setting("_v")
|
||||||
|
private int version;
|
||||||
|
|
||||||
|
@Setting("optimization")
|
||||||
|
private OptimizationSpec optimizationSpec;
|
||||||
|
|
||||||
|
@Setting("locale")
|
||||||
|
private LocaleSpec localeSpec;
|
||||||
|
|
||||||
|
public int getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OptimizationSpec getOptimization() {
|
||||||
|
return optimizationSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocaleSpec getLocale() {
|
||||||
|
return localeSpec;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package io.izzel.arclight.i18n.conf;
|
||||||
|
|
||||||
|
import ninja.leaping.configurate.objectmapping.Setting;
|
||||||
|
import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
|
||||||
|
|
||||||
|
@ConfigSerializable
|
||||||
|
public class LocaleSpec {
|
||||||
|
|
||||||
|
@Setting("current")
|
||||||
|
private String current;
|
||||||
|
|
||||||
|
@Setting("fallback")
|
||||||
|
private String fallback;
|
||||||
|
|
||||||
|
public String getCurrent() {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFallback() {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package io.izzel.arclight.i18n.conf;
|
||||||
|
|
||||||
|
import ninja.leaping.configurate.objectmapping.Setting;
|
||||||
|
import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
|
||||||
|
|
||||||
|
@ConfigSerializable
|
||||||
|
public class OptimizationSpec {
|
||||||
|
|
||||||
|
@Setting("remove-stream")
|
||||||
|
private boolean removeStream;
|
||||||
|
|
||||||
|
public boolean isRemoveStream() {
|
||||||
|
return removeStream;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
i18n-config/src/main/resources/META-INF/arclight.conf
Normal file
8
i18n-config/src/main/resources/META-INF/arclight.conf
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
_v = 1
|
||||||
|
|
||||||
|
locale {
|
||||||
|
fallback = "zh_cn"
|
||||||
|
}
|
||||||
|
optimization {
|
||||||
|
remove-stream = true
|
||||||
|
}
|
||||||
44
i18n-config/src/main/resources/META-INF/i18n/en_us.conf
Normal file
44
i18n-config/src/main/resources/META-INF/i18n/en_us.conf
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
logo = [
|
||||||
|
""
|
||||||
|
""
|
||||||
|
" §1 ___ §9 §3 §6___§e §6 __ /\\"
|
||||||
|
" §1 / |§9 ____§3____§6/ §e(_)§6__ / / / /"
|
||||||
|
" §1 / /| |§9/ __§3/ __§6/ §e/ /§6 _ / _ \\/__/"
|
||||||
|
" §1 / ___ §9/ / §3/ /_§6/ §e/ /§6 / / // / /"
|
||||||
|
" §1/_/ |§9/_/ §3\\__§6/_§e/_/§6\\_ /_//_/ /"
|
||||||
|
" §1 §9 §3 §6 §e §6/__/ \\/"
|
||||||
|
""
|
||||||
|
" §aVersion {}"
|
||||||
|
" §aBuild Date {}"
|
||||||
|
""
|
||||||
|
]
|
||||||
|
|
||||||
|
i18n {
|
||||||
|
current-not-available = "Current locale {0} is not available"
|
||||||
|
using-language = "Using locale {0} and fallback locale {1}"
|
||||||
|
}
|
||||||
|
loading-mapping = "Loading mappings ..."
|
||||||
|
mixin-load {
|
||||||
|
core = "Arclight core mixin added."
|
||||||
|
optimization = "Arclight optimization mixin added."
|
||||||
|
}
|
||||||
|
mod-load = "Arclight Mod loaded."
|
||||||
|
registry {
|
||||||
|
forge-event = "Arclight events registered."
|
||||||
|
begin = "Regitring for Bukkit ..."
|
||||||
|
error = "Error occured registring Forge "
|
||||||
|
enchantment = "Registered {} enchantments"
|
||||||
|
potion = "Registered {} new potion effect types"
|
||||||
|
material = "Registered {} new materials with {} blocks and {} items"
|
||||||
|
}
|
||||||
|
|
||||||
|
comments {
|
||||||
|
_v.comment = [
|
||||||
|
"Repository: https://github.com/IzzelAliz/Arclight"
|
||||||
|
"Issue Tracker: https://github.com/IzzelAliz/Arclight/issues"
|
||||||
|
""
|
||||||
|
""
|
||||||
|
"Config version number, do not edit."
|
||||||
|
]
|
||||||
|
locale.comment = "Language/I18n settings"
|
||||||
|
}
|
||||||
45
i18n-config/src/main/resources/META-INF/i18n/zh_cn.conf
Normal file
45
i18n-config/src/main/resources/META-INF/i18n/zh_cn.conf
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
logo = [
|
||||||
|
""
|
||||||
|
""
|
||||||
|
" §1 ___ §9 §3 §6___§e §6 __ /\\"
|
||||||
|
" §1 / |§9 ____§3____§6/ §e(_)§6__ / / / /"
|
||||||
|
" §1 / /| |§9/ __§3/ __§6/ §e/ /§6 _ / _ \\/__/"
|
||||||
|
" §1 / ___ §9/ / §3/ /_§6/ §e/ /§6 / / // / /"
|
||||||
|
" §1/_/ |§9/_/ §3\\__§6/_§e/_/§6\\_ /_//_/ /"
|
||||||
|
" §1 §9 §3 §6 §e §6/__/ \\/"
|
||||||
|
""
|
||||||
|
" §a运行版本 {}"
|
||||||
|
" §a构建日期 {}"
|
||||||
|
""
|
||||||
|
]
|
||||||
|
|
||||||
|
i18n {
|
||||||
|
current-not-available = "选择的语言 {0} 不可用"
|
||||||
|
using-language = "正在使用 {0} 语言,{1} 作为备选语言"
|
||||||
|
}
|
||||||
|
loading-mapping = "正在加载混淆数据 ..."
|
||||||
|
mixin-load {
|
||||||
|
core = "核心 Mixin 配置已加载"
|
||||||
|
optimization = "服务端优化 Mixin 配置已加载"
|
||||||
|
}
|
||||||
|
mod-load = "Arclight Mod 已加载"
|
||||||
|
registry {
|
||||||
|
forge-event = "Arclight 事件系统已注册"
|
||||||
|
begin = "正在向 Bukkit 注册 ..."
|
||||||
|
error = "处理 Forge 注册时出错 "
|
||||||
|
enchantment = "注册了 {} 个新的附魔"
|
||||||
|
potion = "注册了 {} 个新的药水效果"
|
||||||
|
material = "注册了 {} 个材料,其中 {} 个方块 {} 个物品"
|
||||||
|
}
|
||||||
|
|
||||||
|
comments {
|
||||||
|
_v.comment = [
|
||||||
|
"源代码仓库: https://github.com/IzzelAliz/Arclight"
|
||||||
|
"提交反馈/错误报告: https://github.com/IzzelAliz/Arclight/issues"
|
||||||
|
""
|
||||||
|
""
|
||||||
|
"配置文件版本号,请勿编辑"
|
||||||
|
]
|
||||||
|
locale.comment = "语言/国际化相关设置"
|
||||||
|
optimization.comment = "服务端优化相关设置"
|
||||||
|
}
|
||||||
@ -5,4 +5,5 @@ include 'arclight-common'
|
|||||||
include 'forge-installer'
|
include 'forge-installer'
|
||||||
include 'arclight-api'
|
include 'arclight-api'
|
||||||
include 'arclight-forge-1.15'
|
include 'arclight-forge-1.15'
|
||||||
|
include 'i18n-config'
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user