Update 1.4.5
parent
b48d3d23e3
commit
2c672ee98e
|
@ -112,21 +112,27 @@ public class Orebfuscator extends JavaPlugin {
|
|||
pm.registerEvents(this.entityListener, this);
|
||||
pm.registerEvents(this.blockListener, this);
|
||||
|
||||
//Check if OrebfuscatorSpoutBridge exists
|
||||
if(pm.getPlugin("OrebfuscatorSpoutBridge") != null)
|
||||
//Using Spout
|
||||
if(pm.getPlugin("Spout") != null)
|
||||
{
|
||||
Orebfuscator.log("OrebfuscatorSpoutBridge is integrated into Orebfuscator now. You should remove OrebfuscatorSpoutBridge.jar from the plugins folder.");
|
||||
}
|
||||
|
||||
//Spout events
|
||||
else if(pm.getPlugin("Spout") != null)
|
||||
{
|
||||
//Using Spout
|
||||
try{
|
||||
SpoutLoader.InitializeSpout();
|
||||
Orebfuscator.log("Spout found, using Spout.");
|
||||
}catch(Exception e){
|
||||
Orebfuscator.log("Spout initialization failed. Error: " + e.getMessage());
|
||||
//Try to load spout 10 times...
|
||||
Throwable t = null;
|
||||
boolean spoutLoaded = false;
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
try{
|
||||
SpoutLoader.InitializeSpout();
|
||||
Orebfuscator.log("Spout found, using Spout.");
|
||||
spoutLoaded = true;
|
||||
break;
|
||||
}catch(Throwable e){
|
||||
t = e;
|
||||
}
|
||||
}
|
||||
if(!spoutLoaded && t != null)
|
||||
{
|
||||
Orebfuscator.log("Spout loading error.");
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -215,7 +221,7 @@ public class Orebfuscator extends JavaPlugin {
|
|||
/**
|
||||
* Log an error
|
||||
*/
|
||||
public static void log(Exception e)
|
||||
public static void log(Throwable e)
|
||||
{
|
||||
logger.severe("[OFC] " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -44,6 +44,7 @@ public class OrebfuscatorConfig {
|
|||
private static int MaxLoadedCacheFiles = 64;
|
||||
private static int ProximityHiderDistance = 8;
|
||||
private static int ProximityHiderID = 0;
|
||||
private static int ProximityHiderEnd = 255;
|
||||
private static boolean UseProximityHider = true;
|
||||
private static boolean UseSpecialBlockForProximityHider = true;
|
||||
private static boolean UpdateOnBreak = true;
|
||||
|
@ -57,7 +58,7 @@ public class OrebfuscatorConfig {
|
|||
private static boolean VerboseMode = false;
|
||||
private static boolean NoObfuscationForOps = true;
|
||||
private static boolean NoObfuscationForPermission = true;
|
||||
private static boolean UseCache = true;
|
||||
private static boolean UseCache = false;
|
||||
private static boolean Enabled = true;
|
||||
private static File CacheFolder = new File(Bukkit.getServer().getWorldContainer(), "orebfuscator_cache");
|
||||
|
||||
|
@ -75,8 +76,8 @@ public class OrebfuscatorConfig {
|
|||
|
||||
public static int getUpdateRadius()
|
||||
{
|
||||
if(UpdateRadius < 1)
|
||||
return 1;
|
||||
if(UpdateRadius < 0)
|
||||
return 0;
|
||||
return UpdateRadius;
|
||||
}
|
||||
|
||||
|
@ -119,6 +120,11 @@ public class OrebfuscatorConfig {
|
|||
return ProximityHiderID;
|
||||
}
|
||||
|
||||
public static int getProximityHiderEnd()
|
||||
{
|
||||
return ProximityHiderEnd;
|
||||
}
|
||||
|
||||
public static boolean getUseProximityHider()
|
||||
{
|
||||
return UseProximityHider;
|
||||
|
@ -296,6 +302,12 @@ public class OrebfuscatorConfig {
|
|||
ProximityHiderID = data;
|
||||
}
|
||||
|
||||
public static void setProximityHiderEnd(int data)
|
||||
{
|
||||
setData("Integers.ProximityHiderEnd", data);
|
||||
ProximityHiderEnd = data;
|
||||
}
|
||||
|
||||
public static void setUseProximityHider(boolean data)
|
||||
{
|
||||
setData("Booleans.UseProximityHider", data);
|
||||
|
@ -486,6 +498,7 @@ public class OrebfuscatorConfig {
|
|||
MaxLoadedCacheFiles = getInt("Integers.MaxLoadedCacheFiles", MaxLoadedCacheFiles);
|
||||
ProximityHiderDistance = getInt("Integers.ProximityHiderDistance", ProximityHiderDistance);
|
||||
ProximityHiderID = getInt("Integers.ProximityHiderID", ProximityHiderID);
|
||||
ProximityHiderEnd = getInt("Integers.ProximityHiderEnd", ProximityHiderEnd);
|
||||
UseProximityHider = getBoolean("Booleans.UseProximityHider", UseProximityHider);
|
||||
UseSpecialBlockForProximityHider = getBoolean("Booleans.UseSpecialBlockForProximityHider", UseSpecialBlockForProximityHider);
|
||||
UpdateOnBreak = getBoolean("Booleans.UpdateOnBreak", UpdateOnBreak);
|
||||
|
@ -585,11 +598,27 @@ public class OrebfuscatorConfig {
|
|||
|
||||
public static boolean playerBypassOp(Player player)
|
||||
{
|
||||
return OrebfuscatorConfig.getNoObfuscationForOps() && player.isOp();
|
||||
boolean ret = false;
|
||||
try{
|
||||
ret = OrebfuscatorConfig.getNoObfuscationForOps() && player.isOp();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Orebfuscator.log("Error while obtaining OP status for player" + player.getName() + ": " + e.getMessage());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static boolean playerBypassPerms(Player player)
|
||||
{
|
||||
return OrebfuscatorConfig.getNoObfuscationForPermission() && player.hasPermission("Orebfuscator.deobfuscate");
|
||||
boolean ret = false;
|
||||
try{
|
||||
ret = OrebfuscatorConfig.getNoObfuscationForPermission() && player.hasPermission("Orebfuscator.deobfuscate");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Orebfuscator.log("Error while obtaining permissions for player" + player.getName() + ": " + e.getMessage());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package lishid.orebfuscator.cache;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import lishid.orebfuscator.Orebfuscator;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
public class ChunkCacheInvalidation extends Thread implements Runnable
|
||||
{
|
||||
private static final int QUEUE_CAPACITY = 1024 * 10;
|
||||
private static final LinkedBlockingDeque<Block> queue = new LinkedBlockingDeque<Block>(QUEUE_CAPACITY);
|
||||
private static ChunkCacheInvalidation thread;
|
||||
public static HashSet<Long> invalidChunks = new HashSet<Long>();
|
||||
public static Object invalidationLock = new Object();
|
||||
|
||||
public static void terminate()
|
||||
{
|
||||
if(thread != null)
|
||||
thread.kill.set(true);
|
||||
}
|
||||
|
||||
public static void Queue(Block block)
|
||||
{
|
||||
/*
|
||||
if(thread == null || thread.isInterrupted() || !thread.isAlive())
|
||||
{
|
||||
thread = new ChunkCacheInvalidation();
|
||||
thread.setName("Orebfuscator Cache Invalidation Thread");
|
||||
thread.setPriority(Thread.MIN_PRIORITY);
|
||||
thread.start();
|
||||
}
|
||||
*/
|
||||
|
||||
synchronized(invalidationLock)
|
||||
{
|
||||
long chunk = (long)block.getX() << 32 + block.getZ();
|
||||
invalidChunks.add(chunk);
|
||||
}
|
||||
/*
|
||||
while(true)
|
||||
{
|
||||
try {
|
||||
//Queue block for later processing
|
||||
queue.put(block);
|
||||
return;
|
||||
}
|
||||
catch (Exception e) { Orebfuscator.log(e); }
|
||||
}*/
|
||||
}
|
||||
|
||||
private AtomicBoolean kill = new AtomicBoolean(false);
|
||||
|
||||
public void run() {
|
||||
while (!this.isInterrupted() && !kill.get()) {
|
||||
try {
|
||||
//Remove the first block from the queue
|
||||
Block block = queue.take();
|
||||
//Invalidate the block
|
||||
synchronized(invalidationLock)
|
||||
{
|
||||
long chunk = (long)block.getX() << 32 + block.getZ();
|
||||
invalidChunks.add(chunk);
|
||||
}
|
||||
}
|
||||
catch (Exception e) { Orebfuscator.log(e); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,8 +21,7 @@ import java.io.DataInputStream;
|
|||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
|
||||
import lishid.orebfuscator.Orebfuscator;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.minecraft.server.NBTCompressedStreamTools;
|
||||
import net.minecraft.server.NBTTagCompound;
|
||||
|
@ -70,7 +69,9 @@ public class ObfuscatedCachedChunk {
|
|||
return nbt.getLong("Hash");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Orebfuscator.log("Error reading Orebfuscator Chunk cache hash: " + e.getMessage());
|
||||
//Orebfuscator.log("Error reading Orebfuscator Chunk cache hash: " + e.getMessage());
|
||||
} catch (Error e) {
|
||||
//Orebfuscator.log("Error reading Orebfuscator Chunk cache hash: " + e.getMessage());
|
||||
}
|
||||
|
||||
return 0L;
|
||||
|
@ -96,7 +97,9 @@ public class ObfuscatedCachedChunk {
|
|||
proximityBlockList = new int[0];
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Orebfuscator.log("Error reading Orebfuscator Chunk cache data: " + e.getMessage());
|
||||
//Orebfuscator.log("Error reading Orebfuscator Chunk cache data: " + e.getMessage());
|
||||
} catch (Error e) {
|
||||
//Orebfuscator.log("Error reading Orebfuscator Chunk cache data: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,9 +120,13 @@ public class ObfuscatedCachedChunk {
|
|||
DataOutputStream stream = ObfuscatedDataCache.getOutputStream(hashPath, x, z);
|
||||
NBTCompressedStreamTools.a(nbt, (DataOutput)stream);
|
||||
stream.close();
|
||||
} catch (Exception e) {
|
||||
Orebfuscator.log("Error writing Orebfuscator Chunk cache hash: " + e.getMessage());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
//Orebfuscator.log("Error writing Orebfuscator Chunk cache hash: " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
//Orebfuscator.log("Error writing Orebfuscator Chunk cache hash: " + e.getMessage());
|
||||
} catch (Error e) {
|
||||
//Orebfuscator.log("Error writing Orebfuscator Chunk cache hash: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void setData(byte[] data, int[] proximityBlockList) {
|
||||
|
@ -135,8 +142,12 @@ public class ObfuscatedCachedChunk {
|
|||
DataOutputStream stream = ObfuscatedDataCache.getOutputStream(path, x, z);
|
||||
NBTCompressedStreamTools.a(nbt, (DataOutput)stream);
|
||||
stream.close();
|
||||
} catch (Exception e) {
|
||||
Orebfuscator.log("Error writing Orebfuscator Chunk cache data: " + e.getMessage());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
//Orebfuscator.log("Error writing Orebfuscator Chunk cache data: " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
//Orebfuscator.log("Error writing Orebfuscator Chunk cache data: " + e.getMessage());
|
||||
} catch (Error e) {
|
||||
//Orebfuscator.log("Error writing Orebfuscator Chunk cache data: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,7 +35,7 @@ import org.bukkit.craftbukkit.entity.CraftPlayer;
|
|||
public class OrebfuscatorCommandExecutor {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (command.getName().equalsIgnoreCase("chunk"))
|
||||
if (command.getName().equalsIgnoreCase("chunk") && sender instanceof Player)
|
||||
{
|
||||
int r = 2;
|
||||
if (args.length > 0)
|
||||
|
|
|
@ -18,7 +18,6 @@ package lishid.orebfuscator.hook;
|
|||
|
||||
import lishid.orebfuscator.Orebfuscator;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -44,8 +43,6 @@ public class OrebfuscatorPlayerListenerHook implements Listener{
|
|||
|
||||
if (!(cPlayer.getHandle().netServerHandler instanceof OrebfuscatorNetServerHandler)) {
|
||||
OrebfuscatorNetServerHandler handler = new OrebfuscatorNetServerHandler(server.getHandle().server, cPlayer.getHandle().netServerHandler);
|
||||
Location loc = player.getLocation();
|
||||
handler.a(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
|
||||
cPlayer.getHandle().netServerHandler = handler;
|
||||
cPlayer.getHandle().netServerHandler.networkManager.a(handler);
|
||||
server.getServer().networkListenThread.a(handler);
|
||||
|
|
|
@ -28,23 +28,24 @@ import org.getspout.spoutapi.packet.standard.MCPacket;
|
|||
|
||||
public class SpoutLoader {
|
||||
|
||||
public static void InitializeSpout()
|
||||
{
|
||||
//Add spout listeners
|
||||
SpoutManager.getPacketManager().addListener(51, new PacketListener(){
|
||||
|
||||
//Processing a chunk packet
|
||||
public boolean checkPacket(Player player, MCPacket mcpacket)
|
||||
{
|
||||
if ((player == null) || (mcpacket == null) || (player.getWorld() == null)) return true;
|
||||
|
||||
//Process the chunk
|
||||
if(((MCCraftPacket)mcpacket).getPacket() instanceof Packet51MapChunk)
|
||||
{
|
||||
public static void InitializeSpout() {
|
||||
// Add spout listeners
|
||||
SpoutManager.getPacketManager().addListener(51, new PacketListener() {
|
||||
|
||||
//Obfuscate packet
|
||||
// Processing a chunk packet
|
||||
public boolean checkPacket(Player player, MCPacket mcpacket) {
|
||||
if ((player == null) || (mcpacket == null)
|
||||
|| (player.getWorld() == null))
|
||||
return true;
|
||||
|
||||
// Process the chunk
|
||||
if (((MCCraftPacket) mcpacket).getPacket() instanceof Packet51MapChunk) {
|
||||
|
||||
// Obfuscate packet
|
||||
OrebfuscatorThreadCalculation.SyncThreads();
|
||||
OrebfuscatorThreadCalculation.Queue((Packet51MapChunk)((MCCraftPacket)mcpacket).getPacket(), (CraftPlayer)player);
|
||||
OrebfuscatorThreadCalculation.Queue(
|
||||
(Packet51MapChunk) ((MCCraftPacket) mcpacket)
|
||||
.getPacket(), (CraftPlayer) player);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,38 @@
|
|||
package lishid.orebfuscator.obfuscation;
|
||||
|
||||
public class MemoryManager
|
||||
{
|
||||
public static int MaxCollectPercent = 80;
|
||||
public static int AutoCollectPercent = 90;
|
||||
public static boolean buffer = false;
|
||||
|
||||
public static void CheckAndCollect()
|
||||
{
|
||||
long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
|
||||
long total = Runtime.getRuntime().totalMemory();
|
||||
long max = Runtime.getRuntime().maxMemory();
|
||||
|
||||
if(((float)used * 100 / total) > AutoCollectPercent)
|
||||
{
|
||||
Collect();
|
||||
}
|
||||
else if(((float)used * 100 / max) > MaxCollectPercent)
|
||||
{
|
||||
Collect();
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Collect()
|
||||
{
|
||||
if(buffer == false)
|
||||
{
|
||||
buffer = true;
|
||||
//Orebfuscator.log("Memory is low, performing optimizations.");
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,6 +32,11 @@ public class ProximityHider {
|
|||
HashSet<Block> blocks = proximityHiderTracker.get(p);
|
||||
for(Block b : blocks)
|
||||
{
|
||||
if(b == null || p == null || b.getWorld() == null || p.getWorld() == null)
|
||||
{
|
||||
blocksToRemove.add(b);
|
||||
continue;
|
||||
}
|
||||
if(!p.getWorld().equals(b.getWorld()))
|
||||
{
|
||||
blocksToRemove.add(b);
|
||||
|
|
|
@ -71,6 +71,7 @@ public class OrebfuscatorThreadCalculation extends Thread implements Runnable
|
|||
{
|
||||
OrebfuscatorThreadCalculation thread = new OrebfuscatorThreadCalculation();
|
||||
thread.setName("Orebfuscator Calculation Thread");
|
||||
thread.setPriority(Thread.MIN_PRIORITY);
|
||||
thread.start();
|
||||
threads.add(thread);
|
||||
}
|
||||
|
@ -90,36 +91,12 @@ public class OrebfuscatorThreadCalculation extends Thread implements Runnable
|
|||
{
|
||||
queue.put(new PlayerPacket(player, packet));
|
||||
}
|
||||
/*
|
||||
int x = packet.a >> 4;
|
||||
int z = packet.c >> 4;
|
||||
WorldServer world = player.getHandle().world.getWorld().getHandle();
|
||||
tryLoadChunk(world, x+1, z);
|
||||
tryLoadChunk(world, x-1, z);
|
||||
tryLoadChunk(world, x, z+1);
|
||||
tryLoadChunk(world, x, z-1);
|
||||
tryLoadChunk(world, x+1, z+1);
|
||||
tryLoadChunk(world, x+1, z-1);
|
||||
tryLoadChunk(world, x-1, z+1);
|
||||
tryLoadChunk(world, x-1, z-1);*/
|
||||
return;
|
||||
}
|
||||
catch (Exception e) { Orebfuscator.log(e); }
|
||||
}
|
||||
}
|
||||
/*
|
||||
private static void tryLoadChunk(WorldServer world, int x, int z)
|
||||
{
|
||||
if(!world.isLoaded(x << 4, 0, z << 4))
|
||||
{
|
||||
try
|
||||
{
|
||||
world.chunkProvider.getChunkAt(x+1, z);
|
||||
}
|
||||
catch (Exception e) { Orebfuscator.log(e); }
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private AtomicBoolean kill = new AtomicBoolean(false);
|
||||
private byte[] chunkBuffer = new byte[65536];
|
||||
|
||||
|
@ -133,10 +110,40 @@ public class OrebfuscatorThreadCalculation extends Thread implements Runnable
|
|||
//Try to obfuscate and send the packet
|
||||
Calculations.Obfuscate(packet.packet, packet.player, true, chunkBuffer);
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Throwable e)
|
||||
{
|
||||
Orebfuscator.log(e);
|
||||
//If we run into problems, just send the packet.
|
||||
|
||||
//Compress packets
|
||||
if(packet.packet.buffer == null)
|
||||
{
|
||||
try{
|
||||
synchronized(Calculations.deflateBuffer)
|
||||
{
|
||||
//Compression
|
||||
int dataSize = packet.packet.rawData.length;
|
||||
if (Calculations.deflateBuffer.length < dataSize + 100) {
|
||||
Calculations.deflateBuffer = new byte[dataSize + 100];
|
||||
}
|
||||
|
||||
Calculations.deflater.reset();
|
||||
Calculations.deflater.setLevel(dataSize < 20480 ? 1 : 6);
|
||||
Calculations.deflater.setInput(packet.packet.rawData);
|
||||
Calculations.deflater.finish();
|
||||
int size = Calculations.deflater.deflate(Calculations.deflateBuffer);
|
||||
if (size == 0) {
|
||||
size = Calculations.deflater.deflate(Calculations.deflateBuffer);
|
||||
}
|
||||
|
||||
//Copy compressed packet out
|
||||
packet.packet.buffer = new byte[size];
|
||||
packet.packet.size = size;
|
||||
System.arraycopy(Calculations.deflateBuffer, 0, packet.packet.buffer, 0, size);
|
||||
}
|
||||
} catch (Exception e2) { Orebfuscator.log(e2); }
|
||||
}
|
||||
|
||||
packet.player.getHandle().netServerHandler.sendPacket(packet.packet);
|
||||
}
|
||||
} catch (Exception e) { Orebfuscator.log(e); }
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
|
||||
import lishid.orebfuscator.Orebfuscator;
|
||||
import lishid.orebfuscator.OrebfuscatorConfig;
|
||||
import lishid.orebfuscator.cache.ChunkCacheInvalidation;
|
||||
import lishid.orebfuscator.obfuscation.Calculations;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
|
@ -41,11 +42,14 @@ public class OrebfuscatorThreadUpdate extends Thread implements Runnable
|
|||
public static void Queue(Block block)
|
||||
{
|
||||
//Dont do anything if the block is transparent
|
||||
if (!net.minecraft.server.Block.g((byte)block.getTypeId()))
|
||||
byte id = (byte)block.getTypeId();
|
||||
if (id < 0 || !net.minecraft.server.Block.g(id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChunkCacheInvalidation.Queue(block);
|
||||
|
||||
if(!OrebfuscatorConfig.getUpdateThread())
|
||||
{
|
||||
Calculations.UpdateBlocksNearby(block);
|
||||
|
@ -56,6 +60,7 @@ public class OrebfuscatorThreadUpdate extends Thread implements Runnable
|
|||
{
|
||||
thread = new OrebfuscatorThreadUpdate();
|
||||
thread.setName("Orebfuscator Update Thread");
|
||||
thread.setPriority(Thread.MIN_PRIORITY);
|
||||
thread.start();
|
||||
}
|
||||
while(true)
|
||||
|
|
|
@ -127,7 +127,8 @@ public class NetServerHandlerProxy extends NetServerHandler implements ICommandL
|
|||
|
||||
@Override
|
||||
public void sendPacket(Packet packet) {
|
||||
nshInstance.sendPacket(packet);
|
||||
if(packet != null)
|
||||
nshInstance.sendPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: Orebfuscator
|
||||
main: lishid.orebfuscator.Orebfuscator
|
||||
version: 1.4.2
|
||||
version: 1.4.6
|
||||
author: lishid
|
||||
softdepend: [Spout]
|
||||
load: startup
|
||||
|
|
Loading…
Reference in New Issue