Initial commit
build-and-test / build (push) Has been cancelled
Java-Compatibility / build (17) (push) Has been cancelled
Java-Compatibility / build (21) (push) Has been cancelled
Release Workflow / build-and-release (push) Has been cancelled

This commit is contained in:
2026-09-20 01:56:07 +01:00
commit 82192a4802
943 changed files with 92762 additions and 0 deletions
@@ -0,0 +1,285 @@
package com.legacyminecraft.poseidon;
import org.bukkit.Server;
import org.bukkit.plugin.InvalidDescriptionException;
import org.bukkit.plugin.InvalidPluginException;
import org.bukkit.plugin.PluginDescriptionFile;
import org.yaml.snakeyaml.error.YAMLException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class PluginLoadPlanner {
private final Server server;
private final Set<Pattern> fileFilters;
private final File updateDirectory;
public PluginLoadPlanner(Server server, Set<Pattern> fileFilters, File updateDirectory) {
this.server = server;
this.fileFilters = fileFilters;
this.updateDirectory = updateDirectory;
}
// Generate a load order for plugins in a given directory based on dependencies.
public List<PlannedPlugin> plan(File directory, File[] files) {
if (files == null || files.length == 0) {
return Collections.emptyList();
}
// Normalize filesystem enumeration so plugin order is not platform-dependent.
// Issue identified by RobertWesner
Arrays.sort(files, (left, right) -> left.getName().compareToIgnoreCase(right.getName()));
// Index plugin metadata up front so dependency decisions can be made before any plugin code runs.
LinkedHashMap<String, PluginCandidate> candidates = new LinkedHashMap<>();
// Loop through files in the directory and parse plugin descriptions, skipping duplicates and invalid plugins.
//TODO: We should figure out how we want to handle dupe plugins in Poseidon in the future. No reason exists for them and they just cause hard to trobleshoot issues
for (File file : files) {
PluginCandidate candidate = createCandidate(file);
if (candidate == null) {
continue;
}
PluginCandidate existing = candidates.get(candidate.name);
if (existing != null) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': duplicate plugin name '" + candidate.name + "' also found in '" + existing.file.getPath() + "'");
continue;
}
candidates.put(candidate.name, candidate);
}
List<PlannedPlugin> plan = new ArrayList<>();
// Create a deterministic load order
Set<String> loadedNames = new LinkedHashSet<>();
LinkedHashSet<PluginCandidate> remaining = new LinkedHashSet<>(candidates.values());
// Iterate until no plugins remain or no progress can be made due to missing or circular dependencies.
while (!remaining.isEmpty()) {
List<PluginCandidate> ready = new ArrayList<>();
// First try to satisfy both hard dependencies
for (PluginCandidate candidate : remaining) {
if (hasMissingHardDependencies(candidate, candidates)) {
continue;
}
// Prefer loading after both hard and present soft dependencies when the graph allows it.
if (dependenciesLoaded(candidate.getHardDependencies(), loadedNames)
&& dependenciesLoaded(candidate.getPresentSoftDependencies(candidates), loadedNames)) {
ready.add(candidate);
}
}
// If no plugin can satisfy every soft dependency, fall back to hard-dependency order.
boolean relaxedSoftDependencies = false;
if (ready.isEmpty()) {
for (PluginCandidate candidate : remaining) {
if (hasMissingHardDependencies(candidate, candidates)) {
continue;
}
// This preserves startup progress when soft dependencies form cycles or long chains.
if (dependenciesLoaded(candidate.getHardDependencies(), loadedNames)) {
ready.add(candidate);
}
}
relaxedSoftDependencies = !ready.isEmpty();
}
if (ready.isEmpty()) {
// Anything left here either references a missing hard dependency or is part of a cycle.
break;
}
// Sort deterministically to ensure a stable load order
Collections.sort(ready, (left, right) -> {
int loadOrder = left.description.getLoad().compareTo(right.description.getLoad());
if (loadOrder != 0) {
return loadOrder;
}
int nameOrder = left.name.compareToIgnoreCase(right.name);
if (nameOrder != 0) {
return nameOrder;
}
return left.file.getName().compareToIgnoreCase(right.file.getName());
});
for (PluginCandidate candidate : ready) {
// Tell the legacy loader to ignore soft dependencies only when the planner already relaxed them.
boolean ignoreSoftDependencies = relaxedSoftDependencies || candidate.hasMissingSoftDependencies(candidates);
plan.add(new PlannedPlugin(candidate.file, candidate.name, ignoreSoftDependencies));
loadedNames.add(candidate.name);
remaining.remove(candidate);
}
}
// Print errors
for (PluginCandidate candidate : remaining) {
// If the candidate has missing hard dependencies, report them. Otherwise, report a circular or unresolved dependency chain.
if (hasMissingHardDependencies(candidate, candidates)) {
for (String dependency : candidate.getMissingHardDependencies(candidates)) {
server.getLogger().log(Level.SEVERE, "Could not load '" + candidate.file.getPath() + "' in folder '" + directory.getPath() + "': Unknown dependency " + dependency);
}
} else {
server.getLogger().log(Level.SEVERE, "Could not load '" + candidate.file.getPath() + "' in folder '" + directory.getPath() + "': circular or unresolved dependency chain");
}
}
return plan;
}
private PluginCandidate createCandidate(File file) {
PluginDescriptionFile description;
try {
description = getPluginDescription(file);
} catch (InvalidPluginException | InvalidDescriptionException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "'.", ex);
return null;
}
if (description == null) {
// Non-plugin files in the directory are ignored by the registered file filters.
return null;
}
return new PluginCandidate(file, description);
}
private PluginDescriptionFile getPluginDescription(File file) throws InvalidPluginException, InvalidDescriptionException {
// Read plugin.yml first so ordering can be computed without instantiating plugin classes.
File descriptionSource = getEffectivePluginFile(file); // If plugin has an update, read description from the update file instead as it might have new dependencies.
for (Pattern filter : fileFilters) {
Matcher match = filter.matcher(descriptionSource.getName());
if (!match.find()) {
continue;
}
try (JarFile jar = new JarFile(descriptionSource)) {
JarEntry entry = jar.getJarEntry("plugin.yml");
if (entry == null) {
throw new InvalidPluginException(new IOException("Jar does not contain plugin.yml"));
}
try (InputStream stream = jar.getInputStream(entry)) {
return new PluginDescriptionFile(stream);
}
} catch (IOException ex) {
throw new InvalidPluginException(ex);
} catch (YAMLException ex) {
throw new InvalidPluginException(ex);
}
}
return null;
}
private File getEffectivePluginFile(File file) {
if (updateDirectory == null || !updateDirectory.isDirectory()) {
return file;
}
File updateFile = new File(updateDirectory, file.getName());
if (updateFile.isFile()) {
// Return the update file instead for processing
return updateFile;
}
return file;
}
private boolean hasMissingHardDependencies(PluginCandidate candidate, Map<String, PluginCandidate> candidates) {
return !candidate.getMissingHardDependencies(candidates).isEmpty();
}
private boolean dependenciesLoaded(Collection<String> dependencies, Set<String> loadedNames) {
for (String dependency : dependencies) {
if (!loadedNames.contains(dependency)) {
return false;
}
}
return true;
}
public static final class PlannedPlugin {
public final File file;
public final String name;
public final boolean ignoreSoftDependencies;
PlannedPlugin(File file, String name, boolean ignoreSoftDependencies) {
this.file = file;
this.name = name;
this.ignoreSoftDependencies = ignoreSoftDependencies;
}
}
private static final class PluginCandidate {
private final File file;
private final PluginDescriptionFile description;
private final String name;
private final List<String> hardDependencies;
private final List<String> softDependencies;
private PluginCandidate(File file, PluginDescriptionFile description) {
this.file = file;
this.description = description;
this.name = description.getName();
this.hardDependencies = copyDependencies(description.getDepend());
this.softDependencies = copyDependencies(description.getSoftDepend());
}
private List<String> getHardDependencies() {
return hardDependencies;
}
private List<String> getMissingHardDependencies(Map<String, PluginCandidate> candidates) {
List<String> missing = new ArrayList<>();
for (String dependency : hardDependencies) {
if (!candidates.containsKey(dependency)) {
missing.add(dependency);
}
}
return missing;
}
private List<String> getPresentSoftDependencies(Map<String, PluginCandidate> candidates) {
List<String> present = new ArrayList<>();
for (String dependency : softDependencies) {
if (candidates.containsKey(dependency)) {
present.add(dependency);
}
}
return present;
}
private boolean hasMissingSoftDependencies(Map<String, PluginCandidate> candidates) {
// Missing soft dependencies should not block load, but present ones still influence ordering.
return getPresentSoftDependencies(candidates).size() != softDependencies.size();
}
@SuppressWarnings("unchecked")
private static List<String> copyDependencies(Object dependencies) {
if (dependencies == null) {
return Collections.emptyList();
}
return new ArrayList<>((Collection<String>) dependencies);
}
}
}
@@ -0,0 +1,35 @@
package com.legacyminecraft.poseidon;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.craftbukkit.CraftServer;
import java.util.LinkedList;
public final class Poseidon {
private static PoseidonServer server;
/**
* Returns a list of the server's TPS (Ticks Per Second) records for performance monitoring.
* The list contains Double values indicating the TPS at each second, ordered from most recent to oldest.
*
* @return LinkedList<Double> of TPS records.
*/
public static LinkedList<Double> getTpsRecords() {
return ((CraftServer) Bukkit.getServer()).getServer().getTpsRecords();
}
public static PoseidonServer getServer() {
return server;
}
public static void setServer(PoseidonServer server) {
if (Poseidon.server != null) {
throw new UnsupportedOperationException("Cannot redefine singleton Server");
}
Poseidon.server = server;
}
}
@@ -0,0 +1,395 @@
package com.legacyminecraft.poseidon;
import org.bukkit.util.config.Configuration;
import java.io.File;
import java.util.Arrays;
import java.util.UUID;
import java.util.regex.Pattern;
public class PoseidonConfig extends Configuration {
private static PoseidonConfig singleton;
private final int configVersion = 5;
private Integer[] treeBlacklistIDs;
public Integer[] getTreeBlacklistIDs() {
return treeBlacklistIDs;
}
private PoseidonConfig() {
super(new File("poseidon.yml"));
this.reload();
}
public void reload() {
this.load();
this.write();
this.validation();
this.save();
}
public void resetConfig() {
// Delete all the config options
for (String key : this.getKeys()) {
this.removeProperty(key);
}
// Reload the config
this.write();
}
private void validation() {
//Confirm settings.uuid-fetcher.method.value is either POST or GET
if (!this.getConfigString("settings.uuid-fetcher.method.value").equalsIgnoreCase("POST") && !this.getConfigString("settings.uuid-fetcher.method.value").equalsIgnoreCase("GET")) {
System.out.println("[Poseidon] Config: settings.uuid-fetcher.method.value is not POST or GET. Changing to POST.");
this.setProperty("settings.uuid-fetcher.method.value", "POST");
}
}
private void write() {
if (this.getString("config-version") == null || Integer.valueOf(this.getString("config-version")) < configVersion) {
System.out.println("[Poseidon] Converting from config version " + (this.getString("config-version") == null ? "0" : this.getString("config-version")) + " to " + configVersion);
convertToNewConfig();
this.setProperty("config-version", configVersion);
}
//Main
generateConfigOption("config-version", configVersion);
//Setting
// generateConfigOption("settings.allow-graceful-uuids", true);
generateConfigOption("settings.delete-duplicate-uuids", false);
generateConfigOption("settings.save-playerdata-by-uuid", true);
// Log management and rotation
generateConfigOption("settings.per-day-log-file.info", "This setting causes the server to create a new log file each day. This is useful for log rotation and log file management.");
generateConfigOption("settings.per-day-log-file.enabled", false);
generateConfigOption("settings.per-day-log-file.latest-log.info", "This setting causes the server to create a latest.log similar to modern Minecraft servers. This can be useful for certain control panels and log file management.");
generateConfigOption("settings.per-day-log-file.latest-log.enabled", true);
//generateConfigOption("settings.fetch-uuids-from", "https://api.mojang.com/profiles/minecraft");
// UUID Fetcher Settings
generateConfigOption("settings.uuid-fetcher.post.info", "This setting allows you to change the URL that the server fetches UUIDs from. This is useful if you have a custom UUID server or a proxy server that fetches UUIDs.");
generateConfigOption("settings.uuid-fetcher.post.value", "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname");
generateConfigOption("settings.uuid-fetcher.get.info", "This setting allows you to change the URL that the server fetches UUIDs from. This is useful if you have a custom UUID server or a proxy server that fetches UUIDs.");
generateConfigOption("settings.uuid-fetcher.get.value", "https://api.minecraftservices.com/minecraft/profile/lookup/name/{username}");
generateConfigOption("settings.uuid-fetcher.get.enforce-case-sensitivity.enabled", true);
generateConfigOption("settings.uuid-fetcher.get.enforce-case-sensitivity.info", "The Mojang API is case-insensitive by default meaning usernames with different casing will return the same UUID. This setting checks the case of the username to prevent this issue. If the name is invalid, the player will be kicked.");
generateConfigOption("settings.uuid-fetcher.method.value", "POST");
generateConfigOption("settings.uuid-fetcher.method.info", "This setting allows for POST or GET method for fetching UUIDs. This is useful if you have a custom UUID server, Mojang API is down, or a proxy server that fetches UUIDs.");
generateConfigOption("settings.uuid-fetcher.allow-graceful-uuids.value", true);
generateConfigOption("settings.uuid-fetcher.allow-graceful-uuids.info", "This setting means offline UUIDs are generated for players who don't have a Mojang UUID. This is useful for cracked or semi-cracked servers.");
generateConfigOption("settings.uuid-fetcher.always-use-graceful-uuids.enabled", false);
generateConfigOption("settings.uuid-fetcher.always-use-graceful-uuids.info", "Will always use offline UUIDs. Useful if you need the server to run completely offline.");
// Setting to automatically add a . prefix to cracked account usernames
generateConfigOption("settings.cracked-username-prefix.enabled", false);
generateConfigOption("settings.cracked-username-prefix.info", "This setting automatically adds a . prefix to cracked account usernames to prevent username conflicts with premium accounts.");
generateConfigOption("settings.remove-join-leave-debug", true);
generateConfigOption("settings.enable-tpc-nodelay", false);
//generateConfigOption("settings.use-get-for-uuids.enabled", true);
//generateConfigOption("settings.use-get-for-uuids.info", "This setting causes the server to use the GET method for Username to UUID conversion. This is useful incase the POST method goes offline.");
//generateConfigOption("settings.use-get-for-uuids.case-sensitive.enabled", true);
//generateConfigOption("settings.use-get-for-uuids.case-sensitive.info", "This setting will verify sensitivity of the username as the GET method is case-insensitive.");
generateConfigOption("settings.faster-packets.enabled", true);
generateConfigOption("settings.faster-packets.info", "This setting increases the speed of packets, a fix from newer Minecraft versions.");
generateConfigOption("settings.fix-drowning-push-down.enabled", true);
generateConfigOption("settings.fix-drowning-push-down.info", "This setting fixes taking drowning damage pushing you down.");
generateConfigOption("settings.player-knockback-fix.enabled", true);
generateConfigOption("settings.player-knockback-fix.info", "This setting fixes reduced knockback for certain players on the server.");
//Watchdog
//generateConfigOption("settings.enable-watchdog", true);
generateConfigOption("settings.watchdog.info", "Watchdog is a automatic hang detection system which can print stacktraces and kill the server automatically after a predefined interval.");
generateConfigOption("settings.watchdog.enable", true);
generateConfigOption("settings.watchdog.timeout.value", 120);
generateConfigOption("settings.watchdog.timeout.info", "The number of seconds to kill the server process after no ticks occurring.");
generateConfigOption("settings.watchdog.debug-timeout.enabled", false);
generateConfigOption("settings.watchdog.debug-timeout.value", 30);
generateConfigOption("settings.watchdog.debug-timeout.info", "debug-timeout can be used to print a stack trace at a lower interval then the main timeout allowing admins to locate blocking tasks that cause hangs over a certain duration. Only enable this if you have experienced temporary hangs/server freezes.");
// Performance Monitoring
generateConfigOption("settings.performance-monitoring.listener-reporting.info", "This setting will cause the server to record listener execution times.");
generateConfigOption("settings.performance-monitoring.listener-reporting.enabled", true);
generateConfigOption("settings.performance-monitoring.listener-reporting.print-statistics-on-shutdown.info", "Prints the listener statistics to the console on server shutdown.");
generateConfigOption("settings.performance-monitoring.listener-reporting.print-statistics-on-shutdown.enabled", false);
generateConfigOption("settings.performance-monitoring.listener-reporting.print-on-slow-listeners.info", "Print to console when a listener takes longer than the specified time in milliseconds. It isn't recommended to set this any lower then 10ms to prevent console spam.");
generateConfigOption("settings.performance-monitoring.listener-reporting.print-on-slow-listeners.enabled", true);
generateConfigOption("settings.performance-monitoring.listener-reporting.print-on-slow-listeners.value", 100); // Default to two Minecraft tick
generateConfigOption("settings.performance-monitoring.task-reporting.info", "This setting will cause the server to record synchronous task execution times.");
generateConfigOption("settings.performance-monitoring.task-reporting.enabled", true);
generateConfigOption("settings.performance-monitoring.task-reporting.print-statistics-on-shutdown.info", "Prints the task statistics to the console on server shutdown.");
generateConfigOption("settings.performance-monitoring.task-reporting.print-statistics-on-shutdown.enabled", false);
generateConfigOption("settings.performance-monitoring.task-reporting.print-on-slow-tasks.info", "Print to console when a task takes longer than the specified time in milliseconds. It isn't recommended to set this any lower then 10ms to prevent console spam.");
generateConfigOption("settings.performance-monitoring.task-reporting.print-on-slow-tasks.enabled", true);
generateConfigOption("settings.performance-monitoring.task-reporting.print-on-slow-tasks.value", 100); // Default to two Minecraft tick
//Packet Events
generateConfigOption("settings.packet-events.enabled", false);
generateConfigOption("settings.packet-events.info", "This setting causes the server to fire a Bukkit event for each packet received and sent to a player once they have finished the initial login process. This only needs to be enabled if you have a plugin that uses this specific feature.");
// generateConfigOption("settings.bukkit-event.disabled-plugin-unregister.value", true);
// generateConfigOption("settings.bukkit-event.disabled-plugin-unregister.info", "This setting will automatically unregister listeners from disabled plugins. This is useful if you have a plugin that can get disabled at runtime and you want to prevent errors to the disabled plugin.");
generateConfigOption("settings.packet-spam-detection.enabled", true);
generateConfigOption("settings.packet-spam-detection.info", "This setting causes the server to detect and kick malicious players who send too many packets in a short period of time. This is useful to prevent players from sending too many packets to the server to cause lag.");
generateConfigOption("settings.packet-spam-detection.threshold", 10000);
//Statistics
generateConfigOption("settings.statistics.key", UUID.randomUUID().toString());
generateConfigOption("settings.statistics.enabled", true);
//World Settings
generateConfigOption("world-settings.optimized-explosions", false);
generateConfigOption("world-settings.send-explosion-velocity", true);
generateConfigOption("world-settings.randomize-spawn", true);
generateConfigOption("world-settings.teleport-to-highest-safe-block", true);
generateConfigOption("world-settings.use-modern-fence-bounding-boxes", false);
//TODO: Actually implement the tree growth functionality stuff
generateConfigOption("world.settings.block-tree-growth.enabled", true);
generateConfigOption("world.settings.block-tree-growth.list", "54,63,68");
generateConfigOption("world.settings.block-tree-growth.info", "This setting allows for server owners to easily block trees growing from automatically destroying certain blocks. The list must be a string with numerical item ids separated by commas.");
generateConfigOption("world.settings.block-pistons-pushing-furnaces.info", "This workaround prevents pistons from pushing furnaces which prevents a malicious server crash.");
generateConfigOption("world.settings.block-pistons-pushing-furnaces.enabled", true);
generateConfigOption("world.settings.pistons.transmutation-fix.enabled", true);
generateConfigOption("world.settings.pistons.transmutation-fix.info", "This setting fixes block transmutation exploits.");
generateConfigOption("world.settings.pistons.sand-gravel-duping-fix.enabled", true);
generateConfigOption("world.settings.pistons.sand-gravel-duping-fix.info", "This setting fixes sand/gravel duplication exploits.");
generateConfigOption("world.settings.pistons.other-fixes.enabled", true);
generateConfigOption("world.settings.pistons.other-fixes.info", "This setting fixes various other piston exploits like creating illegal pistons, breaking bedrock and duplicating redstone torches.");
generateConfigOption("world.settings.skeleton-shooting-sound-fix.info", "This setting fixes the sound of skeletons and players shooting not playing on clients.");
generateConfigOption("world.settings.skeleton-shooting-sound-fix.enabled", true);
generateConfigOption("world.settings.speed-hack-check.enable", true);
generateConfigOption("world.settings.speed-hack-check.teleport", true);
generateConfigOption("world.settings.speed-hack-check.distance", 100.0D);
generateConfigOption("world.settings.speed-hack-check.info", "This setting allows you to configure the automatic speedhack detection.");
generateConfigOption("world.settings.flowing-lava-fix.enabled", true);
generateConfigOption("world.settings.flowing-lava-fix.info", "This setting fixes flowing lava not disappearing when the source block is removed.");
//Mob Spawner Area Limit (8 chunks)
generateConfigOption("world.settings.mob-spawner-area-limit.enable", true);
generateConfigOption("world.settings.mob-spawner-area-limit.limit", 150);
generateConfigOption("world.settings.mob-spawner-area-limit.chunk-radius", 8);
generateConfigOption("world.settings.mob-spawner-area-limit.info",
"This setting controls the maximum number of entities of a mob spawner type that can exist within the defined chunk radius around a mob spawner. If the number of entities exceeds this limit, the spawner will stop spawning additional entities of that type. This is useful to stop the extreme lag that can be caused by mob spawners.");
//generateConfigOption("world-settings.eject-from-vehicle-on-teleport.enabled", true);
//generateConfigOption("world-settings.eject-from-vehicle-on-teleport.info", "Eject the player from a boat or minecart before teleporting them preventing cross world coordinate exploits.");
//Release2Beta Settings
generateConfigOption("settings.release2beta.enable-ip-pass-through", false);
generateConfigOption("settings.release2beta.proxy-ip", "127.0.0.1");
//BungeeCord
generateConfigOption("settings.bungeecord.bungee-mode.enable", false);
generateConfigOption("settings.bungeecord.bungee-mode.kick-message", "You must connect through BungeeCord to join this server!");
generateConfigOption("settings.bungeecord.bungee-mode.info", "Only allows connections via BungeeCord to join. Includes optional custom kick message for players not using BungeeCord.");
//Modded Jar Support
generateConfigOption("settings.support.modloader.enable", false);
generateConfigOption("settings.support.modloader.info", "EXPERIMENTAL support for ModloaderMP.");
//Offline Username Check
generateConfigOption("settings.check-username-validity.enabled", true);
generateConfigOption("settings.check-username-validity.info", "If enabled, verifies the validity of a usernames of cracked players.");
generateConfigOption("settings.check-username-validity.regex", "[a-zA-Z0-9_.]*");
generateConfigOption("settings.check-username-validity.max-length", 16);
generateConfigOption("settings.check-username-validity.min-length", 3);
generateConfigOption("emergency.debug.regenerate-corrupt-chunks.enable", false);
generateConfigOption("emergency.debug.regenerate-corrupt-chunks.info", "This setting allows you to automatically regenerate corrupt chunks. This is useful after a ungraceful shutdown while a file is being written to or out of memory exception.");
generateConfigOption("settings.update-checker.enabled", true);
generateConfigOption("settings.update-checker.info", "This setting allows you to disable the update checker. This is useful if you have a custom build of Poseidon or don't want to be notified of updates.");
generateConfigOption("settings.update-checker.notify-staff.enabled", true);
generateConfigOption("settings.update-checker.notify-staff.info", "This setting notifies operators and players with the permission poseidon.update when a new version of Poseidon is available on join.");
generateConfigOption("settings.update-checker.notify-if-up-to-date.enabled", false);
generateConfigOption("settings.update-checker.notify-if-up-to-date.info", "This setting controls if the update checker will print a message in console if the server is up to date.");
generateConfigOption("settings.update-checker.interval.ticks", 20 * 60 * 60);
generateConfigOption("settings.update-checker.interval.info", "Controls how often the update checker will query the latest Poseidon version");
//Messages
generateConfigOption("message.kick.banned", "You are banned from this server!");
generateConfigOption("message.kick.ip-banned", "Your IP address is banned from this server!");
generateConfigOption("message.kick.not-whitelisted", "You are not white-listed on this server!");
generateConfigOption("message.kick.full", "The server is full!");
generateConfigOption("message.kick.shutdown", "\u00A7cServer is shutting down, please rejoin later.");
generateConfigOption("message.kick.already-online", "\u00A7cA player with your username or uuid is already online, try reconnecting in a minute.");
generateConfigOption("message.player.join", "\u00A7e%player% joined the game.");
generateConfigOption("message.player.leave", "\u00A7e%player% left the game.");
generateConfigOption("message.update.available", "\u00A7dA newer version of Poseidon is available: %newversion%");
//Optional Poseidon Commands
generateConfigOption("command.info", "This section allows you to enable or disable optional Poseidon commands. This is useful if you have a plugin that conflicts with a Poseidon command.");
generateConfigOption("command.tps.info", "Enables the /tps command to show the server's TPS for various intervals.");
generateConfigOption("command.tps.enabled", true);
//UberBukkit
generateConfigOption("fix.optimize-sponges.enabled", true);
generateConfigOption("fix.optimize-sponges.info", "Optimizes sponges by removing unnecessary block updates. This can also prevent some block duplication methods.");
//Tree Leave Destroy Blacklist
if (Boolean.valueOf(String.valueOf(getConfigOption("world.settings.block-tree-growth.enabled", true)))) {
if (String.valueOf(this.getConfigOption("world.settings.block-tree-growth.list", "")).trim().isEmpty()) {
//Empty Blacklist
} else {
String[] rawBlacklist = String.valueOf(this.getConfigOption("world.settings.block-tree-growth.list", "")).trim().split(",");
int blackListCount = 0;
for (String stringID : rawBlacklist) {
if (Pattern.compile("-?[0-9]+").matcher(stringID).matches()) {
blackListCount = blackListCount + 1;
} else {
System.out.println("The ID " + stringID + " for leaf decay blocker has been detected as invalid, and won't be used.");
}
}
//Loop a second time to get correct array length. I know this is horrible code, but it works and only runs on server startup.
treeBlacklistIDs = new Integer[blackListCount];
int i = 0;
for (String stringID : rawBlacklist) {
if (Pattern.compile("-?[0-9]+").matcher(stringID).matches()) {
treeBlacklistIDs[i] = Integer.valueOf(stringID);
i = i + 1;
}
}
System.out.println("Leaf blocks can't replace the following block IDs: " + Arrays.toString(treeBlacklistIDs));
}
} else {
treeBlacklistIDs = new Integer[0];
}
}
private void generateConfigOption(String key, Object defaultValue) {
if (this.getProperty(key) == null) {
this.setProperty(key, defaultValue);
}
final Object value = this.getProperty(key);
this.removeProperty(key);
this.setProperty(key, value);
}
//Getters Start
public Object getConfigOption(String key) {
return this.getProperty(key);
}
public Object getConfigOption(String key, Object defaultValue) {
Object value = getConfigOption(key);
if (value == null) {
value = defaultValue;
}
return value;
}
public String getConfigString(String key) {
return String.valueOf(getConfigOption(key));
}
public Integer getConfigInteger(String key) {
return Integer.valueOf(getConfigString(key));
}
public Long getConfigLong(String key) {
return Long.valueOf(getConfigString(key));
}
public Double getConfigDouble(String key) {
return Double.valueOf(getConfigString(key));
}
public Boolean getConfigBoolean(String key) {
return Boolean.valueOf(getConfigString(key));
}
public Boolean getConfigBoolean(String key, Boolean defaultValue) {
Boolean value = getConfigBoolean(key);
if (value == null) {
System.out.println("[Poseidon] Config: " + key + " does not exist. Using default value: " + defaultValue);
System.out.println("[Poseidon] Config: This is likely the result of an error. Please report this to the developer.");
value = defaultValue;
}
return value;
}
//Getters End
private void convertToNewConfig() {
// 1- 2/3 Conversion
convertToNewAddress("settings.statistics.enabled", "settings.enable-statistics");
convertToNewAddress("settings.allow-graceful-uuids", "allowGracefulUUID");
convertToNewAddress("settings.save-playerdata-by-uuid", "savePlayerdataByUUID");
convertToNewAddress("settings.watchdog.enable", "settings.enable-watchdog");
// 3-4 Conversion
// Don't automatically enable the latest log file for servers that have the per-day-logfile setting enabled as this is a change in behavior
if (this.getString("settings.per-day-logfile") != null && this.getConfigBoolean("settings.per-day-logfile")) {
this.setProperty("settings.per-day-log-file.latest-log.enabled", false);
}
convertToNewAddress("settings.per-day-log-file.enabled", "settings.per-day-logfile");
// 4-5 Conversion
convertToNewAddress("settings.uuid-fetcher.post.value", "settings.fetch-uuids-from");
if (this.getString("settings.uuid-fetcher.post.value", "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname").equals("https://api.mojang.com/profiles/minecraft")) {
System.out.println("[Poseidon] Config: settings.fetch-uuids-from is set to the default value (" + this.getString("settings.uuid-fetcher.post.value") + "). Changing to the new default value (https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname)");
this.setProperty("settings.uuid-fetcher.post.value", "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname");
}
boolean usePost = !this.getConfigBoolean("settings.use-get-for-uuids.enabled", false); // Is the server currently using POST?
if (usePost) {
this.setProperty("settings.uuid-fetcher.method.value", "POST");
} else {
this.setProperty("settings.uuid-fetcher.method.value", "GET");
}
removeDeprecatedConfig("settings.use-get-for-uuids.enabled", "settings.use-get-for-uuids.info");
convertToNewAddress("settings.uuid-fetcher.allow-graceful-uuids.value", "settings.allow-graceful-uuids");
convertToNewAddress("settings.uuid-fetcher.get.enforce-case-sensitivity.enabled", "settings.use-get-for-uuids.case-sensitive.enabled");
removeDeprecatedConfig("settings.use-get-for-uuids.case-sensitive.info");
}
//Allow any number of string arguments to be passed to this method
private boolean removeDeprecatedConfig(String... keys) {
boolean removed = false;
for (String key : keys) {
if (this.getString(key) != null) {
System.out.println("[Poseidon] Config: " + key + " is deprecated. Removing.");
this.removeProperty(key);
removed = true;
}
}
return removed;
}
private boolean convertToNewAddress(String newKey, String oldKey) {
if (this.getString(newKey) != null) {
return false;
}
if (this.getString(oldKey) == null) {
System.out.println("[Poseidon] Config: " + oldKey + " does not exist. Skipping conversion.");
return false;
}
System.out.println("[Poseidon] Converting Config: " + oldKey + " to " + newKey);
Object value = this.getProperty(oldKey);
this.setProperty(newKey, value);
this.removeProperty(oldKey);
return true;
}
public synchronized static PoseidonConfig getInstance() {
if (PoseidonConfig.singleton == null) {
PoseidonConfig.singleton = new PoseidonConfig();
}
return PoseidonConfig.singleton;
}
}
@@ -0,0 +1,91 @@
package com.legacyminecraft.poseidon;
import com.avaje.ebean.EbeanServer;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginLoader;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.config.Configuration;
import java.io.File;
public class PoseidonPlugin implements Plugin {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
return false;
}
@Override
public File getDataFolder() {
return null;
}
@Override
public PluginDescriptionFile getDescription() {
return null;
}
@Override
public Configuration getConfiguration() {
return null;
}
@Override
public PluginLoader getPluginLoader() {
return null;
}
@Override
public Server getServer() {
return null;
}
@Override
public boolean isEnabled() {
return false;
}
@Override
public void onDisable() {
}
@Override
public void onLoad() {
}
@Override
public void onEnable() {
}
@Override
public boolean isNaggable() {
return false;
}
@Override
public void setNaggable(boolean canNag) {
}
@Override
public EbeanServer getDatabase() {
return null;
}
@Override
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
return null;
}
}
@@ -0,0 +1,247 @@
package com.legacyminecraft.poseidon;
import com.legacyminecraft.poseidon.utility.PerformanceStatistic;
import com.legacyminecraft.poseidon.utility.PoseidonVersionChecker;
import com.legacyminecraft.poseidon.watchdog.WatchDogThread;
import com.projectposeidon.johnymuffin.UUIDManager;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.NetServerHandler;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftServer;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
public final class PoseidonServer {
private final MinecraftServer server;
private final CraftServer craftServer;
private final List<String> hiddenCommands = new ArrayList<>();
private final Properties versionProperties = new Properties();
private boolean serverInitialized = false;
private PoseidonVersionChecker poseidonVersionChecker;
private WatchDogThread watchDogThread;
private Map<String, PerformanceStatistic> listenerPerformance = new HashMap<String, PerformanceStatistic>();
private Map<String, PerformanceStatistic> taskPerformance = new HashMap<String, PerformanceStatistic>();
private PoseidonConfig config;
public PoseidonServer(MinecraftServer server, CraftServer craftServer) {
this.server = server;
this.craftServer = craftServer;
this.config = PoseidonConfig.getInstance();
loadVersionProperties();
addHiddenCommands(Arrays.asList("login", "l", "register", "reg", "unregister", "changepassword", "changepw"));
}
private void loadVersionProperties() {
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("version.properties")) {
if (inputStream != null) {
versionProperties.load(inputStream);
}
} catch (IOException e) {
getLogger().warning("Failed to load version.properties: " + e.getMessage());
}
}
public void initializeServer() {
if (serverInitialized) {
throw new UnsupportedOperationException("Server already initialized");
}
getLogger().info("[Poseidon] Starting Project Poseidon Modules!");
PoseidonConfig.getInstance();
UUIDManager.getInstance();
initializeUpdateChecker();
//Start Watchdog
watchDogThread = new WatchDogThread(Thread.currentThread());
if (PoseidonConfig.getInstance().getBoolean("settings.watchdog.enable", true)) {
getLogger().info("[Poseidon] Starting Watchdog to detect any server hangs!");
watchDogThread.start();
watchDogThread.tickUpdate();
}
serverInitialized = true;
getLogger().info("[Poseidon] Finished loading Project Poseidon Modules!");
}
private void initializeUpdateChecker() {
if (!PoseidonConfig.getInstance().getConfigBoolean("settings.update-checker.enabled", true)) {
getLogger().info("[Poseidon] Version checker disabled. The server will not check for updates.");
return;
}
String releaseVersion = getReleaseVersion();
if (releaseVersion == null) {
getLogger().warning("[Poseidon] Version checker is disabled as no version.properties file was found.");
return;
}
if (!getBuildType().equalsIgnoreCase("production")) {
getLogger().warning("[Poseidon] Version checker is disabled as this is a " + getBuildType() + " build. The updater will only check for updates on production builds.");
return;
}
poseidonVersionChecker = new PoseidonVersionChecker(craftServer, releaseVersion);
getLogger().info("[Poseidon] Version checker enabled. The server will check for updates every hour.");
// Run the version checker in a separate thread every hour
Bukkit.getScheduler().scheduleAsyncRepeatingTask(new PoseidonPlugin(), new Runnable() {
@Override
public void run() {
poseidonVersionChecker.fetchLatestVersion();
}
}, 0, PoseidonConfig.getInstance().getConfigLong("settings.update-checker.interval.ticks"));
}
public void shutdownServer() {
if (!serverInitialized) {
// throw new UnsupportedOperationException("Server not initialized");
return;
}
getLogger().info("[Poseidon] Stopping Project Poseidon Modules!");
UUIDManager.getInstance().saveJsonArray();
if (watchDogThread != null) {
getLogger().info("[Poseidon] Stopping Watchdog!");
watchDogThread.interrupt();
}
serverInitialized = false;
getLogger().info("[Poseidon] Finished unloading Project Poseidon Modules!");
}
public Logger getLogger() {
return MinecraftServer.log;
}
public String getAppName() {
return versionProperties.getProperty("app_name", "Unknown");
}
public String getReleaseVersion() {
return versionProperties.getProperty("release_version", "Unknown");
}
public String getMavenVersion() {
return versionProperties.getProperty("maven_version", "Unknown");
}
public String getBuildTimestamp() {
return versionProperties.getProperty("build_timestamp", "Unknown");
}
public String getGitCommit() {
return versionProperties.getProperty("git_commit", "Unknown");
}
public String getBuildType() {
return versionProperties.getProperty("build_type", "Unknown");
}
public boolean isUpdateAvailable() {
return poseidonVersionChecker != null && poseidonVersionChecker.isUpdateAvailable();
}
public String getNewestVersion() {
return poseidonVersionChecker == null ? "Unknown" : poseidonVersionChecker.getLatestVersion();
}
public WatchDogThread getWatchDogThread() {
return watchDogThread;
}
/**
* Returns the current hide state of the command from param (Hide from console)
*
* @param cmdName Command name
* @return True if the command from param is hidden and false otherwise
*/
public boolean isCommandHidden(String cmdName) {
return hiddenCommands.contains(cmdName.toLowerCase());
}
/**
* Hides the command from param from being logged to server console
*
* @param cmd Command name
*/
public void addHiddenCommand(String cmd) {
cmd = cmd.toLowerCase();
if (hiddenCommands.contains(cmd)) {
Logger.getLogger(NetServerHandler.class.getName()).warning("List of Hidden commands already contains " + cmd);
return;
}
hiddenCommands.add(cmd);
}
/**
* Hides the commands from param from being logged to server console
*
* @param commands List of command names
*/
public void addHiddenCommands(List<String> commands) {
for (String cmd : commands) {
addHiddenCommand(cmd);
}
}
public Map<String, PerformanceStatistic> getListenerPerformance() {
return listenerPerformance;
}
public Map<String, PerformanceStatistic> getTaskPerformance() {
return taskPerformance;
}
// Generic method to sort any performance map
public Map<String, PerformanceStatistic> getSortedPerformance(Map<String, PerformanceStatistic> unsortedMap) {
return unsortedMap.entrySet()
.stream()
.sorted(Map.Entry.<String, PerformanceStatistic>comparingByValue(
Comparator.comparingLong(PerformanceStatistic::getAverageExecutionTime).reversed()
))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1, // if same key, keep the first
LinkedHashMap::new
));
}
// Specific method to get sorted listener performance
public Map<String, PerformanceStatistic> getSortedListenerPerformance() {
return getSortedPerformance(getListenerPerformance());
}
// Specific method to get sorted task performance
public Map<String, PerformanceStatistic> getSortedTaskPerformance() {
return getSortedPerformance(getTaskPerformance());
}
public PoseidonConfig getConfig() {
return config;
}
}
@@ -0,0 +1,104 @@
package com.legacyminecraft.poseidon;
import net.minecraft.server.MinecraftServer;
import org.bukkit.craftbukkit.CraftServer;
import org.json.simple.JSONObject;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Random;
public class PoseidonStatisticsAgent {
//Default details
private int protocolID = 1;
public final String postTo = "https://poseidon.johnymuffin.com/statistics.php";
//Unique Details
private String uniqueID;
private final String sessionID;
private final String version;
private final String branch;
private final Long startTime;
private Object syncLock = new Object();
public PoseidonStatisticsAgent(MinecraftServer server, CraftServer craftServer) {
//This really shouldn't be needed, but it runs once, whats the harm?
synchronized (syncLock) {
this.startTime = (System.currentTimeMillis() / 1000L);
this.uniqueID = PoseidonConfig.getInstance().getString("settings.statistics.key");
//Create temp value
Random rnd = new Random();
this.sessionID = String.valueOf(100000 + rnd.nextInt(900000));
this.version = craftServer.getPoseidonVersion();
this.branch = craftServer.getPoseidonReleaseType();
}
PoseidonStatisticsSender poseidonStatisticsSender = new PoseidonStatisticsSender();
poseidonStatisticsSender.start();
}
public JSONObject getPing() {
synchronized (syncLock) {
JSONObject ping = new JSONObject();
ping.put("protocol", protocolID);
ping.put("uniqueID", uniqueID);
ping.put("sessionID", sessionID);
ping.put("version", version);
ping.put("branch", branch);
int uptime = (int) ((System.currentTimeMillis() / 1000L) - startTime);
ping.put("uptime", uptime);
return ping;
}
}
public class PoseidonStatisticsSender extends Thread {
public volatile boolean errored = false;
public void run() {
while (true && !this.isInterrupted()) {
HttpURLConnection connection = null;
try {
System.out.println("Submitting Project Poseidon Statistics.");
final JSONObject ping = getPing();
URL url = new URL(postTo);
//Create Connection
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
//Write Body
OutputStream stream = connection.getOutputStream();
stream.write(ping.toJSONString().getBytes());
stream.flush();
stream.close();
//Get Response
String response = String.valueOf(new InputStreamReader(connection.getInputStream()));
connection.disconnect();
errored = false;
} catch (Exception exception) {
if (!errored) {
System.out.println("Failed to submit statistics for Project Poseidon. " + exception + " : " + exception.getMessage() + ".");
}
errored = true;
} finally {
if (connection != null) {
connection.disconnect();
connection = null;
}
try {
Thread.sleep(300000L);
} catch (InterruptedException exception) {
System.out.println("Project Poseidon statistics thread has been closed.");
break;
}
}
}
}
}
}
@@ -0,0 +1,105 @@
package com.legacyminecraft.poseidon.commands;
import com.legacyminecraft.poseidon.Poseidon;
import com.projectposeidon.api.PoseidonUUID;
import com.projectposeidon.api.UUIDType;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Properties;
import java.util.UUID;
public class PoseidonCommand extends Command {
private final Properties versionProperties = new Properties();
public PoseidonCommand(String name) {
super(name);
this.description = "Show data regarding the server's version of Project Poseidon";
this.usageMessage = "/poseidon";
this.setAliases(Arrays.asList("projectposeidon"));
}
@Override
public boolean execute(CommandSender sender, String currentAlias, String[] args) {
if (args.length >= 1 && args[0].equalsIgnoreCase("resolve")) {
String[] subArgs = Arrays.copyOfRange(args, 1, args.length);
ResolveCommand resolver = new ResolveCommand("resolve");
return resolver.execute(sender, "resolve", subArgs);
}
if (args.length == 0) {
String appName = Poseidon.getServer().getAppName();
String releaseVersion = Poseidon.getServer().getReleaseVersion();
String mavenVersion = Poseidon.getServer().getMavenVersion();
String buildTimestamp = Poseidon.getServer().getBuildTimestamp();
String gitCommit = Poseidon.getServer().getGitCommit();
String buildType = Poseidon.getServer().getBuildType();
// Shorten the git commit hash to 7 characters
if (gitCommit.length() > 7) {
gitCommit = gitCommit.substring(0, 7);
}
if ("Unknown".equals(releaseVersion)) {
sender.sendMessage(ChatColor.RED + "Warning: version.properties not found. This is a local or unconfigured build.");
} else {
sender.sendMessage(ChatColor.GRAY + "This server is running " + ChatColor.AQUA + appName + ChatColor.GRAY + ":");
sender.sendMessage(ChatColor.GRAY + " - Version: " + ChatColor.YELLOW + releaseVersion);
sender.sendMessage(ChatColor.GRAY + " - Built at: " + ChatColor.YELLOW + buildTimestamp);
sender.sendMessage(ChatColor.GRAY + " - Git SHA: " + ChatColor.YELLOW + gitCommit);
if ("production".equalsIgnoreCase(buildType)) {
sender.sendMessage(ChatColor.GREEN + "This is a release build.");
} else if ("pull_request".equalsIgnoreCase(buildType)) {
sender.sendMessage(ChatColor.BLUE + "This is a pull request build.");
} else {
sender.sendMessage(ChatColor.GRAY + "This is a development build.");
}
}
} else if (args.length == 1) {
if (args[0].equalsIgnoreCase("uuid")) {
sender.sendMessage(ChatColor.GRAY + "Please specify a user /poseidon uuid (username)");
} else {
sender.sendMessage(ChatColor.GRAY + "Unknown sub command.");
}
} else {
if (!args[0].equalsIgnoreCase("uuid")) {
sender.sendMessage(ChatColor.GRAY + "Unknown sub command.");
} else {
UUID uuid = PoseidonUUID.getPlayerUUIDFromCache(args[1], true);
if (uuid == null) {
uuid = PoseidonUUID.getPlayerUUIDFromCache(args[1], false);
}
if (uuid == null) {
sender.sendMessage(ChatColor.GRAY + "Unable to locate the UUID of the player called: " + ChatColor.WHITE + args[1] + ChatColor.GRAY + ". Please remember usernames are cap sensitive");
} else {
String latestUsername = PoseidonUUID.getPlayerUsernameFromUUID(uuid);
sender.sendMessage(ChatColor.GRAY + "Username: " + latestUsername);
sender.sendMessage(ChatColor.GRAY + "UUID: " + uuid.toString());
UUIDType uuidType = PoseidonUUID.getPlayerUUIDCacheStatus(args[1]);
if (uuidType.equals(UUIDType.ONLINE)) {
sender.sendMessage(ChatColor.GRAY + "UUID Type: " + ChatColor.GREEN + "Online");
} else if (uuidType.equals(UUIDType.OFFLINE)) {
sender.sendMessage(ChatColor.GRAY + "UUID Type: " + ChatColor.RED + "Offline");
} else {
sender.sendMessage(ChatColor.GRAY + "UUID Type: " + ChatColor.DARK_RED + "UNKNOWN");
}
}
}
}
return true;
}
}
@@ -0,0 +1,137 @@
package com.legacyminecraft.poseidon.commands;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.command.SimpleCommandMap;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Field;
import java.util.Map;
public class ResolveCommand extends Command {
public ResolveCommand(String name) {
super(name);
this.description = "Find out what plugin a command belongs to";
this.usageMessage = "/poseidon resolve <command>";
this.setPermission("poseidon.command.resolve");
}
@Override
public boolean execute(CommandSender sender, String currentAlias, String[] args) {
if (!testPermission(sender)) return true;
if (args.length == 0) {
sender.sendMessage(ChatColor.RED + "Usage: /poseidon resolve <command>");
return true;
}
String targetCommand = args[0].toLowerCase();
if (targetCommand.startsWith("/")) {
targetCommand = targetCommand.substring(1);
}
// Try to find the command in the server's command map
Command cmd = Bukkit.getServer().getPluginCommand(targetCommand);
if (cmd != null && cmd instanceof PluginCommand) {
displayPluginCommand(sender, (PluginCommand) cmd, targetCommand);
return true;
}
// If not found as PluginCommand, search through all known commands
try {
SimpleCommandMap commandMap = getCommandMap();
if (commandMap == null) {
sender.sendMessage(ChatColor.RED + "Unable to access command map.");
return true;
}
Field knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands");
knownCommandsField.setAccessible(true);
@SuppressWarnings("unchecked")
Map<String, Command> knownCommands = (Map<String, Command>) knownCommandsField.get(commandMap);
for (Map.Entry<String, Command> entry : knownCommands.entrySet()) {
if (entry.getKey().equalsIgnoreCase(targetCommand) ||
entry.getValue().getName().equalsIgnoreCase(targetCommand)) {
Command foundCmd = entry.getValue();
if (foundCmd instanceof PluginCommand) {
displayPluginCommand(sender, (PluginCommand) foundCmd, targetCommand);
return true;
} else {
displayServerCommand(sender, foundCmd, targetCommand);
return true;
}
}
}
} catch (Exception e) {
sender.sendMessage(ChatColor.RED + "Error while searching for command: " + e.getMessage());
return true;
}
sender.sendMessage(ChatColor.RED + "Command '" + targetCommand + "' not found.");
sender.sendMessage(ChatColor.YELLOW + "Note: The command might not be registered or might be case-sensitive.");
return true;
}
private void displayPluginCommand(CommandSender sender, PluginCommand pluginCmd, String targetCommand) {
Plugin plugin = pluginCmd.getPlugin();
sender.sendMessage(ChatColor.GREEN + "Command: " + ChatColor.WHITE + "/" + targetCommand);
sender.sendMessage(ChatColor.GREEN + "Plugin: " + ChatColor.WHITE + plugin.getDescription().getName());
sender.sendMessage(ChatColor.GREEN + "Author: " + ChatColor.WHITE + plugin.getDescription().getAuthors());
sender.sendMessage(ChatColor.GREEN + "Version: " + ChatColor.WHITE + plugin.getDescription().getVersion());
if (pluginCmd.getAliases() != null && !pluginCmd.getAliases().isEmpty()) {
sender.sendMessage(ChatColor.GREEN + "Aliases: " + ChatColor.WHITE +
String.join(", ", pluginCmd.getAliases()));
}
if (pluginCmd.getDescription() != null && !pluginCmd.getDescription().isEmpty()) {
sender.sendMessage(ChatColor.GREEN + "Description: " + ChatColor.WHITE +
pluginCmd.getDescription());
}
}
private void displayServerCommand(CommandSender sender, Command cmd, String targetCommand) {
sender.sendMessage(ChatColor.GREEN + "Command: " + ChatColor.WHITE + "/" + targetCommand);
sender.sendMessage(ChatColor.AQUA + "Source: " + ChatColor.WHITE + "Server (Poseidon/Bukkit)");
if (!cmd.getAliases().isEmpty()) {
sender.sendMessage(ChatColor.GREEN + "Aliases: " + ChatColor.WHITE +
String.join(", ", cmd.getAliases()));
}
if (cmd.getDescription() != null && !cmd.getDescription().isEmpty()) {
sender.sendMessage(ChatColor.GREEN + "Description: " + ChatColor.WHITE +
cmd.getDescription());
}
if (cmd.getPermission() != null && !cmd.getPermission().isEmpty()) {
sender.sendMessage(ChatColor.GREEN + "Permission: " + ChatColor.WHITE +
cmd.getPermission());
}
}
@SuppressWarnings("CatchMayIgnoreException")
private SimpleCommandMap getCommandMap() {
try {
if (Bukkit.getServer() instanceof CraftServer) {
CraftServer craftServer = (CraftServer) Bukkit.getServer();
Field commandMapField = CraftServer.class.getDeclaredField("commandMap");
commandMapField.setAccessible(true);
return (SimpleCommandMap) commandMapField.get(craftServer);
}
} catch (Exception e) {
}
return null;
}
}
@@ -0,0 +1,75 @@
package com.legacyminecraft.poseidon.commands;
import com.legacyminecraft.poseidon.Poseidon;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.defaults.VanillaCommand;
import java.util.LinkedList;
import java.util.LinkedHashMap;
import java.util.Map;
public class TPSCommand extends Command {
private final LinkedHashMap<String, Integer> intervals = new LinkedHashMap<>();
public TPSCommand(String name) {
super(name);
this.description = "Shows the server's TPS for various intervals";
this.usageMessage = "/tps";
this.setPermission("poseidon.command.tps");
// Define the intervals for TPS calculation
intervals.put("5s", 5);
intervals.put("30s", 30);
intervals.put("1m", 60);
intervals.put("5m", 300);
intervals.put("10m", 600);
intervals.put("15m", 900);
}
@Override
public boolean execute(CommandSender sender, String currentAlias, String[] args) {
if (!testPermission(sender)) return true;
LinkedList<Double> tpsRecords = Poseidon.getTpsRecords();
StringBuilder message = new StringBuilder("§bServer TPS: ");
// Calculate and format TPS for each interval dynamically
for (Map.Entry<String, Integer> entry : intervals.entrySet()) {
double averageTps = calculateAverage(tpsRecords, entry.getValue());
message.append(formatTps(averageTps)).append(" (").append(entry.getKey()).append("), ");
}
// Remove the trailing comma and space
if (message.length() > 0) {
message.setLength(message.length() - 2);
}
sender.sendMessage(message.toString());
return true;
}
private double calculateAverage(LinkedList<Double> records, int seconds) {
int size = Math.min(records.size(), seconds);
if (size == 0) return 20.0;
double total = 0;
for (int i = 0; i < size; i++) {
total += records.get(i);
}
return total / size;
}
private String formatTps(double tps) {
String colorCode;
if (tps >= 19) {
colorCode = "§a";
} else if (tps >= 15) {
colorCode = "§e";
} else {
colorCode = "§c";
}
return colorCode + String.format("%.2f", tps);
}
}
@@ -0,0 +1,54 @@
package com.legacyminecraft.poseidon.event;
import org.bukkit.entity.Entity;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public class PlayerDeathEvent extends EntityDeathEvent {
private String deathMessage = "";
private boolean keepInventory = false;
public PlayerDeathEvent(Entity what, List<ItemStack> drops) {
super(what, drops);
}
/**
* Set the death message that will appear to everyone on the server.
*
* @param deathMessage Message to appear to other players on the server.
*/
public void setDeathMessage(String deathMessage) {
this.deathMessage = deathMessage;
}
/**
* Get the death message that will appear to everyone on the server.
*
* @return Message to appear to other players on the server.
*/
public String getDeathMessage() {
return deathMessage;
}
/**
* Sets if the Player keeps inventory on death.
*
* @param keepInventory True to keep the inventory
*/
public void setKeepInventory(boolean keepInventory) {
this.keepInventory = keepInventory;
}
/**
* Gets if the Player keeps inventory on death.
*
* @return True if the player keeps inventory on death
*/
public boolean getKeepInventory() {
return keepInventory;
}
}
@@ -0,0 +1,46 @@
package com.legacyminecraft.poseidon.event;
import net.minecraft.server.Packet;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.player.PlayerEvent;
public class PlayerPacketEvent extends Event implements Cancellable {
private boolean cancel;
private Packet packet;
private String username;
public PlayerPacketEvent(Type type, String username, Packet packet) {
super(type);
this.cancel = false;
this.packet = packet;
this.username = username;
}
@Override
public boolean isCancelled() {
return cancel;
}
public int getPacketID() {
return packet.b();
}
public Packet getPacket() {
return packet;
}
public void setPacket(Packet packet) {
this.packet = packet;
}
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
public String getUsername() {
return username;
}
}
@@ -0,0 +1,9 @@
package com.legacyminecraft.poseidon.event;
import net.minecraft.server.Packet;
public class PlayerReceivePacketEvent extends PlayerPacketEvent {
public PlayerReceivePacketEvent(String username, Packet packet) {
super(Type.PLAYER_RECEIVE_PACKET, username, packet);
}
}
@@ -0,0 +1,10 @@
package com.legacyminecraft.poseidon.event;
import net.minecraft.server.Packet;
public class PlayerSendPacketEvent extends PlayerPacketEvent {
public PlayerSendPacketEvent(String username, Packet packet) {
super(Type.PLAYER_SEND_PACKET, username, packet);
}
}
@@ -0,0 +1,6 @@
package com.legacyminecraft.poseidon.event;
import org.bukkit.event.Listener;
public interface PoseidonCustomListener extends Listener {
}
@@ -0,0 +1,64 @@
package com.legacyminecraft.poseidon.packets;
import net.minecraft.server.NetHandler;
import net.minecraft.server.Packet;
import net.minecraft.server.World;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class ArtificialPacket53BlockChange extends Packet {
public int a;
public int b;
public int c;
public int material;
public int data;
public ArtificialPacket53BlockChange() {
this.k = true;
}
public ArtificialPacket53BlockChange(int i, int j, int k, World world) {
this.k = true;
this.a = i;
this.b = j;
this.c = k;
this.material = world.getTypeId(i, j, k);
this.data = world.getData(i, j, k);
}
public ArtificialPacket53BlockChange(int i, int j, int k, int materialType, int data) {
this.k = true;
this.a = i;
this.b = j;
this.c = k;
this.material = materialType;
this.data = data;
}
public void a(DataInputStream datainputstream) throws IOException {
this.a = datainputstream.readInt();
this.b = datainputstream.read();
this.c = datainputstream.readInt();
this.material = datainputstream.read();
this.data = datainputstream.read();
}
public void a(DataOutputStream dataoutputstream) throws IOException {
dataoutputstream.writeInt(this.a);
dataoutputstream.write(this.b);
dataoutputstream.writeInt(this.c);
dataoutputstream.write(this.material);
dataoutputstream.write(this.data);
}
public void a(NetHandler nethandler) {
nethandler.a(this);
}
public int a() {
return 11;
}
}
@@ -0,0 +1,128 @@
package com.legacyminecraft.poseidon.util;
import com.legacyminecraft.poseidon.PoseidonConfig;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.UUID;
import java.util.regex.Pattern;
import static com.projectposeidon.johnymuffin.UUIDManager.generateOfflineUUID;
public class GetUUIDFetcher {
public static class UUIDAndUsernameResult {
private UUIDResult uuidResult;
private String returnedUsername;
public UUIDAndUsernameResult(UUIDResult uuidResult, String returnedUsername) {
this.uuidResult = uuidResult;
this.returnedUsername = returnedUsername;
}
public UUIDResult getUuidResult() {
return uuidResult;
}
public String getReturnedUsername() {
return returnedUsername;
}
}
public static UUIDAndUsernameResult getUUID(String username) {
try {
String url = PoseidonConfig.getInstance().getString("settings.uuid-fetcher.get.value", "https://api.minecraftservices.com/minecraft/profile/lookup/name/{username}");
url = url.replace("{username}", encode(username));
JSONObject jsonObject = readJsonFromUrl(url);
UUIDResult uuidResult;
String returnedUsername = null;
if (!jsonObject.containsKey("id")) {
uuidResult = new UUIDResult(generateOfflineUUID(username), UUIDResult.ReturnType.OFFLINE);
} else {
UUID uuid = toUUIDWithDashes(String.valueOf(jsonObject.get("id")));
if (uuid == null) {
uuidResult = new UUIDResult(null, UUIDResult.ReturnType.API_OFFLINE);
} else {
returnedUsername = String.valueOf(jsonObject.get("name"));
uuidResult = new UUIDResult(uuid, UUIDResult.ReturnType.ONLINE);
}
}
return new UUIDAndUsernameResult(uuidResult, returnedUsername);
} catch (Exception exception) {
UUIDResult uuidResult = null;
if (exception == null || exception instanceof FileNotFoundException || exception.getMessage() == null) {
// This is a hacky solution to tell if the API is offline, or the user is cracked.
uuidResult = new UUIDResult(generateOfflineUUID(username), UUIDResult.ReturnType.OFFLINE);
} else {
uuidResult = new UUIDResult(null, UUIDResult.ReturnType.API_OFFLINE);
uuidResult.setException(exception);
}
return new UUIDAndUsernameResult(uuidResult, null);
}
}
public static String encode(String string) {
try {
return URLEncoder.encode(string, "UTF-8");
} catch (UnsupportedEncodingException e) {
return string;
}
}
public static UUID toUUIDWithDashes(String uuid) {
return UUID.fromString(uuid.replaceFirst("(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5"));
}
public static boolean verifyJSONArguments(JSONObject jsonObject, String... arguments) {
for (String s : arguments) {
if (!jsonObject.containsKey(s)) return false;
}
return true;
}
public static boolean isURL(String url) {
try {
new URL(url);
return true;
} catch (Exception e) {
return false;
}
}
public static boolean validUUID(String uuid) {
return Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$").matcher(uuid).matches();
}
private static String readAll(Reader rd) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp);
}
return sb.toString();
}
private static JSONObject readJsonFromUrl(String url) throws IOException, ParseException {
InputStream is = new URL(url).openStream();
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
String jsonText = readAll(rd);
JSONParser jsp = new JSONParser();
JSONObject json = (JSONObject) jsp.parse(jsonText);
return json;
} finally {
is.close();
}
}
}
@@ -0,0 +1,23 @@
package com.legacyminecraft.poseidon.util;
public class HTTPResponse
{
private String response;
private int responseCode;
public HTTPResponse(String response, int responseCode)
{
this.response = response;
this.responseCode = responseCode;
}
public String getResponse()
{
return response;
}
public int getResponseCode()
{
return responseCode;
}
}
@@ -0,0 +1,53 @@
package com.legacyminecraft.poseidon.util;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
public class Release2Beta {
public static long serializeAddress(SocketAddress address) {
String str = address.toString();
String[] parts = str.split(":");
String realAddress = parts[0].substring(1); // remove '/'
return ipToLong(realAddress);
}
public static InetSocketAddress deserializeAddress(long spoofedAddress) {
String realAddress = longToIp(spoofedAddress);
return new InetSocketAddress(realAddress, 0);
}
//Credit: https://mkyong.com/java/java-convert-ip-address-to-decimal-number/
public static long ipToLong(String ipAddress) {
// ipAddressInArray[0] = 192
String[] ipAddressInArray = ipAddress.split("\\.");
long result = 0;
for (int i = 0; i < ipAddressInArray.length; i++) {
int power = 3 - i;
int ip = Integer.parseInt(ipAddressInArray[i]);
// 1. 192 * 256^3
// 2. 168 * 256^2
// 3. 1 * 256^1
// 4. 2 * 256^0
result += ip * Math.pow(256, power);
}
return result;
}
//Credit: https://mkyong.com/java/java-convert-ip-address-to-decimal-number/
private static String longToIp(long i) {
return ((i >> 24) & 0xFF) +
"." + ((i >> 16) & 0xFF) +
"." + ((i >> 8) & 0xFF) +
"." + (i & 0xFF);
}
}
@@ -0,0 +1,150 @@
package com.legacyminecraft.poseidon.util;
import org.bukkit.Bukkit;
import com.legacyminecraft.poseidon.PoseidonPlugin;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import java.util.logging.*;
public class ServerLogRotator {
private final String latestLogFileName;
private final Logger logger;
public ServerLogRotator(String latestLogFileName) {
this.latestLogFileName = latestLogFileName;
this.logger = Logger.getLogger("Minecraft");
}
/**
* Checks if the date in the log line is today's date
* @param date The date in the log line. Format: "yyyy-MM-dd"
* @return True if the date in the log line is today's date, false otherwise
*/
private boolean isToday(String date) {
String[] dateParts = date.split("-");
LocalDateTime logLineDateTime = LocalDateTime.of(Integer.parseInt(dateParts[0]), Integer.parseInt(dateParts[1]), Integer.parseInt(dateParts[2]), 0, 0, 0);
LocalDateTime now = LocalDateTime.now();
return logLineDateTime.getYear() == now.getYear() && logLineDateTime.getMonthValue() == now.getMonthValue() && logLineDateTime.getDayOfMonth() == now.getDayOfMonth();
}
/**
* Archives a log line to a log file with the same date as the date in the log line
* @param parts The log line to archive to a log file haven been split already e.g. ["2024-03-20", "13:02:27", "[INFO]", "This is a log message..."]
*/
private void archiveLine(String[] parts) {
try {
String date = parts[0];
String time = parts[1];
String logLevel = parts[2];
String message = String.join(" ", Arrays.copyOfRange(parts, 3, parts.length));
// check if a log file with this information already exists
File logFile = new File("." + File.separator + "logs" + File.separator + date + ".log");
if (!logFile.exists()) {
logFile.createNewFile();
}
// append the log line to the log file with the same date as the date in the log line
FileWriter fileWriter = new FileWriter(logFile, true);
PrintWriter writer = new PrintWriter(fileWriter);
writer.println(date + " " + time + " " + logLevel + " " + message);
writer.close();
// catch any exceptions that occur during the process, and log them. IOExceptions are possible when calling createNewFile()
} catch (IOException e) {
logger.log(Level.SEVERE, "[Poseidon] Failed to create new log file!");
logger.log(Level.SEVERE, e.toString());
}
}
/**
* Builds historical logs from the latest.log file. Logs from today's date are kept in the latest.log file, while logs from previous dates are archived to log files with the same date as the date in the log line.
* Note that if latest.log contains logs from multiple days, the logs will be split by date and archived to the appropriate log files.
*/
private void buildHistoricalLogsFromLatestLogFile() {
logger.log(Level.INFO, "[Poseidon] Building logs from latest.log...");
try {
// open latest log file
File latestLog = new File("." + File.separator + "logs" + File.separator + this.latestLogFileName + ".log");
if (!latestLog.exists()) {
logger.log(Level.INFO, "[Poseidon] No logs to build from latest.log!");
return;
}
// split the contents of the latest log file by line (and strip the newline character)
String content = new String(Files.readAllBytes(latestLog.toPath()));
String[] lines = content.split("\n");
// create a StringBuilder to store today's logs (to write back to latest.log after archiving the rest of the logs)
StringBuilder todayLogs = new StringBuilder();
for (String line : lines) {
String[] splitLine = line.split(" ");
if (splitLine.length < 3) { // all lines will start with a date, time, and log level e.g. "2024-03-20 13:02:27 [INFO]"
continue;
}
// make sure the first index is a date
if (!splitLine[0].matches("\\d{4}-\\d{2}-\\d{2}")) {
continue;
}
// if the log line is of today's date, do not archive it (ignore times)
if (isToday(splitLine[0])) {
todayLogs.append(line).append("\n");
continue;
}
// archive the log line to a log file with the same date as the date in the log line
archiveLine(splitLine);
}
// clear latest.log and write back today's logs from the StringBuilder
FileWriter fileWriter = new FileWriter(latestLog);
PrintWriter writer = new PrintWriter(fileWriter);
writer.print(todayLogs);
writer.close();
logger.log(Level.INFO, "[Poseidon] Logs built from latest.log!");
// catch any exceptions that occur during the process, and log them
} catch (Exception e) {
logger.log(Level.SEVERE, "[Poseidon] Failed to build logs from latest.log!");
logger.log(Level.SEVERE, e.toString());
}
}
public void start() {
// Calculate the initial delay and period for the log rotation task
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime nextRun = now.withHour(0).withMinute(0).withSecond(0).withNano(0);
if(now.compareTo(nextRun) > 0)
nextRun = nextRun.plusDays(1);
Duration duration = Duration.between(now, nextRun);
long initialDelay = duration.getSeconds();
long period = TimeUnit.DAYS.toSeconds(1);
// do log rotation immediately upon startup to ensure that logs are archived correctly.
buildHistoricalLogsFromLatestLogFile();
// Schedule the log rotation task to run every day at midnight offset by one second to avoid missing logs
logger.log(Level.INFO, "[Poseidon] Log rotation task scheduled for run in " + initialDelay + " seconds, and then every " + period + " seconds.");
logger.log(Level.INFO, "[Poseidon] If latest.log contains logs from earlier, not previously archived dates, they will be archived to the appropriate log files " +
"upon first run of the log rotation task. If log files already exist for these dates, the logs will be appended to the existing log files!");
Bukkit.getScheduler().scheduleAsyncRepeatingTask(new PoseidonPlugin(), this::buildHistoricalLogsFromLatestLogFile, (initialDelay + 1) * 20, period * 20);
}
}
@@ -0,0 +1,75 @@
package com.legacyminecraft.poseidon.util;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* A wrapper class for the Minecraft session API
*
* TODO maybe make the HTTP requests asynchronous? idk if it really matters
*
* @author moderator_man
*/
public class SessionAPI
{
public static final String SESSION_BASE = "http://session.minecraft.net/game/";
public static boolean hasJoined(String username, String serverId)
{
HTTPResponse response = httpGetRequest(SESSION_BASE + String.format("checkserver.jsp?user=%s&serverId=%s", username, serverId));
if (response.getResponse() != "YES")
return false;
return true;
}
public static void hasJoined(String username, String serverId, String ip, SessionRequestRunnable callback)
{
try
{
boolean checkIP = ip == "127.0.0.1" || ip == "localhost";
StringBuilder sb = new StringBuilder();
sb.append(System.getProperty("minecraft.api.session.host", "https://sessionserver.mojang.com") + "/session/minecraft/hasJoined");
sb.append("?username=" + username);
sb.append("&serverId=" + serverId);
if (checkIP)
sb.append("&ip=" + ip);
String requestUrl = sb.toString();
HTTPResponse response = httpGetRequest(requestUrl);
JSONObject obj = (JSONObject) new JSONParser().parse(response.getResponse());
String res_username = (obj.containsKey("name") ? (String) obj.get("name") : "nousername");
String res_uuid = (obj.containsKey("id") ? (String) obj.get("id") : "nouuid");
String res_ip = (obj.containsKey("ip") ? (String) obj.get("ip") : "noip");
callback.callback(response.getResponseCode(), res_username, res_uuid, res_ip);
} catch (Exception ex) {
System.out.println(String.format("Failed to authenticate session for '%s': %s", username, ex.getMessage()));
// TODO: if debug, print the stack trace
}
}
private static HTTPResponse httpGetRequest(String url)
{
try
{
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Project-Poseidon/0");
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null)
response.append(inputLine);
in.close();
return new HTTPResponse(response.toString(), con.getResponseCode());
} catch (Exception ex) {
ex.printStackTrace();
return new HTTPResponse("", -1);
}
}
}
@@ -0,0 +1,6 @@
package com.legacyminecraft.poseidon.util;
public interface SessionRequestRunnable
{
public void callback(int responseCode, String username, String uuid, String ip);
}
@@ -0,0 +1,97 @@
package com.legacyminecraft.poseidon.util;
import com.google.common.collect.ImmutableList;
import com.legacyminecraft.poseidon.PoseidonConfig;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.Callable;
public class UUIDFetcher implements Callable<Map<String, UUID>> {
private static final double PROFILES_PER_REQUEST = 100;
private static final String PROFILE_URL = PoseidonConfig.getInstance().getString("settings.uuid-fetcher.post.value", "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname");
private final JSONParser jsonParser = new JSONParser();
private final List<String> names;
private final boolean rateLimiting;
public UUIDFetcher(List<String> names, boolean rateLimiting) {
this.names = ImmutableList.copyOf(names);
this.rateLimiting = rateLimiting;
}
public UUIDFetcher(List<String> names) {
this(names, true);
}
public Map<String, UUID> call() throws Exception {
Map<String, UUID> uuidMap = new HashMap<String, UUID>();
int requests = (int) Math.ceil(names.size() / PROFILES_PER_REQUEST);
for (int i = 0; i < requests; i++) {
HttpURLConnection connection = createConnection();
String body = JSONArray.toJSONString(names.subList(i * 100, Math.min((i + 1) * 100, names.size())));
writeBody(connection, body);
JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream()));
for (Object profile : array) {
JSONObject jsonProfile = (JSONObject) profile;
String id = (String) jsonProfile.get("id");
String name = (String) jsonProfile.get("name");
UUID uuid = UUIDFetcher.getUUID(id);
uuidMap.put(name, uuid);
}
if (rateLimiting && i != requests - 1) {
Thread.sleep(100L);
}
}
return uuidMap;
}
private static void writeBody(HttpURLConnection connection, String body) throws Exception {
OutputStream stream = connection.getOutputStream();
stream.write(body.getBytes());
stream.flush();
stream.close();
}
private static HttpURLConnection createConnection() throws Exception {
URL url = new URL(PROFILE_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
return connection;
}
private static UUID getUUID(String id) {
return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" +id.substring(20, 32));
}
public static byte[] toBytes(UUID uuid) {
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
byteBuffer.putLong(uuid.getMostSignificantBits());
byteBuffer.putLong(uuid.getLeastSignificantBits());
return byteBuffer.array();
}
public static UUID fromBytes(byte[] array) {
if (array.length != 16) {
throw new IllegalArgumentException("Illegal byte array length: " + array.length);
}
ByteBuffer byteBuffer = ByteBuffer.wrap(array);
long mostSignificant = byteBuffer.getLong();
long leastSignificant = byteBuffer.getLong();
return new UUID(mostSignificant, leastSignificant);
}
public static UUID getUUIDOf(String name) throws Exception {
return new UUIDFetcher(Arrays.asList(name)).call().get(name);
}
}
@@ -0,0 +1,37 @@
package com.legacyminecraft.poseidon.util;
import java.util.UUID;
public class UUIDResult {
private final UUID uuid;
private final ReturnType returnType;
private Exception exception;
public UUIDResult(UUID uuid, ReturnType returnType) {
this.uuid = uuid;
this.returnType = returnType;
}
public UUID getUuid() {
return uuid;
}
public ReturnType getReturnType() {
return returnType;
}
public Exception getException() {
return exception;
}
public void setException(Exception exception) {
this.exception = exception;
}
public enum ReturnType {
ONLINE,
OFFLINE,
API_OFFLINE
}
}
@@ -0,0 +1,50 @@
package com.legacyminecraft.poseidon.utility;
public class PerformanceStatistic {
private long minTime = Long.MAX_VALUE;
private long maxTime = 0;
private long totalTime = 0;
private long count = 0;
// Update the stats with a new execution time
public void update(long duration) {
if (duration < minTime) {
minTime = duration;
}
if (duration > maxTime) {
maxTime = duration;
}
totalTime += duration;
count++;
}
// Retrieve the average execution time
long getAverageTime() {
return count > 0 ? totalTime / count : 0;
}
// Print the statistics for this listener
public String printStats() {
return String.format("Called: %d times, Min: %dms, Avg: %dms, Max: %dms", count, minTime, getAverageTime(), maxTime);
}
public long getEventCount() {
return count;
}
public long getTotalExecutionTime() {
return totalTime;
}
public long getAverageExecutionTime() {
return getAverageTime();
}
public long getMinExecutionTime() {
return minTime;
}
public long getMaxExecutionTime() {
return maxTime;
}
}
@@ -0,0 +1,96 @@
package com.legacyminecraft.poseidon.utility;
import com.legacyminecraft.poseidon.PoseidonConfig;
import org.bukkit.craftbukkit.CraftServer;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
public class PoseidonVersionChecker {
private static final String GITHUB_API_URL = "https://api.github.com/repos/retromcorg/Project-Poseidon/releases/latest";
private static final String releaseUrl = "https://github.com/retromcorg/Project-Poseidon/releases";
private final String currentVersion;
private volatile String latestVersion;
private CraftServer server;
public PoseidonVersionChecker(CraftServer server, String currentVersion) {
this.currentVersion = currentVersion;
this.latestVersion = currentVersion; // Assume the latest version is the current version until checked
this.server = server;
}
/**
* Checks if a new version is available.
*
* @return true if a newer version is available, false otherwise.
*/
public synchronized boolean isUpdateAvailable() {
return latestVersion != null && !currentVersion.equalsIgnoreCase(latestVersion);
}
/**
* Fetches the latest release version from GitHub API.
*
* @return the latest version as a String or null if fetching fails.
*/
public void fetchLatestVersion() {
HttpURLConnection connection = null;
try {
URL url = new URL(GITHUB_API_URL);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/json");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
int responseCode = connection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
server.getLogger().log(Level.WARNING, "[Poseidon] Failed to check GitHub for latest version. HTTP Response Code: " + responseCode);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
JSONParser parser = new JSONParser();
JSONObject json = (JSONObject) parser.parse(response.toString());
this.latestVersion = (String) json.get("tag_name");
if (isUpdateAvailable()) {
server.getLogger().log(Level.INFO, "[Poseidon] A new version is available: " + latestVersion);
server.getLogger().log(Level.INFO, "[Poseidon] You are currently running version: " + currentVersion);
server.getLogger().log(Level.INFO, "[Poseidon] Download the latest version here: " + releaseUrl);
} else {
if (PoseidonConfig.getInstance().getConfigBoolean("settings.update-checker.notify-if-up-to-date.enabled"))
server.getLogger().log(Level.INFO, "[Poseidon] You are running the latest version (" + currentVersion + ") of Project Poseidon.");
}
} catch (Exception e) {
server.getLogger().log(Level.WARNING, "[Poseidon] Failed to check GitHub for latest version.", e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
public String getCurrentVersion() {
return currentVersion;
}
public String getLatestVersion() {
return latestVersion;
}
}
@@ -0,0 +1,117 @@
package com.legacyminecraft.poseidon.uuid;
import com.legacyminecraft.poseidon.PoseidonConfig;
import com.legacyminecraft.poseidon.util.GetUUIDFetcher;
import com.legacyminecraft.poseidon.util.UUIDResult;
import com.projectposeidon.johnymuffin.LoginProcessHandler;
import net.minecraft.server.Packet1Login;
import org.bukkit.ChatColor;
import java.util.UUID;
import static com.legacyminecraft.poseidon.util.UUIDFetcher.getUUIDOf;
import static com.projectposeidon.johnymuffin.UUIDManager.generateOfflineUUID;
public class ThreadUUIDFetcher extends Thread {
final Packet1Login loginPacket;
// final NetLoginHandler netLoginHandler;
final LoginProcessHandler loginProcessHandler;
final boolean useGetMethod;
public ThreadUUIDFetcher(Packet1Login packet1Login, LoginProcessHandler loginProcessHandler, boolean useGetMethod) {
// this.netLoginHandler = netloginhandler; // The login handler
this.loginProcessHandler = loginProcessHandler;
this.loginPacket = packet1Login; // The login packet
this.useGetMethod = useGetMethod;
}
public void run() {
if (PoseidonConfig.getInstance().getBoolean("settings.uuid-fetcher.always-use-graceful-uuids.enabled", false)) {
System.out.println("[Poseidon] Skipping UUID fetching since always-use-graceful-uuids is enabled, " + loginPacket.name + " will use offline UUID.");
UUID offlineUUID = generateOfflineUUID(loginPacket.name);
loginProcessHandler.userUUIDReceived(offlineUUID, false);
return;
} else if (useGetMethod) {
getMethod();
} else {
postMethod();
}
}
public void getMethod() {
UUIDResult uuidResult;
GetUUIDFetcher.UUIDAndUsernameResult uuidAndUsernameResult = GetUUIDFetcher.getUUID(loginPacket.name);
uuidResult = uuidAndUsernameResult.getUuidResult();
if (uuidResult.getReturnType().equals(UUIDResult.ReturnType.ONLINE) && uuidAndUsernameResult.getReturnedUsername().equals(loginPacket.name)) {
System.out.println("[Poseidon] Fetched UUID from Mojang for " + loginPacket.name + " using GET - " + uuidResult.getUuid().toString());
loginProcessHandler.userUUIDReceived(uuidResult.getUuid(), true);
return;
} else if (uuidResult.getReturnType().equals(UUIDResult.ReturnType.ONLINE)) {
if(PoseidonConfig.getInstance().getConfigBoolean("settings.uuid-fetcher.get.enforce-case-sensitivity.enabled")) {
System.out.println("[Poseidon] Fetched UUID from Mojang for " + loginPacket.name + " using GET - " + uuidResult.getUuid().toString() + " however, the username returned was " + uuidAndUsernameResult.getReturnedUsername() + ". The user has been kicked as the server is configured to use case sensitive usernames");
loginProcessHandler.cancelLoginProcess(ChatColor.RED + "Sorry, that username has invalid casing");
return;
} else {
System.out.println("[Poseidon] Fetched UUID from Mojang for " + loginPacket.name + " - " + uuidResult.getUuid().toString());
loginProcessHandler.userUUIDReceived(uuidResult.getUuid(), true);
return;
}
} else if (uuidResult.getReturnType().equals(UUIDResult.ReturnType.OFFLINE)) {
if ((boolean) PoseidonConfig.getInstance().getProperty("settings.uuid-fetcher.allow-graceful-uuids.value")) {
System.out.println("[Poseidon] " + loginPacket.name + " does not have a Mojang UUID associated with their name");
UUID offlineUUID = uuidResult.getUuid();
loginProcessHandler.userUUIDReceived(offlineUUID, false);
System.out.println("[Poseidon] Using Offline Based UUID for " + loginPacket.name + " - " + offlineUUID);
} else {
System.out.println("[Poseidon] " + loginPacket.name + " does not have a UUID with Mojang. Player has been kicked as graceful UUID is disabled");
loginProcessHandler.cancelLoginProcess(ChatColor.RED + "Sorry, we only support premium accounts");
}
return;
}
System.out.println("[Poseidon] Failed to fetch UUID for " + loginPacket.name + " using GET method from Mojang.");
System.out.println("[Poseidon] Mojang's API may be offline, your internet connection may be down, or something else may be wrong.");
uuidResult.getException().printStackTrace();
loginProcessHandler.cancelLoginProcess(ChatColor.RED + "Sorry, we can't connect to Mojang currently, please try again later");
}
public void postMethod() {
UUID uuid;
try {
uuid = getUUIDOf(loginPacket.name);
if (uuid == null) {
if (PoseidonConfig.getInstance().getConfigBoolean("settings.uuid-fetcher.allow-graceful-uuids.value", true)) {
System.out.println("[Poseidon] " + loginPacket.name + " does not have a Mojang UUID associated with their name");
UUID offlineUUID = generateOfflineUUID(loginPacket.name);
loginProcessHandler.userUUIDReceived(offlineUUID, false);
System.out.println("[Poseidon] Using Offline Based UUID for " + loginPacket.name + " - " + offlineUUID);
} else {
System.out.println("[Poseidon] " + loginPacket.name + " does not have a UUID with Mojang. Player has been kicked as graceful UUID is disabled");
loginProcessHandler.cancelLoginProcess(ChatColor.RED + "Sorry, we only support premium accounts");
}
} else {
System.out.println("[Poseidon] Fetched UUID from Mojang for " + loginPacket.name + " using POST - " + uuid.toString());
loginProcessHandler.userUUIDReceived(uuid, true);
}
} catch (Exception e) {
System.out.println("[Poseidon] Mojang failed contact for user " + loginPacket.name + ":");
System.out.println("[Poseidon] If this issue persists, please utilize the GET method. Mojang's API frequently has issues with POST requests.");
System.out.println("[Poseidon] You can do this by changing settings.uuid-fetcher.method.value to GET in the config");
e.printStackTrace();
loginProcessHandler.cancelLoginProcess(ChatColor.RED + "Sorry, we can't connect to Mojang currently, please try again later");
}
}
}
@@ -0,0 +1,72 @@
package com.legacyminecraft.poseidon.watchdog;
import com.legacyminecraft.poseidon.PoseidonConfig;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
public class WatchDogThread extends Thread {
private int count = 0;
private Long lastTick = System.currentTimeMillis() / 1000L;
private volatile AtomicBoolean tickOccurred = new AtomicBoolean(true);
private Thread serverThread;
private final int killTimeout;
//Debug Timeout
private final boolean debugTimeoutEnabled;
private final int debugTimeout;
private boolean printedDebug;
public WatchDogThread(Thread thread) {
this.serverThread = thread;
this.killTimeout = PoseidonConfig.getInstance().getConfigInteger("settings.watchdog.timeout.value");
this.debugTimeoutEnabled = PoseidonConfig.getInstance().getConfigBoolean("settings.watchdog.debug-timeout.enabled");
this.debugTimeout = PoseidonConfig.getInstance().getConfigInteger("settings.watchdog.debug-timeout.value");
}
public void run() {
boolean running = true;
while (true && !this.isInterrupted() && running) {
try {
if (tickOccurred.get()) {
lastTick = System.currentTimeMillis() / 1000L;
tickOccurred.set(false);
printedDebug = false; //Set back tp false so if server hangs again debug is printed.
} else {
//Server timout check
if ((lastTick + killTimeout) < (System.currentTimeMillis() / 1000L)) {
System.out.println("[Poseidon-Watchdog] Server has hanged. Killing the process as a result of the watchdog timeout being exceeded.");
System.out.println("--------------------[Stacktrace For Developers]--------------------");
Arrays.asList(serverThread.getStackTrace()).forEach(System.out::println);
System.out.println("-------------------------------------------------------------------");
Runtime.getRuntime().halt(0);
} else {
System.out.println("[Poseidon-Watchdog] A server tick hasn't occurred in " + ((int) ((System.currentTimeMillis() / 1000L) - lastTick)) + " seconds.");
//Server debug timeout
if((lastTick + debugTimeout) < (System.currentTimeMillis() / 1000L) && debugTimeoutEnabled && !printedDebug) {
System.out.println("[Poseidon-Watchdog] Server hang detected. Printing debug as debug timeout has been exceeded.");
System.out.println("--------------------[Stacktrace For Developers]--------------------");
Arrays.asList(serverThread.getStackTrace()).forEach(System.out::println);
System.out.println("-------------------------------------------------------------------");
printedDebug = true; //This variable prevents debug from printing multiple times during a single tick.
}
}
}
Thread.sleep(3000L);
} catch (InterruptedException e) {
System.out.println("[Poseidon-Watchdog] The watchdog has been interrupted.");
// e.printStackTrace();
running = false;
}
}
}
public void tickUpdate() {
tickOccurred.set(true);
}
public boolean isHangDetected() {
return tickOccurred.get();
}
}
@@ -0,0 +1,11 @@
package com.projectposeidon;
public enum ConnectionType {
NORMAL,
RELEASE2BETA,
RELEASE2BETA_ONLINE_MODE_IP_FORWARDING,
RELEASE2BETA_OFFLINE_MODE_IP_FORWARDING,
BUNGEECORD,
BUNGEECORD_OFFLINE_MODE_IP_FORWARDING,
BUNGEECORD_ONLINE_MODE_IP_FORWARDING,
}
+2
View File
@@ -0,0 +1,2 @@
We will no longer store classes under the name of the developer who created it. Current legacy stuff may stay in its current position tho.
All new classes must be created under com.legacyminecraft.poseidon
@@ -0,0 +1,71 @@
package com.projectposeidon.api;
import com.projectposeidon.johnymuffin.UUIDManager;
import java.util.UUID;
public final class PoseidonUUID {
private PoseidonUUID() {
}
/**
* @param username Username of a player who has connected
* @return A Mojang UUID if known, otherwise null
*/
public static UUID getPlayerMojangUUID(String username) {
return UUIDManager.getInstance().getUUIDFromUsername(username, true);
}
/**
* @param username Username of a player who has connected
* @return A Mojang UUID if known, otherwise a offline uuid
*/
public static UUID getPlayerGracefulUUID(String username) {
return UUIDManager.getInstance().getUUIDGraceful(username);
}
/**
* Get a UUID of a player IF they have joined before.
*
* @param username Username of a player who has connected
* @param onlineUUID Search for online or offline UUIDs?
* @return Returns a UUID if known in cache, otherwise null
*/
public static UUID getPlayerUUIDFromCache(String username, boolean onlineUUID) {
return UUIDManager.getInstance().getUUIDFromUsername(username, onlineUUID);
}
/**
* @param username Username of a player
* @return A offline UUID for a player
*/
public static UUID getPlayerOfflineUUID(String username) {
return UUIDManager.generateOfflineUUID(username);
}
/**
* @param username Username of a player
* @return A UUIDType enum.
*/
public static UUIDType getPlayerUUIDCacheStatus(String username) {
if (getPlayerUUIDFromCache(username, true) != null) {
return UUIDType.ONLINE;
}
if (getPlayerUUIDFromCache(username, false) != null) {
return UUIDType.OFFLINE;
}
return UUIDType.UNKNOWN;
}
/**
* @param uuid UUID for a player
* @return A corresponding username if known, otherwise null
*/
public static String getPlayerUsernameFromUUID(UUID uuid) {
return UUIDManager.getInstance().getUsernameFromUUID(uuid);
}
}
@@ -0,0 +1,9 @@
package com.projectposeidon.api;
public enum UUIDType {
//I was not sure about the coding conventions regarding capitalization. I have followed the ALL caps example in the Java Docs: https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
ONLINE,
OFFLINE,
UNKNOWN
}
@@ -0,0 +1,72 @@
package com.projectposeidon.johnymuffin;
public class ConnectionPause {
private String pluginName;
private String connectionPauseName;
private LoginProcessHandler loginProcessHandler;
private long creationTime;
private long completionTime;
private boolean active;
public ConnectionPause(String PluginName, String connectionPauseName, LoginProcessHandler loginProcessHandler) {
this.pluginName = PluginName;
this.connectionPauseName = connectionPauseName;
this.loginProcessHandler = loginProcessHandler;
this.creationTime = System.currentTimeMillis();
this.active = true;
}
/**
* This method is still undecided, please don't use it in production.
*/
public void removeConnectionPause() {
loginProcessHandler.removeConnectionPause(this);
}
public String getPluginName() {
return this.pluginName;
}
public String getConnectionPauseName() {
return this.connectionPauseName;
}
public long getCreationTime() {
return creationTime;
}
public boolean isActive() {
return active;
}
/**
* This method is for Poseidon, not plugin use. DON'T TOUCH THIS IF YOU DON'T KNOW WHAT YOU ARE DOING.
*/
public void setActive(boolean active) {
if(!active)
this.completionTime = System.currentTimeMillis();
this.active = active;
}
public int getRunningTime() {
int running;
if (active) {
running = (int) (System.currentTimeMillis() - creationTime);
} else {
running = (int) (completionTime - creationTime);
}
running = running / 1000;
return running;
}
public LoginProcessHandler getLoginProcessHandler() {
return loginProcessHandler;
}
public long getCompletionTime() {
return completionTime;
}
}
@@ -0,0 +1,381 @@
package com.projectposeidon.johnymuffin;
import com.legacyminecraft.poseidon.PoseidonConfig;
import com.legacyminecraft.poseidon.PoseidonPlugin;
import com.legacyminecraft.poseidon.uuid.ThreadUUIDFetcher;
import net.minecraft.server.NetLoginHandler;
import net.minecraft.server.Packet1Login;
import net.minecraft.server.ThreadLoginVerifier;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerConnectionInitializationEvent;
import org.bukkit.event.player.PlayerPreLoginEvent;
import org.bukkit.plugin.Plugin;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.UUID;
public class LoginProcessHandler {
private NetLoginHandler netLoginHandler;
private final Packet1Login packet1Login;
private CraftServer server;
private boolean onlineMode;
private boolean loginCancelled = false;
private LoginProcessHandler loginProcessHandler;
private boolean loginSuccessful = false;
private long startTime;
private HashSet<ConnectionPause> connectionPauses = new HashSet<ConnectionPause>();
private final String msgKickAlreadyOnline;
public LoginProcessHandler(NetLoginHandler netloginhandler, Packet1Login packet1login, CraftServer server, boolean onlineMode) {
this.loginProcessHandler = this;
this.netLoginHandler = netloginhandler;
this.packet1Login = packet1login;
this.server = server;
this.onlineMode = onlineMode;
this.msgKickAlreadyOnline = PoseidonConfig.getInstance().getConfigString("message.kick.already-online");
processAuthentication();
long connectionStartTime = System.currentTimeMillis() / 1000L;
runLoginTimer(connectionStartTime);
}
private void runLoginTimer(long connectionStartTime) {
Bukkit.getScheduler().scheduleAsyncDelayedTask(new PoseidonPlugin(), () -> {
int currentRunningTime = (int) (System.currentTimeMillis() / 1000L - connectionStartTime);
if (!loginSuccessful && !loginCancelled) {
//This if statement shouldn't be needed, but this is here just in case a players login fails but the appropriate variables aren't changed
System.out.println("[Poseidon] The login process for " + packet1Login.name + " is still running. It has been running for " + currentRunningTime + " seconds. The following plugins are still currently pausing the login process: " + getConnectionPauseNames(true));
//Cancel the login process if it has been running for more than 20 seconds.
if (currentRunningTime >= 20) {
cancelLoginProcess("Login Process Handler Timeout");
System.out.println("[Poseidon] LoginProcessHandler for user " + packet1Login.name + " has failed to respond after 20 seconds. And future calls to this class will result in error");
System.out.println("[Poseidon] Plugin Pauses: " + getConnectionPauseNames(true));
}
if (currentRunningTime < 60) {
runLoginTimer(connectionStartTime);
}
}
}, 20 * 5);
}
private void processAuthentication() {
PlayerConnectionInitializationEvent event = new PlayerConnectionInitializationEvent(this.packet1Login.name, this.netLoginHandler.getSocket().getInetAddress(), loginProcessHandler);
this.server.getPluginManager().callEvent(event);
if (loginCancelled) {
return;
}
if (onlineMode) {
//Server is running online mode
verifyMojangSession();
} else {
//Server is not running online mode
getUserUUID();
}
}
private void getUserUUID() {
//UUID uuid = UUIDManager.getInstance().getUUIDFromUsername(packet1Login.name, true);
long unixTime = (System.currentTimeMillis() / 1000L);
UUID uuid = UUIDManager.getInstance().getUUIDFromUsername(packet1Login.name, true, unixTime);
if (uuid == null) {
boolean useGetMethod = PoseidonConfig.getInstance().getString("settings.uuid-fetcher.method.value", "POST").equalsIgnoreCase("GET");
(new ThreadUUIDFetcher(packet1Login, this, useGetMethod)).start();
} else {
System.out.println("[Poseidon] Fetched UUID from Cache for " + packet1Login.name + " - " + uuid.toString());
connectPlayer(uuid);
}
}
public synchronized void userUUIDReceived(UUID uuid, boolean onlineMode) {
if (!onlineMode) {
if (Boolean.valueOf(String.valueOf(PoseidonConfig.getInstance().getConfigOption("settings.check-username-validity.enabled", true))) && !isUsernameValid()) {
//Username is invalid, and is a cracked user
return;
}
}
// Connect the player based on their mode
if(onlineMode) {
// Handle saving the UUID for online mode user here
long unixTime = (System.currentTimeMillis() / 1000L) + 1382400;
UUIDManager.getInstance().receivedUUID(packet1Login.name, uuid, unixTime, onlineMode);
connectPlayerPremium(uuid);
} else {
// Handle saving the UUID for cracked user inside connectPlayerCracked method as it may need to be modified
connectPlayerCracked(uuid);
}
}
public void connectPlayerPremium(UUID uuid) {
connectPlayer(uuid);
}
public void connectPlayerCracked(UUID uuid) {
// Append . to the start of the username if not already present and generate offline UUID based on that
String username = this.packet1Login.name;
if (Boolean.valueOf(String.valueOf(PoseidonConfig.getInstance().getConfigOption("settings.check-username-validity.enabled", true))) && !isUsernameValid()) {
//Username is invalid, and is a cracked user
return;
}
boolean prefixDot = PoseidonConfig.getInstance().getConfigBoolean("settings.cracked-username-prefix.enabled", false);
if(prefixDot) {
if (!username.startsWith(".")) {
System.out.println("[Poseidon] Adding . prefix to cracked user " + username + "'s username");
username = "." + username;
}
// Rename the player to have the . prefix
this.packet1Login.name = username;
netLoginHandler.updateUsername(username);
}
UUID offlineUUID = UUIDManager.generateOfflineUUID(username);
// Add new UUID entry for cracked user
long expiresOn = (System.currentTimeMillis() / 1000L) + 1382400;
UUIDManager.getInstance().receivedUUID(username, offlineUUID, expiresOn, false);
connectPlayer(offlineUUID);
}
//This function is only run if the user is cracked
public boolean isUsernameValid() {
String username = this.packet1Login.name;
// Ensure the username length is valid
int minimumLength = Integer.valueOf(String.valueOf(PoseidonConfig.getInstance().getConfigOption("settings.check-username-validity.min-length", 3)));
int maximumLength = Integer.valueOf(String.valueOf(PoseidonConfig.getInstance().getConfigOption("settings.check-username-validity.max-length", 16)));
if (username.length() < minimumLength) {
cancelLoginProcess("Sorry, your username is too short. The minimum length is: " + minimumLength);
return false;
}
// Remove the . prefix for validation if it exists and the server is configured to use it.
boolean prefixDot = PoseidonConfig.getInstance().getConfigBoolean("settings.cracked-username-prefix.enabled", false);
boolean dotAdded = false;
if(prefixDot) {
if (username.startsWith(".")) {
username = username.substring(1);
dotAdded = true;
}
}
if (username.length() > maximumLength) {
cancelLoginProcess("Sorry, your username is too long. The maximum length is: " + (dotAdded ? (maximumLength - 1) : maximumLength)); // Adjust max length if dot was automatically added
return false;
}
if (username.isEmpty()) {
cancelLoginProcess("Sorry, you don't have a username, messing with MC?????");
return false;
}
String regex = String.valueOf(PoseidonConfig.getInstance().getConfigOption("settings.check-username-validity.regex", "[a-zA-Z0-9_?]*"));
if (!username.matches(regex)) {
cancelLoginProcess("Sorry, your username is invalid, allowed characters: " + regex);
return false;
}
return true;
}
private void verifyMojangSession() {
if (!loginSuccessful & !loginCancelled) {
(new ThreadLoginVerifier(this, netLoginHandler, this.packet1Login, this.server)).start(); // CraftBukkit
}
}
public synchronized void userMojangSessionVerified() {
if (!loginSuccessful & !loginCancelled) {
getUserUUID();
}
}
private void connectPlayer(UUID uuid) {
String username = packet1Login.name;
//Check if a player with the same UUID or Username is already online which is mainly an issue in Offline Mode servers.
for (Player p : server.getOnlinePlayers()) {
if (p.getName().equalsIgnoreCase(username) || p.getUniqueId().equals(uuid)) {
cancelLoginProcess(this.msgKickAlreadyOnline);
System.out.println("[Poseidon] User " + username + " has been blocked from connecting as they share a username or UUID with a user who is already online called " + p.getName() +
"\nMost likely the user has changed their UUID or the server is running in offline mode and someone has attempted to connect with their name");
}
}
if (!loginSuccessful && !loginCancelled) {
//Bukkit Login Event Start
if (this.netLoginHandler.getSocket() == null) {
return;
}
PlayerPreLoginEvent event = new PlayerPreLoginEvent(this.packet1Login.name, ((InetSocketAddress) netLoginHandler.networkManager.getSocketAddress()).getAddress(), loginProcessHandler);
this.server.getPluginManager().callEvent(event);
if (event.getResult() != PlayerPreLoginEvent.Result.ALLOWED) {
cancelLoginProcess(event.getKickMessage());
return;
}
//Bukkit Login Event End
if (isPlayerConnectionPaused()) {
startTime = System.currentTimeMillis() / 1000L;
} else {
loginSuccessful = true;
NetLoginHandler.a(netLoginHandler, packet1Login);
}
}
}
/**
* Cancel a players login before join or login events
*/
public void cancelLoginProcess(String s) {
if (!loginCancelled && !loginSuccessful) {
loginCancelled = true;
netLoginHandler.disconnect(s);
}
}
/**
* Set a pause for your plugin
* Connection pauses are for fetching data for a player before they MIGHT be allowed to join
*
* @param plugin Instance of plugin
* @param connectionPauseName Name of connection pause (Ensure no duplicates)
* @return ConnectionPause Object, used to remove a connection pause
*/
public ConnectionPause addConnectionInterrupt(Plugin plugin, String connectionPauseName) {
final ConnectionPause connectionPause = new ConnectionPause(plugin.getDescription().getName(), connectionPauseName, loginProcessHandler);
connectionPauses.add(connectionPause);
return connectionPause;
}
@Deprecated
public void removeConnectionPause(ConnectionPause connectionPause) {
removeConnectionInterrupt(connectionPause);
}
/**
* Remove a connection pause
*
* @param connectionPause ConnectionPause object
*/
public void removeConnectionInterrupt(ConnectionPause connectionPause) {
//Check if the connection pause is registered and active
if (!connectionPauses.contains(connectionPause)) {
System.out.println("[Poseidon] A plugin has tried to remove a connection pause from the player " + packet1Login.name + " called " + connectionPause.getConnectionPauseName() +
" from the plugin " + connectionPause.getPluginName() + ". Please contact the plugin author and get them to check their logic as this is a duplicate remove, or a pause for another player.");
return;
}
//Handle the completion of the pause
connectionPause.setActive(false);
//If there are no more pauses, connect the player
if (!isPlayerConnectionPaused()) {
long endTime = System.currentTimeMillis() / 1000L;
int timeTaken = (int) (endTime - startTime);
//If a pause has cancelled the login, don't connect the player
if (loginCancelled) {
System.out.println("[Poseidon] Player " + loginProcessHandler.packet1Login.name + " was not allowed to join after being on hold for " + timeTaken + " seconds by the following plugins: " + getConnectionPauseNames(false));
return;
}
this.setLoginSuccessful(true);
System.out.println("[Poseidon] Player " + loginProcessHandler.packet1Login.name + " has been allowed to join after being on hold for " + timeTaken + " seconds by the following plugins: " + getConnectionPauseNames(false));
NetLoginHandler.a(netLoginHandler, packet1Login);
}
}
public ConnectionPause[] getActiveConnectionPauses() {
HashSet<ConnectionPause> activePauses = new HashSet<>();
for (ConnectionPause connectionPause : connectionPauses) {
if (connectionPause.isActive()) {
activePauses.add(connectionPause);
}
}
return activePauses.toArray(new ConnectionPause[activePauses.size()]);
}
public String getConnectionPauseNames(boolean activeOnly) {
StringBuilder pauseNames = new StringBuilder();
for (ConnectionPause connectionPause : connectionPauses) {
String pluginName = connectionPause.getPluginName();
String pauseName = connectionPause.getConnectionPauseName();
boolean isActive = connectionPause.isActive();
int time = connectionPause.getRunningTime();
if (activeOnly) {
if (connectionPause.isActive()) {
pauseNames.append(pluginName).append(":").append(pauseName).append(":").append(isActive ? "Running" : "Complete").append(":").append(time).append("-Seconds, ");
}
} else {
pauseNames.append(pluginName).append(":").append(pauseName).append(":").append(isActive ? "Running" : "Complete").append(":").append(time).append("-Seconds, ");
}
}
return pauseNames.toString();
}
private ConnectionPause legacyConnectionPause;
/**
* Set a pause for your plugin
* Connection pauses are for fetching data for a player before they MIGHT be allowed to join
*/
@Deprecated
public void addConnectionPause(Plugin plugin) throws Exception {
System.out.println("[Poseidon] " + plugin.getDescription().getName() + " is using the deprecated connection pause system which will be removed in the future. Contact the plugin author to get an updated version.");
legacyConnectionPause = addConnectionInterrupt(plugin, "Legacy-Connection-Pause");
}
/**
* Remove a pause for your plugin
*/
@Deprecated
public void removeConnectionPause(Plugin plugin) {
if (legacyConnectionPause != null) {
removeConnectionInterrupt(legacyConnectionPause);
return;
}
System.out.println("[Poseidon] " + plugin.getDescription().getName() + " Attempted to remove a legacy (deprecated) connection pause that was never added. Please contact the plugin author and get them to check their logic and update to the new connection pause system.");
}
/**
* See if the players connection currently paused
*/
public boolean isPlayerConnectionPaused() {
return getActiveConnectionPauses().length > 0;
}
private void setLoginSuccessful(boolean loginSuccessful) {
this.loginSuccessful = loginSuccessful;
}
}
@@ -0,0 +1,200 @@
package com.projectposeidon.johnymuffin;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.legacyminecraft.poseidon.PoseidonConfig;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class UUIDManager {
private static UUIDManager singleton;
private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
private final File cacheFile = new File("uuidcache.json");
private final Map<String, List<UUIDEntry>> usernameCache = new ConcurrentHashMap<>();
private final Map<UUID, List<UUIDEntry>> uuidCache = new ConcurrentHashMap<>();
private List<UUIDEntry> uuidCacheList;
private UUIDManager() {
if (!cacheFile.exists()) {
try (FileWriter writer = new FileWriter(cacheFile)) {
System.out.println("[Poseidon] Generating uuidcache.json for Project Poseidon");
uuidCacheList = new ArrayList<>();
gson.toJson(uuidCacheList, writer);
} catch (IOException e) {
e.printStackTrace();
}
}
try (FileReader reader = new FileReader(cacheFile)) {
System.out.println("[Poseidon] Reading uuidcache.json for Project Poseidon");
Type listType = new TypeToken<List<UUIDEntry>>() {}.getType();
uuidCacheList = gson.fromJson(reader, listType);
if (uuidCacheList == null) uuidCacheList = new ArrayList<>();
} catch (Exception e) {
System.out.println("[Poseidon] UUID cache corrupt or unreadable, resetting: " + e);
uuidCacheList = new ArrayList<>();
saveJsonArray();
}
rebuildCaches();
}
public static UUIDManager getInstance() {
if (singleton == null) {
singleton = new UUIDManager();
}
return singleton;
}
private void rebuildCaches() {
usernameCache.clear();
uuidCache.clear();
for (UUIDEntry entry : uuidCacheList) {
usernameCache.computeIfAbsent(entry.name.toLowerCase(), k -> new ArrayList<>()).add(entry);
uuidCache.computeIfAbsent(entry.uuid, k -> new ArrayList<>()).add(entry);
}
}
private void addToCaches(UUIDEntry entry) {
usernameCache.computeIfAbsent(entry.name.toLowerCase(), k -> new ArrayList<>()).add(entry);
uuidCache.computeIfAbsent(entry.uuid, k -> new ArrayList<>()).add(entry);
}
private void removeFromCaches(UUIDEntry entry) {
List<UUIDEntry> userEntries = usernameCache.get(entry.name.toLowerCase());
if (userEntries != null) userEntries.remove(entry);
List<UUIDEntry> uuidEntries = uuidCache.get(entry.uuid);
if (uuidEntries != null) uuidEntries.remove(entry);
}
public static UUID generateOfflineUUID(String username) {
// TODO: Update to modern system: UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
return UUID.nameUUIDFromBytes(username.getBytes());
}
public UUID getUUIDGraceful(String username) {
UUID uuid = getUUIDFromUsername(username, true);
return uuid != null ? uuid : generateOfflineUUID(username);
}
public void saveJsonArray() {
try (FileWriter writer = new FileWriter(cacheFile)) {
gson.toJson(uuidCacheList, writer);
} catch (IOException e) {
e.printStackTrace();
}
}
public void receivedUUID(String username, UUID uuid, Long expiry, boolean online) {
// Check existing entry
List<UUIDEntry> entries = usernameCache.getOrDefault(username.toLowerCase(), Collections.emptyList());
for (UUIDEntry entry : entries) {
if (entry.uuid.equals(uuid) && entry.onlineUUID == online) {
entry.expiresOn = expiry;
return;
}
}
removeInstancesOfUsername(username);
removeInstancesOfUUID(uuid);
UUIDEntry newEntry = new UUIDEntry(username, uuid, expiry, online);
uuidCacheList.add(newEntry);
addToCaches(newEntry);
}
public UUID getUUIDFromUsername(String username) {
List<UUIDEntry> entries = usernameCache.get(username.toLowerCase());
if (entries != null && !entries.isEmpty()) {
return entries.get(0).uuid;
}
return null;
}
public UUID getUUIDFromUsername(String username, boolean online) {
List<UUIDEntry> entries = usernameCache.get(username.toLowerCase());
if (entries != null) {
for (UUIDEntry entry : entries) {
if (entry.onlineUUID == online) {
return entry.uuid;
}
}
}
return null;
}
public UUID getUUIDFromUsername(String username, boolean online, long afterUnix) {
List<UUIDEntry> entries = usernameCache.get(username.toLowerCase());
if (entries != null) {
for (UUIDEntry entry : entries) {
if (entry.onlineUUID == online && entry.expiresOn > afterUnix) {
return entry.uuid;
}
}
}
return null;
}
public String getUsernameFromUUID(UUID uuid) {
List<UUIDEntry> entries = uuidCache.get(uuid);
if (entries == null || entries.isEmpty()) return null;
UUIDEntry newest = entries.get(0);
for (UUIDEntry entry : entries) {
if (entry.expiresOn > newest.expiresOn) {
newest = entry;
}
}
return newest.name;
}
private void removeInstancesOfUsername(String username) {
List<UUIDEntry> entries = usernameCache.get(username.toLowerCase());
if (entries != null) {
for (UUIDEntry entry : new ArrayList<>(entries)) {
uuidCacheList.remove(entry);
removeFromCaches(entry);
}
}
}
private void removeInstancesOfUUID(UUID uuid) {
List<UUIDEntry> entries = uuidCache.get(uuid);
if (entries == null) return;
for (UUIDEntry entry : new ArrayList<>(entries)) {
if ((boolean) PoseidonConfig.getInstance().getConfigOption("settings.delete-duplicate-uuids")) {
uuidCacheList.remove(entry);
removeFromCaches(entry);
} else {
entry.expiresOn = 1L; // mark as outdated
}
}
}
protected class UUIDEntry {
public String name;
public UUID uuid;
public long expiresOn;
public boolean onlineUUID;
public UUIDEntry(String name, UUID uuid, long expiresOn, boolean onlineUUID) {
this.name = name;
this.uuid = uuid;
this.expiresOn = expiresOn;
this.onlineUUID = onlineUUID;
}
}
}
@@ -0,0 +1,60 @@
package net.minecraft.server;
public class Achievement extends Statistic {
public final int a;
public final int b;
public final Achievement c;
private final String l;
public final ItemStack d;
private boolean m;
public Achievement(int i, String s, int j, int k, Item item, Achievement achievement) {
this(i, s, j, k, new ItemStack(item), achievement);
}
public Achievement(int i, String s, int j, int k, Block block, Achievement achievement) {
this(i, s, j, k, new ItemStack(block), achievement);
}
public Achievement(int i, String s, int j, int k, ItemStack itemstack, Achievement achievement) {
super(5242880 + i, StatisticCollector.a("achievement." + s));
this.d = itemstack;
this.l = StatisticCollector.a("achievement." + s + ".desc");
this.a = j;
this.b = k;
if (j < AchievementList.a) {
AchievementList.a = j;
}
if (k < AchievementList.b) {
AchievementList.b = k;
}
if (j > AchievementList.c) {
AchievementList.c = j;
}
if (k > AchievementList.d) {
AchievementList.d = k;
}
this.c = achievement;
}
public Achievement a() {
this.g = true;
return this;
}
public Achievement b() {
this.m = true;
return this;
}
public Achievement c() {
super.d();
AchievementList.e.add(this);
return this;
}
}
@@ -0,0 +1,37 @@
package net.minecraft.server;
import java.util.ArrayList;
import java.util.List;
public class AchievementList {
public static int a;
public static int b;
public static int c;
public static int d;
public static List e = new ArrayList();
public static Achievement f = (new Achievement(0, "openInventory", 0, 0, Item.BOOK, (Achievement) null)).a().c();
public static Achievement g = (new Achievement(1, "mineWood", 2, 1, Block.LOG, f)).c();
public static Achievement h = (new Achievement(2, "buildWorkBench", 4, -1, Block.WORKBENCH, g)).c();
public static Achievement i = (new Achievement(3, "buildPickaxe", 4, 2, Item.WOOD_PICKAXE, h)).c();
public static Achievement j = (new Achievement(4, "buildFurnace", 3, 4, Block.BURNING_FURNACE, i)).c();
public static Achievement k = (new Achievement(5, "acquireIron", 1, 4, Item.IRON_INGOT, j)).c();
public static Achievement l = (new Achievement(6, "buildHoe", 2, -3, Item.WOOD_HOE, h)).c();
public static Achievement m = (new Achievement(7, "makeBread", -1, -3, Item.BREAD, l)).c();
public static Achievement n = (new Achievement(8, "bakeCake", 0, -5, Item.CAKE, l)).c();
public static Achievement o = (new Achievement(9, "buildBetterPickaxe", 6, 2, Item.STONE_PICKAXE, i)).c();
public static Achievement p = (new Achievement(10, "cookFish", 2, 6, Item.COOKED_FISH, j)).c();
public static Achievement q = (new Achievement(11, "onARail", 2, 3, Block.RAILS, k)).b().c();
public static Achievement r = (new Achievement(12, "buildSword", 6, -1, Item.WOOD_SWORD, h)).c();
public static Achievement s = (new Achievement(13, "killEnemy", 8, -1, Item.BONE, r)).c();
public static Achievement t = (new Achievement(14, "killCow", 7, -3, Item.LEATHER, r)).c();
public static Achievement u = (new Achievement(15, "flyPig", 8, -4, Item.SADDLE, t)).b().c();
public AchievementList() {}
public static void a() {}
static {
System.out.println(e.size() + " achievements");
}
}
@@ -0,0 +1,35 @@
package net.minecraft.server;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
public class AchievementMap {
public static AchievementMap a = new AchievementMap();
private Map b = new HashMap();
private AchievementMap() {
try {
BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(AchievementMap.class.getResourceAsStream("/achievement/map.txt")));
String s;
while ((s = bufferedreader.readLine()) != null) {
String[] astring = s.split(",");
int i = Integer.parseInt(astring[0]);
this.b.put(Integer.valueOf(i), astring[1]);
}
bufferedreader.close();
} catch (Exception exception) {
exception.printStackTrace();
}
}
public static String a(int i) {
return (String) a.b.get(Integer.valueOf(i));
}
}
@@ -0,0 +1,334 @@
package net.minecraft.server;
import java.util.ArrayList;
import java.util.List;
public class AxisAlignedBB {
private static List g = new ArrayList();
private static int h = 0;
public double a;
public double b;
public double c;
public double d;
public double e;
public double f;
public static AxisAlignedBB a(double d0, double d1, double d2, double d3, double d4, double d5) {
return new AxisAlignedBB(d0, d1, d2, d3, d4, d5);
}
public static void a() {
h = 0;
}
public static AxisAlignedBB b(double d0, double d1, double d2, double d3, double d4, double d5) {
if (h >= g.size()) {
g.add(a(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D));
}
return ((AxisAlignedBB) g.get(h++)).c(d0, d1, d2, d3, d4, d5);
}
private AxisAlignedBB(double d0, double d1, double d2, double d3, double d4, double d5) {
this.a = d0;
this.b = d1;
this.c = d2;
this.d = d3;
this.e = d4;
this.f = d5;
}
public AxisAlignedBB c(double d0, double d1, double d2, double d3, double d4, double d5) {
this.a = d0;
this.b = d1;
this.c = d2;
this.d = d3;
this.e = d4;
this.f = d5;
return this;
}
public AxisAlignedBB a(double d0, double d1, double d2) {
double d3 = this.a;
double d4 = this.b;
double d5 = this.c;
double d6 = this.d;
double d7 = this.e;
double d8 = this.f;
if (d0 < 0.0D) {
d3 += d0;
}
if (d0 > 0.0D) {
d6 += d0;
}
if (d1 < 0.0D) {
d4 += d1;
}
if (d1 > 0.0D) {
d7 += d1;
}
if (d2 < 0.0D) {
d5 += d2;
}
if (d2 > 0.0D) {
d8 += d2;
}
return b(d3, d4, d5, d6, d7, d8);
}
public AxisAlignedBB b(double d0, double d1, double d2) {
double d3 = this.a - d0;
double d4 = this.b - d1;
double d5 = this.c - d2;
double d6 = this.d + d0;
double d7 = this.e + d1;
double d8 = this.f + d2;
return b(d3, d4, d5, d6, d7, d8);
}
public AxisAlignedBB c(double d0, double d1, double d2) {
return b(this.a + d0, this.b + d1, this.c + d2, this.d + d0, this.e + d1, this.f + d2);
}
public double a(AxisAlignedBB axisalignedbb, double d0) {
if (axisalignedbb.e > this.b && axisalignedbb.b < this.e) {
if (axisalignedbb.f > this.c && axisalignedbb.c < this.f) {
double d1;
if (d0 > 0.0D && axisalignedbb.d <= this.a) {
d1 = this.a - axisalignedbb.d;
if (d1 < d0) {
d0 = d1;
}
}
if (d0 < 0.0D && axisalignedbb.a >= this.d) {
d1 = this.d - axisalignedbb.a;
if (d1 > d0) {
d0 = d1;
}
}
return d0;
} else {
return d0;
}
} else {
return d0;
}
}
public double b(AxisAlignedBB axisalignedbb, double d0) {
if (axisalignedbb.d > this.a && axisalignedbb.a < this.d) {
if (axisalignedbb.f > this.c && axisalignedbb.c < this.f) {
double d1;
if (d0 > 0.0D && axisalignedbb.e <= this.b) {
d1 = this.b - axisalignedbb.e;
if (d1 < d0) {
d0 = d1;
}
}
if (d0 < 0.0D && axisalignedbb.b >= this.e) {
d1 = this.e - axisalignedbb.b;
if (d1 > d0) {
d0 = d1;
}
}
return d0;
} else {
return d0;
}
} else {
return d0;
}
}
public double c(AxisAlignedBB axisalignedbb, double d0) {
if (axisalignedbb.d > this.a && axisalignedbb.a < this.d) {
if (axisalignedbb.e > this.b && axisalignedbb.b < this.e) {
double d1;
if (d0 > 0.0D && axisalignedbb.f <= this.c) {
d1 = this.c - axisalignedbb.f;
if (d1 < d0) {
d0 = d1;
}
}
if (d0 < 0.0D && axisalignedbb.c >= this.f) {
d1 = this.f - axisalignedbb.c;
if (d1 > d0) {
d0 = d1;
}
}
return d0;
} else {
return d0;
}
} else {
return d0;
}
}
public boolean a(AxisAlignedBB axisalignedbb) {
return axisalignedbb.d > this.a && axisalignedbb.a < this.d ? (axisalignedbb.e > this.b && axisalignedbb.b < this.e ? axisalignedbb.f > this.c && axisalignedbb.c < this.f : false) : false;
}
public AxisAlignedBB d(double d0, double d1, double d2) {
this.a += d0;
this.b += d1;
this.c += d2;
this.d += d0;
this.e += d1;
this.f += d2;
return this;
}
public boolean a(Vec3D vec3d) {
return vec3d.a > this.a && vec3d.a < this.d ? (vec3d.b > this.b && vec3d.b < this.e ? vec3d.c > this.c && vec3d.c < this.f : false) : false;
}
public AxisAlignedBB shrink(double d0, double d1, double d2) {
double d3 = this.a + d0;
double d4 = this.b + d1;
double d5 = this.c + d2;
double d6 = this.d - d0;
double d7 = this.e - d1;
double d8 = this.f - d2;
return b(d3, d4, d5, d6, d7, d8);
}
public AxisAlignedBB clone() {
return b(this.a, this.b, this.c, this.d, this.e, this.f);
}
public MovingObjectPosition a(Vec3D vec3d, Vec3D vec3d1) {
Vec3D vec3d2 = vec3d.a(vec3d1, this.a);
Vec3D vec3d3 = vec3d.a(vec3d1, this.d);
Vec3D vec3d4 = vec3d.b(vec3d1, this.b);
Vec3D vec3d5 = vec3d.b(vec3d1, this.e);
Vec3D vec3d6 = vec3d.c(vec3d1, this.c);
Vec3D vec3d7 = vec3d.c(vec3d1, this.f);
if (!this.b(vec3d2)) {
vec3d2 = null;
}
if (!this.b(vec3d3)) {
vec3d3 = null;
}
if (!this.c(vec3d4)) {
vec3d4 = null;
}
if (!this.c(vec3d5)) {
vec3d5 = null;
}
if (!this.d(vec3d6)) {
vec3d6 = null;
}
if (!this.d(vec3d7)) {
vec3d7 = null;
}
Vec3D vec3d8 = null;
if (vec3d2 != null && (vec3d8 == null || vec3d.b(vec3d2) < vec3d.b(vec3d8))) {
vec3d8 = vec3d2;
}
if (vec3d3 != null && (vec3d8 == null || vec3d.b(vec3d3) < vec3d.b(vec3d8))) {
vec3d8 = vec3d3;
}
if (vec3d4 != null && (vec3d8 == null || vec3d.b(vec3d4) < vec3d.b(vec3d8))) {
vec3d8 = vec3d4;
}
if (vec3d5 != null && (vec3d8 == null || vec3d.b(vec3d5) < vec3d.b(vec3d8))) {
vec3d8 = vec3d5;
}
if (vec3d6 != null && (vec3d8 == null || vec3d.b(vec3d6) < vec3d.b(vec3d8))) {
vec3d8 = vec3d6;
}
if (vec3d7 != null && (vec3d8 == null || vec3d.b(vec3d7) < vec3d.b(vec3d8))) {
vec3d8 = vec3d7;
}
if (vec3d8 == null) {
return null;
} else {
byte b0 = -1;
if (vec3d8 == vec3d2) {
b0 = 4;
}
if (vec3d8 == vec3d3) {
b0 = 5;
}
if (vec3d8 == vec3d4) {
b0 = 0;
}
if (vec3d8 == vec3d5) {
b0 = 1;
}
if (vec3d8 == vec3d6) {
b0 = 2;
}
if (vec3d8 == vec3d7) {
b0 = 3;
}
return new MovingObjectPosition(0, 0, 0, b0, vec3d8);
}
}
private boolean b(Vec3D vec3d) {
return vec3d == null ? false : vec3d.b >= this.b && vec3d.b <= this.e && vec3d.c >= this.c && vec3d.c <= this.f;
}
private boolean c(Vec3D vec3d) {
return vec3d == null ? false : vec3d.a >= this.a && vec3d.a <= this.d && vec3d.c >= this.c && vec3d.c <= this.f;
}
private boolean d(Vec3D vec3d) {
return vec3d == null ? false : vec3d.a >= this.a && vec3d.a <= this.d && vec3d.b >= this.b && vec3d.b <= this.e;
}
public void b(AxisAlignedBB axisalignedbb) {
this.a = axisalignedbb.a;
this.b = axisalignedbb.b;
this.c = axisalignedbb.c;
this.d = axisalignedbb.d;
this.e = axisalignedbb.e;
this.f = axisalignedbb.f;
}
public String toString() {
return "box[" + this.a + ", " + this.b + ", " + this.c + " -> " + this.d + ", " + this.e + ", " + this.f + "]";
}
}
@@ -0,0 +1,10 @@
package net.minecraft.server;
public class BedBlockTextures {
public static final int[] a = new int[] { 3, 4, 2, 5};
public static final int[] b = new int[] { 2, 3, 0, 1};
public static final int[][] c = new int[][] { { 1, 0, 3, 2, 5, 4}, { 1, 0, 5, 4, 2, 3}, { 1, 0, 2, 3, 4, 5}, { 1, 0, 4, 5, 3, 2}};
public BedBlockTextures() {}
}
@@ -0,0 +1,121 @@
package net.minecraft.server;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class BiomeBase {
public static final BiomeBase RAINFOREST = (new BiomeRainforest()).b(588342).a("Rainforest").a(2094168);
public static final BiomeBase SWAMPLAND = (new BiomeSwamp()).b(522674).a("Swampland").a(9154376);
public static final BiomeBase SEASONAL_FOREST = (new BiomeBase()).b(10215459).a("Seasonal Forest");
public static final BiomeBase FOREST = (new BiomeForest()).b(353825).a("Forest").a(5159473);
public static final BiomeBase SAVANNA = (new BiomeDesert()).b(14278691).a("Savanna");
public static final BiomeBase SHRUBLAND = (new BiomeBase()).b(10595616).a("Shrubland");
public static final BiomeBase TAIGA = (new BiomeTaiga()).b(3060051).a("Taiga").b().a(8107825);
public static final BiomeBase DESERT = (new BiomeDesert()).b(16421912).a("Desert").e();
public static final BiomeBase PLAINS = (new BiomeDesert()).b(16767248).a("Plains");
public static final BiomeBase ICE_DESERT = (new BiomeDesert()).b(16772499).a("Ice Desert").b().e().a(12899129);
public static final BiomeBase TUNDRA = (new BiomeBase()).b(5762041).a("Tundra").b().a(12899129);
public static final BiomeBase HELL = (new BiomeHell()).b(16711680).a("Hell").e();
public static final BiomeBase SKY = (new BiomeSky()).b(8421631).a("Sky").e();
public String n;
public int o;
public byte p;
public byte q;
public int r;
protected List s;
protected List t;
protected List u;
private boolean v;
private boolean w;
private static BiomeBase[] x = new BiomeBase[4096];
protected BiomeBase() {
this.p = (byte) Block.GRASS.id;
this.q = (byte) Block.DIRT.id;
this.r = 5169201;
this.s = new ArrayList();
this.t = new ArrayList();
this.u = new ArrayList();
this.w = true;
this.s.add(new BiomeMeta(EntitySpider.class, 10));
this.s.add(new BiomeMeta(EntityZombie.class, 10));
this.s.add(new BiomeMeta(EntitySkeleton.class, 10));
this.s.add(new BiomeMeta(EntityCreeper.class, 10));
this.s.add(new BiomeMeta(EntitySlime.class, 10));
this.t.add(new BiomeMeta(EntitySheep.class, 12));
this.t.add(new BiomeMeta(EntityPig.class, 10));
this.t.add(new BiomeMeta(EntityChicken.class, 10));
this.t.add(new BiomeMeta(EntityCow.class, 8));
this.u.add(new BiomeMeta(EntitySquid.class, 10));
}
private BiomeBase e() {
this.w = false;
return this;
}
public static void a() {
for (int i = 0; i < 64; ++i) {
for (int j = 0; j < 64; ++j) {
x[i + j * 64] = a((float) i / 63.0F, (float) j / 63.0F);
}
}
DESERT.p = DESERT.q = (byte) Block.SAND.id;
ICE_DESERT.p = ICE_DESERT.q = (byte) Block.SAND.id;
}
public WorldGenerator a(Random random) {
return (WorldGenerator) (random.nextInt(10) == 0 ? new WorldGenBigTree() : new WorldGenTrees());
}
protected BiomeBase b() {
this.v = true;
return this;
}
protected BiomeBase a(String s) {
this.n = s;
return this;
}
protected BiomeBase a(int i) {
this.r = i;
return this;
}
protected BiomeBase b(int i) {
this.o = i;
return this;
}
public static BiomeBase a(double d0, double d1) {
int i = (int) (d0 * 63.0D);
int j = (int) (d1 * 63.0D);
return x[i + j * 64];
}
public static BiomeBase a(float f, float f1) {
f1 *= f;
return f < 0.1F ? TUNDRA : (f1 < 0.2F ? (f < 0.5F ? TUNDRA : (f < 0.95F ? SAVANNA : DESERT)) : (f1 > 0.5F && f < 0.7F ? SWAMPLAND : (f < 0.5F ? TAIGA : (f < 0.97F ? (f1 < 0.35F ? SHRUBLAND : FOREST) : (f1 < 0.45F ? PLAINS : (f1 < 0.9F ? SEASONAL_FOREST : RAINFOREST))))));
}
public List a(EnumCreatureType enumcreaturetype) {
return enumcreaturetype == EnumCreatureType.MONSTER ? this.s : (enumcreaturetype == EnumCreatureType.CREATURE ? this.t : (enumcreaturetype == EnumCreatureType.WATER_CREATURE ? this.u : null));
}
public boolean c() {
return this.v;
}
public boolean d() {
return this.v ? false : this.w;
}
static {
a();
}
}
@@ -0,0 +1,6 @@
package net.minecraft.server;
public class BiomeDesert extends BiomeBase {
public BiomeDesert() {}
}
@@ -0,0 +1,14 @@
package net.minecraft.server;
import java.util.Random;
public class BiomeForest extends BiomeBase {
public BiomeForest() {
this.t.add(new BiomeMeta(EntityWolf.class, 2));
}
public WorldGenerator a(Random random) {
return (WorldGenerator) (random.nextInt(5) == 0 ? new WorldGenForest() : (random.nextInt(3) == 0 ? new WorldGenBigTree() : new WorldGenTrees()));
}
}
@@ -0,0 +1,12 @@
package net.minecraft.server;
public class BiomeHell extends BiomeBase {
public BiomeHell() {
this.s.clear();
this.t.clear();
this.u.clear();
this.s.add(new BiomeMeta(EntityGhast.class, 10));
this.s.add(new BiomeMeta(EntityPigZombie.class, 10));
}
}
@@ -0,0 +1,12 @@
package net.minecraft.server;
public class BiomeMeta {
public Class a;
public int b;
public BiomeMeta(Class oclass, int i) {
this.a = oclass;
this.b = i;
}
}
@@ -0,0 +1,12 @@
package net.minecraft.server;
import java.util.Random;
public class BiomeRainforest extends BiomeBase {
public BiomeRainforest() {}
public WorldGenerator a(Random random) {
return (WorldGenerator) (random.nextInt(3) == 0 ? new WorldGenBigTree() : new WorldGenTrees());
}
}
@@ -0,0 +1,11 @@
package net.minecraft.server;
public class BiomeSky extends BiomeBase {
public BiomeSky() {
this.s.clear();
this.t.clear();
this.u.clear();
this.t.add(new BiomeMeta(EntityChicken.class, 10));
}
}
@@ -0,0 +1,6 @@
package net.minecraft.server;
public class BiomeSwamp extends BiomeBase {
public BiomeSwamp() {}
}
@@ -0,0 +1,14 @@
package net.minecraft.server;
import java.util.Random;
public class BiomeTaiga extends BiomeBase {
public BiomeTaiga() {
this.t.add(new BiomeMeta(EntityWolf.class, 2));
}
public WorldGenerator a(Random random) {
return (WorldGenerator) (random.nextInt(3) == 0 ? new WorldGenTaiga1() : new WorldGenTaiga2());
}
}
@@ -0,0 +1,555 @@
package net.minecraft.server;
import com.legacyminecraft.poseidon.PoseidonConfig;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class Block {
public static final StepSound d = new StepSound("stone", 1.0F, 1.0F);
public static final StepSound e = new StepSound("wood", 1.0F, 1.0F);
public static final StepSound f = new StepSound("gravel", 1.0F, 1.0F);
public static final StepSound g = new StepSound("grass", 1.0F, 1.0F);
public static final StepSound h = new StepSound("stone", 1.0F, 1.0F);
public static final StepSound i = new StepSound("stone", 1.0F, 1.5F);
public static final StepSound j = new StepSoundStone("stone", 1.0F, 1.0F);
public static final StepSound k = new StepSound("cloth", 1.0F, 1.0F);
public static final StepSound l = new StepSoundSand("sand", 1.0F, 1.0F);
public static final Block[] byId = new Block[256];
public static final boolean[] n = new boolean[256];
public static final boolean[] o = new boolean[256];
public static final boolean[] isTileEntity = new boolean[256];
public static final int[] q = new int[256];
public static final boolean[] r = new boolean[256];
public static final int[] s = new int[256];
public static final boolean[] t = new boolean[256];
public static final Block STONE = (new BlockStone(1, 1)).c(1.5F).b(10.0F).a(h).a("stone");
public static final BlockGrass GRASS = (BlockGrass) (new BlockGrass(2)).c(0.6F).a(g).a("grass");
public static final Block DIRT = (new BlockDirt(3, 2)).c(0.5F).a(f).a("dirt");
public static final Block COBBLESTONE = (new Block(4, 16, Material.STONE)).c(2.0F).b(10.0F).a(h).a("stonebrick");
public static final Block WOOD = (new Block(5, 4, Material.WOOD)).c(2.0F).b(5.0F).a(e).a("wood").g();
public static final Block SAPLING = (new BlockSapling(6, 15)).c(0.0F).a(g).a("sapling").g();
public static final Block BEDROCK = (new Block(7, 17, Material.STONE)).i().b(6000000.0F).a(h).a("bedrock").n();
public static final Block WATER = (new BlockFlowing(8, Material.WATER)).c(100.0F).f(3).a("water").n().g();
public static final Block STATIONARY_WATER = (new BlockStationary(9, Material.WATER)).c(100.0F).f(3).a("water").n().g();
public static final Block LAVA = (new BlockFlowing(10, Material.LAVA)).c(0.0F).a(1.0F).f(255).a("lava").n().g();
public static final Block STATIONARY_LAVA = (new BlockStationary(11, Material.LAVA)).c(100.0F).a(1.0F).f(255).a("lava").n().g();
public static final Block SAND = (new BlockSand(12, 18)).c(0.5F).a(l).a("sand");
public static final Block GRAVEL = (new BlockGravel(13, 19)).c(0.6F).a(f).a("gravel");
public static final Block GOLD_ORE = (new BlockOre(14, 32)).c(3.0F).b(5.0F).a(h).a("oreGold");
public static final Block IRON_ORE = (new BlockOre(15, 33)).c(3.0F).b(5.0F).a(h).a("oreIron");
public static final Block COAL_ORE = (new BlockOre(16, 34)).c(3.0F).b(5.0F).a(h).a("oreCoal");
public static final Block LOG = (new BlockLog(17)).c(2.0F).a(e).a("log").g();
public static final BlockLeaves LEAVES = (BlockLeaves) (new BlockLeaves(18, 52)).c(0.2F).f(1).a(g).a("leaves").n().g();
public static final Block SPONGE = (new BlockSponge(19)).c(0.6F).a(g).a("sponge");
public static final Block GLASS = (new BlockGlass(20, 49, Material.SHATTERABLE, false)).c(0.3F).a(j).a("glass");
public static final Block LAPIS_ORE = (new BlockOre(21, 160)).c(3.0F).b(5.0F).a(h).a("oreLapis");
public static final Block LAPIS_BLOCK = (new Block(22, 144, Material.STONE)).c(3.0F).b(5.0F).a(h).a("blockLapis");
public static final Block DISPENSER = (new BlockDispenser(23)).c(3.5F).a(h).a("dispenser").g();
public static final Block SANDSTONE = (new BlockSandStone(24)).a(h).c(0.8F).a("sandStone");
public static final Block NOTE_BLOCK = (new BlockNote(25)).c(0.8F).a("musicBlock").g();
public static final Block BED = (new BlockBed(26)).c(0.2F).a("bed").n().g();
public static final Block GOLDEN_RAIL = (new BlockMinecartTrack(27, 179, true)).c(0.7F).a(i).a("goldenRail").g();
public static final Block DETECTOR_RAIL = (new BlockMinecartDetector(28, 195)).c(0.7F).a(i).a("detectorRail").g();
public static final Block PISTON_STICKY = (new BlockPiston(29, 106, true)).a("pistonStickyBase").g();
public static final Block WEB = (new BlockWeb(30, 11)).f(1).c(4.0F).a("web");
public static final BlockLongGrass LONG_GRASS = (BlockLongGrass) (new BlockLongGrass(31, 39)).c(0.0F).a(g).a("tallgrass");
public static final BlockDeadBush DEAD_BUSH = (BlockDeadBush) (new BlockDeadBush(32, 55)).c(0.0F).a(g).a("deadbush");
public static final Block PISTON = (new BlockPiston(33, 107, false)).a("pistonBase").g();
public static final BlockPistonExtension PISTON_EXTENSION = (BlockPistonExtension) (new BlockPistonExtension(34, 107)).g();
public static final Block WOOL = (new BlockCloth()).c(0.8F).a(k).a("cloth").g();
public static final BlockPistonMoving PISTON_MOVING = new BlockPistonMoving(36);
public static final BlockFlower YELLOW_FLOWER = (BlockFlower) (new BlockFlower(37, 13)).c(0.0F).a(g).a("flower");
public static final BlockFlower RED_ROSE = (BlockFlower) (new BlockFlower(38, 12)).c(0.0F).a(g).a("rose");
public static final BlockFlower BROWN_MUSHROOM = (BlockFlower) (new BlockMushroom(39, 29)).c(0.0F).a(g).a(0.125F).a("mushroom");
public static final BlockFlower RED_MUSHROOM = (BlockFlower) (new BlockMushroom(40, 28)).c(0.0F).a(g).a("mushroom");
public static final Block GOLD_BLOCK = (new BlockOreBlock(41, 23)).c(3.0F).b(10.0F).a(i).a("blockGold");
public static final Block IRON_BLOCK = (new BlockOreBlock(42, 22)).c(5.0F).b(10.0F).a(i).a("blockIron");
public static final Block DOUBLE_STEP = (new BlockStep(43, true)).c(2.0F).b(10.0F).a(h).a("stoneSlab");
public static final Block STEP = (new BlockStep(44, false)).c(2.0F).b(10.0F).a(h).a("stoneSlab");
public static final Block BRICK = (new Block(45, 7, Material.STONE)).c(2.0F).b(10.0F).a(h).a("brick");
public static final Block TNT = (new BlockTNT(46, 8)).c(0.0F).a(g).a("tnt");
public static final Block BOOKSHELF = (new BlockBookshelf(47, 35)).c(1.5F).a(e).a("bookshelf");
public static final Block MOSSY_COBBLESTONE = (new Block(48, 36, Material.STONE)).c(2.0F).b(10.0F).a(h).a("stoneMoss");
public static final Block OBSIDIAN = (new BlockObsidian(49, 37)).c(10.0F).b(2000.0F).a(h).a("obsidian");
public static final Block TORCH = (new BlockTorch(50, 80)).c(0.0F).a(0.9375F).a(e).a("torch").g();
public static final BlockFire FIRE = (BlockFire) (new BlockFire(51, 31)).c(0.0F).a(1.0F).a(e).a("fire").n().g();
public static final Block MOB_SPAWNER = (new BlockMobSpawner(52, 65)).c(5.0F).a(i).a("mobSpawner").n();
public static final Block WOOD_STAIRS = (new BlockStairs(53, WOOD)).a("stairsWood").g();
public static final Block CHEST = (new BlockChest(54)).c(2.5F).a(e).a("chest").g();
public static final Block REDSTONE_WIRE = (new BlockRedstoneWire(55, 164)).c(0.0F).a(d).a("redstoneDust").n().g();
public static final Block DIAMOND_ORE = (new BlockOre(56, 50)).c(3.0F).b(5.0F).a(h).a("oreDiamond");
public static final Block DIAMOND_BLOCK = (new BlockOreBlock(57, 24)).c(5.0F).b(10.0F).a(i).a("blockDiamond");
public static final Block WORKBENCH = (new BlockWorkbench(58)).c(2.5F).a(e).a("workbench");
public static final Block CROPS = (new BlockCrops(59, 88)).c(0.0F).a(g).a("crops").n().g();
public static final Block SOIL = (new BlockSoil(60)).c(0.6F).a(f).a("farmland");
public static final Block FURNACE = (new BlockFurnace(61, false)).c(3.5F).a(h).a("furnace").g();
public static final Block BURNING_FURNACE = (new BlockFurnace(62, true)).c(3.5F).a(h).a(0.875F).a("furnace").g();
public static final Block SIGN_POST = (new BlockSign(63, TileEntitySign.class, true)).c(1.0F).a(e).a("sign").n().g();
public static final Block WOODEN_DOOR = (new BlockDoor(64, Material.WOOD)).c(3.0F).a(e).a("doorWood").n().g();
public static final Block LADDER = (new BlockLadder(65, 83)).c(0.4F).a(e).a("ladder").g();
public static final Block RAILS = (new BlockMinecartTrack(66, 128, false)).c(0.7F).a(i).a("rail").g();
public static final Block COBBLESTONE_STAIRS = (new BlockStairs(67, COBBLESTONE)).a("stairsStone").g();
public static final Block WALL_SIGN = (new BlockSign(68, TileEntitySign.class, false)).c(1.0F).a(e).a("sign").n().g();
public static final Block LEVER = (new BlockLever(69, 96)).c(0.5F).a(e).a("lever").g();
public static final Block STONE_PLATE = (new BlockPressurePlate(70, STONE.textureId, EnumMobType.MOBS, Material.STONE)).c(0.5F).a(h).a("pressurePlate").g();
public static final Block IRON_DOOR_BLOCK = (new BlockDoor(71, Material.ORE)).c(5.0F).a(i).a("doorIron").n().g();
public static final Block WOOD_PLATE = (new BlockPressurePlate(72, WOOD.textureId, EnumMobType.EVERYTHING, Material.WOOD)).c(0.5F).a(e).a("pressurePlate").g();
public static final Block REDSTONE_ORE = (new BlockRedstoneOre(73, 51, false)).c(3.0F).b(5.0F).a(h).a("oreRedstone").g();
public static final Block GLOWING_REDSTONE_ORE = (new BlockRedstoneOre(74, 51, true)).a(0.625F).c(3.0F).b(5.0F).a(h).a("oreRedstone").g();
public static final Block REDSTONE_TORCH_OFF = (new BlockRedstoneTorch(75, 115, false)).c(0.0F).a(e).a("notGate").g();
public static final Block REDSTONE_TORCH_ON = (new BlockRedstoneTorch(76, 99, true)).c(0.0F).a(0.5F).a(e).a("notGate").g();
public static final Block STONE_BUTTON = (new BlockButton(77, STONE.textureId)).c(0.5F).a(h).a("button").g();
public static final Block SNOW = (new BlockSnow(78, 66)).c(0.1F).a(k).a("snow");
public static final Block ICE = (new BlockIce(79, 67)).c(0.5F).f(3).a(j).a("ice");
public static final Block SNOW_BLOCK = (new BlockSnowBlock(80, 66)).c(0.2F).a(k).a("snow");
public static final Block CACTUS = (new BlockCactus(81, 70)).c(0.4F).a(k).a("cactus");
public static final Block CLAY = (new BlockClay(82, 72)).c(0.6F).a(f).a("clay");
public static final Block SUGAR_CANE_BLOCK = (new BlockReed(83, 73)).c(0.0F).a(g).a("reeds").n();
public static final Block JUKEBOX = (new BlockJukeBox(84, 74)).c(2.0F).b(10.0F).a(h).a("jukebox").g();
public static final Block FENCE = (new BlockFence(85, 4)).c(2.0F).b(5.0F).a(e).a("fence").g();
public static final Block PUMPKIN = (new BlockPumpkin(86, 102, false)).c(1.0F).a(e).a("pumpkin").g();
public static final Block NETHERRACK = (new BlockBloodStone(87, 103)).c(0.4F).a(h).a("hellrock");
public static final Block SOUL_SAND = (new BlockSlowSand(88, 104)).c(0.5F).a(l).a("hellsand");
public static final Block GLOWSTONE = (new BlockLightStone(89, 105, Material.STONE)).c(0.3F).a(j).a(1.0F).a("lightgem");
public static final BlockPortal PORTAL = (BlockPortal) (new BlockPortal(90, 14)).c(-1.0F).a(j).a(0.75F).a("portal");
public static final Block JACK_O_LANTERN = (new BlockPumpkin(91, 102, true)).c(1.0F).a(e).a(1.0F).a("litpumpkin").g();
public static final Block CAKE_BLOCK = (new BlockCake(92, 121)).c(0.5F).a(k).a("cake").n().g();
public static final Block DIODE_OFF = (new BlockDiode(93, false)).c(0.0F).a(e).a("diode").n().g();
public static final Block DIODE_ON = (new BlockDiode(94, true)).c(0.0F).a(0.625F).a(e).a("diode").n().g();
public static final Block LOCKED_CHEST = (new BlockLockedChest(95)).c(0.0F).a(1.0F).a(e).a("lockedchest").a(true).g();
public static final Block TRAP_DOOR = (new BlockTrapdoor(96, Material.WOOD)).c(3.0F).a(e).a("trapdoor").n().g();
public static final List<Integer> leafDecayBlacklist = Arrays.asList(PoseidonConfig.getInstance().getTreeBlacklistIDs());
public int textureId;
public final int id;
protected float strength;
protected float durability;
protected boolean bq;
protected boolean br;
public double minX;
public double minY;
public double minZ;
public double maxX;
public double maxY;
public double maxZ;
public StepSound stepSound;
public float bz;
public final Material material;
public float frictionFactor;
private String name;
protected Block(int i, Material material) {
this.bq = true;
this.br = true;
this.stepSound = d;
this.bz = 1.0F;
this.frictionFactor = 0.6F;
if (byId[i] != null) {
throw new IllegalArgumentException("Slot " + i + " is already occupied by " + byId[i] + " when adding " + this);
} else {
this.material = material;
byId[i] = this;
this.id = i;
this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
o[i] = this.a();
q[i] = this.a() ? 255 : 0;
r[i] = !material.blocksLight();
isTileEntity[i] = false;
}
}
protected Block g() {
t[this.id] = true;
return this;
}
protected void h() {
}
protected Block(int i, int j, Material material) {
this(i, material);
this.textureId = j;
}
protected Block a(StepSound stepsound) {
this.stepSound = stepsound;
return this;
}
protected Block f(int i) {
q[this.id] = i;
return this;
}
protected Block a(float f) {
s[this.id] = (int) (15.0F * f);
return this;
}
protected Block b(float f) {
this.durability = f * 3.0F;
return this;
}
public boolean b() {
return true;
}
protected Block c(float f) {
this.strength = f;
if (this.durability < f * 5.0F) {
this.durability = f * 5.0F;
}
return this;
}
protected Block i() {
this.c(-1.0F);
return this;
}
public float j() {
return this.strength;
}
protected Block a(boolean flag) {
n[this.id] = flag;
return this;
}
public void a(float f, float f1, float f2, float f3, float f4, float f5) {
this.minX = (double) f;
this.minY = (double) f1;
this.minZ = (double) f2;
this.maxX = (double) f3;
this.maxY = (double) f4;
this.maxZ = (double) f5;
}
public boolean b(IBlockAccess iblockaccess, int i, int j, int k, int l) {
return iblockaccess.getMaterial(i, j, k).isBuildable();
}
public int a(int i, int j) {
return this.a(i);
}
public int a(int i) {
return this.textureId;
}
public void a(World world, int i, int j, int k, AxisAlignedBB axisalignedbb, ArrayList arraylist) {
AxisAlignedBB axisalignedbb1 = this.e(world, i, j, k);
if (axisalignedbb1 != null && axisalignedbb.a(axisalignedbb1)) {
arraylist.add(axisalignedbb1);
}
}
public AxisAlignedBB e(World world, int i, int j, int k) {
return AxisAlignedBB.b((double) i + this.minX, (double) j + this.minY, (double) k + this.minZ, (double) i + this.maxX, (double) j + this.maxY, (double) k + this.maxZ);
}
public boolean a() {
return true;
}
public boolean a(int i, boolean flag) {
return this.k_();
}
public boolean k_() {
return true;
}
public void a(World world, int i, int j, int k, Random random) {
}
public void postBreak(World world, int i, int j, int k, int l) {
}
public void doPhysics(World world, int i, int j, int k, int l) {
}
public int c() {
return 10;
}
public void c(World world, int i, int j, int k) {
}
public void remove(World world, int i, int j, int k) {
}
public int a(Random random) {
return 1;
}
public int a(int i, Random random) {
return this.id;
}
public float getDamage(EntityHuman entityhuman) {
return this.strength < 0.0F ? 0.0F : (!entityhuman.b(this) ? 1.0F / this.strength / 100.0F : entityhuman.a(this) / this.strength / 30.0F);
}
public final void g(World world, int i, int j, int k, int l) {
this.dropNaturally(world, i, j, k, l, 1.0F);
}
public void dropNaturally(World world, int i, int j, int k, int l, float f) {
if (!world.isStatic) {
int i1 = this.a(world.random);
for (int j1 = 0; j1 < i1; ++j1) {
// CraftBukkit - <= to < to allow for plugins to completely disable block drops from explosions
if (world.random.nextFloat() < f) {
int k1 = this.a(l, world.random);
if (k1 > 0) {
this.a(world, i, j, k, new ItemStack(k1, 1, this.a_(l)));
}
}
}
}
}
protected void a(World world, int i, int j, int k, ItemStack itemstack) {
if (!world.isStatic) {
float f = 0.7F;
double d0 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
double d1 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
double d2 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
EntityItem entityitem = new EntityItem(world, (double) i + d0, (double) j + d1, (double) k + d2, itemstack);
entityitem.pickupDelay = 10;
world.addEntity(entityitem);
}
}
protected int a_(int i) {
return 0;
}
public float a(Entity entity) {
return this.durability / 5.0F;
}
public MovingObjectPosition a(World world, int i, int j, int k, Vec3D vec3d, Vec3D vec3d1) {
this.a(world, i, j, k);
vec3d = vec3d.add((double) (-i), (double) (-j), (double) (-k));
vec3d1 = vec3d1.add((double) (-i), (double) (-j), (double) (-k));
Vec3D vec3d2 = vec3d.a(vec3d1, this.minX);
Vec3D vec3d3 = vec3d.a(vec3d1, this.maxX);
Vec3D vec3d4 = vec3d.b(vec3d1, this.minY);
Vec3D vec3d5 = vec3d.b(vec3d1, this.maxY);
Vec3D vec3d6 = vec3d.c(vec3d1, this.minZ);
Vec3D vec3d7 = vec3d.c(vec3d1, this.maxZ);
if (!this.a(vec3d2)) {
vec3d2 = null;
}
if (!this.a(vec3d3)) {
vec3d3 = null;
}
if (!this.b(vec3d4)) {
vec3d4 = null;
}
if (!this.b(vec3d5)) {
vec3d5 = null;
}
if (!this.c(vec3d6)) {
vec3d6 = null;
}
if (!this.c(vec3d7)) {
vec3d7 = null;
}
Vec3D vec3d8 = null;
if (vec3d2 != null && (vec3d8 == null || vec3d.a(vec3d2) < vec3d.a(vec3d8))) {
vec3d8 = vec3d2;
}
if (vec3d3 != null && (vec3d8 == null || vec3d.a(vec3d3) < vec3d.a(vec3d8))) {
vec3d8 = vec3d3;
}
if (vec3d4 != null && (vec3d8 == null || vec3d.a(vec3d4) < vec3d.a(vec3d8))) {
vec3d8 = vec3d4;
}
if (vec3d5 != null && (vec3d8 == null || vec3d.a(vec3d5) < vec3d.a(vec3d8))) {
vec3d8 = vec3d5;
}
if (vec3d6 != null && (vec3d8 == null || vec3d.a(vec3d6) < vec3d.a(vec3d8))) {
vec3d8 = vec3d6;
}
if (vec3d7 != null && (vec3d8 == null || vec3d.a(vec3d7) < vec3d.a(vec3d8))) {
vec3d8 = vec3d7;
}
if (vec3d8 == null) {
return null;
} else {
byte b0 = -1;
if (vec3d8 == vec3d2) {
b0 = 4;
}
if (vec3d8 == vec3d3) {
b0 = 5;
}
if (vec3d8 == vec3d4) {
b0 = 0;
}
if (vec3d8 == vec3d5) {
b0 = 1;
}
if (vec3d8 == vec3d6) {
b0 = 2;
}
if (vec3d8 == vec3d7) {
b0 = 3;
}
return new MovingObjectPosition(i, j, k, b0, vec3d8.add((double) i, (double) j, (double) k));
}
}
private boolean a(Vec3D vec3d) {
return vec3d == null ? false : vec3d.b >= this.minY && vec3d.b <= this.maxY && vec3d.c >= this.minZ && vec3d.c <= this.maxZ;
}
private boolean b(Vec3D vec3d) {
return vec3d == null ? false : vec3d.a >= this.minX && vec3d.a <= this.maxX && vec3d.c >= this.minZ && vec3d.c <= this.maxZ;
}
private boolean c(Vec3D vec3d) {
return vec3d == null ? false : vec3d.a >= this.minX && vec3d.a <= this.maxX && vec3d.b >= this.minY && vec3d.b <= this.maxY;
}
public void d(World world, int i, int j, int k) {
}
public boolean canPlace(World world, int i, int j, int k, int l) {
return this.canPlace(world, i, j, k);
}
public boolean canPlace(World world, int i, int j, int k) {
int l = world.getTypeId(i, j, k);
return l == 0 || byId[l].material.isReplacable();
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
return false;
}
public void b(World world, int i, int j, int k, Entity entity) {
}
public void postPlace(World world, int i, int j, int k, int l) {
}
public void b(World world, int i, int j, int k, EntityHuman entityhuman) {
}
public void a(World world, int i, int j, int k, Entity entity, Vec3D vec3d) {
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
}
public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) {
return false;
}
public boolean isPowerSource() {
return false;
}
public void a(World world, int i, int j, int k, Entity entity) {
}
public boolean d(World world, int i, int j, int k, int l) {
return false;
}
public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
entityhuman.a(StatisticList.C[this.id], 1);
this.g(world, i, j, k, l);
}
public boolean f(World world, int i, int j, int k) {
return true;
}
public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) {
}
public Block a(String s) {
this.name = "tile." + s;
return this;
}
public String k() {
return StatisticCollector.a(this.l() + ".name");
}
public String l() {
return this.name;
}
public void a(World world, int i, int j, int k, int l, int i1) {
}
public boolean m() {
return this.br;
}
protected Block n() {
this.br = false;
return this;
}
public int e() {
return this.material.j();
}
static {
Item.byId[WOOL.id] = (new ItemCloth(WOOL.id - 256)).a("cloth");
Item.byId[LOG.id] = (new ItemLog(LOG.id - 256)).a("log");
Item.byId[STEP.id] = (new ItemStep(STEP.id - 256)).a("stoneSlab");
Item.byId[SAPLING.id] = (new ItemSapling(SAPLING.id - 256)).a("sapling");
Item.byId[LEAVES.id] = (new ItemLeaves(LEAVES.id - 256)).a("leaves");
Item.byId[PISTON.id] = new ItemPiston(PISTON.id - 256);
Item.byId[PISTON_STICKY.id] = new ItemPiston(PISTON_STICKY.id - 256);
for (int i = 0; i < 256; ++i) {
if (byId[i] != null && Item.byId[i] == null) {
Item.byId[i] = new ItemBlock(i - 256);
byId[i].h();
}
}
r[0] = true;
StatisticList.b();
}
}
@@ -0,0 +1,201 @@
package net.minecraft.server;
import org.bukkit.event.entity.EntityDamageEvent;
import java.util.Iterator;
import java.util.Random;
public class BlockBed extends Block {
public static final int[][] a = new int[][] { { 0, 1}, { -1, 0}, { 0, -1}, { 1, 0}};
public BlockBed(int i) {
super(i, 134, Material.CLOTH);
this.o();
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
if (world.isStatic) {
return true;
} else {
int l = world.getData(i, j, k);
if (!d(l)) {
int i1 = c(l);
i += a[i1][0];
k += a[i1][1];
if (world.getTypeId(i, j, k) != this.id) {
return true;
}
l = world.getData(i, j, k);
}
if (!world.worldProvider.d()) {
double d0 = (double) i + 0.5D;
double d1 = (double) j + 0.5D;
double d2 = (double) k + 0.5D;
world.setTypeId(i, j, k, 0);
int j1 = c(l);
i += a[j1][0];
k += a[j1][1];
if (world.getTypeId(i, j, k) == this.id) {
world.setTypeId(i, j, k, 0);
d0 = (d0 + (double) i + 0.5D) / 2.0D;
d1 = (d1 + (double) j + 0.5D) / 2.0D;
d2 = (d2 + (double) k + 0.5D) / 2.0D;
}
world.createExplosion((Entity) null, (double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F), 5.0F, true, EntityDamageEvent.DamageCause.BED_EXPLOSION); //Project poseidon
return true;
} else {
if (e(l)) {
EntityHuman entityhuman1 = null;
Iterator iterator = world.players.iterator();
while (iterator.hasNext()) {
EntityHuman entityhuman2 = (EntityHuman) iterator.next();
if (entityhuman2.isSleeping()) {
ChunkCoordinates chunkcoordinates = entityhuman2.A;
if (chunkcoordinates.x == i && chunkcoordinates.y == j && chunkcoordinates.z == k) {
entityhuman1 = entityhuman2;
}
}
}
if (entityhuman1 != null) {
entityhuman.a("tile.bed.occupied");
return true;
}
a(world, i, j, k, false);
}
EnumBedError enumbederror = entityhuman.a(i, j, k);
if (enumbederror == EnumBedError.OK) {
a(world, i, j, k, true);
return true;
} else {
if (enumbederror == EnumBedError.NOT_POSSIBLE_NOW) {
entityhuman.a("tile.bed.noSleep");
}
return true;
}
}
}
}
public int a(int i, int j) {
if (i == 0) {
return Block.WOOD.textureId;
} else {
int k = c(j);
int l = BedBlockTextures.c[k][i];
return d(j) ? (l == 2 ? this.textureId + 2 + 16 : (l != 5 && l != 4 ? this.textureId + 1 : this.textureId + 1 + 16)) : (l == 3 ? this.textureId - 1 + 16 : (l != 5 && l != 4 ? this.textureId : this.textureId + 16));
}
}
public boolean b() {
return false;
}
public boolean a() {
return false;
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
this.o();
}
public void doPhysics(World world, int i, int j, int k, int l) {
int i1 = world.getData(i, j, k);
int j1 = c(i1);
if (d(i1)) {
if (world.getTypeId(i - a[j1][0], j, k - a[j1][1]) != this.id) {
world.setTypeId(i, j, k, 0);
}
} else if (world.getTypeId(i + a[j1][0], j, k + a[j1][1]) != this.id) {
world.setTypeId(i, j, k, 0);
if (!world.isStatic) {
this.g(world, i, j, k, i1);
}
}
}
public int a(int i, Random random) {
return d(i) ? 0 : Item.BED.id;
}
private void o() {
this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.5625F, 1.0F);
}
public static int c(int i) {
return i & 3;
}
public static boolean d(int i) {
return (i & 8) != 0;
}
public static boolean e(int i) {
return (i & 4) != 0;
}
public static void a(World world, int i, int j, int k, boolean flag) {
int l = world.getData(i, j, k);
if (flag) {
l |= 4;
} else {
l &= -5;
}
world.setData(i, j, k, l);
}
public static ChunkCoordinates f(World world, int i, int j, int k, int l) {
int i1 = world.getData(i, j, k);
int j1 = c(i1);
for (int k1 = 0; k1 <= 1; ++k1) {
int l1 = i - a[j1][0] * k1 - 1;
int i2 = k - a[j1][1] * k1 - 1;
int j2 = l1 + 2;
int k2 = i2 + 2;
for (int l2 = l1; l2 <= j2; ++l2) {
for (int i3 = i2; i3 <= k2; ++i3) {
if (world.e(l2, j - 1, i3) && world.isEmpty(l2, j, i3) && world.isEmpty(l2, j + 1, i3)) {
if (l <= 0) {
return new ChunkCoordinates(l2, j, i3);
}
--l;
}
}
}
}
return null;
}
public void dropNaturally(World world, int i, int j, int k, int l, float f) {
if (!d(l)) {
super.dropNaturally(world, i, j, k, l, f);
}
}
public int e() {
return 1;
}
}
@@ -0,0 +1,22 @@
package net.minecraft.server;
import org.bukkit.event.block.BlockRedstoneEvent;
public class BlockBloodStone extends Block {
public BlockBloodStone(int i, int j) {
super(i, j, Material.STONE);
}
// CraftBukkit start
public void doPhysics(World world, int i, int j, int k, int l) {
if (net.minecraft.server.Block.byId[l] != null && net.minecraft.server.Block.byId[l].isPowerSource()) {
org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k);
int power = block.getBlockPower();
BlockRedstoneEvent event = new BlockRedstoneEvent(block, power, power);
world.getServer().getPluginManager().callEvent(event);
}
}
// CraftBukkit end
}
@@ -0,0 +1,18 @@
package net.minecraft.server;
import java.util.Random;
public class BlockBookshelf extends Block {
public BlockBookshelf(int i, int j) {
super(i, j, Material.WOOD);
}
public int a(int i) {
return i <= 1 ? 4 : this.textureId;
}
public int a(Random random) {
return 0;
}
}
@@ -0,0 +1,15 @@
package net.minecraft.server;
public class BlockBreakable extends Block {
private boolean a;
protected BlockBreakable(int i, int j, Material material, boolean flag) {
super(i, j, material);
this.a = flag;
}
public boolean a() {
return false;
}
}
@@ -0,0 +1,248 @@
package net.minecraft.server;
import org.bukkit.event.block.BlockRedstoneEvent;
import java.util.Random;
public class BlockButton extends Block {
protected BlockButton(int i, int j) {
super(i, j, Material.ORIENTABLE);
this.a(true);
}
public AxisAlignedBB e(World world, int i, int j, int k) {
return null;
}
public int c() {
return 20;
}
public boolean a() {
return false;
}
public boolean b() {
return false;
}
public boolean canPlace(World world, int i, int j, int k, int l) {
return l == 2 && world.e(i, j, k + 1) ? true : (l == 3 && world.e(i, j, k - 1) ? true : (l == 4 && world.e(i + 1, j, k) ? true : l == 5 && world.e(i - 1, j, k)));
}
public boolean canPlace(World world, int i, int j, int k) {
return world.e(i - 1, j, k) ? true : (world.e(i + 1, j, k) ? true : (world.e(i, j, k - 1) ? true : world.e(i, j, k + 1)));
}
public void postPlace(World world, int i, int j, int k, int l) {
int i1 = world.getData(i, j, k);
int j1 = i1 & 8;
i1 &= 7;
if (l == 2 && world.e(i, j, k + 1)) {
i1 = 4;
} else if (l == 3 && world.e(i, j, k - 1)) {
i1 = 3;
} else if (l == 4 && world.e(i + 1, j, k)) {
i1 = 2;
} else if (l == 5 && world.e(i - 1, j, k)) {
i1 = 1;
} else {
i1 = this.g(world, i, j, k);
}
world.setData(i, j, k, i1 + j1);
}
private int g(World world, int i, int j, int k) {
return world.e(i - 1, j, k) ? 1 : (world.e(i + 1, j, k) ? 2 : (world.e(i, j, k - 1) ? 3 : (world.e(i, j, k + 1) ? 4 : 1)));
}
public void doPhysics(World world, int i, int j, int k, int l) {
if (this.h(world, i, j, k)) {
int i1 = world.getData(i, j, k) & 7;
boolean flag = false;
if (!world.e(i - 1, j, k) && i1 == 1) {
flag = true;
}
if (!world.e(i + 1, j, k) && i1 == 2) {
flag = true;
}
if (!world.e(i, j, k - 1) && i1 == 3) {
flag = true;
}
if (!world.e(i, j, k + 1) && i1 == 4) {
flag = true;
}
if (flag) {
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
}
}
}
private boolean h(World world, int i, int j, int k) {
if (!this.canPlace(world, i, j, k)) {
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
return false;
} else {
return true;
}
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
int l = iblockaccess.getData(i, j, k);
int i1 = l & 7;
boolean flag = (l & 8) > 0;
float f = 0.375F;
float f1 = 0.625F;
float f2 = 0.1875F;
float f3 = 0.125F;
if (flag) {
f3 = 0.0625F;
}
if (i1 == 1) {
this.a(0.0F, f, 0.5F - f2, f3, f1, 0.5F + f2);
} else if (i1 == 2) {
this.a(1.0F - f3, f, 0.5F - f2, 1.0F, f1, 0.5F + f2);
} else if (i1 == 3) {
this.a(0.5F - f2, f, 0.0F, 0.5F + f2, f1, f3);
} else if (i1 == 4) {
this.a(0.5F - f2, f, 1.0F - f3, 0.5F + f2, f1, 1.0F);
}
}
public void b(World world, int i, int j, int k, EntityHuman entityhuman) {
this.interact(world, i, j, k, entityhuman);
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
int l = world.getData(i, j, k);
int i1 = l & 7;
int j1 = 8 - (l & 8);
if (j1 == 0) {
return true;
} else {
// CraftBukkit start
org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k);
int old = (j1 != 8) ? 1 : 0;
int current = (j1 == 8) ? 1 : 0;
BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, old, current);
world.getServer().getPluginManager().callEvent(eventRedstone);
if ((eventRedstone.getNewCurrent() > 0) != (j1 == 8)) {
return true;
}
// CraftBukkit end
world.setData(i, j, k, i1 + j1);
world.b(i, j, k, i, j, k);
world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "random.click", 0.3F, 0.6F);
world.applyPhysics(i, j, k, this.id);
if (i1 == 1) {
world.applyPhysics(i - 1, j, k, this.id);
} else if (i1 == 2) {
world.applyPhysics(i + 1, j, k, this.id);
} else if (i1 == 3) {
world.applyPhysics(i, j, k - 1, this.id);
} else if (i1 == 4) {
world.applyPhysics(i, j, k + 1, this.id);
} else {
world.applyPhysics(i, j - 1, k, this.id);
}
world.c(i, j, k, this.id, this.c());
return true;
}
}
public void remove(World world, int i, int j, int k) {
int l = world.getData(i, j, k);
if ((l & 8) > 0) {
world.applyPhysics(i, j, k, this.id);
int i1 = l & 7;
if (i1 == 1) {
world.applyPhysics(i - 1, j, k, this.id);
} else if (i1 == 2) {
world.applyPhysics(i + 1, j, k, this.id);
} else if (i1 == 3) {
world.applyPhysics(i, j, k - 1, this.id);
} else if (i1 == 4) {
world.applyPhysics(i, j, k + 1, this.id);
} else {
world.applyPhysics(i, j - 1, k, this.id);
}
}
super.remove(world, i, j, k);
}
public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) {
return (iblockaccess.getData(i, j, k) & 8) > 0;
}
public boolean d(World world, int i, int j, int k, int l) {
int i1 = world.getData(i, j, k);
if ((i1 & 8) == 0) {
return false;
} else {
int j1 = i1 & 7;
return j1 == 5 && l == 1 ? true : (j1 == 4 && l == 2 ? true : (j1 == 3 && l == 3 ? true : (j1 == 2 && l == 4 ? true : j1 == 1 && l == 5)));
}
}
public boolean isPowerSource() {
return true;
}
public void a(World world, int i, int j, int k, Random random) {
if (!world.isStatic) {
int l = world.getData(i, j, k);
if ((l & 8) != 0) {
// CraftBukkit start
org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k);
BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, 1, 0);
world.getServer().getPluginManager().callEvent(eventRedstone);
if (eventRedstone.getNewCurrent() > 0) return;
// CraftBukkit end
world.setData(i, j, k, l & 7);
world.applyPhysics(i, j, k, this.id);
int i1 = l & 7;
if (i1 == 1) {
world.applyPhysics(i - 1, j, k, this.id);
} else if (i1 == 2) {
world.applyPhysics(i + 1, j, k, this.id);
} else if (i1 == 3) {
world.applyPhysics(i, j, k - 1, this.id);
} else if (i1 == 4) {
world.applyPhysics(i, j, k + 1, this.id);
} else {
world.applyPhysics(i, j - 1, k, this.id);
}
world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "random.click", 0.3F, 0.5F);
world.b(i, j, k, i, j, k);
}
}
}
}
@@ -0,0 +1,103 @@
package net.minecraft.server;
// CraftBukkit start
import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import java.util.Random;
// CraftBukkit end
public class BlockCactus extends Block {
protected BlockCactus(int i, int j) {
super(i, j, Material.CACTUS);
this.a(true);
}
public void a(World world, int i, int j, int k, Random random) {
if (world.isEmpty(i, j + 1, k)) {
int l;
for (l = 1; world.getTypeId(i, j - l, k) == this.id; ++l) {
;
}
if (l < 3) {
int i1 = world.getData(i, j, k);
if (i1 == 15) {
world.setTypeId(i, j + 1, k, this.id);
world.setData(i, j, k, 0);
} else {
world.setData(i, j, k, i1 + 1);
}
}
}
}
public AxisAlignedBB e(World world, int i, int j, int k) {
float f = 0.0625F;
return AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) ((float) (j + 1) - f), (double) ((float) (k + 1) - f));
}
public int a(int i) {
return i == 1 ? this.textureId - 1 : (i == 0 ? this.textureId + 1 : this.textureId);
}
public boolean b() {
return false;
}
public boolean a() {
return false;
}
public boolean canPlace(World world, int i, int j, int k) {
return !super.canPlace(world, i, j, k) ? false : this.f(world, i, j, k);
}
public void doPhysics(World world, int i, int j, int k, int l) {
if (!this.f(world, i, j, k)) {
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
}
}
public boolean f(World world, int i, int j, int k) {
if (world.getMaterial(i - 1, j, k).isBuildable()) {
return false;
} else if (world.getMaterial(i + 1, j, k).isBuildable()) {
return false;
} else if (world.getMaterial(i, j, k - 1).isBuildable()) {
return false;
} else if (world.getMaterial(i, j, k + 1).isBuildable()) {
return false;
} else {
int l = world.getTypeId(i, j - 1, k);
return l == Block.CACTUS.id || l == Block.SAND.id;
}
}
public void a(World world, int i, int j, int k, Entity entity) {
// CraftBukkit start - ENTITY_DAMAGEBY_BLOCK event
if (entity instanceof EntityLiving) {
org.bukkit.block.Block damager = world.getWorld().getBlockAt(i, j, k);
org.bukkit.entity.Entity damagee = (entity == null) ? null : entity.getBukkitEntity();
EntityDamageByBlockEvent event = new EntityDamageByBlockEvent(damager, damagee, EntityDamageEvent.DamageCause.CONTACT, 1);
world.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
entity.damageEntity((Entity) null, event.getDamage());
}
return;
}
// CraftBukkit end
entity.damageEntity((Entity) null, 1);
}
}
@@ -0,0 +1,91 @@
package net.minecraft.server;
import java.util.Random;
public class BlockCake extends Block {
protected BlockCake(int i, int j) {
super(i, j, Material.CAKE);
this.a(true);
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
int l = iblockaccess.getData(i, j, k);
float f = 0.0625F;
float f1 = (float) (1 + l * 2) / 16.0F;
float f2 = 0.5F;
this.a(f1, 0.0F, f, 1.0F - f, f2, 1.0F - f);
}
public AxisAlignedBB e(World world, int i, int j, int k) {
int l = world.getData(i, j, k);
float f = 0.0625F;
float f1 = (float) (1 + l * 2) / 16.0F;
float f2 = 0.5F;
return AxisAlignedBB.b((double) ((float) i + f1), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) ((float) j + f2 - f), (double) ((float) (k + 1) - f));
}
public int a(int i, int j) {
return i == 1 ? this.textureId : (i == 0 ? this.textureId + 3 : (j > 0 && i == 4 ? this.textureId + 2 : this.textureId + 1));
}
public int a(int i) {
return i == 1 ? this.textureId : (i == 0 ? this.textureId + 3 : this.textureId + 1);
}
public boolean b() {
return false;
}
public boolean a() {
return false;
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
this.c(world, i, j, k, entityhuman);
return true;
}
public void b(World world, int i, int j, int k, EntityHuman entityhuman) {
this.c(world, i, j, k, entityhuman);
}
private void c(World world, int i, int j, int k, EntityHuman entityhuman) {
if (entityhuman.health < 20) {
entityhuman.b(3);
int l = world.getData(i, j, k) + 1;
if (l >= 6) {
world.setTypeId(i, j, k, 0);
} else {
world.setData(i, j, k, l);
world.i(i, j, k);
}
}
}
public boolean canPlace(World world, int i, int j, int k) {
return !super.canPlace(world, i, j, k) ? false : this.f(world, i, j, k);
}
public void doPhysics(World world, int i, int j, int k, int l) {
if (!this.f(world, i, j, k)) {
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
}
}
public boolean f(World world, int i, int j, int k) {
return world.getMaterial(i, j - 1, k).isBuildable();
}
public int a(Random random) {
return 0;
}
public int a(int i, Random random) {
return 0;
}
}
@@ -0,0 +1,120 @@
package net.minecraft.server;
import java.util.Random;
public class BlockChest extends BlockContainer {
private Random a = new Random();
protected BlockChest(int i) {
super(i, Material.WOOD);
this.textureId = 26;
}
public int a(int i) {
return i == 1 ? this.textureId - 1 : (i == 0 ? this.textureId - 1 : (i == 3 ? this.textureId + 1 : this.textureId));
}
public boolean canPlace(World world, int i, int j, int k) {
int l = 0;
if (world.getTypeId(i - 1, j, k) == this.id) {
++l;
}
if (world.getTypeId(i + 1, j, k) == this.id) {
++l;
}
if (world.getTypeId(i, j, k - 1) == this.id) {
++l;
}
if (world.getTypeId(i, j, k + 1) == this.id) {
++l;
}
return l > 1 ? false : (this.g(world, i - 1, j, k) ? false : (this.g(world, i + 1, j, k) ? false : (this.g(world, i, j, k - 1) ? false : !this.g(world, i, j, k + 1))));
}
private boolean g(World world, int i, int j, int k) {
return world.getTypeId(i, j, k) != this.id ? false : (world.getTypeId(i - 1, j, k) == this.id ? true : (world.getTypeId(i + 1, j, k) == this.id ? true : (world.getTypeId(i, j, k - 1) == this.id ? true : world.getTypeId(i, j, k + 1) == this.id)));
}
public void remove(World world, int i, int j, int k) {
TileEntityChest tileentitychest = (TileEntityChest) world.getTileEntity(i, j, k);
for (int l = 0; l < tileentitychest.getSize(); ++l) {
ItemStack itemstack = tileentitychest.getItem(l);
if (itemstack != null) {
float f = this.a.nextFloat() * 0.8F + 0.1F;
float f1 = this.a.nextFloat() * 0.8F + 0.1F;
float f2 = this.a.nextFloat() * 0.8F + 0.1F;
while (itemstack.count > 0) {
int i1 = this.a.nextInt(21) + 10;
if (i1 > itemstack.count) {
i1 = itemstack.count;
}
itemstack.count -= i1;
EntityItem entityitem = new EntityItem(world, (double) ((float) i + f), (double) ((float) j + f1), (double) ((float) k + f2), new ItemStack(itemstack.id, i1, itemstack.getData()));
float f3 = 0.05F;
entityitem.motX = (double) ((float) this.a.nextGaussian() * f3);
entityitem.motY = (double) ((float) this.a.nextGaussian() * f3 + 0.2F);
entityitem.motZ = (double) ((float) this.a.nextGaussian() * f3);
world.addEntity(entityitem);
}
tileentitychest.setItem(l, null);
}
}
super.remove(world, i, j, k);
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
Object object = (TileEntityChest) world.getTileEntity(i, j, k);
if (world.e(i, j + 1, k)) {
return true;
} else if (world.getTypeId(i - 1, j, k) == this.id && world.e(i - 1, j + 1, k)) {
return true;
} else if (world.getTypeId(i + 1, j, k) == this.id && world.e(i + 1, j + 1, k)) {
return true;
} else if (world.getTypeId(i, j, k - 1) == this.id && world.e(i, j + 1, k - 1)) {
return true;
} else if (world.getTypeId(i, j, k + 1) == this.id && world.e(i, j + 1, k + 1)) {
return true;
} else {
if (world.getTypeId(i - 1, j, k) == this.id) {
object = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(i - 1, j, k), (IInventory) object);
}
if (world.getTypeId(i + 1, j, k) == this.id) {
object = new InventoryLargeChest("Large chest", (IInventory) object, (TileEntityChest) world.getTileEntity(i + 1, j, k));
}
if (world.getTypeId(i, j, k - 1) == this.id) {
object = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(i, j, k - 1), (IInventory) object);
}
if (world.getTypeId(i, j, k + 1) == this.id) {
object = new InventoryLargeChest("Large chest", (IInventory) object, (TileEntityChest) world.getTileEntity(i, j, k + 1));
}
if (world.isStatic) {
return true;
} else {
entityhuman.a((IInventory) object);
return true;
}
}
}
protected TileEntity a_() {
return new TileEntityChest();
}
}
@@ -0,0 +1,18 @@
package net.minecraft.server;
import java.util.Random;
public class BlockClay extends Block {
public BlockClay(int i, int j) {
super(i, j, Material.CLAY);
}
public int a(int i, Random random) {
return Item.CLAY_BALL.id;
}
public int a(Random random) {
return 4;
}
}
@@ -0,0 +1,29 @@
package net.minecraft.server;
public class BlockCloth extends Block {
public BlockCloth() {
super(35, 64, Material.CLOTH);
}
public int a(int i, int j) {
if (j == 0) {
return this.textureId;
} else {
j = ~(j & 15);
return 113 + ((j & 8) >> 3) + (j & 7) * 16;
}
}
protected int a_(int i) {
return i;
}
public static int c(int i) {
return ~i & 15;
}
public static int d(int i) {
return ~i & 15;
}
}
@@ -0,0 +1,26 @@
package net.minecraft.server;
public abstract class BlockContainer extends Block {
protected BlockContainer(int i, Material material) {
super(i, material);
isTileEntity[i] = true;
}
protected BlockContainer(int i, int j, Material material) {
super(i, j, material);
isTileEntity[i] = true;
}
public void c(World world, int i, int j, int k) {
super.c(world, i, j, k);
world.setTileEntity(i, j, k, this.a_());
}
public void remove(World world, int i, int j, int k) {
super.remove(world, i, j, k);
world.o(i, j, k);
}
protected abstract TileEntity a_();
}
@@ -0,0 +1,114 @@
package net.minecraft.server;
import java.util.Random;
public class BlockCrops extends BlockFlower {
protected BlockCrops(int i, int j) {
super(i, j);
this.textureId = j;
this.a(true);
float f = 0.5F;
this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.25F, 0.5F + f);
}
protected boolean c(int i) {
return i == Block.SOIL.id;
}
public void a(World world, int i, int j, int k, Random random) {
super.a(world, i, j, k, random);
if (world.getLightLevel(i, j + 1, k) >= 9) {
int l = world.getData(i, j, k);
if (l < 7) {
float f = this.h(world, i, j, k);
if (random.nextInt((int) (100.0F / f)) == 0) {
++l;
world.setData(i, j, k, l);
}
}
}
}
public void d_(World world, int i, int j, int k) {
world.setData(i, j, k, 7);
}
private float h(World world, int i, int j, int k) {
float f = 1.0F;
int l = world.getTypeId(i, j, k - 1);
int i1 = world.getTypeId(i, j, k + 1);
int j1 = world.getTypeId(i - 1, j, k);
int k1 = world.getTypeId(i + 1, j, k);
int l1 = world.getTypeId(i - 1, j, k - 1);
int i2 = world.getTypeId(i + 1, j, k - 1);
int j2 = world.getTypeId(i + 1, j, k + 1);
int k2 = world.getTypeId(i - 1, j, k + 1);
boolean flag = j1 == this.id || k1 == this.id;
boolean flag1 = l == this.id || i1 == this.id;
boolean flag2 = l1 == this.id || i2 == this.id || j2 == this.id || k2 == this.id;
for (int l2 = i - 1; l2 <= i + 1; ++l2) {
for (int i3 = k - 1; i3 <= k + 1; ++i3) {
int j3 = world.getTypeId(l2, j - 1, i3);
float f1 = 0.0F;
if (j3 == Block.SOIL.id) {
f1 = 1.0F;
if (world.getData(l2, j - 1, i3) > 0) {
f1 = 3.0F;
}
}
if (l2 != i || i3 != k) {
f1 /= 4.0F;
}
f += f1;
}
}
if (flag2 || flag && flag1) {
f /= 2.0F;
}
return f;
}
public int a(int i, int j) {
if (j < 0) {
j = 7;
}
return this.textureId + j;
}
public void dropNaturally(World world, int i, int j, int k, int l, float f) {
super.dropNaturally(world, i, j, k, l, f);
if (!world.isStatic) {
for (int i1 = 0; i1 < 3; ++i1) {
if (world.random.nextInt(15) <= l) {
float f1 = 0.7F;
float f2 = world.random.nextFloat() * f1 + (1.0F - f1) * 0.5F;
float f3 = world.random.nextFloat() * f1 + (1.0F - f1) * 0.5F;
float f4 = world.random.nextFloat() * f1 + (1.0F - f1) * 0.5F;
EntityItem entityitem = new EntityItem(world, (double) ((float) i + f2), (double) ((float) j + f3), (double) ((float) k + f4), new ItemStack(Item.SEEDS));
entityitem.pickupDelay = 10;
world.addEntity(entityitem);
}
}
}
}
public int a(int i, Random random) {
return i == 7 ? Item.WHEAT.id : -1;
}
public int a(Random random) {
return 1;
}
}
@@ -0,0 +1,25 @@
package net.minecraft.server;
import java.util.Random;
public class BlockDeadBush extends BlockFlower {
protected BlockDeadBush(int i, int j) {
super(i, j);
float f = 0.4F;
this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.8F, 0.5F + f);
}
protected boolean c(int i) {
return i == Block.SAND.id;
}
public int a(int i, int j) {
return this.textureId;
}
public int a(int i, Random random) {
return -1;
}
}
@@ -0,0 +1,145 @@
package net.minecraft.server;
import java.util.Random;
public class BlockDiode extends Block {
public static final double[] a = new double[] { -0.0625D, 0.0625D, 0.1875D, 0.3125D};
private static final int[] b = new int[] { 1, 2, 3, 4};
private final boolean c;
protected BlockDiode(int i, boolean flag) {
super(i, 6, Material.ORIENTABLE);
this.c = flag;
this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
}
public boolean b() {
return false;
}
public boolean canPlace(World world, int i, int j, int k) {
return !world.e(i, j - 1, k) ? false : super.canPlace(world, i, j, k);
}
public boolean f(World world, int i, int j, int k) {
return !world.e(i, j - 1, k) ? false : super.f(world, i, j, k);
}
public void a(World world, int i, int j, int k, Random random) {
int l = world.getData(i, j, k);
boolean flag = this.f(world, i, j, k, l);
if (this.c && !flag) {
world.setTypeIdAndData(i, j, k, Block.DIODE_OFF.id, l);
} else if (!this.c) {
world.setTypeIdAndData(i, j, k, Block.DIODE_ON.id, l);
if (!flag) {
int i1 = (l & 12) >> 2;
world.c(i, j, k, Block.DIODE_ON.id, b[i1] * 2);
}
}
}
public int a(int i, int j) {
return i == 0 ? (this.c ? 99 : 115) : (i == 1 ? (this.c ? 147 : 131) : 5);
}
public int a(int i) {
return this.a(i, 0);
}
public boolean d(World world, int i, int j, int k, int l) {
return this.a(world, i, j, k, l);
}
public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) {
if (!this.c) {
return false;
} else {
int i1 = iblockaccess.getData(i, j, k) & 3;
return i1 == 0 && l == 3 ? true : (i1 == 1 && l == 4 ? true : (i1 == 2 && l == 2 ? true : i1 == 3 && l == 5));
}
}
public void doPhysics(World world, int i, int j, int k, int l) {
if (!this.f(world, i, j, k)) {
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
} else {
int i1 = world.getData(i, j, k);
boolean flag = this.f(world, i, j, k, i1);
int j1 = (i1 & 12) >> 2;
if (this.c && !flag) {
world.c(i, j, k, this.id, b[j1] * 2);
} else if (!this.c && flag) {
world.c(i, j, k, this.id, b[j1] * 2);
}
}
}
private boolean f(World world, int i, int j, int k, int l) {
int i1 = l & 3;
switch (i1) {
case 0:
return world.isBlockFaceIndirectlyPowered(i, j, k + 1, 3) || world.getTypeId(i, j, k + 1) == Block.REDSTONE_WIRE.id && world.getData(i, j, k + 1) > 0;
case 1:
return world.isBlockFaceIndirectlyPowered(i - 1, j, k, 4) || world.getTypeId(i - 1, j, k) == Block.REDSTONE_WIRE.id && world.getData(i - 1, j, k) > 0;
case 2:
return world.isBlockFaceIndirectlyPowered(i, j, k - 1, 2) || world.getTypeId(i, j, k - 1) == Block.REDSTONE_WIRE.id && world.getData(i, j, k - 1) > 0;
case 3:
return world.isBlockFaceIndirectlyPowered(i + 1, j, k, 5) || world.getTypeId(i + 1, j, k) == Block.REDSTONE_WIRE.id && world.getData(i + 1, j, k) > 0;
default:
return false;
}
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
int l = world.getData(i, j, k);
int i1 = (l & 12) >> 2;
i1 = i1 + 1 << 2 & 12;
world.setData(i, j, k, i1 | l & 3);
return true;
}
public boolean isPowerSource() {
return false;
}
public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) {
int l = ((MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 0.5D) & 3) + 2) % 4;
world.setData(i, j, k, l);
boolean flag = this.f(world, i, j, k, l);
if (flag) {
world.c(i, j, k, this.id, 1);
}
}
public void c(World world, int i, int j, int k) {
world.applyPhysics(i + 1, j, k, this.id);
world.applyPhysics(i - 1, j, k, this.id);
world.applyPhysics(i, j, k + 1, this.id);
world.applyPhysics(i, j, k - 1, this.id);
world.applyPhysics(i, j - 1, k, this.id);
world.applyPhysics(i, j + 1, k, this.id);
}
public boolean a() {
return false;
}
public int a(int i, Random random) {
return Item.DIODE.id;
}
}
@@ -0,0 +1,8 @@
package net.minecraft.server;
public class BlockDirt extends Block {
protected BlockDirt(int i, int j) {
super(i, j, Material.EARTH);
}
}
@@ -0,0 +1,249 @@
package net.minecraft.server;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.event.block.BlockDispenseEvent;
import org.bukkit.util.Vector;
import java.util.Random;
// CraftBukkit start
// CraftBukkit end
public class BlockDispenser extends BlockContainer {
private Random a = new Random();
protected BlockDispenser(int i) {
super(i, Material.STONE);
this.textureId = 45;
}
public int c() {
return 4;
}
public int a(int i, Random random) {
return Block.DISPENSER.id;
}
public void c(World world, int i, int j, int k) {
super.c(world, i, j, k);
this.g(world, i, j, k);
}
private void g(World world, int i, int j, int k) {
if (!world.isStatic) {
int l = world.getTypeId(i, j, k - 1);
int i1 = world.getTypeId(i, j, k + 1);
int j1 = world.getTypeId(i - 1, j, k);
int k1 = world.getTypeId(i + 1, j, k);
byte b0 = 3;
if (Block.o[l] && !Block.o[i1]) {
b0 = 3;
}
if (Block.o[i1] && !Block.o[l]) {
b0 = 2;
}
if (Block.o[j1] && !Block.o[k1]) {
b0 = 5;
}
if (Block.o[k1] && !Block.o[j1]) {
b0 = 4;
}
world.setData(i, j, k, b0);
}
}
public int a(int i) {
return i == 1 ? this.textureId + 17 : (i == 0 ? this.textureId + 17 : (i == 3 ? this.textureId + 1 : this.textureId));
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
if (world.isStatic) {
return true;
} else {
TileEntityDispenser tileentitydispenser = (TileEntityDispenser) world.getTileEntity(i, j, k);
entityhuman.a(tileentitydispenser);
return true;
}
}
// CraftBukkit - private -> public
public void dispense(World world, int i, int j, int k, Random random) {
int l = world.getData(i, j, k);
byte b0 = 0;
byte b1 = 0;
if (l == 3) {
b1 = 1;
} else if (l == 2) {
b1 = -1;
} else if (l == 5) {
b0 = 1;
} else {
b0 = -1;
}
TileEntityDispenser tileentitydispenser = (TileEntityDispenser) world.getTileEntity(i, j, k);
// CraftBukkit start
int dispenseSlot = tileentitydispenser.findDispenseSlot();
ItemStack itemstack = null;
if (dispenseSlot > -1) {
itemstack = tileentitydispenser.getContents()[dispenseSlot];
// Copy item stack, because we want it to have 1 item
itemstack = new ItemStack(itemstack.id, 1, itemstack.damage);
}
// CraftBukkit end
double d0 = (double) i + (double) b0 * 0.6D + 0.5D;
double d1 = (double) j + 0.5D;
double d2 = (double) k + (double) b1 * 0.6D + 0.5D;
if (itemstack == null) {
world.e(1001, i, j, k, 0);
} else {
// CraftBukkit start
double d3 = random.nextDouble() * 0.1D + 0.2D;
double motX = (double) b0 * d3;
double motY = 0.20000000298023224D;
double motZ = (double) b1 * d3;
motX += random.nextGaussian() * 0.007499999832361937D * 6.0D;
motY += random.nextGaussian() * 0.007499999832361937D * 6.0D;
motZ += random.nextGaussian() * 0.007499999832361937D * 6.0D;
org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k);
org.bukkit.inventory.ItemStack bukkitItem = new CraftItemStack(itemstack).clone();
BlockDispenseEvent event = new BlockDispenseEvent(block, bukkitItem, new Vector(motX, motY, motZ));
world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
// Actually remove the item
tileentitydispenser.splitStack(dispenseSlot, 1);
motX = event.getVelocity().getX();
motY = event.getVelocity().getY();
motZ = event.getVelocity().getZ();
itemstack = new ItemStack(event.getItem().getTypeId(), event.getItem().getAmount(), event.getItem().getDurability());
// CraftBukkit end
if (itemstack.id == Item.ARROW.id) {
EntityArrow entityarrow = new EntityArrow(world, d0, d1, d2);
entityarrow.a((double) b0, 0.10000000149011612D, (double) b1, 1.1F, 6.0F);
entityarrow.fromPlayer = true;
world.addEntity(entityarrow);
world.e(1002, i, j, k, 0);
} else if (itemstack.id == Item.EGG.id) {
EntityEgg entityegg = new EntityEgg(world, d0, d1, d2);
entityegg.a((double) b0, 0.10000000149011612D, (double) b1, 1.1F, 6.0F);
world.addEntity(entityegg);
world.e(1002, i, j, k, 0);
} else if (itemstack.id == Item.SNOW_BALL.id) {
EntitySnowball entitysnowball = new EntitySnowball(world, d0, d1, d2);
entitysnowball.a((double) b0, 0.10000000149011612D, (double) b1, 1.1F, 6.0F);
world.addEntity(entitysnowball);
world.e(1002, i, j, k, 0);
} else {
EntityItem entityitem = new EntityItem(world, d0, d1 - 0.3D, d2, itemstack);
// CraftBukkit start
// double d3 = random.nextDouble() * 0.1D + 0.2D; // Moved up
entityitem.motX = motX;
entityitem.motY = motY;
entityitem.motZ = motZ;
// CraftBukkit end
world.addEntity(entityitem);
world.e(1000, i, j, k, 0);
}
world.e(2000, i, j, k, b0 + 1 + (b1 + 1) * 3);
}
}
public void doPhysics(World world, int i, int j, int k, int l) {
if (l > 0 && Block.byId[l].isPowerSource()) {
boolean flag = world.isBlockIndirectlyPowered(i, j, k) || world.isBlockIndirectlyPowered(i, j + 1, k);
if (flag) {
world.c(i, j, k, this.id, this.c());
}
}
}
public void a(World world, int i, int j, int k, Random random) {
if (world.isBlockIndirectlyPowered(i, j, k) || world.isBlockIndirectlyPowered(i, j + 1, k)) {
this.dispense(world, i, j, k, random);
}
}
protected TileEntity a_() {
return new TileEntityDispenser();
}
public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) {
int l = MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 0.5D) & 3;
if (l == 0) {
world.setData(i, j, k, 2);
}
if (l == 1) {
world.setData(i, j, k, 5);
}
if (l == 2) {
world.setData(i, j, k, 3);
}
if (l == 3) {
world.setData(i, j, k, 4);
}
}
public void remove(World world, int i, int j, int k) {
TileEntityDispenser tileentitydispenser = (TileEntityDispenser) world.getTileEntity(i, j, k);
for (int l = 0; l < tileentitydispenser.getSize(); ++l) {
ItemStack itemstack = tileentitydispenser.getItem(l);
if (itemstack != null) {
float f = this.a.nextFloat() * 0.8F + 0.1F;
float f1 = this.a.nextFloat() * 0.8F + 0.1F;
float f2 = this.a.nextFloat() * 0.8F + 0.1F;
while (itemstack.count > 0) {
int i1 = this.a.nextInt(21) + 10;
if (i1 > itemstack.count) {
i1 = itemstack.count;
}
itemstack.count -= i1;
EntityItem entityitem = new EntityItem(world, (double) ((float) i + f), (double) ((float) j + f1), (double) ((float) k + f2), new ItemStack(itemstack.id, i1, itemstack.getData()));
float f3 = 0.05F;
entityitem.motX = (double) ((float) this.a.nextGaussian() * f3);
entityitem.motY = (double) ((float) this.a.nextGaussian() * f3 + 0.2F);
entityitem.motZ = (double) ((float) this.a.nextGaussian() * f3);
world.addEntity(entityitem);
}
tileentitydispenser.setItem(l, null);
}
}
super.remove(world, i, j, k);
}
}
@@ -0,0 +1,211 @@
package net.minecraft.server;
import org.bukkit.event.block.BlockRedstoneEvent;
import java.util.Random;
public class BlockDoor extends Block {
protected BlockDoor(int i, Material material) {
super(i, material);
this.textureId = 97;
if (material == Material.ORE) {
++this.textureId;
}
float f = 0.5F;
float f1 = 1.0F;
this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f1, 0.5F + f);
}
public int a(int i, int j) {
if (i != 0 && i != 1) {
int k = this.d(j);
if ((k == 0 || k == 2) ^ i <= 3) {
return this.textureId;
} else {
int l = k / 2 + (i & 1 ^ k);
l += (j & 4) / 4;
int i1 = this.textureId - (j & 8) * 2;
if ((l & 1) != 0) {
i1 = -i1;
}
return i1;
}
} else {
return this.textureId;
}
}
public boolean a() {
return false;
}
public boolean b() {
return false;
}
public AxisAlignedBB e(World world, int i, int j, int k) {
this.a(world, i, j, k);
return super.e(world, i, j, k);
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
this.c(this.d(iblockaccess.getData(i, j, k)));
}
public void c(int i) {
float f = 0.1875F;
this.a(0.0F, 0.0F, 0.0F, 1.0F, 2.0F, 1.0F);
if (i == 0) {
this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
}
if (i == 1) {
this.a(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
if (i == 2) {
this.a(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
}
if (i == 3) {
this.a(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
}
}
public void b(World world, int i, int j, int k, EntityHuman entityhuman) {
this.interact(world, i, j, k, entityhuman);
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
if (this.material == Material.ORE) {
return true;
} else {
int l = world.getData(i, j, k);
if ((l & 8) != 0) {
if (world.getTypeId(i, j - 1, k) == this.id) {
this.interact(world, i, j - 1, k, entityhuman);
}
return true;
} else {
if (world.getTypeId(i, j + 1, k) == this.id) {
world.setData(i, j + 1, k, (l ^ 4) + 8);
}
world.setData(i, j, k, l ^ 4);
world.b(i, j - 1, k, i, j, k);
world.a(entityhuman, 1003, i, j, k, 0);
return true;
}
}
}
public void setDoor(World world, int i, int j, int k, boolean flag) {
int l = world.getData(i, j, k);
if ((l & 8) != 0) {
if (world.getTypeId(i, j - 1, k) == this.id) {
this.setDoor(world, i, j - 1, k, flag);
}
} else {
boolean flag1 = (world.getData(i, j, k) & 4) > 0;
if (flag1 != flag) {
if (world.getTypeId(i, j + 1, k) == this.id) {
world.setData(i, j + 1, k, (l ^ 4) + 8);
}
world.setData(i, j, k, l ^ 4);
world.b(i, j - 1, k, i, j, k);
world.a((EntityHuman) null, 1003, i, j, k, 0);
}
}
}
public void doPhysics(World world, int i, int j, int k, int l) {
int i1 = world.getData(i, j, k);
if ((i1 & 8) != 0) {
if (world.getTypeId(i, j - 1, k) != this.id) {
world.setTypeId(i, j, k, 0);
}
if (l > 0 && Block.byId[l].isPowerSource()) {
this.doPhysics(world, i, j - 1, k, l);
}
} else {
boolean flag = false;
if (world.getTypeId(i, j + 1, k) != this.id) {
world.setTypeId(i, j, k, 0);
flag = true;
}
if (!world.e(i, j - 1, k)) {
world.setTypeId(i, j, k, 0);
flag = true;
if (world.getTypeId(i, j + 1, k) == this.id) {
world.setTypeId(i, j + 1, k, 0);
}
}
if (flag) {
if (!world.isStatic) {
this.g(world, i, j, k, i1);
}
} else if (l > 0 && Block.byId[l].isPowerSource()) {
// CraftBukkit start
org.bukkit.World bworld = world.getWorld();
org.bukkit.block.Block block = bworld.getBlockAt(i, j, k);
org.bukkit.block.Block blockTop = bworld.getBlockAt(i, j + 1, k);
int power = block.getBlockPower();
int powerTop = blockTop.getBlockPower();
if (powerTop > power) power = powerTop;
int oldPower = (world.getData(i, j, k) & 4) > 0 ? 15 : 0;
if (oldPower == 0 ^ power == 0) {
BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, oldPower, power);
world.getServer().getPluginManager().callEvent(eventRedstone);
this.setDoor(world, i, j, k, eventRedstone.getNewCurrent() > 0);
}
// CraftBukkit end
}
}
}
public int a(int i, Random random) {
return (i & 8) != 0 ? 0 : (this.material == Material.ORE ? Item.IRON_DOOR.id : Item.WOOD_DOOR.id);
}
public MovingObjectPosition a(World world, int i, int j, int k, Vec3D vec3d, Vec3D vec3d1) {
this.a(world, i, j, k);
return super.a(world, i, j, k, vec3d, vec3d1);
}
public int d(int i) {
return (i & 4) == 0 ? i - 1 & 3 : i & 3;
}
public boolean canPlace(World world, int i, int j, int k) {
return j >= 127 ? false : world.e(i, j - 1, k) && super.canPlace(world, i, j, k) && super.canPlace(world, i, j + 1, k);
}
public static boolean e(int i) {
return (i & 4) != 0;
}
public int e() {
return 1;
}
}
@@ -0,0 +1,70 @@
package net.minecraft.server;
import com.legacyminecraft.poseidon.PoseidonConfig;
public class BlockFence extends Block {
private boolean modernFencingBounding = false;
public BlockFence(int i, int j) {
super(i, j, Material.WOOD);
modernFencingBounding = (boolean) PoseidonConfig.getInstance().getConfigOption("world-settings.use-modern-fence-bounding-boxes", false);
}
public boolean canPlace(World world, int i, int j, int k) {
return world.getTypeId(i, j - 1, k) == this.id ? true : (!world.getMaterial(i, j - 1, k).isBuildable() ? false : super.canPlace(world, i, j, k));
}
public AxisAlignedBB e(World world, int i, int j, int k) {
if(!modernFencingBounding) {
return AxisAlignedBB.b((double) i, (double) j, (double) k, (double) (i + 1), (double) ((float) j + 1.5F), (double) (k + 1));
}
boolean flag = this.b(world, i, j, k - 1);
boolean flag1 = this.b(world, i, j, k + 1);
boolean flag2 = this.b(world, i - 1, j, k);
boolean flag3 = this.b(world, i + 1, j, k);
float f = 0.375F;
float f1 = 0.625F;
float f2 = 0.375F;
float f3 = 0.625F;
if (flag) {
f2 = 0.0F;
}
if (flag1) {
f3 = 1.0F;
}
if (flag2) {
f = 0.0F;
}
if (flag3) {
f1 = 1.0F;
}
return AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f2), (double) ((float) i + f1), (double) ((float) j + 1.5F), (double) ((float) k + f3));
}
public boolean b(IBlockAccess iblockaccess, int i, int j, int k) {
int l = iblockaccess.getTypeId(i, j, k);
if (l != this.id) {
Block block = Block.byId[l];
return block != null && block.material.h() && block.b() ? block.material != Material.PUMPKIN : false;
} else {
return true;
}
}
public boolean a() {
return false;
}
public boolean b() {
return false;
}
}
@@ -0,0 +1,242 @@
package net.minecraft.server;
import org.bukkit.event.block.BlockBurnEvent;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.block.BlockIgniteEvent.IgniteCause;
import org.bukkit.event.block.BlockSpreadEvent;
import org.bukkit.material.MaterialData;
import java.util.Random;
// CraftBukkit start
// CraftBukkit end
public class BlockFire extends Block {
private int[] a = new int[256];
private int[] b = new int[256];
protected BlockFire(int i, int j) {
super(i, j, Material.FIRE);
this.a(true);
}
public void h() {
this.a(Block.WOOD.id, 5, 20);
this.a(Block.FENCE.id, 5, 20);
this.a(Block.WOOD_STAIRS.id, 5, 20);
this.a(Block.LOG.id, 5, 5);
this.a(Block.LEAVES.id, 30, 60);
this.a(Block.BOOKSHELF.id, 30, 20);
this.a(Block.TNT.id, 15, 100);
this.a(Block.LONG_GRASS.id, 60, 100);
this.a(Block.WOOL.id, 30, 60);
}
private void a(int i, int j, int k) {
this.a[i] = j;
this.b[i] = k;
}
public AxisAlignedBB e(World world, int i, int j, int k) {
return null;
}
public boolean a() {
return false;
}
public boolean b() {
return false;
}
public int a(Random random) {
return 0;
}
public int c() {
return 40;
}
public void a(World world, int i, int j, int k, Random random) {
boolean flag = world.getTypeId(i, j - 1, k) == Block.NETHERRACK.id;
if (!this.canPlace(world, i, j, k)) {
world.setTypeId(i, j, k, 0);
}
if (!flag && world.v() && (world.s(i, j, k) || world.s(i - 1, j, k) || world.s(i + 1, j, k) || world.s(i, j, k - 1) || world.s(i, j, k + 1))) {
world.setTypeId(i, j, k, 0);
} else {
int l = world.getData(i, j, k);
if (l < 15) {
world.setRawData(i, j, k, l + random.nextInt(3) / 2);
}
world.c(i, j, k, this.id, this.c());
if (!flag && !this.g(world, i, j, k)) {
if (!world.e(i, j - 1, k) || l > 3) {
world.setTypeId(i, j, k, 0);
}
} else if (!flag && !this.b(world, i, j - 1, k) && l == 15 && random.nextInt(4) == 0) {
world.setTypeId(i, j, k, 0);
} else {
this.a(world, i + 1, j, k, 300, random, l);
this.a(world, i - 1, j, k, 300, random, l);
this.a(world, i, j - 1, k, 250, random, l);
this.a(world, i, j + 1, k, 250, random, l);
this.a(world, i, j, k - 1, 300, random, l);
this.a(world, i, j, k + 1, 300, random, l);
// CraftBukkit start - Call to stop spread of fire.
org.bukkit.Server server = world.getServer();
org.bukkit.World bworld = world.getWorld();
IgniteCause igniteCause = BlockIgniteEvent.IgniteCause.SPREAD;
org.bukkit.block.Block fromBlock = bworld.getBlockAt(i, j, k);
// CraftBukkit end
for (int i1 = i - 1; i1 <= i + 1; ++i1) {
for (int j1 = k - 1; j1 <= k + 1; ++j1) {
for (int k1 = j - 1; k1 <= j + 4; ++k1) {
if (i1 != i || k1 != j || j1 != k) {
int l1 = 100;
if (k1 > j + 1) {
l1 += (k1 - (j + 1)) * 100;
}
int i2 = this.h(world, i1, k1, j1);
if (i2 > 0) {
int j2 = (i2 + 40) / (l + 30);
if (j2 > 0 && random.nextInt(l1) <= j2 && (!world.v() || !world.s(i1, k1, j1)) && !world.s(i1 - 1, k1, k) && !world.s(i1 + 1, k1, j1) && !world.s(i1, k1, j1 - 1) && !world.s(i1, k1, j1 + 1)) {
int k2 = l + random.nextInt(5) / 4;
if (k2 > 15) {
k2 = 15;
}
// CraftBukkit start - Call to stop spread of fire.
org.bukkit.block.Block block = bworld.getBlockAt(i1, k1, j1);
if (block.getTypeId() != Block.FIRE.id) {
BlockIgniteEvent event = new BlockIgniteEvent(block, igniteCause, null);
server.getPluginManager().callEvent(event);
if (event.isCancelled()) {
continue;
}
org.bukkit.block.BlockState blockState = bworld.getBlockAt(i1, k1, j1).getState();
blockState.setTypeId(this.id);
blockState.setData(new MaterialData(this.id, (byte) k2));
BlockSpreadEvent spreadEvent = new BlockSpreadEvent(blockState.getBlock(), fromBlock, blockState);
server.getPluginManager().callEvent(spreadEvent);
if (!spreadEvent.isCancelled()) {
blockState.update(true);
}
}
// CraftBukkit end
}
}
}
}
}
}
}
}
}
private void a(World world, int i, int j, int k, int l, Random random, int i1) {
int j1 = this.b[world.getTypeId(i, j, k)];
if (random.nextInt(l) < j1) {
boolean flag = world.getTypeId(i, j, k) == Block.TNT.id;
// CraftBukkit start
org.bukkit.block.Block theBlock = world.getWorld().getBlockAt(i, j, k);
BlockBurnEvent event = new BlockBurnEvent(theBlock);
world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
// CraftBukkit end
if (random.nextInt(i1 + 10) < 5 && !world.s(i, j, k)) {
int k1 = i1 + random.nextInt(5) / 4;
if (k1 > 15) {
k1 = 15;
}
world.setTypeIdAndData(i, j, k, this.id, k1);
} else {
world.setTypeId(i, j, k, 0);
}
if (flag) {
Block.TNT.postBreak(world, i, j, k, 1);
}
}
}
private boolean g(World world, int i, int j, int k) {
return this.b(world, i + 1, j, k) ? true : (this.b(world, i - 1, j, k) ? true : (this.b(world, i, j - 1, k) ? true : (this.b(world, i, j + 1, k) ? true : (this.b(world, i, j, k - 1) ? true : this.b(world, i, j, k + 1)))));
}
private int h(World world, int i, int j, int k) {
byte b0 = 0;
if (!world.isEmpty(i, j, k)) {
return 0;
} else {
int l = this.f(world, i + 1, j, k, b0);
l = this.f(world, i - 1, j, k, l);
l = this.f(world, i, j - 1, k, l);
l = this.f(world, i, j + 1, k, l);
l = this.f(world, i, j, k - 1, l);
l = this.f(world, i, j, k + 1, l);
return l;
}
}
public boolean k_() {
return false;
}
public boolean b(IBlockAccess iblockaccess, int i, int j, int k) {
return this.a[iblockaccess.getTypeId(i, j, k)] > 0;
}
public int f(World world, int i, int j, int k, int l) {
int i1 = this.a[world.getTypeId(i, j, k)];
return i1 > l ? i1 : l;
}
public boolean canPlace(World world, int i, int j, int k) {
return world.e(i, j - 1, k) || this.g(world, i, j, k);
}
public void doPhysics(World world, int i, int j, int k, int l) {
if (!world.e(i, j - 1, k) && !this.g(world, i, j, k)) {
world.setTypeId(i, j, k, 0);
}
}
public void c(World world, int i, int j, int k) {
if (world.getTypeId(i, j - 1, k) != Block.OBSIDIAN.id || !Block.PORTAL.a_(world, i, j, k)) {
if (!world.e(i, j - 1, k) && !this.g(world, i, j, k)) {
world.setTypeId(i, j, k, 0);
} else {
world.c(i, j, k, this.id, this.c());
}
}
}
}
@@ -0,0 +1,55 @@
package net.minecraft.server;
import java.util.Random;
public class BlockFlower extends Block {
protected BlockFlower(int i, int j) {
super(i, Material.PLANT);
this.textureId = j;
this.a(true);
float f = 0.2F;
this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f * 3.0F, 0.5F + f);
}
public boolean canPlace(World world, int i, int j, int k) {
return super.canPlace(world, i, j, k) && this.c(world.getTypeId(i, j - 1, k));
}
protected boolean c(int i) {
return i == Block.GRASS.id || i == Block.DIRT.id || i == Block.SOIL.id;
}
public void doPhysics(World world, int i, int j, int k, int l) {
super.doPhysics(world, i, j, k, l);
this.g(world, i, j, k);
}
public void a(World world, int i, int j, int k, Random random) {
this.g(world, i, j, k);
}
protected final void g(World world, int i, int j, int k) {
if (!this.f(world, i, j, k)) {
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
}
}
public boolean f(World world, int i, int j, int k) {
return (world.k(i, j, k) >= 8 || world.isChunkLoaded(i, j, k)) && this.c(world.getTypeId(i, j - 1, k));
}
public AxisAlignedBB e(World world, int i, int j, int k) {
return null;
}
public boolean a() {
return false;
}
public boolean b() {
return false;
}
}
@@ -0,0 +1,308 @@
package net.minecraft.server;
import com.legacyminecraft.poseidon.PoseidonConfig;
import org.bukkit.block.BlockFace;
import org.bukkit.event.block.BlockFromToEvent;
import java.util.Random;
// CraftBukkit start
// CraftBukkit end
public class BlockFlowing extends BlockFluids {
int a = 0;
boolean[] b = new boolean[4];
int[] c = new int[4];
protected BlockFlowing(int i, Material material) {
super(i, material);
}
private void i(World world, int i, int j, int k) {
int l = world.getData(i, j, k);
world.setRawTypeIdAndData(i, j, k, this.id + 1, l);
world.b(i, j, k, i, j, k);
world.notify(i, j, k);
}
public void a(World world, int i, int j, int k, Random random) {
// CraftBukkit start
org.bukkit.World bworld = world.getWorld();
org.bukkit.Server server = world.getServer();
org.bukkit.block.Block source = bworld == null ? null : bworld.getBlockAt(i, j, k);
// CraftBukkit end
int l = this.g(world, i, j, k);
byte b0 = 1;
if (this.material == Material.LAVA && !world.worldProvider.d) {
b0 = 2;
}
boolean flag = true;
int i1;
if (l > 0) {
byte b1 = -100;
this.a = 0;
int j1 = this.f(world, i - 1, j, k, b1);
j1 = this.f(world, i + 1, j, k, j1);
j1 = this.f(world, i, j, k - 1, j1);
j1 = this.f(world, i, j, k + 1, j1);
i1 = j1 + b0;
if (i1 >= 8 || j1 < 0) {
i1 = -1;
}
if (this.g(world, i, j + 1, k) >= 0) {
int k1 = this.g(world, i, j + 1, k);
if (k1 >= 8) {
i1 = k1;
} else {
i1 = k1 + 8;
}
}
if (this.a >= 2 && this.material == Material.WATER) {
if (world.getMaterial(i, j - 1, k).isBuildable()) {
i1 = 0;
} else if (world.getMaterial(i, j - 1, k) == this.material && world.getData(i, j, k) == 0) {
i1 = 0;
}
}
if (this.material == Material.LAVA && l < 8 && i1 < 8 && i1 > l && random.nextInt(4) != 0) {
// Poseidon start - Fix flowing lava not disappearing
boolean fixFlowingLava = PoseidonConfig.getInstance().getConfigBoolean("world.settings.flowing-lava-fix.enabled", true);
if (!fixFlowingLava) {
i1 = l;
}
// Poseidon end
flag = false;
}
if (i1 != l) {
l = i1;
if (i1 < 0) {
world.setTypeId(i, j, k, 0);
} else {
world.setData(i, j, k, i1);
world.c(i, j, k, this.id, this.c());
world.applyPhysics(i, j, k, this.id);
}
} else if (flag) {
this.i(world, i, j, k);
}
} else {
this.i(world, i, j, k);
}
if (this.l(world, i, j - 1, k)) {
// CraftBukkit start - send "down" to the server
BlockFromToEvent event = new BlockFromToEvent(source, BlockFace.DOWN);
if (server != null) {
server.getPluginManager().callEvent(event);
}
if (!event.isCancelled()) {
if (l >= 8) {
world.setTypeIdAndData(i, j - 1, k, this.id, l);
} else {
world.setTypeIdAndData(i, j - 1, k, this.id, l + 8);
}
}
// CraftBukkit end
} else if (l >= 0 && (l == 0 || this.k(world, i, j - 1, k))) {
boolean[] aboolean = this.j(world, i, j, k);
i1 = l + b0;
if (l >= 8) {
i1 = 1;
}
if (i1 >= 8) {
return;
}
// CraftBukkit start - all four cardinal directions. Do not change the order!
BlockFace[] faces = new BlockFace[] { BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST };
int index = 0;
for (BlockFace currentFace: faces) {
if (aboolean[index]) {
BlockFromToEvent event = new BlockFromToEvent(source, currentFace);
if (server != null) {
server.getPluginManager().callEvent(event);
}
if (!event.isCancelled()) {
this.flow(world, i + currentFace.getModX(), j, k + currentFace.getModZ(), i1);
}
}
index++;
}
// CraftBukkit end
}
}
private void flow(World world, int i, int j, int k, int l) {
if (this.l(world, i, j, k)) {
int i1 = world.getTypeId(i, j, k);
if (i1 > 0) {
if (this.material == Material.LAVA) {
this.h(world, i, j, k);
} else {
Block.byId[i1].g(world, i, j, k, world.getData(i, j, k));
}
}
world.setTypeIdAndData(i, j, k, this.id, l);
}
}
private int b(World world, int i, int j, int k, int l, int i1) {
int j1 = 1000;
for (int k1 = 0; k1 < 4; ++k1) {
if ((k1 != 0 || i1 != 1) && (k1 != 1 || i1 != 0) && (k1 != 2 || i1 != 3) && (k1 != 3 || i1 != 2)) {
int l1 = i;
int i2 = k;
if (k1 == 0) {
l1 = i - 1;
}
if (k1 == 1) {
++l1;
}
if (k1 == 2) {
i2 = k - 1;
}
if (k1 == 3) {
++i2;
}
if (!this.k(world, l1, j, i2) && (world.getMaterial(l1, j, i2) != this.material || world.getData(l1, j, i2) != 0)) {
if (!this.k(world, l1, j - 1, i2)) {
return l;
}
if (l < 4) {
int j2 = this.b(world, l1, j, i2, l + 1, k1);
if (j2 < j1) {
j1 = j2;
}
}
}
}
}
return j1;
}
private boolean[] j(World world, int i, int j, int k) {
int l;
int i1;
for (l = 0; l < 4; ++l) {
this.c[l] = 1000;
i1 = i;
int j1 = k;
if (l == 0) {
i1 = i - 1;
}
if (l == 1) {
++i1;
}
if (l == 2) {
j1 = k - 1;
}
if (l == 3) {
++j1;
}
if (!this.k(world, i1, j, j1) && (world.getMaterial(i1, j, j1) != this.material || world.getData(i1, j, j1) != 0)) {
if (!this.k(world, i1, j - 1, j1)) {
this.c[l] = 0;
} else {
this.c[l] = this.b(world, i1, j, j1, 1, l);
}
}
}
l = this.c[0];
for (i1 = 1; i1 < 4; ++i1) {
if (this.c[i1] < l) {
l = this.c[i1];
}
}
for (i1 = 0; i1 < 4; ++i1) {
this.b[i1] = this.c[i1] == l;
}
return this.b;
}
private boolean k(World world, int i, int j, int k) {
int l = world.getTypeId(i, j, k);
if (l != Block.WOODEN_DOOR.id && l != Block.IRON_DOOR_BLOCK.id && l != Block.SIGN_POST.id && l != Block.LADDER.id && l != Block.SUGAR_CANE_BLOCK.id) {
if (l == 0) {
return false;
} else {
Material material = Block.byId[l].material;
return material.isSolid();
}
} else {
return true;
}
}
protected int f(World world, int i, int j, int k, int l) {
int i1 = this.g(world, i, j, k);
if (i1 < 0) {
return l;
} else {
if (i1 == 0) {
++this.a;
}
if (i1 >= 8) {
i1 = 0;
}
return l >= 0 && i1 >= l ? l : i1;
}
}
private boolean l(World world, int i, int j, int k) {
Material material = world.getMaterial(i, j, k);
return material == this.material ? false : (material == Material.LAVA ? false : !this.k(world, i, j, k));
}
public void c(World world, int i, int j, int k) {
super.c(world, i, j, k);
if (world.getTypeId(i, j, k) == this.id) {
world.c(i, j, k, this.id, this.c());
}
}
}
@@ -0,0 +1,234 @@
package net.minecraft.server;
import java.util.Random;
public abstract class BlockFluids extends Block {
protected BlockFluids(int i, Material material) {
super(i, (material == Material.LAVA ? 14 : 12) * 16 + 13, material);
float f = 0.0F;
float f1 = 0.0F;
this.a(0.0F + f1, 0.0F + f, 0.0F + f1, 1.0F + f1, 1.0F + f, 1.0F + f1);
this.a(true);
}
public static float c(int i) {
if (i >= 8) {
i = 0;
}
float f = (float) (i + 1) / 9.0F;
return f;
}
public int a(int i) {
return i != 0 && i != 1 ? this.textureId + 1 : this.textureId;
}
protected int g(World world, int i, int j, int k) {
return world.getMaterial(i, j, k) != this.material ? -1 : world.getData(i, j, k);
}
protected int b(IBlockAccess iblockaccess, int i, int j, int k) {
if (iblockaccess.getMaterial(i, j, k) != this.material) {
return -1;
} else {
int l = iblockaccess.getData(i, j, k);
if (l >= 8) {
l = 0;
}
return l;
}
}
public boolean b() {
return false;
}
public boolean a() {
return false;
}
public boolean a(int i, boolean flag) {
return flag && i == 0;
}
public boolean b(IBlockAccess iblockaccess, int i, int j, int k, int l) {
Material material = iblockaccess.getMaterial(i, j, k);
return material == this.material ? false : (material == Material.ICE ? false : (l == 1 ? true : super.b(iblockaccess, i, j, k, l)));
}
public AxisAlignedBB e(World world, int i, int j, int k) {
return null;
}
public int a(int i, Random random) {
return 0;
}
public int a(Random random) {
return 0;
}
private Vec3D c(IBlockAccess iblockaccess, int i, int j, int k) {
Vec3D vec3d = Vec3D.create(0.0D, 0.0D, 0.0D);
int l = this.b(iblockaccess, i, j, k);
for (int i1 = 0; i1 < 4; ++i1) {
int j1 = i;
int k1 = k;
if (i1 == 0) {
j1 = i - 1;
}
if (i1 == 1) {
k1 = k - 1;
}
if (i1 == 2) {
++j1;
}
if (i1 == 3) {
++k1;
}
int l1 = this.b(iblockaccess, j1, j, k1);
int i2;
if (l1 < 0) {
if (!iblockaccess.getMaterial(j1, j, k1).isSolid()) {
l1 = this.b(iblockaccess, j1, j - 1, k1);
if (l1 >= 0) {
i2 = l1 - (l - 8);
vec3d = vec3d.add((double) ((j1 - i) * i2), (double) ((j - j) * i2), (double) ((k1 - k) * i2));
}
}
} else if (l1 >= 0) {
i2 = l1 - l;
vec3d = vec3d.add((double) ((j1 - i) * i2), (double) ((j - j) * i2), (double) ((k1 - k) * i2));
}
}
if (iblockaccess.getData(i, j, k) >= 8) {
boolean flag = false;
if (flag || this.b(iblockaccess, i, j, k - 1, 2)) {
flag = true;
}
if (flag || this.b(iblockaccess, i, j, k + 1, 3)) {
flag = true;
}
if (flag || this.b(iblockaccess, i - 1, j, k, 4)) {
flag = true;
}
if (flag || this.b(iblockaccess, i + 1, j, k, 5)) {
flag = true;
}
if (flag || this.b(iblockaccess, i, j + 1, k - 1, 2)) {
flag = true;
}
if (flag || this.b(iblockaccess, i, j + 1, k + 1, 3)) {
flag = true;
}
if (flag || this.b(iblockaccess, i - 1, j + 1, k, 4)) {
flag = true;
}
if (flag || this.b(iblockaccess, i + 1, j + 1, k, 5)) {
flag = true;
}
if (flag) {
vec3d = vec3d.b().add(0.0D, -6.0D, 0.0D);
}
}
vec3d = vec3d.b();
return vec3d;
}
public void a(World world, int i, int j, int k, Entity entity, Vec3D vec3d) {
Vec3D vec3d1 = this.c((IBlockAccess) world, i, j, k);
vec3d.a += vec3d1.a;
vec3d.b += vec3d1.b;
vec3d.c += vec3d1.c;
}
public int c() {
return this.material == Material.WATER ? 5 : (this.material == Material.LAVA ? 30 : 0);
}
public void a(World world, int i, int j, int k, Random random) {
super.a(world, i, j, k, random);
}
public void c(World world, int i, int j, int k) {
this.i(world, i, j, k);
}
public void doPhysics(World world, int i, int j, int k, int l) {
this.i(world, i, j, k);
}
private void i(World world, int i, int j, int k) {
if (world.getTypeId(i, j, k) == this.id) {
if (this.material == Material.LAVA) {
boolean flag = false;
if (flag || world.getMaterial(i, j, k - 1) == Material.WATER) {
flag = true;
}
if (flag || world.getMaterial(i, j, k + 1) == Material.WATER) {
flag = true;
}
if (flag || world.getMaterial(i - 1, j, k) == Material.WATER) {
flag = true;
}
if (flag || world.getMaterial(i + 1, j, k) == Material.WATER) {
flag = true;
}
if (flag || world.getMaterial(i, j + 1, k) == Material.WATER) {
flag = true;
}
if (flag) {
int l = world.getData(i, j, k);
if (l == 0) {
world.setTypeId(i, j, k, Block.OBSIDIAN.id);
} else if (l <= 4) {
world.setTypeId(i, j, k, Block.COBBLESTONE.id);
}
this.h(world, i, j, k);
}
}
}
}
protected void h(World world, int i, int j, int k) {
world.makeSound((double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F), "random.fizz", 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F);
for (int l = 0; l < 8; ++l) {
world.a("largesmoke", (double) i + Math.random(), (double) j + 1.2D, (double) k + Math.random(), 0.0D, 0.0D, 0.0D);
}
}
}
@@ -0,0 +1,147 @@
package net.minecraft.server;
import java.util.Random;
public class BlockFurnace extends BlockContainer {
private Random a = new Random();
private final boolean b;
private static boolean c = false;
protected BlockFurnace(int i, boolean flag) {
super(i, Material.STONE);
this.b = flag;
this.textureId = 45;
}
public int a(int i, Random random) {
return Block.FURNACE.id;
}
public void c(World world, int i, int j, int k) {
super.c(world, i, j, k);
this.g(world, i, j, k);
}
private void g(World world, int i, int j, int k) {
if (!world.isStatic) {
int l = world.getTypeId(i, j, k - 1);
int i1 = world.getTypeId(i, j, k + 1);
int j1 = world.getTypeId(i - 1, j, k);
int k1 = world.getTypeId(i + 1, j, k);
byte b0 = 3;
if (Block.o[l] && !Block.o[i1]) {
b0 = 3;
}
if (Block.o[i1] && !Block.o[l]) {
b0 = 2;
}
if (Block.o[j1] && !Block.o[k1]) {
b0 = 5;
}
if (Block.o[k1] && !Block.o[j1]) {
b0 = 4;
}
world.setData(i, j, k, b0);
}
}
public int a(int i) {
return i == 1 ? this.textureId + 17 : (i == 0 ? this.textureId + 17 : (i == 3 ? this.textureId - 1 : this.textureId));
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
if (world.isStatic) {
return true;
} else {
TileEntityFurnace tileentityfurnace = (TileEntityFurnace) world.getTileEntity(i, j, k);
entityhuman.a(tileentityfurnace);
return true;
}
}
public static void a(boolean flag, World world, int i, int j, int k) {
int l = world.getData(i, j, k);
TileEntity tileentity = world.getTileEntity(i, j, k);
if (tileentity == null) return; // CraftBukkit
c = true;
if (flag) {
world.setTypeId(i, j, k, Block.BURNING_FURNACE.id);
} else {
world.setTypeId(i, j, k, Block.FURNACE.id);
}
c = false;
world.setData(i, j, k, l);
tileentity.j();
world.setTileEntity(i, j, k, tileentity);
}
protected TileEntity a_() {
return new TileEntityFurnace();
}
public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) {
int l = MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 0.5D) & 3;
if (l == 0) {
world.setData(i, j, k, 2);
}
if (l == 1) {
world.setData(i, j, k, 5);
}
if (l == 2) {
world.setData(i, j, k, 3);
}
if (l == 3) {
world.setData(i, j, k, 4);
}
}
public void remove(World world, int i, int j, int k) {
if (!c) {
TileEntityFurnace tileentityfurnace = (TileEntityFurnace) world.getTileEntity(i, j, k);
if (tileentityfurnace == null) return; // CraftBukkit
for (int l = 0; l < tileentityfurnace.getSize(); ++l) {
ItemStack itemstack = tileentityfurnace.getItem(l);
if (itemstack != null) {
float f = this.a.nextFloat() * 0.8F + 0.1F;
float f1 = this.a.nextFloat() * 0.8F + 0.1F;
float f2 = this.a.nextFloat() * 0.8F + 0.1F;
while (itemstack.count > 0) {
int i1 = this.a.nextInt(21) + 10;
if (i1 > itemstack.count) {
i1 = itemstack.count;
}
itemstack.count -= i1;
EntityItem entityitem = new EntityItem(world, (double) ((float) i + f), (double) ((float) j + f1), (double) ((float) k + f2), new ItemStack(itemstack.id, i1, itemstack.getData()));
float f3 = 0.05F;
entityitem.motX = (double) ((float) this.a.nextGaussian() * f3);
entityitem.motY = (double) ((float) this.a.nextGaussian() * f3 + 0.2F);
entityitem.motZ = (double) ((float) this.a.nextGaussian() * f3);
world.addEntity(entityitem);
}
tileentityfurnace.setItem(l, null);
}
}
}
super.remove(world, i, j, k);
}
}
@@ -0,0 +1,14 @@
package net.minecraft.server;
import java.util.Random;
public class BlockGlass extends BlockBreakable {
public BlockGlass(int i, int j, Material material, boolean flag) {
super(i, j, material, flag);
}
public int a(Random random) {
return 0;
}
}
@@ -0,0 +1,64 @@
package net.minecraft.server;
import java.util.Random;
// CraftBukkit start
import org.bukkit.event.block.BlockSpreadEvent;
import org.bukkit.event.block.BlockFadeEvent;
//CraftBukkit end
public class BlockGrass extends Block {
protected BlockGrass(int i) {
super(i, Material.GRASS);
this.textureId = 3;
this.a(true);
}
public void a(World world, int i, int j, int k, Random random) {
if (!world.isStatic) {
if (world.getLightLevel(i, j + 1, k) < 4 && Block.q[world.getTypeId(i, j + 1, k)] > 2) {
if (random.nextInt(4) != 0) {
return;
}
// CraftBukkit start
org.bukkit.World bworld = world.getWorld();
org.bukkit.block.BlockState blockState = bworld.getBlockAt(i, j, k).getState();
blockState.setTypeId(Block.DIRT.id);
BlockFadeEvent event = new BlockFadeEvent(blockState.getBlock(), blockState);
world.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
blockState.update(true);
}
// CraftBukkit end
} else if (world.getLightLevel(i, j + 1, k) >= 9) {
int l = i + random.nextInt(3) - 1;
int i1 = j + random.nextInt(5) - 3;
int j1 = k + random.nextInt(3) - 1;
int k1 = world.getTypeId(l, i1 + 1, j1);
if (world.getTypeId(l, i1, j1) == Block.DIRT.id && world.getLightLevel(l, i1 + 1, j1) >= 4 && Block.q[k1] <= 2) {
// CraftBukkit start
org.bukkit.World bworld = world.getWorld();
org.bukkit.block.BlockState blockState = bworld.getBlockAt(l, i1, j1).getState();
blockState.setTypeId(this.id);
BlockSpreadEvent event = new BlockSpreadEvent(blockState.getBlock(), bworld.getBlockAt(i, j, k), blockState);
world.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
blockState.update(true);
}
// CraftBukkit end
}
}
}
}
public int a(int i, Random random) {
return Block.DIRT.a(0, random);
}
}
@@ -0,0 +1,14 @@
package net.minecraft.server;
import java.util.Random;
public class BlockGravel extends BlockSand {
public BlockGravel(int i, int j) {
super(i, j);
}
public int a(int i, Random random) {
return random.nextInt(10) == 0 ? Item.FLINT.id : this.id;
}
}
@@ -0,0 +1,44 @@
package net.minecraft.server;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import java.util.Random;
public class BlockIce extends BlockBreakable {
public BlockIce(int i, int j) {
super(i, j, Material.ICE, false);
this.frictionFactor = 0.98F;
this.a(true);
}
public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
super.a(world, entityhuman, i, j, k, l);
Material material = world.getMaterial(i, j - 1, k);
if (material.isSolid() || material.isLiquid()) {
world.setTypeId(i, j, k, Block.WATER.id);
}
}
public int a(Random random) {
return 0;
}
public void a(World world, int i, int j, int k, Random random) {
if (world.a(EnumSkyBlock.BLOCK, i, j, k) > 11 - Block.q[this.id]) {
// CraftBukkit start
if (CraftEventFactory.callBlockFadeEvent(world.getWorld().getBlockAt(i, j, k), Block.STATIONARY_WATER.id).isCancelled()) {
return;
}
// CraftBukkit end
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, Block.STATIONARY_WATER.id);
}
}
public int e() {
return 0;
}
}
@@ -0,0 +1,70 @@
package net.minecraft.server;
public class BlockJukeBox extends BlockContainer {
protected BlockJukeBox(int i, int j) {
super(i, j, Material.WOOD);
}
public int a(int i) {
return this.textureId + (i == 1 ? 1 : 0);
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
if (world.getData(i, j, k) == 0) {
return false;
} else {
this.b_(world, i, j, k);
return true;
}
}
public void f(World world, int i, int j, int k, int l) {
if (!world.isStatic) {
TileEntityRecordPlayer tileentityrecordplayer = (TileEntityRecordPlayer) world.getTileEntity(i, j, k);
tileentityrecordplayer.a = l;
tileentityrecordplayer.update();
world.setData(i, j, k, 1);
}
}
public void b_(World world, int i, int j, int k) {
if (!world.isStatic) {
TileEntityRecordPlayer tileentityrecordplayer = (TileEntityRecordPlayer) world.getTileEntity(i, j, k);
if (tileentityrecordplayer == null) return; // CraftBukkit
int l = tileentityrecordplayer.a;
if (l != 0) {
world.e(1005, i, j, k, 0);
world.a((String) null, i, j, k);
tileentityrecordplayer.a = 0;
tileentityrecordplayer.update();
world.setData(i, j, k, 0);
float f = 0.7F;
double d0 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
double d1 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.2D + 0.6D;
double d2 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
EntityItem entityitem = new EntityItem(world, (double) i + d0, (double) j + d1, (double) k + d2, new ItemStack(l, 1, 0));
entityitem.pickupDelay = 10;
world.addEntity(entityitem);
}
}
}
public void remove(World world, int i, int j, int k) {
this.b_(world, i, j, k);
super.remove(world, i, j, k);
}
public void dropNaturally(World world, int i, int j, int k, int l, float f) {
if (!world.isStatic) {
super.dropNaturally(world, i, j, k, l, f);
}
}
protected TileEntity a_() {
return new TileEntityRecordPlayer();
}
}
@@ -0,0 +1,99 @@
package net.minecraft.server;
import java.util.Random;
public class BlockLadder extends Block {
protected BlockLadder(int i, int j) {
super(i, j, Material.ORIENTABLE);
}
public AxisAlignedBB e(World world, int i, int j, int k) {
int l = world.getData(i, j, k);
float f = 0.125F;
if (l == 2) {
this.a(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
}
if (l == 3) {
this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
}
if (l == 4) {
this.a(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
if (l == 5) {
this.a(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
}
return super.e(world, i, j, k);
}
public boolean a() {
return false;
}
public boolean b() {
return false;
}
public boolean canPlace(World world, int i, int j, int k) {
return world.e(i - 1, j, k) ? true : (world.e(i + 1, j, k) ? true : (world.e(i, j, k - 1) ? true : world.e(i, j, k + 1)));
}
public void postPlace(World world, int i, int j, int k, int l) {
int i1 = world.getData(i, j, k);
if ((i1 == 0 || l == 2) && world.e(i, j, k + 1)) {
i1 = 2;
}
if ((i1 == 0 || l == 3) && world.e(i, j, k - 1)) {
i1 = 3;
}
if ((i1 == 0 || l == 4) && world.e(i + 1, j, k)) {
i1 = 4;
}
if ((i1 == 0 || l == 5) && world.e(i - 1, j, k)) {
i1 = 5;
}
world.setData(i, j, k, i1);
}
public void doPhysics(World world, int i, int j, int k, int l) {
int i1 = world.getData(i, j, k);
boolean flag = false;
if (i1 == 2 && world.e(i, j, k + 1)) {
flag = true;
}
if (i1 == 3 && world.e(i, j, k - 1)) {
flag = true;
}
if (i1 == 4 && world.e(i + 1, j, k)) {
flag = true;
}
if (i1 == 5 && world.e(i - 1, j, k)) {
flag = true;
}
if (!flag) {
this.g(world, i, j, k, i1);
world.setTypeId(i, j, k, 0);
}
super.doPhysics(world, i, j, k, l);
}
public int a(Random random) {
return 1;
}
}
@@ -0,0 +1,165 @@
package net.minecraft.server;
import org.bukkit.event.block.LeavesDecayEvent;
import java.util.Random;
public class BlockLeaves extends BlockLeavesBase {
private int c;
int[] a;
protected BlockLeaves(int i, int j) {
super(i, j, Material.LEAVES, false);
this.c = j;
this.a(true);
}
public void remove(World world, int i, int j, int k) {
byte b0 = 1;
int l = b0 + 1;
if (world.a(i - l, j - l, k - l, i + l, j + l, k + l)) {
for (int i1 = -b0; i1 <= b0; ++i1) {
for (int j1 = -b0; j1 <= b0; ++j1) {
for (int k1 = -b0; k1 <= b0; ++k1) {
int l1 = world.getTypeId(i + i1, j + j1, k + k1);
if (l1 == Block.LEAVES.id) {
int i2 = world.getData(i + i1, j + j1, k + k1);
world.setRawData(i + i1, j + j1, k + k1, i2 | 8);
}
}
}
}
}
}
public void a(World world, int i, int j, int k, Random random) {
if (!world.isStatic) {
int l = world.getData(i, j, k);
if ((l & 8) != 0) {
byte b0 = 4;
int i1 = b0 + 1;
byte b1 = 32;
int j1 = b1 * b1;
int k1 = b1 / 2;
if (this.a == null) {
this.a = new int[b1 * b1 * b1];
}
int l1;
if (world.a(i - i1, j - i1, k - i1, i + i1, j + i1, k + i1)) {
int i2;
int j2;
int k2;
for (l1 = -b0; l1 <= b0; ++l1) {
for (i2 = -b0; i2 <= b0; ++i2) {
for (j2 = -b0; j2 <= b0; ++j2) {
k2 = world.getTypeId(i + l1, j + i2, k + j2);
if (k2 == Block.LOG.id) {
this.a[(l1 + k1) * j1 + (i2 + k1) * b1 + j2 + k1] = 0;
} else if (k2 == Block.LEAVES.id) {
this.a[(l1 + k1) * j1 + (i2 + k1) * b1 + j2 + k1] = -2;
} else {
this.a[(l1 + k1) * j1 + (i2 + k1) * b1 + j2 + k1] = -1;
}
}
}
}
for (l1 = 1; l1 <= 4; ++l1) {
for (i2 = -b0; i2 <= b0; ++i2) {
for (j2 = -b0; j2 <= b0; ++j2) {
for (k2 = -b0; k2 <= b0; ++k2) {
if (this.a[(i2 + k1) * j1 + (j2 + k1) * b1 + k2 + k1] == l1 - 1) {
if (this.a[(i2 + k1 - 1) * j1 + (j2 + k1) * b1 + k2 + k1] == -2) {
this.a[(i2 + k1 - 1) * j1 + (j2 + k1) * b1 + k2 + k1] = l1;
}
if (this.a[(i2 + k1 + 1) * j1 + (j2 + k1) * b1 + k2 + k1] == -2) {
this.a[(i2 + k1 + 1) * j1 + (j2 + k1) * b1 + k2 + k1] = l1;
}
if (this.a[(i2 + k1) * j1 + (j2 + k1 - 1) * b1 + k2 + k1] == -2) {
this.a[(i2 + k1) * j1 + (j2 + k1 - 1) * b1 + k2 + k1] = l1;
}
if (this.a[(i2 + k1) * j1 + (j2 + k1 + 1) * b1 + k2 + k1] == -2) {
this.a[(i2 + k1) * j1 + (j2 + k1 + 1) * b1 + k2 + k1] = l1;
}
if (this.a[(i2 + k1) * j1 + (j2 + k1) * b1 + (k2 + k1 - 1)] == -2) {
this.a[(i2 + k1) * j1 + (j2 + k1) * b1 + (k2 + k1 - 1)] = l1;
}
if (this.a[(i2 + k1) * j1 + (j2 + k1) * b1 + k2 + k1 + 1] == -2) {
this.a[(i2 + k1) * j1 + (j2 + k1) * b1 + k2 + k1 + 1] = l1;
}
}
}
}
}
}
}
l1 = this.a[k1 * j1 + k1 * b1 + k1];
if (l1 >= 0) {
world.setRawData(i, j, k, l & -9);
} else {
this.g(world, i, j, k);
}
}
}
}
private void g(World world, int i, int j, int k) {
// CraftBukkit start
LeavesDecayEvent event = new LeavesDecayEvent(world.getWorld().getBlockAt(i, j, k));
world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) return;
// CraftBukkit end
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
}
public int a(Random random) {
return random.nextInt(20) == 0 ? 1 : 0;
}
public int a(int i, Random random) {
return Block.SAPLING.id;
}
public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
if (!world.isStatic && entityhuman.G() != null && entityhuman.G().id == Item.SHEARS.id) {
entityhuman.a(StatisticList.C[this.id], 1);
this.a(world, i, j, k, new ItemStack(Block.LEAVES.id, 1, l & 3));
} else {
super.a(world, entityhuman, i, j, k, l);
}
}
protected int a_(int i) {
return i & 3;
}
public boolean a() {
return !this.b;
}
public int a(int i, int j) {
return (j & 3) == 1 ? this.textureId + 80 : this.textureId;
}
public void b(World world, int i, int j, int k, Entity entity) {
super.b(world, i, j, k, entity);
}
}
@@ -0,0 +1,15 @@
package net.minecraft.server;
public class BlockLeavesBase extends Block {
protected boolean b;
protected BlockLeavesBase(int i, int j, Material material, boolean flag) {
super(i, j, material);
this.b = flag;
}
public boolean a() {
return false;
}
}
@@ -0,0 +1,216 @@
package net.minecraft.server;
import org.bukkit.event.block.BlockRedstoneEvent;
public class BlockLever extends Block {
protected BlockLever(int i, int j) {
super(i, j, Material.ORIENTABLE);
}
public AxisAlignedBB e(World world, int i, int j, int k) {
return null;
}
public boolean a() {
return false;
}
public boolean b() {
return false;
}
public boolean canPlace(World world, int i, int j, int k, int l) {
return l == 1 && world.e(i, j - 1, k) ? true : (l == 2 && world.e(i, j, k + 1) ? true : (l == 3 && world.e(i, j, k - 1) ? true : (l == 4 && world.e(i + 1, j, k) ? true : l == 5 && world.e(i - 1, j, k))));
}
public boolean canPlace(World world, int i, int j, int k) {
return world.e(i - 1, j, k) ? true : (world.e(i + 1, j, k) ? true : (world.e(i, j, k - 1) ? true : (world.e(i, j, k + 1) ? true : world.e(i, j - 1, k))));
}
public void postPlace(World world, int i, int j, int k, int l) {
int i1 = world.getData(i, j, k);
int j1 = i1 & 8;
i1 &= 7;
i1 = -1;
if (l == 1 && world.e(i, j - 1, k)) {
i1 = 5 + world.random.nextInt(2);
}
if (l == 2 && world.e(i, j, k + 1)) {
i1 = 4;
}
if (l == 3 && world.e(i, j, k - 1)) {
i1 = 3;
}
if (l == 4 && world.e(i + 1, j, k)) {
i1 = 2;
}
if (l == 5 && world.e(i - 1, j, k)) {
i1 = 1;
}
if (i1 == -1) {
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
} else {
world.setData(i, j, k, i1 + j1);
}
}
public void doPhysics(World world, int i, int j, int k, int l) {
if (this.g(world, i, j, k)) {
int i1 = world.getData(i, j, k) & 7;
boolean flag = false;
if (!world.e(i - 1, j, k) && i1 == 1) {
flag = true;
}
if (!world.e(i + 1, j, k) && i1 == 2) {
flag = true;
}
if (!world.e(i, j, k - 1) && i1 == 3) {
flag = true;
}
if (!world.e(i, j, k + 1) && i1 == 4) {
flag = true;
}
if (!world.e(i, j - 1, k) && i1 == 5) {
flag = true;
}
if (!world.e(i, j - 1, k) && i1 == 6) {
flag = true;
}
if (flag) {
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
}
}
}
private boolean g(World world, int i, int j, int k) {
if (!this.canPlace(world, i, j, k)) {
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
return false;
} else {
return true;
}
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
int l = iblockaccess.getData(i, j, k) & 7;
float f = 0.1875F;
if (l == 1) {
this.a(0.0F, 0.2F, 0.5F - f, f * 2.0F, 0.8F, 0.5F + f);
} else if (l == 2) {
this.a(1.0F - f * 2.0F, 0.2F, 0.5F - f, 1.0F, 0.8F, 0.5F + f);
} else if (l == 3) {
this.a(0.5F - f, 0.2F, 0.0F, 0.5F + f, 0.8F, f * 2.0F);
} else if (l == 4) {
this.a(0.5F - f, 0.2F, 1.0F - f * 2.0F, 0.5F + f, 0.8F, 1.0F);
} else {
f = 0.25F;
this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.6F, 0.5F + f);
}
}
public void b(World world, int i, int j, int k, EntityHuman entityhuman) {
this.interact(world, i, j, k, entityhuman);
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
if (world.isStatic) {
return true;
} else {
int l = world.getData(i, j, k);
int i1 = l & 7;
int j1 = 8 - (l & 8);
// CraftBukkit start - Interact Lever
org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k);
int old = (j1 != 8) ? 1 : 0;
int current = (j1 == 8) ? 1 : 0;
BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, old, current);
world.getServer().getPluginManager().callEvent(eventRedstone);
if ((eventRedstone.getNewCurrent() > 0) != (j1 == 8)) {
return true;
}
// CraftBukkit end
world.setData(i, j, k, i1 + j1);
world.b(i, j, k, i, j, k);
world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "random.click", 0.3F, j1 > 0 ? 0.6F : 0.5F);
world.applyPhysics(i, j, k, this.id);
if (i1 == 1) {
world.applyPhysics(i - 1, j, k, this.id);
} else if (i1 == 2) {
world.applyPhysics(i + 1, j, k, this.id);
} else if (i1 == 3) {
world.applyPhysics(i, j, k - 1, this.id);
} else if (i1 == 4) {
world.applyPhysics(i, j, k + 1, this.id);
} else {
world.applyPhysics(i, j - 1, k, this.id);
}
return true;
}
}
public void remove(World world, int i, int j, int k) {
int l = world.getData(i, j, k);
if ((l & 8) > 0) {
world.applyPhysics(i, j, k, this.id);
int i1 = l & 7;
if (i1 == 1) {
world.applyPhysics(i - 1, j, k, this.id);
} else if (i1 == 2) {
world.applyPhysics(i + 1, j, k, this.id);
} else if (i1 == 3) {
world.applyPhysics(i, j, k - 1, this.id);
} else if (i1 == 4) {
world.applyPhysics(i, j, k + 1, this.id);
} else {
world.applyPhysics(i, j - 1, k, this.id);
}
}
super.remove(world, i, j, k);
}
public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) {
return (iblockaccess.getData(i, j, k) & 8) > 0;
}
public boolean d(World world, int i, int j, int k, int l) {
int i1 = world.getData(i, j, k);
if ((i1 & 8) == 0) {
return false;
} else {
int j1 = i1 & 7;
return j1 == 6 && l == 1 ? true : (j1 == 5 && l == 1 ? true : (j1 == 4 && l == 2 ? true : (j1 == 3 && l == 3 ? true : (j1 == 2 && l == 4 ? true : j1 == 1 && l == 5))));
}
}
public boolean isPowerSource() {
return true;
}
}
@@ -0,0 +1,18 @@
package net.minecraft.server;
import java.util.Random;
public class BlockLightStone extends Block {
public BlockLightStone(int i, int j, Material material) {
super(i, j, material);
}
public int a(Random random) {
return 2 + random.nextInt(3);
}
public int a(int i, Random random) {
return Item.GLOWSTONE_DUST.id;
}
}
@@ -0,0 +1,23 @@
package net.minecraft.server;
import java.util.Random;
public class BlockLockedChest extends Block {
protected BlockLockedChest(int i) {
super(i, Material.WOOD);
this.textureId = 26;
}
public int a(int i) {
return i == 1 ? this.textureId - 1 : (i == 0 ? this.textureId - 1 : (i == 3 ? this.textureId + 1 : this.textureId));
}
public boolean canPlace(World world, int i, int j, int k) {
return true;
}
public void a(World world, int i, int j, int k, Random random) {
world.setTypeId(i, j, k, 0);
}
}
@@ -0,0 +1,54 @@
package net.minecraft.server;
import java.util.Random;
public class BlockLog extends Block {
protected BlockLog(int i) {
super(i, Material.WOOD);
this.textureId = 20;
}
public int a(Random random) {
return 1;
}
public int a(int i, Random random) {
return Block.LOG.id;
}
public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
super.a(world, entityhuman, i, j, k, l);
}
public void remove(World world, int i, int j, int k) {
byte b0 = 4;
int l = b0 + 1;
if (world.a(i - l, j - l, k - l, i + l, j + l, k + l)) {
for (int i1 = -b0; i1 <= b0; ++i1) {
for (int j1 = -b0; j1 <= b0; ++j1) {
for (int k1 = -b0; k1 <= b0; ++k1) {
int l1 = world.getTypeId(i + i1, j + j1, k + k1);
if (l1 == Block.LEAVES.id) {
int i2 = world.getData(i + i1, j + j1, k + k1);
if ((i2 & 8) == 0) {
world.setRawData(i + i1, j + j1, k + k1, i2 | 8);
}
}
}
}
}
}
}
public int a(int i, int j) {
return i == 1 ? 21 : (i == 0 ? 21 : (j == 1 ? 116 : (j == 2 ? 117 : 20)));
}
protected int a_(int i) {
return i;
}
}
@@ -0,0 +1,21 @@
package net.minecraft.server;
import java.util.Random;
public class BlockLongGrass extends BlockFlower {
protected BlockLongGrass(int i, int j) {
super(i, j);
float f = 0.4F;
this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.8F, 0.5F + f);
}
public int a(int i, int j) {
return j == 1 ? this.textureId : (j == 2 ? this.textureId + 16 + 1 : (j == 0 ? this.textureId + 16 : this.textureId));
}
public int a(int i, Random random) {
return random.nextInt(8) == 0 ? Item.SEEDS.id : -1;
}
}
@@ -0,0 +1,90 @@
package net.minecraft.server;
import org.bukkit.event.block.BlockRedstoneEvent;
import java.util.List;
import java.util.Random;
public class BlockMinecartDetector extends BlockMinecartTrack {
public BlockMinecartDetector(int i, int j) {
super(i, j, true);
this.a(true);
}
public int c() {
return 20;
}
public boolean isPowerSource() {
return true;
}
public void a(World world, int i, int j, int k, Entity entity) {
if (!world.isStatic) {
int l = world.getData(i, j, k);
if ((l & 8) == 0) {
this.f(world, i, j, k, l);
}
}
}
public void a(World world, int i, int j, int k, Random random) {
if (!world.isStatic) {
int l = world.getData(i, j, k);
if ((l & 8) != 0) {
this.f(world, i, j, k, l);
}
}
}
public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) {
return (iblockaccess.getData(i, j, k) & 8) != 0;
}
public boolean d(World world, int i, int j, int k, int l) {
return (world.getData(i, j, k) & 8) == 0 ? false : l == 1;
}
private void f(World world, int i, int j, int k, int l) {
boolean flag = (l & 8) != 0;
boolean flag1 = false;
float f = 0.125F;
List list = world.a(EntityMinecart.class, AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) j + 0.25D, (double) ((float) (k + 1) - f)));
if (list.size() > 0) {
flag1 = true;
}
// CraftBukkit start
if (flag != flag1) {
org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k);
BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, flag ? 1 : 0, flag1 ? 1 : 0);
world.getServer().getPluginManager().callEvent(eventRedstone);
flag1 = eventRedstone.getNewCurrent() > 0;
}
// CraftBukkit end
if (flag1 && !flag) {
world.setData(i, j, k, l | 8);
world.applyPhysics(i, j, k, this.id);
world.applyPhysics(i, j - 1, k, this.id);
world.b(i, j, k, i, j, k);
}
if (!flag1 && flag) {
world.setData(i, j, k, l & 7);
world.applyPhysics(i, j, k, this.id);
world.applyPhysics(i, j - 1, k, this.id);
world.b(i, j, k, i, j, k);
}
if (flag1) {
world.c(i, j, k, this.id, this.c());
}
}
}
@@ -0,0 +1,258 @@
package net.minecraft.server;
import java.util.Random;
public class BlockMinecartTrack extends Block {
private final boolean a;
public static final boolean g(World world, int i, int j, int k) {
int l = world.getTypeId(i, j, k);
return l == Block.RAILS.id || l == Block.GOLDEN_RAIL.id || l == Block.DETECTOR_RAIL.id;
}
public static final boolean c(int i) {
return i == Block.RAILS.id || i == Block.GOLDEN_RAIL.id || i == Block.DETECTOR_RAIL.id;
}
protected BlockMinecartTrack(int i, int j, boolean flag) {
super(i, j, Material.ORIENTABLE);
this.a = flag;
this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
}
public boolean f() {
return this.a;
}
public AxisAlignedBB e(World world, int i, int j, int k) {
return null;
}
public boolean a() {
return false;
}
public MovingObjectPosition a(World world, int i, int j, int k, Vec3D vec3d, Vec3D vec3d1) {
this.a(world, i, j, k);
return super.a(world, i, j, k, vec3d, vec3d1);
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
int l = iblockaccess.getData(i, j, k);
if (l >= 2 && l <= 5) {
this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F);
} else {
this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
}
}
public int a(int i, int j) {
if (this.a) {
if (this.id == Block.GOLDEN_RAIL.id && (j & 8) == 0) {
return this.textureId - 16;
}
} else if (j >= 6) {
return this.textureId - 16;
}
return this.textureId;
}
public boolean b() {
return false;
}
public int a(Random random) {
return 1;
}
public boolean canPlace(World world, int i, int j, int k) {
return world.e(i, j - 1, k);
}
public void c(World world, int i, int j, int k) {
if (!world.isStatic) {
this.a(world, i, j, k, true);
}
}
public void doPhysics(World world, int i, int j, int k, int l) {
if (!world.isStatic) {
int i1 = world.getData(i, j, k);
int j1 = i1;
if (this.a) {
j1 = i1 & 7;
}
boolean flag = false;
if (!world.e(i, j - 1, k)) {
flag = true;
}
if (j1 == 2 && !world.e(i + 1, j, k)) {
flag = true;
}
if (j1 == 3 && !world.e(i - 1, j, k)) {
flag = true;
}
if (j1 == 4 && !world.e(i, j, k - 1)) {
flag = true;
}
if (j1 == 5 && !world.e(i, j, k + 1)) {
flag = true;
}
if (flag) {
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
} else if (this.id == Block.GOLDEN_RAIL.id) {
boolean flag1 = world.isBlockIndirectlyPowered(i, j, k) || world.isBlockIndirectlyPowered(i, j + 1, k);
flag1 = flag1 || this.a(world, i, j, k, i1, true, 0) || this.a(world, i, j, k, i1, false, 0);
boolean flag2 = false;
if (flag1 && (i1 & 8) == 0) {
world.setData(i, j, k, j1 | 8);
flag2 = true;
} else if (!flag1 && (i1 & 8) != 0) {
world.setData(i, j, k, j1);
flag2 = true;
}
if (flag2) {
world.applyPhysics(i, j - 1, k, this.id);
if (j1 == 2 || j1 == 3 || j1 == 4 || j1 == 5) {
world.applyPhysics(i, j + 1, k, this.id);
}
}
} else if (l > 0 && Block.byId[l].isPowerSource() && !this.a && MinecartTrackLogic.a(new MinecartTrackLogic(this, world, i, j, k)) == 3) {
this.a(world, i, j, k, false);
}
}
}
private void a(World world, int i, int j, int k, boolean flag) {
if (!world.isStatic) {
(new MinecartTrackLogic(this, world, i, j, k)).a(world.isBlockIndirectlyPowered(i, j, k), flag);
}
}
private boolean a(World world, int i, int j, int k, int l, boolean flag, int i1) {
if (i1 >= 8) {
return false;
} else {
int j1 = l & 7;
boolean flag1 = true;
switch (j1) {
case 0:
if (flag) {
++k;
} else {
--k;
}
break;
case 1:
if (flag) {
--i;
} else {
++i;
}
break;
case 2:
if (flag) {
--i;
} else {
++i;
++j;
flag1 = false;
}
j1 = 1;
break;
case 3:
if (flag) {
--i;
++j;
flag1 = false;
} else {
++i;
}
j1 = 1;
break;
case 4:
if (flag) {
++k;
} else {
--k;
++j;
flag1 = false;
}
j1 = 0;
break;
case 5:
if (flag) {
++k;
++j;
flag1 = false;
} else {
--k;
}
j1 = 0;
}
return this.a(world, i, j, k, flag, i1, j1) ? true : flag1 && this.a(world, i, j - 1, k, flag, i1, j1);
}
}
private boolean a(World world, int i, int j, int k, boolean flag, int l, int i1) {
int j1 = world.getTypeId(i, j, k);
if (j1 == Block.GOLDEN_RAIL.id) {
int k1 = world.getData(i, j, k);
int l1 = k1 & 7;
if (i1 == 1 && (l1 == 0 || l1 == 4 || l1 == 5)) {
return false;
}
if (i1 == 0 && (l1 == 1 || l1 == 2 || l1 == 3)) {
return false;
}
if ((k1 & 8) != 0) {
if (!world.isBlockIndirectlyPowered(i, j, k) && !world.isBlockIndirectlyPowered(i, j + 1, k)) {
return this.a(world, i, j, k, k1, flag, l + 1);
}
return true;
}
}
return false;
}
public int e() {
return 0;
}
static boolean a(BlockMinecartTrack blockminecarttrack) {
return blockminecarttrack.a;
}
}
@@ -0,0 +1,26 @@
package net.minecraft.server;
import java.util.Random;
public class BlockMobSpawner extends BlockContainer {
protected BlockMobSpawner(int i, int j) {
super(i, j, Material.STONE);
}
protected TileEntity a_() {
return new TileEntityMobSpawner();
}
public int a(int i, Random random) {
return 0;
}
public int a(Random random) {
return 0;
}
public boolean a() {
return false;
}
}
@@ -0,0 +1,52 @@
package net.minecraft.server;
import org.bukkit.event.block.BlockSpreadEvent;
import java.util.Random;
public class BlockMushroom extends BlockFlower {
protected BlockMushroom(int i, int j) {
super(i, j);
float f = 0.2F;
this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f * 2.0F, 0.5F + f);
this.a(true);
}
public void a(World world, int i, int j, int k, Random random) {
if (random.nextInt(100) == 0) {
int l = i + random.nextInt(3) - 1;
int i1 = j + random.nextInt(2) - random.nextInt(2);
int j1 = k + random.nextInt(3) - 1;
if (world.isEmpty(l, i1, j1) && this.f(world, l, i1, j1)) {
int k1 = i + (random.nextInt(3) - 1);
k1 = k + (random.nextInt(3) - 1);
if (world.isEmpty(l, i1, j1) && this.f(world, l, i1, j1)) {
// CraftBukkit start
org.bukkit.World bworld = world.getWorld();
org.bukkit.block.BlockState blockState = bworld.getBlockAt(l, i1, j1).getState();
blockState.setTypeId(this.id);
BlockSpreadEvent event = new BlockSpreadEvent(blockState.getBlock(), bworld.getBlockAt(i, j, k), blockState);
world.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
blockState.update(true);
}
// CraftBukkit end
}
}
}
}
protected boolean c(int i) {
return Block.o[i];
}
public boolean f(World world, int i, int j, int k) {
return j >= 0 && j < 128 ? world.k(i, j, k) < 13 && this.c(world.getTypeId(i, j - 1, k)) : false;
}
}
@@ -0,0 +1,75 @@
package net.minecraft.server;
public class BlockNote extends BlockContainer {
public BlockNote(int i) {
super(i, 74, Material.WOOD);
}
public int a(int i) {
return this.textureId;
}
public void doPhysics(World world, int i, int j, int k, int l) {
if (l > 0 && Block.byId[l].isPowerSource()) {
boolean flag = world.isBlockPowered(i, j, k);
TileEntityNote tileentitynote = (TileEntityNote) world.getTileEntity(i, j, k);
if (tileentitynote.b != flag) {
if (flag) {
tileentitynote.play(world, i, j, k);
}
tileentitynote.b = flag;
}
}
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
if (world.isStatic) {
return true;
} else {
TileEntityNote tileentitynote = (TileEntityNote) world.getTileEntity(i, j, k);
tileentitynote.a();
tileentitynote.play(world, i, j, k);
return true;
}
}
public void b(World world, int i, int j, int k, EntityHuman entityhuman) {
if (!world.isStatic) {
TileEntityNote tileentitynote = (TileEntityNote) world.getTileEntity(i, j, k);
tileentitynote.play(world, i, j, k);
}
}
protected TileEntity a_() {
return new TileEntityNote();
}
public void a(World world, int i, int j, int k, int l, int i1) {
float f = (float) Math.pow(2.0D, (double) (i1 - 12) / 12.0D);
String s = "harp";
if (l == 1) {
s = "bd";
}
if (l == 2) {
s = "snare";
}
if (l == 3) {
s = "hat";
}
if (l == 4) {
s = "bassattack";
}
world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "note." + s, 3.0F, f);
world.a("note", (double) i + 0.5D, (double) j + 1.2D, (double) k + 0.5D, (double) i1 / 24.0D, 0.0D, 0.0D);
}
}
@@ -0,0 +1,18 @@
package net.minecraft.server;
import java.util.Random;
public class BlockObsidian extends BlockStone {
public BlockObsidian(int i, int j) {
super(i, j);
}
public int a(Random random) {
return 1;
}
public int a(int i, Random random) {
return Block.OBSIDIAN.id;
}
}
@@ -0,0 +1,22 @@
package net.minecraft.server;
import java.util.Random;
public class BlockOre extends Block {
public BlockOre(int i, int j) {
super(i, j, Material.STONE);
}
public int a(int i, Random random) {
return this.id == Block.COAL_ORE.id ? Item.COAL.id : (this.id == Block.DIAMOND_ORE.id ? Item.DIAMOND.id : (this.id == Block.LAPIS_ORE.id ? Item.INK_SACK.id : this.id));
}
public int a(Random random) {
return this.id == Block.LAPIS_ORE.id ? 4 + random.nextInt(5) : 1;
}
protected int a_(int i) {
return this.id == Block.LAPIS_ORE.id ? 4 : 0;
}
}
@@ -0,0 +1,13 @@
package net.minecraft.server;
public class BlockOreBlock extends Block {
public BlockOreBlock(int i, int j) {
super(i, Material.ORE);
this.textureId = j;
}
public int a(int i) {
return this.textureId;
}
}
@@ -0,0 +1,374 @@
package net.minecraft.server;
import com.legacyminecraft.poseidon.PoseidonConfig;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
import java.util.ArrayList;
// CraftBukkit start
// CraftBukkit end
public class BlockPiston extends Block {
private boolean a;
private boolean b;
public BlockPiston(int i, int j, boolean flag) {
super(i, j, Material.PISTON);
this.a = flag;
this.a(h);
this.c(0.5F);
}
public int a(int i, int j) {
int k = c(j);
return k > 5 ? this.textureId : (i == k ? (!d(j) && this.minX <= 0.0D && this.minY <= 0.0D && this.minZ <= 0.0D && this.maxX >= 1.0D && this.maxY >= 1.0D && this.maxZ >= 1.0D ? this.textureId : 110) : (i == PistonBlockTextures.a[k] ? 109 : 108));
}
public boolean a() {
return false;
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
return false;
}
public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) {
int l = c(world, i, j, k, (EntityHuman) entityliving);
world.setData(i, j, k, l);
if (!world.isStatic) {
this.g(world, i, j, k);
}
}
public void doPhysics(World world, int i, int j, int k, int l) {
if (!world.isStatic && !this.b) {
this.g(world, i, j, k);
}
}
public void c(World world, int i, int j, int k) {
if (!world.isStatic && world.getTileEntity(i, j, k) == null) {
this.g(world, i, j, k);
}
}
private void g(World world, int i, int j, int k) {
int l = world.getData(i, j, k);
int i1 = c(l);
boolean flag = this.f(world, i, j, k, i1);
if (l != 7) {
if (flag && !d(l)) {
// CraftBukkit start
int length;
try {
length = h(world, i, j, k, i1);
} catch (RuntimeException exception) {
System.out.println("[Poseidon] A piston crash attempt occurred at " + i + " " + j + " " + k + " in " + world.getWorld().getName());
return;
}
if (length >= 0) {
org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k);
BlockPistonExtendEvent event = new BlockPistonExtendEvent(block, length);
world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
// CraftBukkit end
world.setRawData(i, j, k, i1 | 8);
world.playNote(i, j, k, 0, i1);
}
} else if (!flag && d(l)) {
// CraftBukkit start
org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k);
BlockPistonRetractEvent event = new BlockPistonRetractEvent(block);
world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
// CraftBukkit end
world.setRawData(i, j, k, i1);
world.playNote(i, j, k, 1, i1);
}
}
}
private boolean f(World world, int i, int j, int k, int l) {
return l != 0 && world.isBlockFaceIndirectlyPowered(i, j - 1, k, 0) ? true : (l != 1 && world.isBlockFaceIndirectlyPowered(i, j + 1, k, 1) ? true : (l != 2 && world.isBlockFaceIndirectlyPowered(i, j, k - 1, 2) ? true : (l != 3 && world.isBlockFaceIndirectlyPowered(i, j, k + 1, 3) ? true : (l != 5 && world.isBlockFaceIndirectlyPowered(i + 1, j, k, 5) ? true : (l != 4 && world.isBlockFaceIndirectlyPowered(i - 1, j, k, 4) ? true : (world.isBlockFaceIndirectlyPowered(i, j, k, 0) ? true : (world.isBlockFaceIndirectlyPowered(i, j + 2, k, 1) ? true : (world.isBlockFaceIndirectlyPowered(i, j + 1, k - 1, 2) ? true : (world.isBlockFaceIndirectlyPowered(i, j + 1, k + 1, 3) ? true : (world.isBlockFaceIndirectlyPowered(i - 1, j + 1, k, 4) ? true : world.isBlockFaceIndirectlyPowered(i + 1, j + 1, k, 5)))))))))));
}
public void a(World world, int i, int j, int k, int l, int i1) {
this.b = true;
if (l == 0) {
if (this.i(world, i, j, k, i1)) {
world.setData(i, j, k, i1 | 8);
world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "tile.piston.out", 0.5F, world.random.nextFloat() * 0.25F + 0.6F);
}
} else if (l == 1) {
TileEntity tileentity = world.getTileEntity(i + PistonBlockTextures.b[i1], j + PistonBlockTextures.c[i1], k + PistonBlockTextures.d[i1]);
if (tileentity != null && tileentity instanceof TileEntityPiston) {
((TileEntityPiston) tileentity).k();
}
world.setRawTypeIdAndData(i, j, k, Block.PISTON_MOVING.id, i1);
world.setTileEntity(i, j, k, BlockPistonMoving.a(this.id, i1, i1, false, true));
if (this.a) {
int j1 = i + PistonBlockTextures.b[i1] * 2;
int k1 = j + PistonBlockTextures.c[i1] * 2;
int l1 = k + PistonBlockTextures.d[i1] * 2;
int i2 = world.getTypeId(j1, k1, l1);
int j2 = world.getData(j1, k1, l1);
boolean flag = false;
if (i2 == Block.PISTON_MOVING.id) {
TileEntity tileentity1 = world.getTileEntity(j1, k1, l1);
if (tileentity1 != null && tileentity1 instanceof TileEntityPiston) {
TileEntityPiston tileentitypiston = (TileEntityPiston) tileentity1;
if (tileentitypiston.d() == i1 && tileentitypiston.c()) {
tileentitypiston.k();
i2 = tileentitypiston.a();
j2 = tileentitypiston.e();
flag = true;
}
}
}
if (!flag && i2 > 0 && a(i2, world, j1, k1, l1, false) && (Block.byId[i2].e() == 0 || i2 == Block.PISTON.id || i2 == Block.PISTON_STICKY.id)) {
this.b = false;
world.setTypeId(j1, k1, l1, 0);
this.b = true;
i += PistonBlockTextures.b[i1];
j += PistonBlockTextures.c[i1];
k += PistonBlockTextures.d[i1];
world.setRawTypeIdAndData(i, j, k, Block.PISTON_MOVING.id, j2);
world.setTileEntity(i, j, k, BlockPistonMoving.a(i2, j2, i1, false, false));
} else if (!flag) {
this.b = false;
world.setTypeId(i + PistonBlockTextures.b[i1], j + PistonBlockTextures.c[i1], k + PistonBlockTextures.d[i1], 0);
this.b = true;
}
} else {
this.b = false;
world.setTypeId(i + PistonBlockTextures.b[i1], j + PistonBlockTextures.c[i1], k + PistonBlockTextures.d[i1], 0);
this.b = true;
}
world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "tile.piston.in", 0.5F, world.random.nextFloat() * 0.15F + 0.6F);
}
this.b = false;
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
int l = iblockaccess.getData(i, j, k);
if (d(l)) {
switch (c(l)) {
case 0:
this.a(0.0F, 0.25F, 0.0F, 1.0F, 1.0F, 1.0F);
break;
case 1:
this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.75F, 1.0F);
break;
case 2:
this.a(0.0F, 0.0F, 0.25F, 1.0F, 1.0F, 1.0F);
break;
case 3:
this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.75F);
break;
case 4:
this.a(0.25F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
break;
case 5:
this.a(0.0F, 0.0F, 0.0F, 0.75F, 1.0F, 1.0F);
}
} else {
this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
}
public void a(World world, int i, int j, int k, AxisAlignedBB axisalignedbb, ArrayList arraylist) {
this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
super.a(world, i, j, k, axisalignedbb, arraylist);
}
public boolean b() {
return false;
}
public static int c(int i) {
return i & 7;
}
public static boolean d(int i) {
return (i & 8) != 0;
}
private static int c(World world, int i, int j, int k, EntityHuman entityhuman) {
if (MathHelper.abs((float) entityhuman.locX - (float) i) < 2.0F && MathHelper.abs((float) entityhuman.locZ - (float) k) < 2.0F) {
double d0 = entityhuman.locY + 1.82D - (double) entityhuman.height;
if (d0 - (double) j > 2.0D) {
return 1;
}
if ((double) j - d0 > 0.0D) {
return 0;
}
}
int l = MathHelper.floor((double) (entityhuman.yaw * 4.0F / 360.0F) + 0.5D) & 3;
return l == 0 ? 2 : (l == 1 ? 5 : (l == 2 ? 3 : (l == 3 ? 4 : 0)));
}
private static boolean a(int i, World world, int j, int k, int l, boolean flag) {
if (i == Block.OBSIDIAN.id) {
return false;
} else if ((i == Block.FURNACE.id || i == Block.BURNING_FURNACE.id) && PoseidonConfig.getInstance().getBoolean("world.settings.block-pistons-pushing-furnaces.enabled", true)) {
// System.out.println("Blocking a piston from being pushed.");
return false;
} else {
if (i != Block.PISTON.id && i != Block.PISTON_STICKY.id) {
if (Block.byId[i].j() == -1.0F) {
return false;
}
if (Block.byId[i].e() == 2) {
return false;
}
if (!flag && Block.byId[i].e() == 1) {
return false;
}
} else if (d(world.getData(j, k, l))) {
return false;
}
TileEntity tileentity = world.getTileEntity(j, k, l);
return tileentity == null;
}
}
// CraftBukkkit boolean -> int
private static int h(World world, int i, int j, int k, int l) {
int i1 = i + PistonBlockTextures.b[l];
int j1 = j + PistonBlockTextures.c[l];
int k1 = k + PistonBlockTextures.d[l];
int l1 = 0;
while (true) {
if (l1 < 13) {
if (j1 <= 0 || j1 >= 127) {
return -1; // CraftBukkit
}
int i2 = world.getTypeId(i1, j1, k1);
if (i2 != 0) {
if (!a(i2, world, i1, j1, k1, true)) {
return -1; // CraftBukkit
}
if (Block.byId[i2].e() != 1) {
if (l1 == 12) {
return -1; // CraftBukkit
}
i1 += PistonBlockTextures.b[l];
j1 += PistonBlockTextures.c[l];
k1 += PistonBlockTextures.d[l];
++l1;
continue;
}
}
}
return l1; // CraftBukkit
}
}
private boolean i(World world, int i, int j, int k, int l) {
int i1 = i + PistonBlockTextures.b[l];
int j1 = j + PistonBlockTextures.c[l];
int k1 = k + PistonBlockTextures.d[l];
int l1 = 0;
while (true) {
int i2;
if (l1 < 13) {
if (j1 <= 0 || j1 >= 127) {
return false;
}
i2 = world.getTypeId(i1, j1, k1);
if (i2 != 0) {
if (!a(i2, world, i1, j1, k1, true)) {
return false;
}
if (Block.byId[i2].e() != 1) {
if (l1 == 12) {
return false;
}
i1 += PistonBlockTextures.b[l];
j1 += PistonBlockTextures.c[l];
k1 += PistonBlockTextures.d[l];
++l1;
continue;
}
Block.byId[i2].g(world, i1, j1, k1, world.getData(i1, j1, k1));
if (PoseidonConfig.getInstance().getConfigBoolean("world.settings.pistons.other-fixes.enabled", true)) {
world.setRawTypeId(i1, j1, k1, 0);
} else {
world.setTypeId(i1, j1, k1, 0);
}
}
}
while (i1 != i || j1 != j || k1 != k) {
l1 = i1 - PistonBlockTextures.b[l];
i2 = j1 - PistonBlockTextures.c[l];
int j2 = k1 - PistonBlockTextures.d[l];
int k2 = world.getTypeId(l1, i2, j2);
int l2 = world.getData(l1, i2, j2);
if (k2 == this.id && l1 == i && i2 == j && j2 == k) {
world.setRawTypeIdAndData(i1, j1, k1, Block.PISTON_MOVING.id, l | (this.a ? 8 : 0));
world.setTileEntity(i1, j1, k1, BlockPistonMoving.a(Block.PISTON_EXTENSION.id, l | (this.a ? 8 : 0), l, true, false));
} else {
world.setRawTypeIdAndData(i1, j1, k1, Block.PISTON_MOVING.id, l2);
world.setTileEntity(i1, j1, k1, BlockPistonMoving.a(k2, l2, l, true, false));
}
i1 = l1;
j1 = i2;
k1 = j2;
}
return true;
}
}
}
@@ -0,0 +1,155 @@
package net.minecraft.server;
import java.util.ArrayList;
import java.util.Random;
public class BlockPistonExtension extends Block {
private int a = -1;
public BlockPistonExtension(int i, int j) {
super(i, j, Material.PISTON);
this.a(h);
this.c(0.5F);
}
public void remove(World world, int i, int j, int k) {
super.remove(world, i, j, k);
int l = world.getData(i, j, k);
if (l < 0 || l == 6 || l == 7 || l > 13) return; // CraftBukkit - fixed a piston AIOOBE issue.
int i1 = PistonBlockTextures.a[b(l)];
i += PistonBlockTextures.b[i1];
j += PistonBlockTextures.c[i1];
k += PistonBlockTextures.d[i1];
int j1 = world.getTypeId(i, j, k);
if (j1 == Block.PISTON.id || j1 == Block.PISTON_STICKY.id) {
l = world.getData(i, j, k);
if (BlockPiston.d(l)) {
Block.byId[j1].g(world, i, j, k, l);
world.setTypeId(i, j, k, 0);
}
}
}
public int a(int i, int j) {
int k = b(j);
return i == k ? (this.a >= 0 ? this.a : ((j & 8) != 0 ? this.textureId - 1 : this.textureId)) : (i == PistonBlockTextures.a[k] ? 107 : 108);
}
public boolean a() {
return false;
}
public boolean b() {
return false;
}
public boolean canPlace(World world, int i, int j, int k) {
return false;
}
public boolean canPlace(World world, int i, int j, int k, int l) {
return false;
}
public int a(Random random) {
return 0;
}
public void a(World world, int i, int j, int k, AxisAlignedBB axisalignedbb, ArrayList arraylist) {
int l = world.getData(i, j, k);
switch (b(l)) {
case 0:
this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.25F, 1.0F);
super.a(world, i, j, k, axisalignedbb, arraylist);
this.a(0.375F, 0.25F, 0.375F, 0.625F, 1.0F, 0.625F);
super.a(world, i, j, k, axisalignedbb, arraylist);
break;
case 1:
this.a(0.0F, 0.75F, 0.0F, 1.0F, 1.0F, 1.0F);
super.a(world, i, j, k, axisalignedbb, arraylist);
this.a(0.375F, 0.0F, 0.375F, 0.625F, 0.75F, 0.625F);
super.a(world, i, j, k, axisalignedbb, arraylist);
break;
case 2:
this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.25F);
super.a(world, i, j, k, axisalignedbb, arraylist);
this.a(0.25F, 0.375F, 0.25F, 0.75F, 0.625F, 1.0F);
super.a(world, i, j, k, axisalignedbb, arraylist);
break;
case 3:
this.a(0.0F, 0.0F, 0.75F, 1.0F, 1.0F, 1.0F);
super.a(world, i, j, k, axisalignedbb, arraylist);
this.a(0.25F, 0.375F, 0.0F, 0.75F, 0.625F, 0.75F);
super.a(world, i, j, k, axisalignedbb, arraylist);
break;
case 4:
this.a(0.0F, 0.0F, 0.0F, 0.25F, 1.0F, 1.0F);
super.a(world, i, j, k, axisalignedbb, arraylist);
this.a(0.375F, 0.25F, 0.25F, 0.625F, 0.75F, 1.0F);
super.a(world, i, j, k, axisalignedbb, arraylist);
break;
case 5:
this.a(0.75F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
super.a(world, i, j, k, axisalignedbb, arraylist);
this.a(0.0F, 0.375F, 0.25F, 0.75F, 0.625F, 0.75F);
super.a(world, i, j, k, axisalignedbb, arraylist);
}
this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
int l = iblockaccess.getData(i, j, k);
switch (b(l)) {
case 0:
this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.25F, 1.0F);
break;
case 1:
this.a(0.0F, 0.75F, 0.0F, 1.0F, 1.0F, 1.0F);
break;
case 2:
this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.25F);
break;
case 3:
this.a(0.0F, 0.0F, 0.75F, 1.0F, 1.0F, 1.0F);
break;
case 4:
this.a(0.0F, 0.0F, 0.0F, 0.25F, 1.0F, 1.0F);
break;
case 5:
this.a(0.75F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
}
public void doPhysics(World world, int i, int j, int k, int l) {
int i1 = b(world.getData(i, j, k));
if (i1 > 5 || i1 < 0) return; // CraftBukkit - fixed a piston AIOOBE issue.
int j1 = world.getTypeId(i - PistonBlockTextures.b[i1], j - PistonBlockTextures.c[i1], k - PistonBlockTextures.d[i1]);
if (j1 != Block.PISTON.id && j1 != Block.PISTON_STICKY.id) {
world.setTypeId(i, j, k, 0);
} else {
Block.byId[j1].doPhysics(world, i - PistonBlockTextures.b[i1], j - PistonBlockTextures.c[i1], k - PistonBlockTextures.d[i1], l);
}
}
public static int b(int i) {
return i & 7;
}
}
@@ -0,0 +1,146 @@
package net.minecraft.server;
import java.util.Random;
public class BlockPistonMoving extends BlockContainer {
public BlockPistonMoving(int i) {
super(i, Material.PISTON);
this.c(-1.0F);
}
protected TileEntity a_() {
return null;
}
public void c(World world, int i, int j, int k) {}
public void remove(World world, int i, int j, int k) {
TileEntity tileentity = world.getTileEntity(i, j, k);
if (tileentity != null && tileentity instanceof TileEntityPiston) {
((TileEntityPiston) tileentity).k();
} else {
super.remove(world, i, j, k);
}
}
public boolean canPlace(World world, int i, int j, int k) {
return false;
}
public boolean canPlace(World world, int i, int j, int k, int l) {
return false;
}
public boolean a() {
return false;
}
public boolean b() {
return false;
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
if (!world.isStatic && world.getTileEntity(i, j, k) == null) {
world.setTypeId(i, j, k, 0);
return true;
} else {
return false;
}
}
public int a(int i, Random random) {
return 0;
}
public void dropNaturally(World world, int i, int j, int k, int l, float f) {
if (!world.isStatic) {
TileEntityPiston tileentitypiston = this.b(world, i, j, k);
if (tileentitypiston != null) {
Block.byId[tileentitypiston.a()].g(world, i, j, k, tileentitypiston.e());
}
}
}
public void doPhysics(World world, int i, int j, int k, int l) {
if (!world.isStatic && world.getTileEntity(i, j, k) == null) {
;
}
}
public static TileEntity a(int i, int j, int k, boolean flag, boolean flag1) {
return new TileEntityPiston(i, j, k, flag, flag1);
}
public AxisAlignedBB e(World world, int i, int j, int k) {
TileEntityPiston tileentitypiston = this.b(world, i, j, k);
if (tileentitypiston == null) {
return null;
} else {
float f = tileentitypiston.a(0.0F);
if (tileentitypiston.c()) {
f = 1.0F - f;
}
return this.a(world, i, j, k, tileentitypiston.a(), f, tileentitypiston.d());
}
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
TileEntityPiston tileentitypiston = this.b(iblockaccess, i, j, k);
if (tileentitypiston != null) {
Block block = Block.byId[tileentitypiston.a()];
if (block == null || block == this) {
return;
}
block.a(iblockaccess, i, j, k);
float f = tileentitypiston.a(0.0F);
if (tileentitypiston.c()) {
f = 1.0F - f;
}
int l = tileentitypiston.d();
this.minX = block.minX - (double) ((float) PistonBlockTextures.b[l] * f);
this.minY = block.minY - (double) ((float) PistonBlockTextures.c[l] * f);
this.minZ = block.minZ - (double) ((float) PistonBlockTextures.d[l] * f);
this.maxX = block.maxX - (double) ((float) PistonBlockTextures.b[l] * f);
this.maxY = block.maxY - (double) ((float) PistonBlockTextures.c[l] * f);
this.maxZ = block.maxZ - (double) ((float) PistonBlockTextures.d[l] * f);
}
}
public AxisAlignedBB a(World world, int i, int j, int k, int l, float f, int i1) {
if (l != 0 && l != this.id) {
AxisAlignedBB axisalignedbb = Block.byId[l].e(world, i, j, k);
if (axisalignedbb == null) {
return null;
} else {
axisalignedbb.a -= (double) ((float) PistonBlockTextures.b[i1] * f);
axisalignedbb.d -= (double) ((float) PistonBlockTextures.b[i1] * f);
axisalignedbb.b -= (double) ((float) PistonBlockTextures.c[i1] * f);
axisalignedbb.e -= (double) ((float) PistonBlockTextures.c[i1] * f);
axisalignedbb.c -= (double) ((float) PistonBlockTextures.d[i1] * f);
axisalignedbb.f -= (double) ((float) PistonBlockTextures.d[i1] * f);
return axisalignedbb;
}
} else {
return null;
}
}
private TileEntityPiston b(IBlockAccess iblockaccess, int i, int j, int k) {
TileEntity tileentity = iblockaccess.getTileEntity(i, j, k);
return tileentity != null && tileentity instanceof TileEntityPiston ? (TileEntityPiston) tileentity : null;
}
}
@@ -0,0 +1,173 @@
package net.minecraft.server;
import org.bukkit.event.entity.EntityPortalEnterEvent;
import org.bukkit.event.world.PortalCreateEvent;
import java.util.Random;
// CraftBukkit start
// CraftBukkit end
public class BlockPortal extends BlockBreakable {
public BlockPortal(int i, int j) {
super(i, j, Material.PORTAL, false);
}
public AxisAlignedBB e(World world, int i, int j, int k) {
return null;
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
float f;
float f1;
if (iblockaccess.getTypeId(i - 1, j, k) != this.id && iblockaccess.getTypeId(i + 1, j, k) != this.id) {
f = 0.125F;
f1 = 0.5F;
this.a(0.5F - f, 0.0F, 0.5F - f1, 0.5F + f, 1.0F, 0.5F + f1);
} else {
f = 0.5F;
f1 = 0.125F;
this.a(0.5F - f, 0.0F, 0.5F - f1, 0.5F + f, 1.0F, 0.5F + f1);
}
}
public boolean a() {
return false;
}
public boolean b() {
return false;
}
public boolean a_(World world, int i, int j, int k) {
byte b0 = 0;
byte b1 = 0;
if (world.getTypeId(i - 1, j, k) == Block.OBSIDIAN.id || world.getTypeId(i + 1, j, k) == Block.OBSIDIAN.id) {
b0 = 1;
}
if (world.getTypeId(i, j, k - 1) == Block.OBSIDIAN.id || world.getTypeId(i, j, k + 1) == Block.OBSIDIAN.id) {
b1 = 1;
}
if (b0 == b1) {
return false;
} else {
// CraftBukkit start
java.util.Collection<org.bukkit.block.Block> blocks = new java.util.HashSet<org.bukkit.block.Block>();
org.bukkit.World bworld = world.getWorld();
// CraftBukkit end
if (world.getTypeId(i - b0, j, k - b1) == 0) {
i -= b0;
k -= b1;
}
int l;
int i1;
for (l = -1; l <= 2; ++l) {
for (i1 = -1; i1 <= 3; ++i1) {
boolean flag = l == -1 || l == 2 || i1 == -1 || i1 == 3;
if (l != -1 && l != 2 || i1 != -1 && i1 != 3) {
int j1 = world.getTypeId(i + b0 * l, j + i1, k + b1 * l);
if (flag) {
if (j1 != Block.OBSIDIAN.id) {
return false;
} else {
blocks.add(bworld.getBlockAt(i + b0 * l, j + i1, k + b1 * l)); // CraftBukkit
}
} else if (j1 != 0 && j1 != Block.FIRE.id) {
return false;
}
}
}
}
// CraftBukkit start
for (l = 0; l < 2; ++l) {
for (i1 = 0; i1 < 3; ++i1) {
blocks.add(bworld.getBlockAt(i + b0 * l, j + i1, k + b1 * l));
}
}
PortalCreateEvent event = new PortalCreateEvent(blocks, bworld);
world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return false;
}
// CraftBukkit end
world.suppressPhysics = true;
for (l = 0; l < 2; ++l) {
for (i1 = 0; i1 < 3; ++i1) {
world.setTypeId(i + b0 * l, j + i1, k + b1 * l, Block.PORTAL.id);
}
}
world.suppressPhysics = false;
return true;
}
}
public void doPhysics(World world, int i, int j, int k, int l) {
byte b0 = 0;
byte b1 = 1;
if (world.getTypeId(i - 1, j, k) == this.id || world.getTypeId(i + 1, j, k) == this.id) {
b0 = 1;
b1 = 0;
}
int i1;
for (i1 = j; world.getTypeId(i, i1 - 1, k) == this.id; --i1) {
;
}
if (world.getTypeId(i, i1 - 1, k) != Block.OBSIDIAN.id) {
world.setTypeId(i, j, k, 0);
} else {
int j1;
for (j1 = 1; j1 < 4 && world.getTypeId(i, i1 + j1, k) == this.id; ++j1) {
;
}
if (j1 == 3 && world.getTypeId(i, i1 + j1, k) == Block.OBSIDIAN.id) {
boolean flag = world.getTypeId(i - 1, j, k) == this.id || world.getTypeId(i + 1, j, k) == this.id;
boolean flag1 = world.getTypeId(i, j, k - 1) == this.id || world.getTypeId(i, j, k + 1) == this.id;
if (flag && flag1) {
world.setTypeId(i, j, k, 0);
} else if ((world.getTypeId(i + b0, j, k + b1) != Block.OBSIDIAN.id || world.getTypeId(i - b0, j, k - b1) != this.id) && (world.getTypeId(i - b0, j, k - b1) != Block.OBSIDIAN.id || world.getTypeId(i + b0, j, k + b1) != this.id)) {
world.setTypeId(i, j, k, 0);
}
} else {
world.setTypeId(i, j, k, 0);
}
}
}
public int a(Random random) {
return 0;
}
public void a(World world, int i, int j, int k, Entity entity) {
if (entity.vehicle == null && entity.passenger == null) {
// CraftBukkit start - Entity in portal
EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), i, j, k));
world.getServer().getPluginManager().callEvent(event);
// CraftBukkit end
entity.P();
}
}
}
@@ -0,0 +1,189 @@
package net.minecraft.server;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.event.block.BlockRedstoneEvent;
import org.bukkit.event.entity.EntityInteractEvent;
import java.util.List;
import java.util.Random;
// CraftBukkit start
// CraftBukkit end
public class BlockPressurePlate extends Block {
private EnumMobType a;
protected BlockPressurePlate(int i, int j, EnumMobType enummobtype, Material material) {
super(i, j, material);
this.a = enummobtype;
this.a(true);
float f = 0.0625F;
this.a(f, 0.0F, f, 1.0F - f, 0.03125F, 1.0F - f);
}
public int c() {
return 20;
}
public AxisAlignedBB e(World world, int i, int j, int k) {
return null;
}
public boolean a() {
return false;
}
public boolean b() {
return false;
}
public boolean canPlace(World world, int i, int j, int k) {
return world.e(i, j - 1, k);
}
public void c(World world, int i, int j, int k) {}
public void doPhysics(World world, int i, int j, int k, int l) {
boolean flag = false;
if (!world.e(i, j - 1, k)) {
flag = true;
}
if (flag) {
this.g(world, i, j, k, world.getData(i, j, k));
world.setTypeId(i, j, k, 0);
}
}
public void a(World world, int i, int j, int k, Random random) {
if (!world.isStatic) {
if (world.getData(i, j, k) != 0) {
this.g(world, i, j, k);
}
}
}
public void a(World world, int i, int j, int k, Entity entity) {
if (!world.isStatic) {
if (world.getData(i, j, k) != 1) {
this.g(world, i, j, k);
}
}
}
private void g(World world, int i, int j, int k) {
boolean flag = world.getData(i, j, k) == 1;
boolean flag1 = false;
float f = 0.125F;
List list = null;
if (this.a == EnumMobType.EVERYTHING) {
list = world.b((Entity) null, AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) j + 0.25D, (double) ((float) (k + 1) - f)));
}
if (this.a == EnumMobType.MOBS) {
list = world.a(EntityLiving.class, AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) j + 0.25D, (double) ((float) (k + 1) - f)));
}
if (this.a == EnumMobType.PLAYERS) {
list = world.a(EntityHuman.class, AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) j + 0.25D, (double) ((float) (k + 1) - f)));
}
if (list.size() > 0) {
flag1 = true;
}
// CraftBukkit start - Interact Pressure Plate
org.bukkit.World bworld = world.getWorld();
org.bukkit.plugin.PluginManager manager = world.getServer().getPluginManager();
if (flag != flag1) {
if (flag1) {
for (Object object: list) {
if (object != null) {
org.bukkit.event.Cancellable cancellable;
if (object instanceof EntityHuman) {
cancellable = CraftEventFactory.callPlayerInteractEvent((EntityHuman) object, org.bukkit.event.block.Action.PHYSICAL, i, j, k, -1, null);
} else if (object instanceof Entity) {
cancellable = new EntityInteractEvent(((Entity) object).getBukkitEntity(), bworld.getBlockAt(i, j, k));
manager.callEvent((EntityInteractEvent) cancellable);
} else {
continue;
}
if (cancellable.isCancelled()) {
return;
}
}
}
}
BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(bworld.getBlockAt(i, j, k), flag ? 1 : 0, flag1 ? 1 : 0);
manager.callEvent(eventRedstone);
flag1 = eventRedstone.getNewCurrent() > 0;
}
// CraftBukkit end
if (flag1 && !flag) {
world.setData(i, j, k, 1);
world.applyPhysics(i, j, k, this.id);
world.applyPhysics(i, j - 1, k, this.id);
world.b(i, j, k, i, j, k);
world.makeSound((double) i + 0.5D, (double) j + 0.1D, (double) k + 0.5D, "random.click", 0.3F, 0.6F);
}
if (!flag1 && flag) {
world.setData(i, j, k, 0);
world.applyPhysics(i, j, k, this.id);
world.applyPhysics(i, j - 1, k, this.id);
world.b(i, j, k, i, j, k);
world.makeSound((double) i + 0.5D, (double) j + 0.1D, (double) k + 0.5D, "random.click", 0.3F, 0.5F);
}
if (flag1) {
world.c(i, j, k, this.id, this.c());
}
}
public void remove(World world, int i, int j, int k) {
int l = world.getData(i, j, k);
if (l > 0) {
world.applyPhysics(i, j, k, this.id);
world.applyPhysics(i, j - 1, k, this.id);
}
super.remove(world, i, j, k);
}
public void a(IBlockAccess iblockaccess, int i, int j, int k) {
boolean flag = iblockaccess.getData(i, j, k) == 1;
float f = 0.0625F;
if (flag) {
this.a(f, 0.0F, f, 1.0F - f, 0.03125F, 1.0F - f);
} else {
this.a(f, 0.0F, f, 1.0F - f, 0.0625F, 1.0F - f);
}
}
public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) {
return iblockaccess.getData(i, j, k) > 0;
}
public boolean d(World world, int i, int j, int k, int l) {
return world.getData(i, j, k) == 0 ? false : l == 1;
}
public boolean isPowerSource() {
return true;
}
public int e() {
return 1;
}
}
@@ -0,0 +1,63 @@
package net.minecraft.server;
import org.bukkit.event.block.BlockRedstoneEvent;
public class BlockPumpkin extends Block {
private boolean a;
protected BlockPumpkin(int i, int j, boolean flag) {
super(i, Material.PUMPKIN);
this.textureId = j;
this.a(true);
this.a = flag;
}
public int a(int i, int j) {
if (i == 1) {
return this.textureId;
} else if (i == 0) {
return this.textureId;
} else {
int k = this.textureId + 1 + 16;
if (this.a) {
++k;
}
return j == 2 && i == 2 ? k : (j == 3 && i == 5 ? k : (j == 0 && i == 3 ? k : (j == 1 && i == 4 ? k : this.textureId + 16)));
}
}
public int a(int i) {
return i == 1 ? this.textureId : (i == 0 ? this.textureId : (i == 3 ? this.textureId + 1 + 16 : this.textureId + 16));
}
public void c(World world, int i, int j, int k) {
super.c(world, i, j, k);
}
public boolean canPlace(World world, int i, int j, int k) {
int l = world.getTypeId(i, j, k);
return (l == 0 || Block.byId[l].material.isReplacable()) && world.e(i, j - 1, k);
}
public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) {
int l = MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 2.5D) & 3;
world.setData(i, j, k, l);
}
// CraftBukkit start
public void doPhysics(World world, int i, int j, int k, int l) {
if (net.minecraft.server.Block.byId[l] != null && net.minecraft.server.Block.byId[l].isPowerSource()) {
org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k);
int power = block.getBlockPower();
BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, power, power);
world.getServer().getPluginManager().callEvent(eventRedstone);
}
}
// CraftBukkit end
}
@@ -0,0 +1,96 @@
package net.minecraft.server;
import java.util.Random;
public class BlockRedstoneOre extends Block {
private boolean a;
public BlockRedstoneOre(int i, int j, boolean flag) {
super(i, j, Material.STONE);
if (flag) {
this.a(true);
}
this.a = flag;
}
public int c() {
return 30;
}
public void b(World world, int i, int j, int k, EntityHuman entityhuman) {
this.g(world, i, j, k);
super.b(world, i, j, k, entityhuman);
}
public void b(World world, int i, int j, int k, Entity entity) {
this.g(world, i, j, k);
super.b(world, i, j, k, entity);
}
public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) {
this.g(world, i, j, k);
return super.interact(world, i, j, k, entityhuman);
}
private void g(World world, int i, int j, int k) {
this.h(world, i, j, k);
if (this.id == Block.REDSTONE_ORE.id) {
world.setTypeId(i, j, k, Block.GLOWING_REDSTONE_ORE.id);
}
}
public void a(World world, int i, int j, int k, Random random) {
if (this.id == Block.GLOWING_REDSTONE_ORE.id) {
world.setTypeId(i, j, k, Block.REDSTONE_ORE.id);
}
}
public int a(int i, Random random) {
return Item.REDSTONE.id;
}
public int a(Random random) {
return 4 + random.nextInt(2);
}
private void h(World world, int i, int j, int k) {
Random random = world.random;
double d0 = 0.0625D;
for (int l = 0; l < 6; ++l) {
double d1 = (double) ((float) i + random.nextFloat());
double d2 = (double) ((float) j + random.nextFloat());
double d3 = (double) ((float) k + random.nextFloat());
if (l == 0 && !world.p(i, j + 1, k)) {
d2 = (double) (j + 1) + d0;
}
if (l == 1 && !world.p(i, j - 1, k)) {
d2 = (double) (j + 0) - d0;
}
if (l == 2 && !world.p(i, j, k + 1)) {
d3 = (double) (k + 1) + d0;
}
if (l == 3 && !world.p(i, j, k - 1)) {
d3 = (double) (k + 0) - d0;
}
if (l == 4 && !world.p(i + 1, j, k)) {
d1 = (double) (i + 1) + d0;
}
if (l == 5 && !world.p(i - 1, j, k)) {
d1 = (double) (i + 0) - d0;
}
if (d1 < (double) i || d1 > (double) (i + 1) || d2 < 0.0D || d2 > (double) (j + 1) || d3 < (double) k || d3 > (double) (k + 1)) {
world.a("reddust", d1, d2, d3, 0.0D, 0.0D, 0.0D);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More