From 6bc15b24f6aee6be927ad55790cd307cd0cb9e47 Mon Sep 17 00:00:00 2001 From: Marc Baloup Date: Tue, 16 Feb 2016 20:07:51 +0100 Subject: [PATCH] =?UTF-8?q?Cr=C3=A9ation=20de=20la=20librairie=20Java=20Pa?= =?UTF-8?q?ndacubeUtil?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Utilisé par PandacubeBungee et PandacubeSpigot --- .classpath | 10 + .gitignore | 1 + .project | 17 + make_jar.jardesc | 17 + manifest | 1 + resources/bungee.yml | 4 + resources/plugin.yml | 4 + .../earth2me/essentials/utils/DateUtil.java | 175 ++++ .../SunriseSunsetCalculator.java | 290 +++++++ .../luckycatlabs/sunrisesunset/Zenith.java | 46 ++ .../calculator/SolarEventCalculator.java | 406 +++++++++ .../sunrisesunset/dto/Location.java | 93 +++ src/fr/pandacube/java/BungeeMain.java | 11 + src/fr/pandacube/java/SpigotMain.java | 12 + .../ConvertToSQLBungeePerms.java | 84 ++ src/fr/pandacube/java/util/Callback.java | 7 + src/fr/pandacube/java/util/EnumUtil.java | 67 ++ .../java/util/JArithmeticInterpreter.java | 772 ++++++++++++++++++ src/fr/pandacube/java/util/MemoryUtil.java | 25 + .../pandacube/java/util/MinecraftVersion.java | 21 + src/fr/pandacube/java/util/PlayerFinder.java | 52 ++ src/fr/pandacube/java/util/RandomUtil.java | 19 + .../java/util/ServerPropertyFile.java | 167 ++++ src/fr/pandacube/java/util/StringUtil.java | 26 + src/fr/pandacube/java/util/TimeUtil.java | 39 + .../java/util/chat_display/Display.java | 185 +++++ .../java/util/chat_display/DisplayUtil.java | 223 +++++ .../util/chat_display/TextProgressBar.java | 72 ++ .../pandacube/java/util/db/DBConnection.java | 57 ++ .../java/util/db/LoginHistoryElement.java | 114 +++ .../java/util/db/LoginHistoryTable.java | 36 + .../java/util/db/MPGroupElement.java | 63 ++ .../pandacube/java/util/db/MPGroupTable.java | 26 + .../java/util/db/MPGroupUserElement.java | 71 ++ .../java/util/db/MPGroupUserTable.java | 42 + .../java/util/db/MPMessageElement.java | 177 ++++ .../java/util/db/MPMessageTable.java | 99 +++ .../java/util/db/ModoHistoryElement.java | 141 ++++ .../java/util/db/ModoHistoryTable.java | 40 + src/fr/pandacube/java/util/db/ORM.java | 86 ++ .../pandacube/java/util/db/PlayerElement.java | 163 ++++ .../java/util/db/PlayerIgnoreElement.java | 66 ++ .../java/util/db/PlayerIgnoreTable.java | 79 ++ .../pandacube/java/util/db/PlayerTable.java | 70 ++ src/fr/pandacube/java/util/db/SQLElement.java | 160 ++++ src/fr/pandacube/java/util/db/SQLTable.java | 140 ++++ .../java/util/db/ShopStockElement.java | 74 ++ .../java/util/db/ShopStockTable.java | 30 + .../java/util/db/StaffTicketElement.java | 77 ++ .../java/util/db/StaffTicketTable.java | 37 + .../network_api/client/AbstractRequest.java | 32 + .../network_api/client/NetworkAPISender.java | 28 + .../network_api/client/ResponseAnalyser.java | 63 ++ .../server/AbstractRequestExecutor.java | 46 ++ .../server/NAPIExecutionHandler.java | 13 + .../server/NetworkAPIListener.java | 125 +++ .../network_api/server/PacketExecutor.java | 51 ++ .../network_api/server/RequestAnalyser.java | 84 ++ .../util/network_api/server/Response.java | 32 + .../server/ThreadNAPIExecutionHandler.java | 10 + 60 files changed, 5178 insertions(+) create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .project create mode 100644 make_jar.jardesc create mode 100644 manifest create mode 100644 resources/bungee.yml create mode 100644 resources/plugin.yml create mode 100644 src/com/earth2me/essentials/utils/DateUtil.java create mode 100644 src/com/luckycatlabs/sunrisesunset/SunriseSunsetCalculator.java create mode 100644 src/com/luckycatlabs/sunrisesunset/Zenith.java create mode 100644 src/com/luckycatlabs/sunrisesunset/calculator/SolarEventCalculator.java create mode 100644 src/com/luckycatlabs/sunrisesunset/dto/Location.java create mode 100644 src/fr/pandacube/java/BungeeMain.java create mode 100644 src/fr/pandacube/java/SpigotMain.java create mode 100644 src/fr/pandacube/java/external_tools/ConvertToSQLBungeePerms.java create mode 100644 src/fr/pandacube/java/util/Callback.java create mode 100644 src/fr/pandacube/java/util/EnumUtil.java create mode 100644 src/fr/pandacube/java/util/JArithmeticInterpreter.java create mode 100644 src/fr/pandacube/java/util/MemoryUtil.java create mode 100644 src/fr/pandacube/java/util/MinecraftVersion.java create mode 100644 src/fr/pandacube/java/util/PlayerFinder.java create mode 100644 src/fr/pandacube/java/util/RandomUtil.java create mode 100644 src/fr/pandacube/java/util/ServerPropertyFile.java create mode 100644 src/fr/pandacube/java/util/StringUtil.java create mode 100644 src/fr/pandacube/java/util/TimeUtil.java create mode 100644 src/fr/pandacube/java/util/chat_display/Display.java create mode 100644 src/fr/pandacube/java/util/chat_display/DisplayUtil.java create mode 100644 src/fr/pandacube/java/util/chat_display/TextProgressBar.java create mode 100644 src/fr/pandacube/java/util/db/DBConnection.java create mode 100644 src/fr/pandacube/java/util/db/LoginHistoryElement.java create mode 100644 src/fr/pandacube/java/util/db/LoginHistoryTable.java create mode 100644 src/fr/pandacube/java/util/db/MPGroupElement.java create mode 100644 src/fr/pandacube/java/util/db/MPGroupTable.java create mode 100644 src/fr/pandacube/java/util/db/MPGroupUserElement.java create mode 100644 src/fr/pandacube/java/util/db/MPGroupUserTable.java create mode 100644 src/fr/pandacube/java/util/db/MPMessageElement.java create mode 100644 src/fr/pandacube/java/util/db/MPMessageTable.java create mode 100644 src/fr/pandacube/java/util/db/ModoHistoryElement.java create mode 100644 src/fr/pandacube/java/util/db/ModoHistoryTable.java create mode 100644 src/fr/pandacube/java/util/db/ORM.java create mode 100644 src/fr/pandacube/java/util/db/PlayerElement.java create mode 100644 src/fr/pandacube/java/util/db/PlayerIgnoreElement.java create mode 100644 src/fr/pandacube/java/util/db/PlayerIgnoreTable.java create mode 100644 src/fr/pandacube/java/util/db/PlayerTable.java create mode 100644 src/fr/pandacube/java/util/db/SQLElement.java create mode 100644 src/fr/pandacube/java/util/db/SQLTable.java create mode 100644 src/fr/pandacube/java/util/db/ShopStockElement.java create mode 100644 src/fr/pandacube/java/util/db/ShopStockTable.java create mode 100644 src/fr/pandacube/java/util/db/StaffTicketElement.java create mode 100644 src/fr/pandacube/java/util/db/StaffTicketTable.java create mode 100644 src/fr/pandacube/java/util/network_api/client/AbstractRequest.java create mode 100644 src/fr/pandacube/java/util/network_api/client/NetworkAPISender.java create mode 100644 src/fr/pandacube/java/util/network_api/client/ResponseAnalyser.java create mode 100644 src/fr/pandacube/java/util/network_api/server/AbstractRequestExecutor.java create mode 100644 src/fr/pandacube/java/util/network_api/server/NAPIExecutionHandler.java create mode 100644 src/fr/pandacube/java/util/network_api/server/NetworkAPIListener.java create mode 100644 src/fr/pandacube/java/util/network_api/server/PacketExecutor.java create mode 100644 src/fr/pandacube/java/util/network_api/server/RequestAnalyser.java create mode 100644 src/fr/pandacube/java/util/network_api/server/Response.java create mode 100644 src/fr/pandacube/java/util/network_api/server/ThreadNAPIExecutionHandler.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..972e07b --- /dev/null +++ b/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2797df0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +convertToBungeePerms.txt diff --git a/.project b/.project new file mode 100644 index 0000000..20d5f32 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + PandacubeUtil + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/make_jar.jardesc b/make_jar.jardesc new file mode 100644 index 0000000..eb108cd --- /dev/null +++ b/make_jar.jardesc @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/manifest b/manifest new file mode 100644 index 0000000..9d885be --- /dev/null +++ b/manifest @@ -0,0 +1 @@ +Manifest-Version: 1.0 diff --git a/resources/bungee.yml b/resources/bungee.yml new file mode 100644 index 0000000..b997068 --- /dev/null +++ b/resources/bungee.yml @@ -0,0 +1,4 @@ +name: PandacubeUtil +main: fr.pandacube.java.BungeeMain +version: 1.0-beta1 +author: Marc Baloup (marcbal) \ No newline at end of file diff --git a/resources/plugin.yml b/resources/plugin.yml new file mode 100644 index 0000000..1d06e2f --- /dev/null +++ b/resources/plugin.yml @@ -0,0 +1,4 @@ +name: PandacubeUtil +main: fr.pandacube.java.SpigotMain +version: 1.0-beta1 +author: Marc Baloup (marcbal) \ No newline at end of file diff --git a/src/com/earth2me/essentials/utils/DateUtil.java b/src/com/earth2me/essentials/utils/DateUtil.java new file mode 100644 index 0000000..b725ac1 --- /dev/null +++ b/src/com/earth2me/essentials/utils/DateUtil.java @@ -0,0 +1,175 @@ +package com.earth2me.essentials.utils; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public class DateUtil +{ + public static long parseDateDiff(String time, boolean future) throws Exception + { + Pattern timePattern = Pattern.compile("(?:([0-9]+)\\s*y[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*mo[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*w[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*d[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*h[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*m[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*(?:s[a-z]*)?)?", Pattern.CASE_INSENSITIVE); + Matcher m = timePattern.matcher(time); + int years = 0; + int months = 0; + int weeks = 0; + int days = 0; + int hours = 0; + int minutes = 0; + int seconds = 0; + boolean found = false; + while (m.find()) + { + if (m.group() == null || m.group().isEmpty()) + { + continue; + } + for (int i = 0; i < m.groupCount(); i++) + { + if (m.group(i) != null && !m.group(i).isEmpty()) + { + found = true; + break; + } + } + if (found) + { + if (m.group(1) != null && !m.group(1).isEmpty()) + { + years = Integer.parseInt(m.group(1)); + } + if (m.group(2) != null && !m.group(2).isEmpty()) + { + months = Integer.parseInt(m.group(2)); + } + if (m.group(3) != null && !m.group(3).isEmpty()) + { + weeks = Integer.parseInt(m.group(3)); + } + if (m.group(4) != null && !m.group(4).isEmpty()) + { + days = Integer.parseInt(m.group(4)); + } + if (m.group(5) != null && !m.group(5).isEmpty()) + { + hours = Integer.parseInt(m.group(5)); + } + if (m.group(6) != null && !m.group(6).isEmpty()) + { + minutes = Integer.parseInt(m.group(6)); + } + if (m.group(7) != null && !m.group(7).isEmpty()) + { + seconds = Integer.parseInt(m.group(7)); + } + break; + } + } + if (!found) + { + throw new Exception("Format de durée invalide"); + } + Calendar c = new GregorianCalendar(); + if (years > 0) + { + c.add(Calendar.YEAR, years * (future ? 1 : -1)); + } + if (months > 0) + { + c.add(Calendar.MONTH, months * (future ? 1 : -1)); + } + if (weeks > 0) + { + c.add(Calendar.WEEK_OF_YEAR, weeks * (future ? 1 : -1)); + } + if (days > 0) + { + c.add(Calendar.DAY_OF_MONTH, days * (future ? 1 : -1)); + } + if (hours > 0) + { + c.add(Calendar.HOUR_OF_DAY, hours * (future ? 1 : -1)); + } + if (minutes > 0) + { + c.add(Calendar.MINUTE, minutes * (future ? 1 : -1)); + } + if (seconds > 0) + { + c.add(Calendar.SECOND, seconds * (future ? 1 : -1)); + } + Calendar max = new GregorianCalendar(); + max.add(Calendar.YEAR, 10); + if (c.after(max)) + { + return max.getTimeInMillis(); + } + return c.getTimeInMillis(); + } + + static int dateDiff(int type, Calendar fromDate, Calendar toDate, boolean future) + { + int diff = 0; + long savedDate = fromDate.getTimeInMillis(); + while ((future && !fromDate.after(toDate)) || (!future && !fromDate.before(toDate))) + { + savedDate = fromDate.getTimeInMillis(); + fromDate.add(type, future ? 1 : -1); + diff++; + } + diff--; + fromDate.setTimeInMillis(savedDate); + return diff; + } + + public static String formatDateDiff(long date) + { + Calendar c = new GregorianCalendar(); + c.setTimeInMillis(date); + Calendar now = new GregorianCalendar(); + return DateUtil.formatDateDiff(now, c); + } + + public static String formatDateDiff(Calendar fromDate, Calendar toDate) + { + boolean future = false; + if (toDate.equals(fromDate)) + { + return "now"; + } + if (toDate.after(fromDate)) + { + future = true; + } + StringBuilder sb = new StringBuilder(); + int[] types = new int[] + { + Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, Calendar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND + }; + String[] names = new String[] + { + "year", "years", "month", "months", "day", "days", "hour", "hours", "minute", "minutes", "second", "seconds" + }; + int accuracy = 0; + for (int i = 0; i < types.length; i++) + { + if (accuracy > 2) + { + break; + } + int diff = dateDiff(types[i], fromDate, toDate, future); + if (diff > 0) + { + accuracy++; + sb.append(" ").append(diff).append(" ").append(names[i * 2 + (diff > 1 ? 1 : 0)]); + } + } + if (sb.length() == 0) + { + return "now"; + } + return sb.toString().trim(); + } +} \ No newline at end of file diff --git a/src/com/luckycatlabs/sunrisesunset/SunriseSunsetCalculator.java b/src/com/luckycatlabs/sunrisesunset/SunriseSunsetCalculator.java new file mode 100644 index 0000000..e14b0d9 --- /dev/null +++ b/src/com/luckycatlabs/sunrisesunset/SunriseSunsetCalculator.java @@ -0,0 +1,290 @@ +/* + * Copyright 2008-2009 Mike Reedell / LuckyCatLabs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.luckycatlabs.sunrisesunset; + +import java.util.Calendar; +import java.util.TimeZone; + +import com.luckycatlabs.sunrisesunset.calculator.SolarEventCalculator; +import com.luckycatlabs.sunrisesunset.dto.Location; + +/** + * Public interface for getting the various types of sunrise/sunset. + */ +public class SunriseSunsetCalculator { + + private Location location; + + private SolarEventCalculator calculator; + + /** + * Constructs a new SunriseSunsetCalculator with the given Location + * + * @param location + * Location object containing the Latitude/Longitude of the location to compute + * the sunrise/sunset for. + * @param timeZoneIdentifier + * String identifier for the timezone to compute the sunrise/sunset times in. In the form + * "America/New_York". Please see the zi directory under the JDK installation for supported + * time zones. + */ + public SunriseSunsetCalculator(Location location, String timeZoneIdentifier) { + this.location = location; + this.calculator = new SolarEventCalculator(location, timeZoneIdentifier); + } + + /** + * Constructs a new SunriseSunsetCalculator with the given Location + * + * @param location + * Location object containing the Latitude/Longitude of the location to compute + * the sunrise/sunset for. + * @param timeZone + * timezone to compute the sunrise/sunset times in. + */ + public SunriseSunsetCalculator(Location location, TimeZone timeZone) { + this.location = location; + this.calculator = new SolarEventCalculator(location, timeZone); + } + + /** + * Returns the astronomical (108deg) sunrise for the given date. + * + * @param date + * Calendar object containing the date to compute the astronomical sunrise for. + * @return the astronomical sunrise time in HH:MM (24-hour clock) form. + */ + public String getAstronomicalSunriseForDate(Calendar date) { + return calculator.computeSunriseTime(Zenith.ASTRONOMICAL, date); + } + + /** + * Returns the astronomical (108deg) sunrise for the given date. + * + * @param date + * Calendar object containing the date to compute the astronomical sunrise for. + * @return the astronomical sunrise time as a Calendar + */ + public Calendar getAstronomicalSunriseCalendarForDate(Calendar date) { + return calculator.computeSunriseCalendar(Zenith.ASTRONOMICAL, date); + } + + /** + * Returns the astronomical (108deg) sunset for the given date. + * + * @param date + * Calendar object containing the date to compute the astronomical sunset for. + * @return the astronomical sunset time in HH:MM (24-hour clock) form. + */ + public String getAstronomicalSunsetForDate(Calendar date) { + return calculator.computeSunsetTime(Zenith.ASTRONOMICAL, date); + } + + /** + * Returns the astronomical (108deg) sunset for the given date. + * + * @param date + * Calendar object containing the date to compute the astronomical sunset for. + * @return the astronomical sunset time as a Calendar + */ + public Calendar getAstronomicalSunsetCalendarForDate(Calendar date) { + return calculator.computeSunsetCalendar(Zenith.ASTRONOMICAL, date); + } + + /** + * Returns the nautical (102deg) sunrise for the given date. + * + * @param date + * Calendar object containing the date to compute the nautical sunrise for. + * @return the nautical sunrise time in HH:MM (24-hour clock) form. + */ + public String getNauticalSunriseForDate(Calendar date) { + return calculator.computeSunriseTime(Zenith.NAUTICAL, date); + } + + /** + * Returns the nautical (102deg) sunrise for the given date. + * + * @param date + * Calendar object containing the date to compute the nautical sunrise for. + * @return the nautical sunrise time as a Calendar + */ + public Calendar getNauticalSunriseCalendarForDate(Calendar date) { + return calculator.computeSunriseCalendar(Zenith.NAUTICAL, date); + } + + /** + * Returns the nautical (102deg) sunset for the given date. + * + * @param date + * Calendar object containing the date to compute the nautical sunset for. + * @return the nautical sunset time in HH:MM (24-hour clock) form. + */ + public String getNauticalSunsetForDate(Calendar date) { + return calculator.computeSunsetTime(Zenith.NAUTICAL, date); + } + + /** + * Returns the nautical (102deg) sunset for the given date. + * + * @param date + * Calendar object containing the date to compute the nautical sunset for. + * @return the nautical sunset time as a Calendar + */ + public Calendar getNauticalSunsetCalendarForDate(Calendar date) { + return calculator.computeSunsetCalendar(Zenith.NAUTICAL, date); + } + + /** + * Returns the civil sunrise (twilight, 96deg) for the given date. + * + * @param date + * Calendar object containing the date to compute the civil sunrise for. + * @return the civil sunrise time in HH:MM (24-hour clock) form. + */ + public String getCivilSunriseForDate(Calendar date) { + return calculator.computeSunriseTime(Zenith.CIVIL, date); + } + + /** + * Returns the civil sunrise (twilight, 96deg) for the given date. + * + * @param date + * Calendar object containing the date to compute the civil sunrise for. + * @return the civil sunrise time as a Calendar + */ + public Calendar getCivilSunriseCalendarForDate(Calendar date) { + return calculator.computeSunriseCalendar(Zenith.CIVIL, date); + } + + /** + * Returns the civil sunset (twilight, 96deg) for the given date. + * + * @param date + * Calendar object containing the date to compute the civil sunset for. + * @return the civil sunset time in HH:MM (24-hour clock) form. + */ + public String getCivilSunsetForDate(Calendar date) { + return calculator.computeSunsetTime(Zenith.CIVIL, date); + } + + /** + * Returns the civil sunset (twilight, 96deg) for the given date. + * + * @param date + * Calendar object containing the date to compute the civil sunset for. + * @return the civil sunset time as a Calendar + */ + public Calendar getCivilSunsetCalendarForDate(Calendar date) { + return calculator.computeSunsetCalendar(Zenith.CIVIL, date); + } + + /** + * Returns the official sunrise (90deg 50', 90.8333deg) for the given date. + * + * @param date + * Calendar object containing the date to compute the official sunrise for. + * @return the official sunrise time in HH:MM (24-hour clock) form. + */ + public String getOfficialSunriseForDate(Calendar date) { + return calculator.computeSunriseTime(Zenith.OFFICIAL, date); + } + + /** + * Returns the official sunrise (90deg 50', 90.8333deg) for the given date. + * + * @param date + * Calendar object containing the date to compute the official sunrise for. + * @return the official sunrise time as a Calendar + */ + public Calendar getOfficialSunriseCalendarForDate(Calendar date) { + return calculator.computeSunriseCalendar(Zenith.OFFICIAL, date); + } + + /** + * Returns the official sunrise (90deg 50', 90.8333deg) for the given date. + * + * @param date + * Calendar object containing the date to compute the official sunset for. + * @return the official sunset time in HH:MM (24-hour clock) form. + */ + public String getOfficialSunsetForDate(Calendar date) { + return calculator.computeSunsetTime(Zenith.OFFICIAL, date); + } + + /** + * Returns the official sunrise (90deg 50', 90.8333deg) for the given date. + * + * @param date + * Calendar object containing the date to compute the official sunset for. + * @return the official sunset time as a Calendar + */ + public Calendar getOfficialSunsetCalendarForDate(Calendar date) { + return calculator.computeSunsetCalendar(Zenith.OFFICIAL, date); + } + + /** + * Computes the sunrise for an arbitrary declination. + * + * @param latitude + * @param longitude + * Coordinates for the location to compute the sunrise/sunset for. + * @param timeZone + * timezone to compute the sunrise/sunset times in. + * @param date + * Calendar object containing the date to compute the official sunset for. + * @param degrees + * Angle under the horizon for which to compute sunrise. For example, "civil sunrise" + * corresponds to 6 degrees. + * @return the requested sunset time as a Calendar object. + */ + + public static Calendar getSunrise(double latitude, double longitude, TimeZone timeZone, Calendar date, double degrees) { + SolarEventCalculator solarEventCalculator = new SolarEventCalculator(new Location(latitude, longitude), timeZone); + return solarEventCalculator.computeSunriseCalendar(new Zenith(90 - degrees), date); + } + + /** + * Computes the sunset for an arbitrary declination. + * + * @param latitude + * @param longitude + * Coordinates for the location to compute the sunrise/sunset for. + * @param timeZone + * timezone to compute the sunrise/sunset times in. + * @param date + * Calendar object containing the date to compute the official sunset for. + * @param degrees + * Angle under the horizon for which to compute sunrise. For example, "civil sunset" + * corresponds to 6 degrees. + * @return the requested sunset time as a Calendar object. + */ + + public static Calendar getSunset(double latitude, double longitude, TimeZone timeZone, Calendar date, double degrees) { + SolarEventCalculator solarEventCalculator = new SolarEventCalculator(new Location(latitude, longitude), timeZone); + return solarEventCalculator.computeSunsetCalendar(new Zenith(90 - degrees), date); + } + + /** + * Returns the location where the sunrise/sunset is calculated for. + * + * @return Location object representing the location of the computed sunrise/sunset. + */ + public Location getLocation() { + return location; + } +} diff --git a/src/com/luckycatlabs/sunrisesunset/Zenith.java b/src/com/luckycatlabs/sunrisesunset/Zenith.java new file mode 100644 index 0000000..7157d38 --- /dev/null +++ b/src/com/luckycatlabs/sunrisesunset/Zenith.java @@ -0,0 +1,46 @@ +/* + * Copyright 2008-2009 Mike Reedell / LuckyCatLabs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.luckycatlabs.sunrisesunset; + +import java.math.BigDecimal; + +/** + * Defines the solar declination used in computing the sunrise/sunset. + */ +public class Zenith { + /** Astronomical sunrise/set is when the sun is 18 degrees below the horizon. */ + public static final Zenith ASTRONOMICAL = new Zenith(108); + + /** Nautical sunrise/set is when the sun is 12 degrees below the horizon. */ + public static final Zenith NAUTICAL = new Zenith(102); + + /** Civil sunrise/set (dawn/dusk) is when the sun is 6 degrees below the horizon. */ + public static final Zenith CIVIL = new Zenith(96); + + /** Official sunrise/set is when the sun is 50' below the horizon. */ + public static final Zenith OFFICIAL = new Zenith(90.8333); + + private final BigDecimal degrees; + + public Zenith(double degrees) { + this.degrees = BigDecimal.valueOf(degrees); + } + + public BigDecimal degrees() { + return degrees; + } +} diff --git a/src/com/luckycatlabs/sunrisesunset/calculator/SolarEventCalculator.java b/src/com/luckycatlabs/sunrisesunset/calculator/SolarEventCalculator.java new file mode 100644 index 0000000..323fc7a --- /dev/null +++ b/src/com/luckycatlabs/sunrisesunset/calculator/SolarEventCalculator.java @@ -0,0 +1,406 @@ +/* + * Copyright 2008-2009 Mike Reedell / LuckyCatLabs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.luckycatlabs.sunrisesunset.calculator; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.Calendar; +import java.util.TimeZone; + +import com.luckycatlabs.sunrisesunset.Zenith; +import com.luckycatlabs.sunrisesunset.dto.Location; + +/** + * Parent class of the Sunrise and Sunset calculator classes. + */ +public class SolarEventCalculator { + final private Location location; + final private TimeZone timeZone; + + /** + * Constructs a new SolarEventCalculator using the given parameters. + * + * @param location + * Location of the place where the solar event should be calculated from. + * @param timeZoneIdentifier + * time zone identifier of the timezone of the location parameter. For example, + * "America/New_York". + */ + public SolarEventCalculator(Location location, String timeZoneIdentifier) { + this.location = location; + this.timeZone = TimeZone.getTimeZone(timeZoneIdentifier); + } + + /** + * Constructs a new SolarEventCalculator using the given parameters. + * + * @param location + * Location of the place where the solar event should be calculated from. + * @param timeZone + * timezone of the location parameter. + */ + public SolarEventCalculator(Location location, TimeZone timeZone) { + this.location = location; + this.timeZone = timeZone; + } + + /** + * Computes the sunrise time for the given zenith at the given date. + * + * @param solarZenith + * Zenith enum corresponding to the type of sunrise to compute. + * @param date + * Calendar object representing the date to compute the sunrise for. + * @return the sunrise time, in HH:MM format (24-hour clock), 00:00 if the sun does not rise on the given + * date. + */ + public String computeSunriseTime(Zenith solarZenith, Calendar date) { + return getLocalTimeAsString(computeSolarEventTime(solarZenith, date, true)); + } + + /** + * Computes the sunrise time for the given zenith at the given date. + * + * @param solarZenith + * Zenith enum corresponding to the type of sunrise to compute. + * @param date + * Calendar object representing the date to compute the sunrise for. + * @return the sunrise time as a calendar or null for no sunrise + */ + public Calendar computeSunriseCalendar(Zenith solarZenith, Calendar date) { + return getLocalTimeAsCalendar(computeSolarEventTime(solarZenith, date, true), date); + } + + /** + * Computes the sunset time for the given zenith at the given date. + * + * @param solarZenith + * Zenith enum corresponding to the type of sunset to compute. + * @param date + * Calendar object representing the date to compute the sunset for. + * @return the sunset time, in HH:MM format (24-hour clock), 00:00 if the sun does not set on the given + * date. + */ + public String computeSunsetTime(Zenith solarZenith, Calendar date) { + return getLocalTimeAsString(computeSolarEventTime(solarZenith, date, false)); + } + + /** + * Computes the sunset time for the given zenith at the given date. + * + * @param solarZenith + * Zenith enum corresponding to the type of sunset to compute. + * @param date + * Calendar object representing the date to compute the sunset for. + * @return the sunset time as a Calendar or null for no sunset. + */ + public Calendar computeSunsetCalendar(Zenith solarZenith, Calendar date) { + return getLocalTimeAsCalendar(computeSolarEventTime(solarZenith, date, false), date); + } + + private BigDecimal computeSolarEventTime(Zenith solarZenith, Calendar date, boolean isSunrise) { + date.setTimeZone(this.timeZone); + BigDecimal longitudeHour = getLongitudeHour(date, isSunrise); + + BigDecimal meanAnomaly = getMeanAnomaly(longitudeHour); + BigDecimal sunTrueLong = getSunTrueLongitude(meanAnomaly); + BigDecimal cosineSunLocalHour = getCosineSunLocalHour(sunTrueLong, solarZenith); + if ((cosineSunLocalHour.doubleValue() < -1.0) || (cosineSunLocalHour.doubleValue() > 1.0)) { + return null; + } + + BigDecimal sunLocalHour = getSunLocalHour(cosineSunLocalHour, isSunrise); + BigDecimal localMeanTime = getLocalMeanTime(sunTrueLong, longitudeHour, sunLocalHour); + BigDecimal localTime = getLocalTime(localMeanTime, date); + return localTime; + } + + /** + * Computes the base longitude hour, lngHour in the algorithm. + * + * @return the longitude of the location of the solar event divided by 15 (deg/hour), in + * BigDecimal form. + */ + private BigDecimal getBaseLongitudeHour() { + return divideBy(location.getLongitude(), BigDecimal.valueOf(15)); + } + + /** + * Computes the longitude time, t in the algorithm. + * + * @return longitudinal time in BigDecimal form. + */ + private BigDecimal getLongitudeHour(Calendar date, Boolean isSunrise) { + int offset = 18; + if (isSunrise) { + offset = 6; + } + BigDecimal dividend = BigDecimal.valueOf(offset).subtract(getBaseLongitudeHour()); + BigDecimal addend = divideBy(dividend, BigDecimal.valueOf(24)); + BigDecimal longHour = getDayOfYear(date).add(addend); + return setScale(longHour); + } + + /** + * Computes the mean anomaly of the Sun, M in the algorithm. + * + * @return the suns mean anomaly, M, in BigDecimal form. + */ + private BigDecimal getMeanAnomaly(BigDecimal longitudeHour) { + BigDecimal meanAnomaly = multiplyBy(new BigDecimal("0.9856"), longitudeHour).subtract(new BigDecimal("3.289")); + return setScale(meanAnomaly); + } + + /** + * Computes the true longitude of the sun, L in the algorithm, at the given location, adjusted to fit in + * the range [0-360]. + * + * @param meanAnomaly + * the suns mean anomaly. + * @return the suns true longitude, in BigDecimal form. + */ + private BigDecimal getSunTrueLongitude(BigDecimal meanAnomaly) { + BigDecimal sinMeanAnomaly = new BigDecimal(Math.sin(convertDegreesToRadians(meanAnomaly).doubleValue())); + BigDecimal sinDoubleMeanAnomaly = new BigDecimal(Math.sin(multiplyBy(convertDegreesToRadians(meanAnomaly), BigDecimal.valueOf(2)) + .doubleValue())); + + BigDecimal firstPart = meanAnomaly.add(multiplyBy(sinMeanAnomaly, new BigDecimal("1.916"))); + BigDecimal secondPart = multiplyBy(sinDoubleMeanAnomaly, new BigDecimal("0.020")).add(new BigDecimal("282.634")); + BigDecimal trueLongitude = firstPart.add(secondPart); + + if (trueLongitude.doubleValue() > 360) { + trueLongitude = trueLongitude.subtract(BigDecimal.valueOf(360)); + } + return setScale(trueLongitude); + } + + /** + * Computes the suns right ascension, RA in the algorithm, adjusting for the quadrant of L and turning it + * into degree-hours. Will be in the range [0,360]. + * + * @param sunTrueLong + * Suns true longitude, in BigDecimal + * @return suns right ascension in degree-hours, in BigDecimal form. + */ + private BigDecimal getRightAscension(BigDecimal sunTrueLong) { + BigDecimal tanL = new BigDecimal(Math.tan(convertDegreesToRadians(sunTrueLong).doubleValue())); + + BigDecimal innerParens = multiplyBy(convertRadiansToDegrees(tanL), new BigDecimal("0.91764")); + BigDecimal rightAscension = new BigDecimal(Math.atan(convertDegreesToRadians(innerParens).doubleValue())); + rightAscension = setScale(convertRadiansToDegrees(rightAscension)); + + if (rightAscension.doubleValue() < 0) { + rightAscension = rightAscension.add(BigDecimal.valueOf(360)); + } else if (rightAscension.doubleValue() > 360) { + rightAscension = rightAscension.subtract(BigDecimal.valueOf(360)); + } + + BigDecimal ninety = BigDecimal.valueOf(90); + BigDecimal longitudeQuadrant = sunTrueLong.divide(ninety, 0, RoundingMode.FLOOR); + longitudeQuadrant = longitudeQuadrant.multiply(ninety); + + BigDecimal rightAscensionQuadrant = rightAscension.divide(ninety, 0, RoundingMode.FLOOR); + rightAscensionQuadrant = rightAscensionQuadrant.multiply(ninety); + + BigDecimal augend = longitudeQuadrant.subtract(rightAscensionQuadrant); + return divideBy(rightAscension.add(augend), BigDecimal.valueOf(15)); + } + + private BigDecimal getCosineSunLocalHour(BigDecimal sunTrueLong, Zenith zenith) { + BigDecimal sinSunDeclination = getSinOfSunDeclination(sunTrueLong); + BigDecimal cosineSunDeclination = getCosineOfSunDeclination(sinSunDeclination); + + BigDecimal zenithInRads = convertDegreesToRadians(zenith.degrees()); + BigDecimal cosineZenith = BigDecimal.valueOf(Math.cos(zenithInRads.doubleValue())); + BigDecimal sinLatitude = BigDecimal.valueOf(Math.sin(convertDegreesToRadians(location.getLatitude()).doubleValue())); + BigDecimal cosLatitude = BigDecimal.valueOf(Math.cos(convertDegreesToRadians(location.getLatitude()).doubleValue())); + + BigDecimal sinDeclinationTimesSinLat = sinSunDeclination.multiply(sinLatitude); + BigDecimal dividend = cosineZenith.subtract(sinDeclinationTimesSinLat); + BigDecimal divisor = cosineSunDeclination.multiply(cosLatitude); + + return setScale(divideBy(dividend, divisor)); + } + + private BigDecimal getSinOfSunDeclination(BigDecimal sunTrueLong) { + BigDecimal sinTrueLongitude = BigDecimal.valueOf(Math.sin(convertDegreesToRadians(sunTrueLong).doubleValue())); + BigDecimal sinOfDeclination = sinTrueLongitude.multiply(new BigDecimal("0.39782")); + return setScale(sinOfDeclination); + } + + private BigDecimal getCosineOfSunDeclination(BigDecimal sinSunDeclination) { + BigDecimal arcSinOfSinDeclination = BigDecimal.valueOf(Math.asin(sinSunDeclination.doubleValue())); + BigDecimal cosDeclination = BigDecimal.valueOf(Math.cos(arcSinOfSinDeclination.doubleValue())); + return setScale(cosDeclination); + } + + private BigDecimal getSunLocalHour(BigDecimal cosineSunLocalHour, Boolean isSunrise) { + BigDecimal arcCosineOfCosineHourAngle = getArcCosineFor(cosineSunLocalHour); + BigDecimal localHour = convertRadiansToDegrees(arcCosineOfCosineHourAngle); + if (isSunrise) { + localHour = BigDecimal.valueOf(360).subtract(localHour); + } + return divideBy(localHour, BigDecimal.valueOf(15)); + } + + private BigDecimal getLocalMeanTime(BigDecimal sunTrueLong, BigDecimal longitudeHour, BigDecimal sunLocalHour) { + BigDecimal rightAscension = this.getRightAscension(sunTrueLong); + BigDecimal innerParens = longitudeHour.multiply(new BigDecimal("0.06571")); + BigDecimal localMeanTime = sunLocalHour.add(rightAscension).subtract(innerParens); + localMeanTime = localMeanTime.subtract(new BigDecimal("6.622")); + + if (localMeanTime.doubleValue() < 0) { + localMeanTime = localMeanTime.add(BigDecimal.valueOf(24)); + } else if (localMeanTime.doubleValue() > 24) { + localMeanTime = localMeanTime.subtract(BigDecimal.valueOf(24)); + } + return setScale(localMeanTime); + } + + private BigDecimal getLocalTime(BigDecimal localMeanTime, Calendar date) { + BigDecimal utcTime = localMeanTime.subtract(getBaseLongitudeHour()); + BigDecimal utcOffSet = getUTCOffSet(date); + BigDecimal utcOffSetTime = utcTime.add(utcOffSet); + return adjustForDST(utcOffSetTime, date); + } + + private BigDecimal adjustForDST(BigDecimal localMeanTime, Calendar date) { + BigDecimal localTime = localMeanTime; + if (timeZone.inDaylightTime(date.getTime())) { + localTime = localTime.add(BigDecimal.ONE); + } + if (localTime.doubleValue() > 24.0) { + localTime = localTime.subtract(BigDecimal.valueOf(24)); + } + return localTime; + } + + /** + * Returns the local rise/set time in the form HH:MM. + * + * @param localTime + * BigDecimal representation of the local rise/set time. + * @return String representation of the local rise/set time in HH:MM format. + */ + private String getLocalTimeAsString(BigDecimal localTimeParam) { + if (localTimeParam == null) { + return "99:99"; + } + + BigDecimal localTime = localTimeParam; + if (localTime.compareTo(BigDecimal.ZERO) == -1) { + localTime = localTime.add(BigDecimal.valueOf(24.0D)); + } + String[] timeComponents = localTime.toPlainString().split("\\."); + int hour = Integer.parseInt(timeComponents[0]); + + BigDecimal minutes = new BigDecimal("0." + timeComponents[1]); + minutes = minutes.multiply(BigDecimal.valueOf(60)).setScale(0, RoundingMode.HALF_EVEN); + if (minutes.intValue() == 60) { + minutes = BigDecimal.ZERO; + hour += 1; + } + if (hour == 24) { + hour = 0; + } + + String minuteString = minutes.intValue() < 10 ? "0" + minutes.toPlainString() : minutes.toPlainString(); + String hourString = (hour < 10) ? "0" + String.valueOf(hour) : String.valueOf(hour); + return hourString + ":" + minuteString; + } + + /** + * Returns the local rise/set time in the form HH:MM. + * + * @param localTimeParam + * BigDecimal representation of the local rise/set time. + * @return Calendar representation of the local time as a calendar, or null for none. + */ + protected Calendar getLocalTimeAsCalendar(BigDecimal localTimeParam, Calendar date) { + if (localTimeParam == null) { + return null; + } + + // Create a clone of the input calendar so we get locale/timezone information. + Calendar resultTime = (Calendar) date.clone(); + + BigDecimal localTime = localTimeParam; + if (localTime.compareTo(BigDecimal.ZERO) == -1) { + localTime = localTime.add(BigDecimal.valueOf(24.0D)); + resultTime.add(Calendar.HOUR_OF_DAY, -24); + } + String[] timeComponents = localTime.toPlainString().split("\\."); + int hour = Integer.parseInt(timeComponents[0]); + + BigDecimal minutes = new BigDecimal("0." + timeComponents[1]); + minutes = minutes.multiply(BigDecimal.valueOf(60)).setScale(0, RoundingMode.HALF_EVEN); + if (minutes.intValue() == 60) { + minutes = BigDecimal.ZERO; + hour += 1; + } + if (hour == 24) { + hour = 0; + } + + // Set the local time + resultTime.set(Calendar.HOUR_OF_DAY, hour); + resultTime.set(Calendar.MINUTE, minutes.intValue()); + resultTime.set(Calendar.SECOND, 0); + resultTime.set(Calendar.MILLISECOND, 0); + resultTime.setTimeZone(date.getTimeZone()); + + return resultTime; + } + + /** ******* UTILITY METHODS (Should probably go somewhere else. ***************** */ + + private BigDecimal getDayOfYear(Calendar date) { + return new BigDecimal(date.get(Calendar.DAY_OF_YEAR)); + } + + private BigDecimal getUTCOffSet(Calendar date) { + BigDecimal offSetInMillis = new BigDecimal(date.get(Calendar.ZONE_OFFSET)); + BigDecimal offSet = offSetInMillis.divide(new BigDecimal(3600000), new MathContext(2)); + return offSet; + } + + private BigDecimal getArcCosineFor(BigDecimal radians) { + BigDecimal arcCosine = BigDecimal.valueOf(Math.acos(radians.doubleValue())); + return setScale(arcCosine); + } + + private BigDecimal convertRadiansToDegrees(BigDecimal radians) { + return multiplyBy(radians, new BigDecimal(180 / Math.PI)); + } + + private BigDecimal convertDegreesToRadians(BigDecimal degrees) { + return multiplyBy(degrees, BigDecimal.valueOf(Math.PI / 180.0)); + } + + private BigDecimal multiplyBy(BigDecimal multiplicand, BigDecimal multiplier) { + return setScale(multiplicand.multiply(multiplier)); + } + + private BigDecimal divideBy(BigDecimal dividend, BigDecimal divisor) { + return dividend.divide(divisor, 4, RoundingMode.HALF_EVEN); + } + + private BigDecimal setScale(BigDecimal number) { + return number.setScale(4, RoundingMode.HALF_EVEN); + } +} diff --git a/src/com/luckycatlabs/sunrisesunset/dto/Location.java b/src/com/luckycatlabs/sunrisesunset/dto/Location.java new file mode 100644 index 0000000..ca268ef --- /dev/null +++ b/src/com/luckycatlabs/sunrisesunset/dto/Location.java @@ -0,0 +1,93 @@ +/* + * Copyright 2008-2009 Mike Reedell / LuckyCatLabs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.luckycatlabs.sunrisesunset.dto; + +import java.math.BigDecimal; + +/** + * Simple VO class to store latitude/longitude information. + */ +public class Location { + private BigDecimal latitude; + private BigDecimal longitude; + + /** + * Creates a new instance of Location with the given parameters. + * + * @param latitude + * the latitude, in degrees, of this location. North latitude is positive, south negative. + * @param longitude + * the longitude, in degrees of this location. East longitude is positive, west negative. + */ + public Location(String latitude, String longitude) { + this.latitude = new BigDecimal(latitude); + this.longitude = new BigDecimal(longitude); + } + + /** + * Creates a new instance of Location with the given parameters. + * + * @param latitude + * the latitude, in degrees, of this location. North latitude is positive, south negative. + * @param longitude + * the longitude, in degrees, of this location. East longitude is positive, east negative. + */ + public Location(double latitude, double longitude) { + this.latitude = new BigDecimal(latitude); + this.longitude = new BigDecimal(longitude); + } + + /** + * @return the latitude + */ + public BigDecimal getLatitude() { + return latitude; + } + + /** + * @return the longitude + */ + public BigDecimal getLongitude() { + return longitude; + } + + /** + * Sets the coordinates of the location object. + * + * @param latitude + * the latitude, in degrees, of this location. North latitude is positive, south negative. + * @param longitude + * the longitude, in degrees, of this location. East longitude is positive, east negative. + */ + public void setLocation(String latitude, String longitude) { + this.latitude = new BigDecimal(latitude); + this.longitude = new BigDecimal(longitude); + } + + /** + * Sets the coordinates of the location object. + * + * @param latitude + * the latitude, in degrees, of this location. North latitude is positive, south negative. + * @param longitude + * the longitude, in degrees, of this location. East longitude is positive, east negative. + */ + public void setLocation(double latitude, double longitude) { + this.latitude = new BigDecimal(latitude); + this.longitude = new BigDecimal(longitude); + } +} diff --git a/src/fr/pandacube/java/BungeeMain.java b/src/fr/pandacube/java/BungeeMain.java new file mode 100644 index 0000000..378aa7f --- /dev/null +++ b/src/fr/pandacube/java/BungeeMain.java @@ -0,0 +1,11 @@ +package fr.pandacube.java; + +import net.md_5.bungee.api.plugin.Plugin; + +public class BungeeMain extends Plugin { + + @Override + public void onLoad() { + + } +} diff --git a/src/fr/pandacube/java/SpigotMain.java b/src/fr/pandacube/java/SpigotMain.java new file mode 100644 index 0000000..8c6f5a8 --- /dev/null +++ b/src/fr/pandacube/java/SpigotMain.java @@ -0,0 +1,12 @@ +package fr.pandacube.java; + +import org.bukkit.plugin.java.JavaPlugin; + +public class SpigotMain extends JavaPlugin { + + @Override + public void onLoad() { + + } + +} diff --git a/src/fr/pandacube/java/external_tools/ConvertToSQLBungeePerms.java b/src/fr/pandacube/java/external_tools/ConvertToSQLBungeePerms.java new file mode 100644 index 0000000..2b1776b --- /dev/null +++ b/src/fr/pandacube/java/external_tools/ConvertToSQLBungeePerms.java @@ -0,0 +1,84 @@ +package fr.pandacube.java.external_tools; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ConvertToSQLBungeePerms { + public static void main(String[] ç) throws Exception { + + List content = getFileLines(true, false, true, new File("convertToBungeePerms.txt")); + FileOutputStream output = new FileOutputStream(new File("output.sql")); + + + String currentSQLFormat = null; + + + for (String line : content) { + + if (line.startsWith("#sql:")) + currentSQLFormat = line.substring("#sql:".length()); + else + output.write(currentSQLFormat.replace("%%%perm%%%", line).concat("\n").getBytes()); + } + + output.flush(); + output.close(); + + + + + } + + + + + + + + + /** + * Retourne toutes les lignes d'un fichier donné + * @param ignoreEmpty true si on doit ignorer les lignes vides + * @param ignoreHashtagComment true si on doit ignorer les lignes commentés (commençant par un #) + * @param trimOutput true si on doit appeller la méthode String.trim() sur chaque ligne retournée + * @param f le fichier à lire + * @return la liste des lignes utiles + * @throws IOException + */ + protected static List getFileLines(boolean ignoreEmpty, boolean ignoreHashtagComment, boolean trimOutput, File f) throws IOException { + if (!f.isFile()) + return null; + + BufferedReader reader = new BufferedReader(new FileReader(f)); + + List lines = new ArrayList(); + + String line; + while ((line = reader.readLine()) != null) { + String trimmedLine = line.trim(); + + if (ignoreEmpty && trimmedLine.equals("")) + continue; + + if (ignoreHashtagComment && trimmedLine.startsWith("#")) + continue; + + if (trimOutput) + lines.add(trimmedLine); + else + lines.add(line); + } + + + reader.close(); + + return lines; + } + + +} diff --git a/src/fr/pandacube/java/util/Callback.java b/src/fr/pandacube/java/util/Callback.java new file mode 100644 index 0000000..346a658 --- /dev/null +++ b/src/fr/pandacube/java/util/Callback.java @@ -0,0 +1,7 @@ +package fr.pandacube.java.util; + +@FunctionalInterface +public interface Callback { + public void done(T arg); +} + diff --git a/src/fr/pandacube/java/util/EnumUtil.java b/src/fr/pandacube/java/util/EnumUtil.java new file mode 100644 index 0000000..f3fb75e --- /dev/null +++ b/src/fr/pandacube/java/util/EnumUtil.java @@ -0,0 +1,67 @@ +package fr.pandacube.java.util; + +public class EnumUtil { + + /** + * List all enum constants which are in the specified enum class. + * @param enumType the enum class. + * @param separator a string which will be used as a separator + * @return a string representation of the enum class. + */ + public static > String enumList(Class enumType, String separator) { + T[] elements = enumType.getEnumConstants(); + + String out = ""; + boolean first = true; + for (T el : elements) { + if (!first) { + out += separator; + } + first = false; + out += el.name(); + + } + return out; + } + + + /** + * List all enum constants which are in the specified enum class. It is equivalent to call + * {@link #enumList(Class, String)} with the second parameter ", " + * @param enumType the enum class. + * @return a string representation of the enum class. + */ + public static > String enumList(Class enumType) { + return enumList(enumType, ", "); + } + + /** + * Permet de rechercher l'existance d'un élément dans un enum, de façon insensible à la casse + * @param enumType la classe correpondant à l'enum à lister + * @param search l'élément à rechercher, insensible à la casse + * @return l'élément de l'énumarétion, si elle a été trouvée, null sinon + */ + public static > T searchEnum(Class enumType, String search) { + T[] elements = enumType.getEnumConstants(); + + for (T el : elements) + if (el.name().equalsIgnoreCase(search)) + return el; + return null; + } + + + + + /** + * Retourne une valeur aléatoire parmis les élément de l'Enum spécifié en paramètre. + * @param enumType l'enum dans lequel piocher la valeur + * @return une des valeurs de l'enum + */ + public static > T randomValue(Class enumType) { + T[] elements = enumType.getEnumConstants(); + + return elements[RandomUtil.rand.nextInt(elements.length)]; + } + +} diff --git a/src/fr/pandacube/java/util/JArithmeticInterpreter.java b/src/fr/pandacube/java/util/JArithmeticInterpreter.java new file mode 100644 index 0000000..9e17d88 --- /dev/null +++ b/src/fr/pandacube/java/util/JArithmeticInterpreter.java @@ -0,0 +1,772 @@ +package fr.pandacube.java.util; + +//****************************************************************************** +//*** +//*** INTERPRETEUR ARITHMETIQUE version 2.1 Version Java +//*** +//*** +//*** +//****************************************************************************** + +/* +Historique: + +2.1: + - Version Java disponible: + # les operateurs mathematiques disponibles sont ceux de Java donc certains manquent. + +2.0: + - Portage en C++ et debut en Java + +Version C++: + + - Meilleure gestion memoire lors de la construction de l'expression. + - Acceleration de certaines operations. + +Version Java: + + - Premiere version. Normalement ca doit marcher + +1.3b: ajoute les fonctions suivantes: (NON DISTRIBUEE) + - reconnaissance du symbole � + - ecriture formatee d'expression (� ameliorer) + +1.2: corrige les bugs suivants: + - erreur sur l'interpretation de fonctions unaires imbriquees telles que ln(exp(x)). + - la fonction puissance (pour les puissances entieres). + ajoute: + - la verification de la chaine entree (voir code d'erreur) + - la verification de l'existence de l'evaluation (voir code d'erreur) + + +1.1: corrige un bug au niveau de l'interpretation des fonctions du type: + + exp(-(x+y)) + +1.0: premiere version + +Le code source peut etre librement modifie et distribue. + +Puisqu'il s'agit d'un essai en Java, le code ne doit pas etre super genial et merite sans doute +quelques modifications.En particulier, il serait interessant de rajouter le support des Exceptions +pour les calculs (division par zero, etc...). + +*/ + +// Classe servant � palier l'absence de passage par variables ou reference + +class VariableInt { + public int mValue; +} + +// Classe principale + +public class JArithmeticInterpreter { + + // Variables + + int mOperator; + double mValue; + JArithmeticInterpreter fg, fd; + + // Methods + + //.................................................................................... Node + + private JArithmeticInterpreter() { + this(0, 0, null, null); + } + + //.................................................................................... Node + + private JArithmeticInterpreter(int Operator,double Value,JArithmeticInterpreter Fg,JArithmeticInterpreter Fd) { + mOperator=Operator; + mValue=Value; + fg=Fg; + fd=Fd; + } + + private JArithmeticInterpreter(int Operator,double Value) { + this(Operator, Value, null, null); + } + + //.................................................................................... Construct_Tree + + private static JArithmeticInterpreter constructTree(StringBuffer string,int length,int error) { + int imbric,Bimbric; + int priorite,ope; + int position,positionv,i,j; + int opetemp=0; + int espa=0,espat=0; + int caspp=0; + + JArithmeticInterpreter node; + + // Initialisation des variables + + if (length<=0) { + error=3; + return null; + } + + ope=0; + imbric=0;Bimbric=128; + priorite=6; + i=0; + positionv=position=0; + + // Mise en place des donnees sur le morceau de chaine + + while (i47) && (string.charAt(i)<58)) || (string.charAt(i)=='�')) { + if (priorite>5) { + priorite=5; + positionv=i; + } + i++; + } + else { + if ((string.charAt(i)>96) && (string.charAt(i)<117)) { + VariableInt Vopetemp,Vespat; + + Vopetemp= new VariableInt(); + Vespat= new VariableInt(); + + Vopetemp.mValue=opetemp; + Vespat.mValue=espat; + + FindOperator(Vopetemp,Vespat,string,i); + + opetemp=Vopetemp.mValue; + espat=Vespat.mValue; + + if (opetemp>=0) { + if (imbric=4)) { + ope=opetemp; + position=i; + priorite=4; + espa=espat; + } + j=i+1; + i+=espat; + while(j=1)) { + priorite=1; + ope=1; + position=i; + caspp=0; + } + i++; + break; + case '-': + if (imbric5) { + priorite=1; + position=i; + ope=2; + Bimbric=imbric; + caspp=1; + } + } + else if (string.charAt(i-1)=='(') { + if (priorite>1){ + priorite=1; + position=i; + Bimbric=imbric; + caspp=1; + ope=2; + } + } + else { + Bimbric=imbric; + priorite=1; + ope=2; + position=i; + caspp=0; + } + } + else if ((imbric==Bimbric) && (priorite>=1)) { + if ((i-1)<0) { + if (priorite>5) { + priorite=1; + position=i; + ope=2; + caspp=1; + } + } + else if (string.charAt(i-1)=='(') { + if (priorite>1){ + priorite=1; + position=i; + caspp=1; + ope=2; + } + } + else { + priorite=1; + ope=2; + position=i; + caspp=0; + } + } + i++; + break; + case '*': + if (imbric=2)) { + priorite=2; + ope=3; + position=i; + } + i++; + break; + case '/': + if (imbric=2)) { + priorite=2; + ope=4; + position=i; + } + i++; + break; + case '^': + if (imbric=3)) { + priorite=3; + ope=5; + position=i; + } + i++; + break; + case '.': + i++; + break; + default: + error=2; // symbole non reconnu + return null; + } + } + } + } + + if (imbric!=0) { + error=1; // erreur de "parenthesage" + return null; + } + + // Traitement des donnees + + if (priorite==6) { + node =new JArithmeticInterpreter(ope,0.0); + return node; + } + else if (caspp==1) { + node = new JArithmeticInterpreter(2,0); + + node.fg= new JArithmeticInterpreter(0,0); + node.fd= new JArithmeticInterpreter(); + + if ((length-position-1-Bimbric)==0) { // argument absent + error=3; + return null; + } + StringBuffer temp=CopyPartialString(string,(position+1),(length-1-Bimbric)); + node.fd=constructTree(temp,(length-position-1-Bimbric),error); + + return node; + } + + else if (priorite==5) { + node = new JArithmeticInterpreter(0,calc_const(string,positionv),null,null); + + return node; + } + else if (ope>5) { + node = new JArithmeticInterpreter(ope,0,null,null); + + if ((length-position-espa-Bimbric)==0) { // argument absent + error=3; + return null; + } + StringBuffer temp=CopyPartialString(string,(position+espa),(length-1)); + node.fg=constructTree(temp,(length-position-espa-Bimbric),error); + return node; + } + else{ + node = new JArithmeticInterpreter(ope,0,null,null); + + if ((position-Bimbric)==0) { // argument absent + error=3; + return null; + } + StringBuffer temp=CopyPartialString(string,Bimbric,(position-1)); + node.fg=constructTree(temp,(position-Bimbric),error); + if ((length-position-1-Bimbric)==0) { // argument absent + error=3; + return null; + } + temp=CopyPartialString(string,(position+1),(length-1-Bimbric)); + node.fd=constructTree(temp,(length-position-1-Bimbric),error); + return node; + } + } + + //.................................................................................... + + private double computeTree() { + if (mOperator==0) return mValue; + int error = 0; + + double valueL=fg.computeTree(); + + if (error!=0) return 0; + double valueR=0; + + if (fd!=null) valueR=fd.computeTree(); + if (error!=0) return 0; + + switch(mOperator) { + case 1: // + + return (valueL+valueR); + case 2: // - + return (valueL-valueR); + case 3: // * + return (valueL*valueR); + case 4: // - + if (valueR==0) { + error=1; + return 0; + } + return (valueL/valueR); + case 5: // ^ + return Math.pow(valueL,valueR); + case 6: // exp + return Math.exp(valueL); + case 7: // ln + if (valueL<=0) { + if (valueL<0) error=2; + else error=1; + return 0; + } + return (Math.log(valueL)/Math.log(2)); + case 8: // log + if (valueL<=0) { + if (valueL<0) error=2; + else error=1; + return 0; + } + return Math.log(valueL); + case 9: // sqrt + if (valueL<0) { + error=2; + return 0; + } + return Math.sqrt(valueL); + case 10: // abs + return Math.abs(valueL); + case 11: + return Math.sin(valueL); // sin + case 12: + return Math.cos(valueL); // cos + case 13: + return Math.tan(valueL); // tan + case 14: + return Math.asin(valueL); // asin + case 15: + return Math.acos(valueL); // acos + case 16: + return Math.atan(valueL); // atan + default: + return 0; + } + } + + //.................................................................................... Write_Tree + + private void writeTree(StringBuffer string) { + boolean parenthese=false; + + switch(mOperator) { + case 0: + string.append(StringUtil.formatDouble(mValue)); + break; + case 1: + fg.writeTree(string); + string.append('+'); + fd.writeTree(string); + break; + case 2: + if ((fg.mOperator==0) && (fg.mValue==0)); + else fg.writeTree(string); + string.append('-'); + if ((fd.mOperator==1) || (fd.mOperator==2)) { + parenthese=true; + string.append('('); + } + fd.writeTree(string); + if (parenthese==true) { + string.append(')'); + } + break; + case 3: + if ((fg.mOperator==1) || (fg.mOperator==2)) { + parenthese=true; + string.append('('); + } + fg.writeTree(string); + if (parenthese==true) + string.append(')'); + parenthese=false; + string.append('*'); + if ((fd.mOperator==1) || (fd.mOperator==2)) { + parenthese=true; + string.append('('); + } + fd.writeTree(string); + if (parenthese==true) + string.append(')'); + break; + case 4: + if ((fg.mOperator==1) || (fg.mOperator==2)) { + parenthese=true; + string.append('('); + } + fg.writeTree(string); + if (parenthese==true) + string.append(')'); + parenthese=false; + string.append('/'); + if ((fd.mOperator>0) && (fd.mOperator<5)) { + parenthese=true; + string.append('('); + } + fd.writeTree(string); + if (parenthese==true) + string.append(')'); + break; + case 5: + if ((fg.mOperator>0) && (fg.mOperator<5)) { + parenthese=true; + string.append('('); + } + fg.writeTree(string); + if (parenthese==true) + string.append(')'); + parenthese=false; + string.append('^'); + if ((fd.mOperator>0) && (fd.mOperator<5)) { + parenthese=true; + string.append('('); + } + fd.writeTree(string); + if (parenthese==true) + string.append(')'); + break; + case 6: + string.append("exp("); + fg.writeTree(string); + string.append(')'); + break; + case 7: + string.append("log("); + fg.writeTree(string); + string.append(')'); + break; + case 8: + string.append("ln("); + fg.writeTree(string); + string.append(')'); + break; + case 9: + string.append("sqrt("); + fg.writeTree(string); + string.append(')'); + break; + case 10: + string.append("|"); + fg.writeTree(string); + string.append('|'); + break; + case 11: + string.append("sin("); + fg.writeTree(string); + string.append(')'); + break; + case 12: + string.append("cos("); + fg.writeTree(string); + string.append(')'); + break; + case 13: + string.append("tan("); + fg.writeTree(string); + string.append(')'); + break; + case 14: + string.append("asin("); + fg.writeTree(string); + string.append(')'); + break; + case 15: + string.append("acos("); + fg.writeTree(string); + string.append(')'); + break; + case 16: + string.append("atan("); + fg.writeTree(string); + string.append(')'); + break; + } + } + + //.................................................................................... calc_const + + private static double calc_const(StringBuffer chaine,int pos) { + int i=pos,j; + double temp=0; + int signe=1; + int longueur=chaine.length(); + + + if (chaine.charAt(i)=='-') { + signe=-1; + i++; + } + if (chaine.charAt(i)=='π') return signe*Math.PI; + + while (i47 && chaine.charAt(i)<58) { + temp=temp*10+(chaine.charAt(i)-48); + i++; + } + if (i47 && chaine.charAt(i)<58) { + temp=temp+(chaine.charAt(i)-48)*Math.exp(-j*2.30258509); + i++; + j++; + } + } + return (signe*temp); + } + + //.................................................................................... FindOperator + + private static void FindOperator(VariableInt oper,VariableInt esp,StringBuffer chaine,int pos) { + switch(chaine.charAt(pos)) { + case 'a': + switch(chaine.charAt(pos+1)) { + case 'b': + esp.mValue=3; + oper.mValue=10; + break; + case 'c': + esp.mValue=4; + oper.mValue=15; + break; + case 's': + esp.mValue=4; + oper.mValue=14; + break; + case 't': + esp.mValue=4; + oper.mValue=16; + break; + } + break; + case 'c': + if (chaine.charAt(pos+1)=='h') { + esp.mValue=2; + oper.mValue=18; + } + else if ((chaine.charAt(pos+1)=='o') && (chaine.charAt(pos+2)=='s')) { + if (chaine.charAt(pos+3)=='h') { + esp.mValue=4; + oper.mValue=18; + } + else { + esp.mValue=3; + oper.mValue=12; + } + } + break; + case 'e': + if ((chaine.charAt(pos+1)=='x') && (chaine.charAt(pos+2)=='p')) { + esp.mValue=3; + oper.mValue=6; + } + else oper.mValue=-10; + break; + case 'l': + if (chaine.charAt(pos+1)=='n') { + esp.mValue=2; + oper.mValue=7; + } + else if ((chaine.charAt(pos+1)=='o') && (chaine.charAt(pos+2)=='g')){ + esp.mValue=3; + oper.mValue=8; + } + else oper.mValue=-10; + break; + case 's': + if (chaine.charAt(pos+1)=='h') { + esp.mValue=2; + oper.mValue=17; + } + else if (chaine.charAt(pos+1)=='q') { + esp.mValue=4; + oper.mValue=9; + } + else { + if (chaine.charAt(pos+3)=='h') { + esp.mValue=4; + oper.mValue=17; + } + else { + esp.mValue=3; + oper.mValue=11; + } + } + break; + case 't': + if (chaine.charAt(pos+1)=='h') { + esp.mValue=2; + oper.mValue=19; + } + else if ((chaine.charAt(pos+1)=='a') && (chaine.charAt(pos+2)=='n')) { + if (chaine.charAt(pos+3)=='h') { + esp.mValue=4; + oper.mValue=19; + } + else { + esp.mValue=3; + oper.mValue=13; + } + } + else oper.mValue=-10; + break; + default: + oper.mValue=-10; + break; + } + } + + //.................................................................................... CopyPartialString + + private static StringBuffer CopyPartialString(StringBuffer chaine,int debut,int fin) { + StringBuffer chartemp; + int a=fin-debut+1; + chartemp=new StringBuffer(a+1); + + for(int i=0;i data; + + + public ServerPropertyFile(File f) { + if (f == null) throw new IllegalArgumentException("f ne doit pas être null"); + file = f; + + data = new HashMap(); + data.put("name", "default_name"); + data.put("memory", "512M"); + data.put("javaArgs", ""); + data.put("MinecraftArgs", ""); + data.put("jarFile", ""); + data.put("isLobby", false); + } + + + /** + * Charge le fichier de configuration dans cette instance de la classe + * @return true si le chargement a réussi, false sinon + */ + public boolean loadFromFile() { + BufferedReader in = null; + try { + in = new BufferedReader(new FileReader(file)); + + + @SuppressWarnings("unchecked") + Map dataFile = new Gson().fromJson(in, Map.class); + + if (!dataFile.containsKey("name") || !(dataFile.get("name") instanceof String)) + return false; + + if (!dataFile.containsKey("memory") || !(dataFile.get("memory") instanceof String)) + return false; + + if (!dataFile.containsKey("javaArgs") || !(dataFile.get("javaArgs") instanceof String)) + return false; + + if (!dataFile.containsKey("MinecraftArgs") || !(dataFile.get("MinecraftArgs") instanceof String)) + return false; + + if (!dataFile.containsKey("jarFile") || !(dataFile.get("jarFile") instanceof String)) + return false; + + if (!dataFile.containsKey("isLobby") || !(dataFile.get("isLobby") instanceof Boolean)) + return false; + + data = dataFile; + + return true; + } + catch (IOException e) { + e.printStackTrace(); + } + finally { + try { + in.close(); + } catch (Exception e) { } + } + return false; + } + + + + public boolean save() { + BufferedWriter out = null; + try { + out = new BufferedWriter(new FileWriter(file,false)); + + String jsonStr = new Gson().toJson(data); + + out.append(jsonStr); + + out.flush(); + + return true; + } catch (IOException e) { + e.printStackTrace(); + } + finally { + try { + out.close(); + } catch (Exception e) { } + } + + return false; + } + + + + + + public String getName() { + return (String) data.get("name"); + } + public String getMemory() { + return (String) data.get("memory"); + } + public String getJavaArgs() { + return (String) data.get("javaArgs"); + } + public String getMinecraftArgs() { + return (String) data.get("MinecraftArgs"); + } + public String getJarFile() { + return (String) data.get("jarFile"); + } + public boolean getIsLobby() { + return (boolean) data.get("isLobby"); + } + + + + + + + public void setName(String n) { + if (n == null || !n.matches("^[a-zA-Z]$")) + throw new IllegalArgumentException(); + data.put("name", n); + } + public void setMemory(String m) { + if (m == null || !m.matches("^[0-9]+[mgMG]$")) + throw new IllegalArgumentException(); + data.put("memory", m); + } + public void setJavaArgs(String ja) { + if (ja == null) + throw new IllegalArgumentException(); + data.put("javaArgs", ja); + } + public void setMinecraftArgs(String ma) { + if (ma == null) + throw new IllegalArgumentException(); + data.put("MinecraftArgs", ma); + } + + public void setJarFile(String j) { + if (j == null) + throw new IllegalArgumentException(); + data.put("jarFile", j); + } + + public void setIsLobby(boolean l) { + data.put("isLobby", l); + } + + +} diff --git a/src/fr/pandacube/java/util/StringUtil.java b/src/fr/pandacube/java/util/StringUtil.java new file mode 100644 index 0000000..5aa891c --- /dev/null +++ b/src/fr/pandacube/java/util/StringUtil.java @@ -0,0 +1,26 @@ +package fr.pandacube.java.util; + +public class StringUtil { + public static String formatDouble(double d) + { + if(d == (long) d) + return String.format("%d",(long)d); + else + return String.valueOf(d); + } + + /** + * @param s Chaine de caractère à parcourir + * @param c_match le caractère dont on doit retourner le nombre d'occurence + * @return nombre d'occurence de c_match dans s + */ + public static int char_count(CharSequence s, char c_match) + { + char[] chars = s.toString().toCharArray(); + int count = 0; + for (char c : chars) + if (c == c_match) + count++; + return count; + } +} diff --git a/src/fr/pandacube/java/util/TimeUtil.java b/src/fr/pandacube/java/util/TimeUtil.java new file mode 100644 index 0000000..2947525 --- /dev/null +++ b/src/fr/pandacube/java/util/TimeUtil.java @@ -0,0 +1,39 @@ +package fr.pandacube.java.util; + +public class TimeUtil { + public static String durationToString (long msec_time, boolean dec_seconde) + { + int j = 0, h = 0, m = 0, s = 0; + long msec = msec_time; + + j = (int) (msec / (1000 * 60 * 60 * 24)); + msec -= (1000 * 60 * 60 * 24) * j; + h = (int) (msec / (1000 * 60 * 60)); + msec -= (1000 * 60 * 60) * h; + m = (int) (msec / (1000 * 60)); + msec -= (1000 * 60) * m; + s = (int) (msec / 1000); + msec -= 1000 * s; + + String result = ""; + if (j>0) result = result.concat(j+"j "); + if (h>0) result = result.concat(h+"h "); + if (m>0) result = result.concat(m+"m "); + if (s>0 && !dec_seconde) result = result.concat(s+"s"); + else if (dec_seconde && (s>0 || msec > 0)) + { + msec += s*1000; + result = result.concat((msec/1000D)+"s"); + } + + if (result.equals("")) + result = "0"; + + return result.trim(); + } + + public static String durationToString (long msec_time) + { + return durationToString(msec_time, false); + } +} diff --git a/src/fr/pandacube/java/util/chat_display/Display.java b/src/fr/pandacube/java/util/chat_display/Display.java new file mode 100644 index 0000000..a382372 --- /dev/null +++ b/src/fr/pandacube/java/util/chat_display/Display.java @@ -0,0 +1,185 @@ +package fr.pandacube.java.util.chat_display; + +import java.util.List; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; + +public class Display { + + private BaseComponent first = new TextComponent(""); + + private BaseComponent current = null; + + + public Display() { + } + + + /** + * Après l'appel de ce contructeur, vous devez appeler nextComponent() pour initialiser la composante suivante + */ + public Display(String legacyText) { + convertAndAddLegacy(legacyText); + } + + /** + * Construit un message en mettant à la ligne après chaque chaine passé en paramètre.
+ * Après l'appel de ce contructeur, vous devez appeler nextComponent() pour initialiser la composante suivante + */ + public Display(String[] legacyText) { + boolean f = true; + for (String s : legacyText) { + if (s == null) s = ""; + if (!f) + first.addExtra("\n"); + f = false; + convertAndAddLegacy(s); + } + } + /** + * Construit un message en mettant à la ligne après chaque chaine passé en paramètre.
+ * Après l'appel de ce contructeur, vous devez appeler nextComponent() pour initialiser la composante suivante + */ + public Display(List legacyText) { + this(legacyText.toArray(new String[legacyText.size()])); + } + + /** + * Après l'appel de ce contructeur, vous devez appeler nextComponent() pour initialiser la composante suivante + */ + public Display(BaseComponent firstComponent) { + if (firstComponent == null) throw new IllegalArgumentException("le paramètre ne doit pas être null"); + first.addExtra(firstComponent); + } + + + + + /** + * Après l'appel de cette méthode, vous devez appeler nextComponent() pour initialiser la composante suivante + */ + public Display convertAndAddLegacy(String legacyText) { + finalizeCurrentComponent(); + + if (legacyText == null) + return this; + BaseComponent[] compo = TextComponent.fromLegacyText(legacyText); + + for (BaseComponent c : compo) { + first.addExtra(c); + } + return this; + } + + + + + + public Display nextComponent(String str) { + finalizeCurrentComponent(); + if (str == null) str = ""; + current = new TextComponent(str); + return this; + } + + + + + public Display addComponent(BaseComponent cmp) { + if (cmp == null) throw new IllegalArgumentException("le paramètre ne doit pas être null"); + finalizeCurrentComponent(); + first.addExtra(cmp); + return this; + } + + /** + * Équivalent à nextComponent("\n"), sauf qu'un nouvel appel à nextComponent() est nécessaire après. + */ + public Display nextLine() { + finalizeCurrentComponent(); + first.addExtra(new TextComponent("\n")); + return this; + } + + public Display setColor(ChatColor color) { + current.setColor(color); + return this; + } + + public Display setBold(boolean b) { + current.setBold(b); + return this; + } + + public Display setItalic(boolean i) { + current.setItalic(i); + return this; + } + + public Display setUnderlined(boolean u) { + current.setUnderlined(u); + return this; + } + + public Display setObfuscated(boolean o) { + current.setObfuscated(o); + return this; + } + + public Display setStrikethrough(boolean s) { + current.setStrikethrough(s); + return this; + } + + public Display setHoverText(Display content) { + current.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new BaseComponent[] {content.get()})); + return this; + } + + public Display setClickURL(String url) { + current.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)); + return this; + } + + public Display setClickCommand(String cmd) { + current.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, cmd)); + return this; + } + + public Display setClickSuggest(String cmd) { + current.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, cmd)); + return this; + } + + + + + + + + + + + + + + + + private void finalizeCurrentComponent() { + if (current != null) + first.addExtra(current); + current = null; + } + + + + public BaseComponent get() { + finalizeCurrentComponent(); + return first; + } + +} diff --git a/src/fr/pandacube/java/util/chat_display/DisplayUtil.java b/src/fr/pandacube/java/util/chat_display/DisplayUtil.java new file mode 100644 index 0000000..babd4aa --- /dev/null +++ b/src/fr/pandacube/java/util/chat_display/DisplayUtil.java @@ -0,0 +1,223 @@ +package fr.pandacube.java.util.chat_display; + +import java.util.HashMap; +import java.util.Map; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; + +public class DisplayUtil { + + @SuppressWarnings("serial") + private static Map charList = new HashMap(){{ + put(-6, "§"); + put(2, "!.,:;i|¡"); + put(3, "'`lìí"); + put(4, " I[]tï×"); + put(5, "\"()*<>fk{}"); + put(7, "@~®"); + }}; + + + private static final int defaultChatMaxWidth = 320; + private static int chatMaxWidth = defaultChatMaxWidth; + + private static final int defaultNbCharPerLineForConsole = 50; + private static int nbCharPerLineForConsole = defaultNbCharPerLineForConsole; + + public static final ChatColor COLOR_TITLE = ChatColor.GOLD; + public static final ChatColor COLOR_LINK = ChatColor.GREEN; + public static final ChatColor COLOR_COMMAND = ChatColor.GRAY; + + + + + public static BaseComponent createURLLink(String textLink, String url, String hoverText) { + String dispURL = (url.length() > 50) ? (url.substring(0, 48)+"...") : url; + + return new Display() + .nextComponent(textLink) + .setClickURL(url) + .setHoverText(new Display(ChatColor.GRAY+((hoverText == null)?"Cliquez pour accéder au site :":hoverText)+"\n"+ChatColor.GRAY+dispURL)) + .setColor(COLOR_LINK) + .get(); + } + + + public static BaseComponent createCommandLink(String textLink, String commandWithSlash, String hoverText) { + Display d = new Display() + .nextComponent(textLink) + .setClickCommand(commandWithSlash) + .setColor(COLOR_COMMAND); + if (hoverText != null) + d.setHoverText(new Display(hoverText)); + return d.get(); + } + + + public static BaseComponent createCommandSuggest(String textLink, String commandWithSlash, String hoverText) { + Display d = new Display() + .nextComponent(textLink) + .setClickSuggest(commandWithSlash) + .setColor(COLOR_COMMAND); + if (hoverText != null) + d.setHoverText(new Display(hoverText)); + return d.get(); + } + + + public static BaseComponent centerText(BaseComponent text, char repeatedChar, ChatColor decorationColor, boolean console) { + + int textWidth = strWidth(text.toPlainText(), console); + if (textWidth > ((console)?nbCharPerLineForConsole:chatMaxWidth)) return text; + + + String current = text.toPlainText(); + int count = 0; + do { + count++; + current = repeatedChar + current + repeatedChar; + } while (strWidth(current, console) <= ((console)?nbCharPerLineForConsole:chatMaxWidth)); + count--; + + String finalLeftOrRight = ""; + + for (int i=0; i ((console)?nbCharPerLineForConsole:chatMaxWidth) || textWidth + nbLeft*charW(repeatedChar, console) > ((console)?nbCharPerLineForConsole:chatMaxWidth)) return text; + + Display d = new Display(); + + String finalLeft = ""; + if (nbLeft > 0) { + for (int i=0; i ((console)?nbCharPerLineForConsole:chatMaxWidth) || textWidth + nbRight*charW(repeatedChar, console) > ((console)?nbCharPerLineForConsole:chatMaxWidth)) return text; + + + String tempText = text.toPlainText(); + if (nbRight > 0) { + tempText += decorationColor; + for (int i=0; i= 0) + return px; + return 6; + } + + + + + public static void setNbCharPerLineForConsole(int nb) { + if (nb < 0) nb = 0; + nbCharPerLineForConsole = nb; + } + public static void resetNbCharPerLineForConsole() { + nbCharPerLineForConsole = defaultNbCharPerLineForConsole; + } + public static void setChatMaxWidth(int px) { + if (px < 0) px = 0; + chatMaxWidth = px; + } + public static void resetChatMaxWidth() { + chatMaxWidth = defaultChatMaxWidth; + } + + +} diff --git a/src/fr/pandacube/java/util/chat_display/TextProgressBar.java b/src/fr/pandacube/java/util/chat_display/TextProgressBar.java new file mode 100644 index 0000000..a2e9536 --- /dev/null +++ b/src/fr/pandacube/java/util/chat_display/TextProgressBar.java @@ -0,0 +1,72 @@ +package fr.pandacube.java.util.chat_display; + +import net.md_5.bungee.api.ChatColor; + +public class TextProgressBar { + private static String pattern_start = "["; + private static String pattern_end = "]"; + private static ChatColor color_empty = ChatColor.DARK_GRAY; + private static ChatColor color_decoration = ChatColor.GOLD; + private static ChatColor color_default = ChatColor.RESET; + private static String pattern_empty = "."; + private static String pattern_full = "|"; + + public static String progressBar(double[] values, ChatColor[] colors, double total, int nbCar) + { + long[] sizes = new long[values.length]; + + int max_size = nbCar - pattern_start.length() - pattern_end.length(); + + for (int i=0; i=0; j--) + sum_values_before += values[j]; + + long car_position = Math.round(max_size * sum_values_before / total); + + // évite les barre de progressions plus grandes que la taille demandée + if (car_position > max_size) car_position = max_size; + + long sum_sizes_before = 0; + for (int j = i-1 ; j>=0; j--) + sum_sizes_before += sizes[j]; + + sizes[i] = car_position - sum_sizes_before; + } + int sum_sizes = 0; + + + String bar = color_decoration+pattern_start; + for (int i=0; i { + + public LoginHistoryTable() throws SQLException { + super("pandacube_login_history"); + } + + @Override + protected String createTableParameters() { + return "id INT AUTO_INCREMENT PRIMARY KEY," + + "time BIGINT NOT NULL," + + "playerId CHAR(36) NOT NULL," + + "ip VARCHAR(128) NOT NULL," + + "actionType ENUM('LOGIN', 'LOGOUT') NOT NULL," + + "nbOnline INT NOT NULL"; + } + + @Override + protected LoginHistoryElement getElementInstance(ResultSet sqlResult) throws SQLException { + LoginHistoryElement el = new LoginHistoryElement( + sqlResult.getInt("id"), + sqlResult.getLong("time"), + sqlResult.getString("playerId"), + sqlResult.getString("ip"), + ActionType.valueOf(sqlResult.getString("actionType")), + sqlResult.getInt("nbOnline")); + return el; + } + +} diff --git a/src/fr/pandacube/java/util/db/MPGroupElement.java b/src/fr/pandacube/java/util/db/MPGroupElement.java new file mode 100644 index 0000000..18c09a6 --- /dev/null +++ b/src/fr/pandacube/java/util/db/MPGroupElement.java @@ -0,0 +1,63 @@ +package fr.pandacube.java.util.db; + +import java.sql.SQLException; +import java.util.List; + +import fr.pandacube.java.util.PlayerFinder; + +public class MPGroupElement extends SQLElement { + + private String groupName; + + + + public MPGroupElement(String name) { + super("pandacube_mp_group"); + setGroupName(name); + } + + protected MPGroupElement(int id, String name) { + super("pandacube_mp_group", id); + setGroupName(name); + } + + + + + + + + @Override + protected String[] getValues() { + return new String[] { + groupName + }; + } + + @Override + protected String[] getFieldsName() { + return new String[] { + "groupName" + }; + } + + + + public String getGroupName() { return groupName; } + + public void setGroupName(String name) { + if (name == null) + throw new NullPointerException(); + if (!PlayerFinder.isValidPlayerName(name)) + throw new IllegalArgumentException("Le nom d'un groupe doit respecter le pattern d'un pseudo valide"); + groupName = name; + } + + + + public List getUsers() throws SQLException { + return ORM.getTable(MPGroupUserTable.class) + .getAll("groupId = "+getId(), "id ASC", null, null); + } + +} diff --git a/src/fr/pandacube/java/util/db/MPGroupTable.java b/src/fr/pandacube/java/util/db/MPGroupTable.java new file mode 100644 index 0000000..41d1da9 --- /dev/null +++ b/src/fr/pandacube/java/util/db/MPGroupTable.java @@ -0,0 +1,26 @@ +package fr.pandacube.java.util.db; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class MPGroupTable extends SQLTable { + + public MPGroupTable() throws SQLException { + super("pandacube_mp_group"); + } + + @Override + protected String createTableParameters() { + return "id INT AUTO_INCREMENT PRIMARY KEY," + + "groupName VARCHAR(16) NOT NULL"; + } + + @Override + protected MPGroupElement getElementInstance(ResultSet sqlResult) + throws SQLException { + return new MPGroupElement( + sqlResult.getInt("id"), + sqlResult.getString("groupName")); + } + +} diff --git a/src/fr/pandacube/java/util/db/MPGroupUserElement.java b/src/fr/pandacube/java/util/db/MPGroupUserElement.java new file mode 100644 index 0000000..d2f4491 --- /dev/null +++ b/src/fr/pandacube/java/util/db/MPGroupUserElement.java @@ -0,0 +1,71 @@ +package fr.pandacube.java.util.db; + +import java.sql.SQLException; +import java.util.UUID; + +public class MPGroupUserElement extends SQLElement { + + private int groupId; + private String playerId; + + + public MPGroupUserElement(int gId, UUID pId) { + super("pandacube_mp_group_user"); + setGroupId(gId); + setPlayerId(pId); + } + + protected MPGroupUserElement(int id, int gId, String pId) { + super("pandacube_mp_group_user", id); + setGroupId(gId); + setPlayerId(UUID.fromString(pId)); + } + + + + @Override + protected String[] getValues() { + return new String[] { + Integer.toString(groupId), + playerId + }; + } + + @Override + protected String[] getFieldsName() { + return new String[] { + "groupId", + "playerId" + }; + } + + + + + + + + public int getGroupId() { return groupId; } + public UUID getPlayerId() { return UUID.fromString(playerId); } + + public void setGroupId(int gId) { groupId = gId; } + public void setPlayerId(UUID pId) { + if (pId == null) + throw new NullPointerException(); + this.playerId = pId.toString(); + } + + + + + + + public PlayerElement getPlayerElement() throws SQLException { + return ORM.getTable(PlayerTable.class) + .getFirst("playerId LIKE '"+getPlayerId()+"'", "id ASC"); + } + + + + +} diff --git a/src/fr/pandacube/java/util/db/MPGroupUserTable.java b/src/fr/pandacube/java/util/db/MPGroupUserTable.java new file mode 100644 index 0000000..07a04bf --- /dev/null +++ b/src/fr/pandacube/java/util/db/MPGroupUserTable.java @@ -0,0 +1,42 @@ +package fr.pandacube.java.util.db; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +public class MPGroupUserTable extends SQLTable { + + public MPGroupUserTable() throws SQLException { + super("pandacube_mp_group_user"); + } + + @Override + protected String createTableParameters() { + return "id INT AUTO_INCREMENT PRIMARY KEY," + + "groupId INT NOT NULL," + + "playerId VARCHAR(36) NOT NULL"; + } + + @Override + protected MPGroupUserElement getElementInstance(ResultSet sqlResult) + throws SQLException { + return new MPGroupUserElement( + sqlResult.getInt("id"), + sqlResult.getInt("groupId"), + sqlResult.getString("playerId")); + } + + + /** + * Retourne l'instance de MPGroupUserElement correcpondant à la présence d'un joueur dans un groupe + * @param group le groupe concerné, sous forme d'instance de MPGroupElement + * @param player l'identifiant du joueur + * @return null si la correspondance n'a pas été trouvée + * @throws SQLException + */ + public MPGroupUserElement getPlayerInGroup(MPGroupElement group, UUID player) throws SQLException { + if (player == null || group == null) return null; + return getFirst("groupId = "+group.getId()+" AND playerId = '"+player+"'", "id"); + } + +} diff --git a/src/fr/pandacube/java/util/db/MPMessageElement.java b/src/fr/pandacube/java/util/db/MPMessageElement.java new file mode 100644 index 0000000..5283c34 --- /dev/null +++ b/src/fr/pandacube/java/util/db/MPMessageElement.java @@ -0,0 +1,177 @@ +package fr.pandacube.java.util.db; + +import java.sql.SQLException; +import java.util.UUID; + +/** + * Représente un message dans la base de donnée
+ *
+ * Les propriétés suivantes doivent être complétés hors constructeur (par défaut null) : + *
    + *
  • destNick
  • + *
  • ou destGroup
  • + *
+ * La propriété deleted est défini par défaut à Faux. + * @author Marc Baloup + * + */ +public class MPMessageElement extends SQLElement { + + private long time; + private int securityKey; // permet de différencier deux message, dans le cas où 2 messages ont exactement la même valeur time + private String viewerId; + private String sourceId; + private String destId = null; + private Integer destGroup = null; + private String message; + private boolean wasRead; + private boolean deleted = false; + private boolean serverSync; + + + + public MPMessageElement(long t, int secKey, UUID viewId, UUID srcId, String msg, boolean r, boolean sync) { + super("pandacube_mp_message"); + setTime(t); + setSecurityKey(secKey); + setViewerId(viewId); + setSourceId(srcId); + setMessage(msg); + setRead(r); + setServerSync(sync); + } + + + protected MPMessageElement(int id, long t, int secKey, String viewNick, String srcNick, String msg, boolean r, boolean sync) { + super("pandacube_mp_message", id); + setTime(t); + setSecurityKey(secKey); + setViewerId(UUID.fromString(viewNick)); + setSourceId((srcNick == null) ? null : UUID.fromString(srcNick)); + setMessage(msg); + setRead(r); + setServerSync(sync); + } + + + + + + + + + + + + + + + + + + + @Override + protected String[] getValues() { + return new String[] { + Long.toString(time), + Integer.toString(securityKey), + viewerId, + sourceId, + destId, + (destGroup==null)?null:destGroup.toString(), + message, + (wasRead)?"1":"0", + (deleted)?"1":"0", + (serverSync)?"1":"0" + }; + } + + + + + @Override + protected String[] getFieldsName() { + return new String[] { + "time", + "securityKey", + "viewerId", + "sourceId", + "destId", + "destGroup", + "message", + "wasRead", + "deleted", + "serverSync" + }; + } + + + public long getTime() { return time; } + public int getSecurityKey() { return securityKey; } + public UUID getViewerId() { return UUID.fromString(viewerId); } + public UUID getSourceId() { + if (sourceId == null) return null; + return UUID.fromString(sourceId); + } + public UUID getDestId() { + if (destId == null) return null; + return UUID.fromString(destId); + } + public Integer getDestGroup() { return destGroup; } + public String getMessage() { return message; } + public boolean isRead() { return wasRead; } + public boolean isDeleted() { return deleted; } + public boolean isServerSync() { return serverSync; } + + + + + public void setTime(long t) { time = t; } + public void setSecurityKey(int secKey) { securityKey = secKey; } + + public void setViewerId(UUID viewId) { + if (viewId == null) + throw new NullPointerException(); + viewerId = viewId.toString(); + } + + public void setSourceId(UUID srcId) { + if (srcId == null) sourceId = null; + else sourceId = srcId.toString(); + } + + public void setDestId(UUID destId) { + if (destId == null) this.destId = null; + else { + this.destId = destId.toString(); + destGroup = null; + } + } + + public void setDestGroup(Integer destGroup) { + this.destGroup = destGroup; + if (destGroup != null) + destId = null; + } + + public void setMessage(String msg) { + if (msg == null) + throw new NullPointerException(); + message = msg; + } + + public void setRead(boolean r) { wasRead = r; } + public void setDeleted(boolean del) { deleted = del; } + public void setServerSync(boolean sync) { serverSync = sync; } + + + + + + public MPGroupElement getDestGroupElement() throws SQLException { + if (getDestGroup() == null) return null; + + return ORM.getTable(MPGroupTable.class).get(getDestGroup()); + } + +} diff --git a/src/fr/pandacube/java/util/db/MPMessageTable.java b/src/fr/pandacube/java/util/db/MPMessageTable.java new file mode 100644 index 0000000..8239d5d --- /dev/null +++ b/src/fr/pandacube/java/util/db/MPMessageTable.java @@ -0,0 +1,99 @@ +package fr.pandacube.java.util.db; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +import fr.pandacube.java.util.PlayerFinder; + +public class MPMessageTable extends SQLTable { + + public MPMessageTable() throws SQLException { + super("pandacube_mp_message"); + } + + @Override + protected String createTableParameters() { + return "id INT AUTO_INCREMENT PRIMARY KEY," + + "time BIGINT NOT NULL," + + "securityKey INT NOT NULL," + + "viewerId VARCHAR(36) NOT NULL," + + "sourceId VARCHAR(36) NULL," // Null si la source est la console ou une autre entité qu'un joueur + + "destId VARCHAR(36) NULL," + + "destGroup INT NULL," + + "message VARCHAR(512) NOT NULL," + + "wasRead TINYINT NOT NULL," + + "deleted TINYINT NOT NULL," + + "serverSync TINYINT NOT NULL"; + } + + @Override + protected MPMessageElement getElementInstance(ResultSet sqlResult) + throws SQLException { + MPMessageElement el = new MPMessageElement( + sqlResult.getInt("id"), + sqlResult.getLong("time"), + sqlResult.getInt("securityKey"), + sqlResult.getString("viewerId"), + sqlResult.getString("sourceId"), + sqlResult.getString("message"), + sqlResult.getBoolean("wasRead"), + sqlResult.getBoolean("serverSync")); + String destId = sqlResult.getString("destId"); + el.setDestId(destId==null ? null : UUID.fromString(destId)); + + int group = sqlResult.getInt("destGroup"); + el.setDestGroup(sqlResult.wasNull()?null:group); + + el.setDeleted(sqlResult.getBoolean("deleted")); + + return el; + } + + + + + + public List getAllUnsyncMessage() throws SQLException { + return getAll("serverSync = 0", "time ASC", null, null); + } + + + + public List getAllUnreadForPlayer(UUID player) throws SQLException { + return getForPlayer(player, true, null, false); + } + + + public List getOneDiscussionForPlayer(UUID player, Object discussion, Integer numberLast, boolean revert) throws SQLException { + if (player == null) return null; + if (discussion != null && !(discussion instanceof String) && !(discussion instanceof UUID)) return null; + if (discussion != null && discussion instanceof String && !PlayerFinder.isValidPlayerName(discussion.toString())) return null; + + String where = "viewerId = '"+player+"'"; + if (discussion == null) + where += " AND sourceId IS NULL AND destGroup IS NULL"; + else if (discussion instanceof String) + where += " AND destGroup IN (SELECT id FROM "+ORM.getTable(MPGroupTable.class).getTableName()+" WHERE groupName LIKE '"+discussion+"')"; + else if (discussion instanceof UUID && discussion.equals(player)) + where += " AND destId LIKE '"+discussion+"' AND sourceId LIKE '"+discussion+"' AND destGroup IS NULL"; + else // discussion instanceof UUID + where += " AND (destId LIKE '"+discussion+"' OR sourceId LIKE '"+discussion+"') AND destGroup IS NULL"; + + return getAll(where, (revert)?"time DESC":"time ASC", numberLast, null); + } + + + public List getForPlayer(UUID player, boolean onlyUnread, Integer numberLast, boolean revert) throws SQLException { + if (player == null) return null; + + String where = "viewerId = '"+player+"'"; + if (onlyUnread) + where += " AND wasRead = 0"; + + return getAll(where, (revert)?"time DESC":"time ASC", numberLast, null); + } + + +} diff --git a/src/fr/pandacube/java/util/db/ModoHistoryElement.java b/src/fr/pandacube/java/util/db/ModoHistoryElement.java new file mode 100644 index 0000000..2f20bf3 --- /dev/null +++ b/src/fr/pandacube/java/util/db/ModoHistoryElement.java @@ -0,0 +1,141 @@ +package fr.pandacube.java.util.db; + +import java.util.UUID; + +public class ModoHistoryElement extends SQLElement { + + private String modoId = null; + private ActionType actionType; + private long time; + private String playerId; + private Long value = null; + private String message; + + + public ModoHistoryElement(UUID modo, ActionType type, UUID player, String message) { + super("pandacube_modo_history"); + setModoId(modo); + setActionType(type); + setPlayerId(player); + setMessage(message); + time = System.currentTimeMillis(); + } + + ModoHistoryElement(int id, String modo, ActionType type, String player, String message) { + super("pandacube_modo_history", id); + setModoId((modo == null)?null:UUID.fromString(modo)); + setActionType(type); + setPlayerId(UUID.fromString(player)); + setMessage(message); + time = System.currentTimeMillis(); + } + + @Override + protected String[] getValues() { + return new String[] { + modoId, + actionType.name(), + String.valueOf(time), + playerId, + (value == null)?null:value.toString(), + message + }; + } + + @Override + protected String[] getFieldsName() { + return new String[] { + "modoId", + "actionType", + "time", + "playerId", + "value", + "message" + }; + } + + + + public UUID getModoId() { + return modoId == null ? null : UUID.fromString(modoId); + } + + public void setModoId(UUID modo) { + this.modoId = modo == null ? null : modo.toString(); + } + + + + public ActionType getActionType() { + return actionType; + } + + public void setActionType(ActionType actionType) { + if (actionType == null) throw new IllegalArgumentException("le paramètre ne peut être null"); + this.actionType = actionType; + } + + + /** + * Retourne la durée de la sanction appliquée (en secondes), ou la somme d'argent retirée du compte + * @return + */ + public long getValue() { + return value; + } + + /** + * Value correspond soit à la durée de la sanction appliquée (en secondes), soit à la valeur de l'amende appliquée + * @param value + */ + public void setValue(Long value) { + if (value != null && value.longValue() < 0) value = null; + this.value = value; + } + + + + public UUID getPlayerId() { + return UUID.fromString(playerId); + } + + public void setPlayerId(UUID player) { + if (player == null) throw new IllegalArgumentException("le paramètre ne peut être null"); + this.playerId = player.toString(); + } + + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + if (message == null) throw new IllegalArgumentException("le paramètre ne peut être null"); + this.message = message; + } + + + + + + + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + + + + + + + public enum ActionType{ + BAN, UNBAN, MUTE, UNMUTE, REPORT, KICK + } + +} diff --git a/src/fr/pandacube/java/util/db/ModoHistoryTable.java b/src/fr/pandacube/java/util/db/ModoHistoryTable.java new file mode 100644 index 0000000..1ca4e36 --- /dev/null +++ b/src/fr/pandacube/java/util/db/ModoHistoryTable.java @@ -0,0 +1,40 @@ +package fr.pandacube.java.util.db; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import fr.pandacube.java.util.db.ModoHistoryElement.ActionType; + +public class ModoHistoryTable extends SQLTable { + + + + public ModoHistoryTable() throws SQLException { + super("pandacube_modo_history"); + } + + @Override + protected String createTableParameters() { + return "id INT AUTO_INCREMENT PRIMARY KEY," + + "modoId CHAR(36) NULL," // null si c'est la console + + "actionType ENUM('BAN', 'UNBAN', 'MUTE', 'UNMUTE', 'REPORT', 'KICK') NOT NULL," + + "time BIGINT NOT NULL," + + "playerId CHAR(36) NOT NULL," + + "value BIGINT NULL," + + "message VARCHAR(512) NOT NULL"; + } + + @Override + protected ModoHistoryElement getElementInstance(ResultSet sqlResult) throws SQLException { + ModoHistoryElement el = new ModoHistoryElement( + sqlResult.getInt("id"), + sqlResult.getString("modoId"), + ActionType.valueOf(sqlResult.getString("actionType")), + sqlResult.getString("playerId"), + sqlResult.getString("message")); + el.setValue(sqlResult.getLong("value")); + el.setTime(sqlResult.getLong("time")); + return el; + } + +} diff --git a/src/fr/pandacube/java/util/db/ORM.java b/src/fr/pandacube/java/util/db/ORM.java new file mode 100644 index 0000000..34126b5 --- /dev/null +++ b/src/fr/pandacube/java/util/db/ORM.java @@ -0,0 +1,86 @@ +package fr.pandacube.java.util.db; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * ORM = Object-Relational Mapping
+ * Liste des tables avec leur classes : + *
    + *
  • LoginHistoryTable
  • + *
  • ModoHistoryTable
  • + *
  • StaffTicketTable
  • + *
  • MPMessageTable
  • + *
  • MPGroupTable
  • + *
  • MPGroupUserTable
  • + *
  • MPWebSessionTable
  • + *
  • PlayerIgnoreTable
  • + *
+ * @author Marc Baloup + * + */ +public final class ORM { + + @SuppressWarnings("rawtypes") + private static List tables = new ArrayList(); + + /* package */ static DBConnection connection; + + + public synchronized static void init(DBConnection conn) { + try { + + connection = conn; + /* + * Les tables SQL sont à instancier ici ! + */ + + tables.add(new LoginHistoryTable()); + + tables.add(new ModoHistoryTable()); + + tables.add(new StaffTicketTable()); + + tables.add(new MPMessageTable()); + tables.add(new MPGroupTable()); + tables.add(new MPGroupUserTable()); + tables.add(new PlayerTable()); + + tables.add(new PlayerIgnoreTable()); + + tables.add(new ShopStockTable()); + + + } catch (SQLException e) { + e.printStackTrace(); + } + } + + + + + + @SuppressWarnings("rawtypes") + public synchronized static T getTable(Class c) { + if (c == null) return null; + for (SQLTable table : tables) { + + if (c.isAssignableFrom(table.getClass())) { + return c.cast(table); + } + } + return null; + } + + + + + + + + + private ORM() { } // rend la classe non instanciable + + +} diff --git a/src/fr/pandacube/java/util/db/PlayerElement.java b/src/fr/pandacube/java/util/db/PlayerElement.java new file mode 100644 index 0000000..df62fb9 --- /dev/null +++ b/src/fr/pandacube/java/util/db/PlayerElement.java @@ -0,0 +1,163 @@ +package fr.pandacube.java.util.db; + +import java.sql.Date; +import java.util.UUID; + +public class PlayerElement extends SQLElement { + + private String playerId; + private String token = null; + private String mailCheck = null; + private String password = null; + private String mail = null; + private String playerDisplayName; + private long firstTimeInGame; + private long timeWebRegister = 0; + private long lastTimeInGame = 0; + private long lastWebActivity = 0; + private String onlineInServer = null; + private String skinURL = null; + private boolean isVanish = false; + private Date birthday = null; + private int lastYearCelebratedBirthday = 0; + private Long banTimeout = null; + private Long muteTimeout = null; + private boolean isWhitelisted = false; + + public PlayerElement(UUID pId, String dispName, long firstTimeIG, long lastWebAct, String onlineInServer) { + super("pandacube_player"); + setPlayerId(pId); + setOnlineInServer(onlineInServer); + setLastWebActivity(lastWebAct); + setPlayerDisplayName(dispName); + setFirstTimeInGame(firstTimeIG); + } + + protected PlayerElement(int id, String pId, String dispName, long firstTimeIG, long lastWebAct, String onlineInServer) { + super("pandacube_player", id); + setPlayerId(UUID.fromString(pId)); + setOnlineInServer(onlineInServer); + setLastWebActivity(lastWebAct); + setPlayerDisplayName(dispName); + setFirstTimeInGame(firstTimeIG); + } + + @Override + protected String[] getValues() { + return new String[] { + playerId, + token, + mailCheck, + password, + mail, + playerDisplayName, + Long.toString(firstTimeInGame), + Long.toString(timeWebRegister), + Long.toString(lastTimeInGame), + Long.toString(lastWebActivity), + onlineInServer, + skinURL, + isVanish?"1":"0", + (birthday!=null)?birthday.toString():null, + Integer.toString(lastYearCelebratedBirthday), + (banTimeout!=null)?banTimeout.toString():null, + (muteTimeout!=null)?muteTimeout.toString():null, + isWhitelisted?"1":"0" + }; + } + + @Override + protected String[] getFieldsName() { + return new String[] { + "playerId", + "token", + "mailCheck", + "password", + "mail", + "playerDisplayName", + "firstTimeInGame", + "timeWebRegister", + "lastTimeInGame", + "lastWebActivity", + "onlineInServer", + "skinURL", + "isVanish", + "birthday", + "lastYearCelebratedBirthday", + "banTimeout", + "muteTimeout", + "isWhitelisted" + }; + } + + public UUID getPlayerId() { return UUID.fromString(playerId); } + public UUID getToken() { return (token == null) ? null : UUID.fromString(token); } + public String getMailCheck() { return mailCheck; } + public String getPasswordHash() { return password; } + public String getMail() { return mail; } + public long getFirstTimeInGame() { return firstTimeInGame; } + public long getTimeWebRegister() { return timeWebRegister; } + public long getLastTimeInGame() { return lastTimeInGame; } + public long getLastWebActivity() { return lastWebActivity; } + public String getOnlineInServer() { return onlineInServer; } + public String getPlayerDisplayName() { return playerDisplayName; } + public String getSkinURL() { return skinURL; } + public boolean isVanish() { return isVanish; } + public Date getBirthday() { return birthday; } + public int getLastYearCelebratedBirthday() { return lastYearCelebratedBirthday; } + public Long getBanTimeout() { return banTimeout; } + public Long getMuteTimeout() { return muteTimeout; } + public boolean isWhitelisted() { return isWhitelisted; } + + + + public void setPlayerId(UUID pName) { + if (pName == null) + throw new NullPointerException(); + playerId = pName.toString(); + } + + public void setToken(UUID t) { + if (t == null) + token = null; + else + token = t.toString(); + } + + public void setMailCheck(String mCheck) { mailCheck = mCheck; } + + public void setPasswordHash(String pass) { password = pass; } + + public void setMail(String m) { mail = m; } + + public void setFirstTimeInGame(long time) { firstTimeInGame = time; } + + public void setTimeWebRegister(long time) { timeWebRegister = time; } + + public void setLastTimeInGame(long time) { lastTimeInGame = time; } + + public void setLastWebActivity(long time) { lastWebActivity = time; } + + public void setOnlineInServer(String onlineInServer) { this.onlineInServer = onlineInServer; } + + public void setSkinURL(String skinURL) { this.skinURL = skinURL; } + + public void setPlayerDisplayName(String dispName) { + if (dispName == null) + throw new NullPointerException(); + playerDisplayName = dispName; + } + + public void setVanish(boolean v) { isVanish = v; } + + public void setBirthday(Date b) { birthday = b; } + + public void setLastYearCelebratedBirthday(int y) { lastYearCelebratedBirthday = y; } + + public void setBanTimeout(Long banT) { banTimeout = banT; } + + public void setMuteTimeout(Long muteT) { muteTimeout = muteT; } + + public void setWhitelisted(boolean w) { isWhitelisted = w; } + +} diff --git a/src/fr/pandacube/java/util/db/PlayerIgnoreElement.java b/src/fr/pandacube/java/util/db/PlayerIgnoreElement.java new file mode 100644 index 0000000..1b560bc --- /dev/null +++ b/src/fr/pandacube/java/util/db/PlayerIgnoreElement.java @@ -0,0 +1,66 @@ +package fr.pandacube.java.util.db; + +import java.util.UUID; + +public class PlayerIgnoreElement extends SQLElement { + + private String ignore; + private String ignored; + + + public PlayerIgnoreElement(UUID ignore, UUID ignored) { + super("pandacube_player_ignore"); + setIgnore(ignore); + setIgnored(ignored); + } + + + protected PlayerIgnoreElement(int id, String ignore, String ignored) { + super("pandacube_player_ignore", id); + this.ignore = ignore; + this.ignored = ignored; + } + + + @Override + protected String[] getValues() { + return new String[] { + ignore, + ignored + }; + } + + + @Override + protected String[] getFieldsName() { + return new String[] { + "ignorer", + "ignored" + }; + } + + + public UUID getIgnore() { + return UUID.fromString(ignore); + } + + + public void setIgnore(UUID i) { + if (i == null) + throw new IllegalArgumentException("i can't be null"); + ignore = i.toString(); + } + + + public UUID getIgnored() { + return UUID.fromString(ignored); + } + + + public void setIgnored(UUID i) { + if (i == null) + throw new IllegalArgumentException("i can't be null"); + ignored = i.toString(); + } + +} diff --git a/src/fr/pandacube/java/util/db/PlayerIgnoreTable.java b/src/fr/pandacube/java/util/db/PlayerIgnoreTable.java new file mode 100644 index 0000000..0636058 --- /dev/null +++ b/src/fr/pandacube/java/util/db/PlayerIgnoreTable.java @@ -0,0 +1,79 @@ +package fr.pandacube.java.util.db; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class PlayerIgnoreTable extends SQLTable { + + public PlayerIgnoreTable() throws SQLException { + super("pandacube_player_ignore"); + } + + @Override + protected String createTableParameters() { + return "id INT AUTO_INCREMENT PRIMARY KEY," + + "ignorer CHAR(36) NOT NULL," + + "ignored CHAR(36) NOT NULL"; + } + + @Override + protected PlayerIgnoreElement getElementInstance(ResultSet sqlResult) throws SQLException { + return new PlayerIgnoreElement(sqlResult.getInt("id"), + sqlResult.getString("ignorer"), + sqlResult.getString("ignored")); + } + + + + public List getListIgnoredPlayer(UUID ignore) throws SQLException { + if (ignore == null) + throw new IllegalArgumentException("ignore can't be null"); + + List dbIgnored = getAll("ignorer = '"+ignore+"'", "id", null, null); + + List ret = new ArrayList(); + + for (PlayerIgnoreElement el : dbIgnored) { + ret.add(el.getIgnored()); + } + + return ret; + + } + + + public boolean isPlayerIgnoringPlayer(UUID ignore, UUID ignored) throws SQLException { + if (ignore == null) + throw new IllegalArgumentException("ignore can't be null"); + if (ignored == null) + throw new IllegalArgumentException("ignored can't be null"); + + return getFirst("ignorer = '"+ignore+"' AND ignored = '"+ignored+"'", "id") != null; + + } + + + public void setPlayerIgnorePlayer(UUID ignore, UUID ignored, boolean set) throws SQLException { + if (ignore == null) + throw new IllegalArgumentException("ignore can't be null"); + if (ignored == null) + throw new IllegalArgumentException("ignored can't be null"); + if (ignore.equals(ignored)) // on ne peut pas s'auto ignorer + return; + + PlayerIgnoreElement el = getFirst("ignorer = '"+ignore+"' AND ignored = '"+ignored+"'", "id"); + + if (set && el == null) { + el = new PlayerIgnoreElement(ignore, ignored); + el.save(); + } + else if (!set && el != null) { + el.delete(); + } + + } + +} diff --git a/src/fr/pandacube/java/util/db/PlayerTable.java b/src/fr/pandacube/java/util/db/PlayerTable.java new file mode 100644 index 0000000..3f4cb6e --- /dev/null +++ b/src/fr/pandacube/java/util/db/PlayerTable.java @@ -0,0 +1,70 @@ +package fr.pandacube.java.util.db; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +public class PlayerTable extends SQLTable { + + public PlayerTable() throws SQLException { + super("pandacube_player"); + } + + @Override + protected String createTableParameters() { + return "id INT AUTO_INCREMENT PRIMARY KEY," + + "playerId CHAR(36) NOT NULL," + + "token CHAR(36) NULL," + + "mailCheck VARCHAR(255) NULL," + + "password VARCHAR(255) NULL," + + "mail VARCHAR(255) NULL," + + "playerDisplayName VARCHAR(255) NOT NULL," + + "firstTimeInGame BIGINT NOT NULL," + + "timeWebRegister BIGINT NULL," + + "lastTimeInGame BIGINT NULL," + + "lastWebActivity BIGINT NOT NULL," + + "onlineInServer VARCHAR(32) NULL," + + "skinURL VARCHAR(255) NULL," + + "isVanish TINYINT NULL," + + "birthday DATE NULL," + + "lastYearCelebratedBirthday INT NOT NULL DEFAULT 0," + + "banTimeout BIGINT NULL," + + "muteTimeout BIGINT NULL," + + "isWhitelisted TINYINT NOT NULL DEFAULT 0"; + } + + @Override + protected PlayerElement getElementInstance(ResultSet sqlResult) + throws SQLException { + PlayerElement el = new PlayerElement( + sqlResult.getInt("id"), + sqlResult.getString("playerId"), + sqlResult.getString("playerDisplayName"), + sqlResult.getLong("firstTimeInGame"), + sqlResult.getLong("lastWebActivity"), + sqlResult.getString("onlineInServer")); + String token = sqlResult.getString("token"); + el.setToken((token == null) ? null : UUID.fromString(token)); + el.setMailCheck(sqlResult.getString("mailCheck")); + el.setPasswordHash(sqlResult.getString("password")); + el.setMail(sqlResult.getString("mail")); + el.setFirstTimeInGame(sqlResult.getLong("firstTimeInGame")); + el.setTimeWebRegister(sqlResult.getLong("timeWebRegister")); + el.setLastTimeInGame(sqlResult.getLong("lastTimeInGame")); + el.setSkinURL(sqlResult.getString("skinURL")); + el.setVanish(sqlResult.getBoolean("isVanish")); + el.setBirthday(sqlResult.getDate("birthday")); + el.setLastYearCelebratedBirthday(sqlResult.getInt("lastYearCelebratedBirthday")); + + long longVal; + + longVal = sqlResult.getLong("banTimeout"); + el.setBanTimeout(sqlResult.wasNull()?null:longVal); + longVal = sqlResult.getLong("muteTimeout"); + el.setMuteTimeout(sqlResult.wasNull()?null:longVal); + + el.setWhitelisted(sqlResult.getBoolean("isWhitelisted")); + return el; + } + +} diff --git a/src/fr/pandacube/java/util/db/SQLElement.java b/src/fr/pandacube/java/util/db/SQLElement.java new file mode 100644 index 0000000..4ce3543 --- /dev/null +++ b/src/fr/pandacube/java/util/db/SQLElement.java @@ -0,0 +1,160 @@ +package fr.pandacube.java.util.db; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import org.apache.commons.lang.StringUtils; + +public abstract class SQLElement { + + DBConnection db = ORM.connection; + + + private boolean saved = false; + + protected final String tableName; + + // champ relatif aux données + private int id = 0; + + + + public SQLElement(String name) { + tableName = name; + saved = false; + } + protected SQLElement(String name, int id) { + tableName = name; + this.id = id; + saved = true; + } + + + + + + public void save() { + + try { + Connection conn; + conn = db.getConnection(); + + String[] fields = getFieldsName(), values = getValues(); + + + + if (saved) + { // mettre à jour les valeurs dans la base + String sql = ""; + for (int i=0; i 0) + sql = sql.substring(0, sql.length()-1); + + PreparedStatement st = conn.prepareStatement("UPDATE "+tableName+" SET "+sql+" WHERE id="+id); + try { + for (int i=0; iid + * @return les valeurs des champs sous la forme de chaine de caractères + */ + protected abstract String[] getValues(); + + + + /** + * Récupère la liste des noms des champs de la table correspondante, excepté + * le champ id + * @return les noms des champs sous la forme de chaine de caractères + */ + protected abstract String[] getFieldsName(); +} diff --git a/src/fr/pandacube/java/util/db/SQLTable.java b/src/fr/pandacube/java/util/db/SQLTable.java new file mode 100644 index 0000000..1a91ec0 --- /dev/null +++ b/src/fr/pandacube/java/util/db/SQLTable.java @@ -0,0 +1,140 @@ +package fr.pandacube.java.util.db; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +public abstract class SQLTable { + + DBConnection db = ORM.connection; + + private final String tableName; + + + public SQLTable(String name) throws SQLException { + tableName = name; + + if (!tableExist()) + createTable(); + + + } + + + private void createTable() throws SQLException { + Statement stmt = db.getConnection().createStatement(); + String sql = "CREATE TABLE IF NOT EXISTS "+tableName+" " + + "("+createTableParameters()+")"; + try { + stmt.executeUpdate(sql); + } finally { + stmt.close(); + } + } + + + private boolean tableExist() throws SQLException { + ResultSet set = null; + boolean exist = false; + try { + set = db.getConnection().getMetaData().getTables(null, null, tableName, null); + exist = set.next(); + } finally { + if (set != null) + set.close(); + } + return exist; + } + + + /** + * Retourne une chaine de caractère qui sera inclu dans la requête SQL de création de la table. + * La requête est de la forme : CRATE TABLE tableName (); + * La chaine retournée sera ajoutée entre les parenthèses. + */ + protected abstract String createTableParameters(); + + + + /** + * Crée une instance de l'élément courant se trouvant dans le resultSet passé en paramètre + * @param sqlResult le set de résultat, déjà positionné sur un élément. Ne surtout pas appeler la méthode next() ! + * @return + * @throws SQLException + */ + protected abstract T getElementInstance(ResultSet sqlResult) throws SQLException; + + + + + public String getTableName() { + return tableName; + } + + + + public T get(int id) throws SQLException { + T elementInstance = null; + Statement stmt = db.getConnection().createStatement(); + try { + String sql = "SELECT * FROM "+tableName+" WHERE id = "+id+";"; + + ResultSet set = stmt.executeQuery(sql); + try { + if (set.next()) + elementInstance = getElementInstance(set); + } finally { + set.close(); + } + } finally { + stmt.close(); + } + return elementInstance; + } + + + + public List getAll() throws SQLException { + return getAll(null, null, null, null); + } + + + + public T getFirst(String where, String orderBy) throws SQLException { + List elts = getAll(where, orderBy, 1, null); + return (elts.size() == 0)? null : elts.get(0); + } + + + public List getAll(String where, String orderBy, Integer limit, Integer offset) throws SQLException { + Statement stmt = db.getConnection().createStatement(); + String sql = "SELECT * FROM "+tableName; + + if (where != null) + sql += " WHERE "+where; + if (orderBy != null) + sql += " ORDER BY "+orderBy; + if (limit != null) + sql += " LIMIT "+limit; + if (offset != null) + sql += " OFFSET "+offset; + sql += ";"; + + List elmts = new ArrayList(); + try { + ResultSet set = stmt.executeQuery(sql); + try { + while (set.next()) + elmts.add(getElementInstance(set)); + } finally { + set.close(); + } + } finally { + stmt.close(); + } + return elmts; + } + +} diff --git a/src/fr/pandacube/java/util/db/ShopStockElement.java b/src/fr/pandacube/java/util/db/ShopStockElement.java new file mode 100644 index 0000000..29f421a --- /dev/null +++ b/src/fr/pandacube/java/util/db/ShopStockElement.java @@ -0,0 +1,74 @@ +package fr.pandacube.java.util.db; + +public class ShopStockElement extends SQLElement { + + private String material; + private short damage = 0; + private double quantity; + private String server; + + + public ShopStockElement(String m, short d, double q, String s) { + super("pandacube_shop_stock"); + setMaterial(m); + setDamage(d); + setQuantity(q); + setServer(s); + } + + protected ShopStockElement(int id, String m, short d, double q, String s) { + super("pandacube_shop_stock", id); + setMaterial(m); + setDamage(d); + setQuantity(q); + setServer(s); + } + + @Override + protected String[] getValues() { + return new String[] { + material, + Short.toString(damage), + Double.toString(quantity), + server + }; + } + + @Override + protected String[] getFieldsName() { + return new String[] { + "material", + "damage", + "quantity", + "server" + }; + } + + public String getMaterial() { return material; } + + public void setMaterial(String m) { + if (m == null) throw new IllegalArgumentException("Material can't be null"); + material = m; + } + + public short getDamage() { return damage; } + + public void setDamage(short d) { + damage = d; + } + + public double getQuantity() { return quantity; } + + public void setQuantity(double q) { + if (q < 0) q = 0; + quantity = q; + } + + public String getServer() { return server; } + + public void setServer(String s) { + if (s == null) throw new IllegalArgumentException("Server can't be null"); + server = s; + } + +} diff --git a/src/fr/pandacube/java/util/db/ShopStockTable.java b/src/fr/pandacube/java/util/db/ShopStockTable.java new file mode 100644 index 0000000..7f769e1 --- /dev/null +++ b/src/fr/pandacube/java/util/db/ShopStockTable.java @@ -0,0 +1,30 @@ +package fr.pandacube.java.util.db; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class ShopStockTable extends SQLTable { + + public ShopStockTable() throws SQLException { + super("pandacube_shop_stock"); + } + + @Override + protected String createTableParameters() { + return "id INT AUTO_INCREMENT PRIMARY KEY," + + "material varchar(50) NOT NULL," + + "damage int(11) NOT NULL DEFAULT '0'," + + "quantity double NOT NULL," + + "server varchar(50) NOT NULL"; + } + + @Override + protected ShopStockElement getElementInstance(ResultSet sqlResult) throws SQLException { + return new ShopStockElement(sqlResult.getInt("id"), + sqlResult.getString("material"), + sqlResult.getShort("damage"), + sqlResult.getDouble("quantity"), + sqlResult.getString("server")); + } + +} diff --git a/src/fr/pandacube/java/util/db/StaffTicketElement.java b/src/fr/pandacube/java/util/db/StaffTicketElement.java new file mode 100644 index 0000000..cd6b28d --- /dev/null +++ b/src/fr/pandacube/java/util/db/StaffTicketElement.java @@ -0,0 +1,77 @@ +package fr.pandacube.java.util.db; + +import java.util.UUID; + +public class StaffTicketElement extends SQLElement { + + + private String playerId; + private String message; + private long creationTime; + private String staffPlayerId = null; + + + public StaffTicketElement(UUID pId, String m, long creaTime) { + super("pandacube_staff_ticket"); + setPlayerId(pId); + setMessage(m); + setCreationTime(creaTime); + + } + protected StaffTicketElement(int id, String pId, String m, long creaTime) { + super("pandacube_staff_ticket", id); + setPlayerId(UUID.fromString(pId)); + setMessage(m); + setCreationTime(creaTime); + } + + + @Override + protected String[] getValues() { + return new String[] { + playerId, + message, + Long.toString(creationTime), + staffPlayerId, + }; + } + + @Override + protected String[] getFieldsName() { + return new String[] { + "playerId", + "message", + "creationTime", + "staffPlayerId" + }; + } + public UUID getPlayerId() { + return UUID.fromString(playerId); + } + public void setPlayerId(UUID pId) { + if (pId == null) throw new IllegalArgumentException("playerName can't be null"); + this.playerId = pId.toString(); + } + public String getMessage() { + return message; + } + public void setMessage(String message) { + if (message == null) throw new IllegalArgumentException("message can't be null"); + this.message = message; + } + public long getCreationTime() { + return creationTime; + } + public void setCreationTime(long creationTime) { + this.creationTime = creationTime; + } + public UUID getStaffPlayer() { + if (staffPlayerId == null) return null; + return UUID.fromString(staffPlayerId); + } + public void setStaffPlayer(UUID staffId) { + if (staffId == null) staffPlayerId = null; + else staffPlayerId = staffId.toString(); + } + +} diff --git a/src/fr/pandacube/java/util/db/StaffTicketTable.java b/src/fr/pandacube/java/util/db/StaffTicketTable.java new file mode 100644 index 0000000..a3896c9 --- /dev/null +++ b/src/fr/pandacube/java/util/db/StaffTicketTable.java @@ -0,0 +1,37 @@ +package fr.pandacube.java.util.db; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +public class StaffTicketTable extends SQLTable { + + + public StaffTicketTable() throws SQLException { + super("pandacube_staff_ticket"); + } + + @Override + protected String createTableParameters() { + return "id INT AUTO_INCREMENT PRIMARY KEY," + + "playerId CHAR(36) NOT NULL," + + "message VARCHAR(1024) NOT NULL," + + "creationTime BIGINT NOT NULL," + + "staffPlayerId CHAR(36) NULL"; + } + + @Override + protected StaffTicketElement getElementInstance(ResultSet sqlResult) + throws SQLException { + StaffTicketElement el = new StaffTicketElement( + sqlResult.getInt("id"), + sqlResult.getString("playerId"), + sqlResult.getString("message"), + sqlResult.getLong("creationTime")); + String staffId = sqlResult.getString("staffPlayerId"); + el.setStaffPlayer((staffId == null) ? null : UUID.fromString(staffId)); + + return el; + } + +} diff --git a/src/fr/pandacube/java/util/network_api/client/AbstractRequest.java b/src/fr/pandacube/java/util/network_api/client/AbstractRequest.java new file mode 100644 index 0000000..43322c9 --- /dev/null +++ b/src/fr/pandacube/java/util/network_api/client/AbstractRequest.java @@ -0,0 +1,32 @@ +package fr.pandacube.java.util.network_api.client; + +import java.io.PrintStream; + +public abstract class AbstractRequest { + + private final String pass; + private String command; + private String data; + + + protected AbstractRequest(String cmd, String p) { + if (cmd == null || cmd.isEmpty()) throw new IllegalArgumentException("Un message doit-être défini"); + command = cmd; + pass = p; + } + + + protected void setData(String d) { + if (d == null) d = ""; + data = d; + } + + + public void sendPacket(PrintStream out) { + out.print(pass+"\n"); + out.print(command+"\n"); + out.print(data.getBytes().length+"\n"); + out.print(data); + out.flush(); + } +} diff --git a/src/fr/pandacube/java/util/network_api/client/NetworkAPISender.java b/src/fr/pandacube/java/util/network_api/client/NetworkAPISender.java new file mode 100644 index 0000000..77b74e1 --- /dev/null +++ b/src/fr/pandacube/java/util/network_api/client/NetworkAPISender.java @@ -0,0 +1,28 @@ +package fr.pandacube.java.util.network_api.client; + +import java.io.IOException; +import java.io.PrintStream; +import java.net.InetSocketAddress; +import java.net.Socket; + +public class NetworkAPISender { + + public static ResponseAnalyser sendRequest(InetSocketAddress cible, AbstractRequest request) throws IOException { + Socket s = new Socket(cible.getAddress(), cible.getPort()); + + PrintStream out = new PrintStream(s.getOutputStream()); + + request.sendPacket(out); + s.shutdownOutput(); + + ResponseAnalyser response = new ResponseAnalyser(s); + + s.close(); + + return response; + } + + +} + + diff --git a/src/fr/pandacube/java/util/network_api/client/ResponseAnalyser.java b/src/fr/pandacube/java/util/network_api/client/ResponseAnalyser.java new file mode 100644 index 0000000..a8381bb --- /dev/null +++ b/src/fr/pandacube/java/util/network_api/client/ResponseAnalyser.java @@ -0,0 +1,63 @@ +package fr.pandacube.java.util.network_api.client; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Socket; + +public class ResponseAnalyser { + /** + * Indique si la requête s'est bien exécutée (l'entête de la réponse est 'ok') + */ + public final boolean good; + + + public final String data; + + + public ResponseAnalyser(Socket socket) throws IOException { + if (socket == null || socket.isClosed() || socket.isInputShutdown()) throw new IllegalArgumentException("le socket doit être non null et doit être ouvert sur le flux d'entrée"); + + // on lis la réponse + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + String line; + + + // lecture de la première ligne + line = in.readLine(); + good = line.equalsIgnoreCase("OK"); + + + + + // lecture de la deuxième ligne + line = in.readLine(); + + int data_size = 0; + try { + data_size = Integer.parseInt(line); + } catch (NumberFormatException e) { throw new RuntimeException("Réponse mal formée : la deuxième ligne doit-être un nombre entier"); } + + + + + + + // lecture du reste + StringBuilder sB_data = new StringBuilder(); + char[] c = new char[100]; + int nbC = 0; + while((nbC = in.read(c)) != -1) + sB_data.append(c, 0, nbC); + data = sB_data.toString(); + + if (data.getBytes().length != data_size) + throw new RuntimeException("Réponse mal formée : "+data_size+" caractères annoncée dans la requête, mais "+data.getBytes().length+" s'y trouvent."); + + + } + + + +} diff --git a/src/fr/pandacube/java/util/network_api/server/AbstractRequestExecutor.java b/src/fr/pandacube/java/util/network_api/server/AbstractRequestExecutor.java new file mode 100644 index 0000000..89b038d --- /dev/null +++ b/src/fr/pandacube/java/util/network_api/server/AbstractRequestExecutor.java @@ -0,0 +1,46 @@ +package fr.pandacube.java.util.network_api.server; + +import java.io.IOException; +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.Socket; + +public abstract class AbstractRequestExecutor { + + + + public final String command; + + + public AbstractRequestExecutor(String cmd, NetworkAPIListener napiListener) { + command = cmd.toLowerCase(); + napiListener.registerRequestExecutor(command, this); + } + + + + public void execute(String data, Socket socket) throws IOException { + if (socket == null || socket.isClosed() || socket.isOutputShutdown()) throw new IllegalArgumentException("le socket doit être non null et doit être ouvert sur le flux d'entrée"); + + try { + + Response rep = run(socket.getInetAddress(), data); + rep.sendPacket(new PrintStream(socket.getOutputStream())); + + } catch(Exception e) { + new Response(false, e.toString()).sendPacket(new PrintStream(socket.getOutputStream())); + e.printStackTrace(); + } + + } + + + /** + * + * @param data La représentation sous forme de String des données envoyés dans la requête + * @return La réponse à retourner au client + */ + protected abstract Response run(InetAddress source, String data); + + +} diff --git a/src/fr/pandacube/java/util/network_api/server/NAPIExecutionHandler.java b/src/fr/pandacube/java/util/network_api/server/NAPIExecutionHandler.java new file mode 100644 index 0000000..075357f --- /dev/null +++ b/src/fr/pandacube/java/util/network_api/server/NAPIExecutionHandler.java @@ -0,0 +1,13 @@ +package fr.pandacube.java.util.network_api.server; + +/** + * Interface permettant de gérer l'exécution asynchrone d'un PacketExecutor. + * @author Marc Baloup + * + */ +@FunctionalInterface +public interface NAPIExecutionHandler { + + public void handleRun(Runnable executor); + +} diff --git a/src/fr/pandacube/java/util/network_api/server/NetworkAPIListener.java b/src/fr/pandacube/java/util/network_api/server/NetworkAPIListener.java new file mode 100644 index 0000000..08d312e --- /dev/null +++ b/src/fr/pandacube/java/util/network_api/server/NetworkAPIListener.java @@ -0,0 +1,125 @@ +package fr.pandacube.java.util.network_api.server; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Arrays; +import java.util.HashMap; + +public class NetworkAPIListener implements Runnable { + + + + + + + + + + + + + + private int port = 0; + String pass; + private ServerSocket serverSocket; + private HashMap requestExecutors = new HashMap(); + private String name; + private NAPIExecutionHandler nAPIExecutionHandler; + + /** + * Instencie le côté serveur du NetworkAPI + * @param n nom du networkAPI (permet l'identification dans les logs) + * @param p le port d'écoute + * @param pa le mot de passe réseau + * @param peh PacketExecutionHandler permettant de prendre en charge l'exécution asynchrone d'une requête reçu pas un client + */ + public NetworkAPIListener(String n, int p, String pa, NAPIExecutionHandler peh) { + port = p; + pass = pa; + name = n; + nAPIExecutionHandler = peh; + } + + + @Override + public void run() { + synchronized (this) { + try { + serverSocket = new ServerSocket(port); + } catch (IOException e) { + System.err.println(e.getMessage()); + return; + } + } + + + + System.out.println("NetworkAPI '"+name+"' à l'écoute sur le port "+port); + + + try { + // réception des connexion client + while (!serverSocket.isClosed()) { + Socket socketClient = serverSocket.accept(); + nAPIExecutionHandler.handleRun(new PacketExecutor(socketClient, this)); + } + } catch(IOException e) { } + + synchronized (this) { + try { + if (!serverSocket.isClosed()) + serverSocket.close(); + } catch (IOException e) { } + } + + System.out.println("NetworkAPI '"+name+"' ferme le port "+port); + + + } + + + /** + * Ferme le ServerSocket. Ceci provoque l'arrêt du thread associé à l'instance de la classe + */ + public synchronized void closeServerSocket() { + if (serverSocket != null) + { + try { + serverSocket.close(); + } catch (IOException e) { } + } + } + + + + + + public int getPort() { return port; } + + + + + public void registerRequestExecutor(String command, AbstractRequestExecutor executor) { + requestExecutors.put(command, executor); + } + + public AbstractRequestExecutor getRequestExecutor(String command) { + return requestExecutors.get(command); + } + + + public String getCommandList() { + return Arrays.toString(requestExecutors.keySet().toArray()); + } + + +} + + + + + + + + diff --git a/src/fr/pandacube/java/util/network_api/server/PacketExecutor.java b/src/fr/pandacube/java/util/network_api/server/PacketExecutor.java new file mode 100644 index 0000000..3bf01b4 --- /dev/null +++ b/src/fr/pandacube/java/util/network_api/server/PacketExecutor.java @@ -0,0 +1,51 @@ +package fr.pandacube.java.util.network_api.server; + +import java.io.IOException; +import java.io.PrintStream; +import java.net.Socket; + + +/** + * Prends en charge un socket client et le transmet au gestionnaire de paquet correspondant.
+ * La connexion est fermée après chaque requête du client (règle pouvant évoluer) + * @author Marc Baloup + * + */ +public class PacketExecutor implements Runnable { + private Socket socket; + private NetworkAPIListener networkAPIListener; + + public PacketExecutor(Socket s, NetworkAPIListener napiListener) { + socket = s; + networkAPIListener = napiListener; + } + + @Override + public void run() { + try { + + // analyse de la requête + RequestAnalyser analyse = new RequestAnalyser(socket, networkAPIListener); + + + AbstractRequestExecutor executor = networkAPIListener.getRequestExecutor(analyse.command); + + executor.execute(analyse.data, socket); + + + + } catch(Throwable e) { + Response rep = new Response(); + rep.good = false; + rep.data = e.toString(); + try { + rep.sendPacket(new PrintStream(socket.getOutputStream())); + } catch (IOException e1) { } + e.printStackTrace(); + } + + try { + socket.close(); + } catch (Exception e) { } + } +} diff --git a/src/fr/pandacube/java/util/network_api/server/RequestAnalyser.java b/src/fr/pandacube/java/util/network_api/server/RequestAnalyser.java new file mode 100644 index 0000000..2fdcf6e --- /dev/null +++ b/src/fr/pandacube/java/util/network_api/server/RequestAnalyser.java @@ -0,0 +1,84 @@ +package fr.pandacube.java.util.network_api.server; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Socket; + +public class RequestAnalyser { + + private NetworkAPIListener networkAPIListener; + public final String command; + public final String data; + + public RequestAnalyser(Socket socket, NetworkAPIListener napiListener) throws IOException, BadRequestException { + if (socket == null || socket.isClosed() || socket.isInputShutdown() || napiListener == null) throw new IllegalArgumentException("le socket doit être non null et doit être ouvert sur le flux d'entrée et napiListener ne doit pas être null"); + + networkAPIListener = napiListener; + + // on lis la réponse + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + String line; + + + + // lecture de la première ligne + line = in.readLine(); + if (line == null || !line.equals(networkAPIListener.pass)) + throw new BadRequestException("wrong_password"); + + + + + + // lecture de la deuxième ligne + line = in.readLine(); + if (line == null || networkAPIListener.getRequestExecutor(line) == null) + throw new BadRequestException("command_not_exists"); + command = line; + + + + // lecture de la troisième ligne + line = in.readLine(); + + int data_size = 0; + try { + data_size = Integer.parseInt(line); + } catch (NumberFormatException e) { throw new BadRequestException("wrong_data_size_format"); } + + + // lecture du reste + StringBuilder sB_data = new StringBuilder(); + char[] c = new char[100]; + int nbC = 0; + while((nbC = in.read(c)) != -1) + sB_data.append(c, 0, nbC); + + data = sB_data.toString(); + + if (data.getBytes().length != data_size) + throw new BadRequestException("wrong_data_size"); + + + socket.shutdownInput(); + } + + + + + + + public class BadRequestException extends Exception { + + private static final long serialVersionUID = 1L; + + public BadRequestException(String message) { + super(message); + } + + } + + +} diff --git a/src/fr/pandacube/java/util/network_api/server/Response.java b/src/fr/pandacube/java/util/network_api/server/Response.java new file mode 100644 index 0000000..5235ef4 --- /dev/null +++ b/src/fr/pandacube/java/util/network_api/server/Response.java @@ -0,0 +1,32 @@ +package fr.pandacube.java.util.network_api.server; + +import java.io.PrintStream; + +public class Response { + public boolean good = true; + public String data = ""; + + + public Response(boolean good, String data) { + this.good = good; + this.data = data; + } + + /** + * Construit une réponse positive avec aucune donnée. Équivaut à + * new Response(true, "") + */ + public Response() { + } + + + public void sendPacket(PrintStream out) { + + if (data == null) data = ""; + + out.print((good?"OK":"ERROR")+"\n"); + out.print(data.getBytes().length+"\n"); + out.print(data); + out.flush(); + } +} diff --git a/src/fr/pandacube/java/util/network_api/server/ThreadNAPIExecutionHandler.java b/src/fr/pandacube/java/util/network_api/server/ThreadNAPIExecutionHandler.java new file mode 100644 index 0000000..09e7d58 --- /dev/null +++ b/src/fr/pandacube/java/util/network_api/server/ThreadNAPIExecutionHandler.java @@ -0,0 +1,10 @@ +package fr.pandacube.java.util.network_api.server; + +public class ThreadNAPIExecutionHandler implements NAPIExecutionHandler { + + @Override + public void handleRun(Runnable executor) { + new Thread(executor).start(); + } + +}