Compare commits

...

18 Commits

Author SHA1 Message Date
Ponk
7ef471f1e2 Merge pull request #197 from wangxiaobao0851/fix-mts #patch
Fix MTS sql syntax error and month error
2023-11-07 17:28:16 +01:00
王小宝
c3404d296a Fix MTS sql syntax error and month error 2023-10-13 21:16:40 +08:00
Ponk
c609bcf2ee Merge pull request #193 from P0nk/fix-192/playernpc #patch
Fix #192 - Unable to create PlayerNPC
2023-09-19 17:15:00 +02:00
P0nk
0aee9d7c3f Fix unable to create playernpc
The initialization of the running world counters depended on worlds already having been initialized, so I made that dependency more explicit.
2023-09-19 12:56:51 +02:00
P0nk
a49c1703ae Remove developer player npc 2023-09-18 23:26:37 +02:00
Ponk
38eecd0db7 Merge pull request #188 from leevccc/master #patch
fix: error flag after use karma
2023-09-09 07:56:33 +02:00
leevccc
e320bafa8b fix: error flag after use karma
setFalg() function is designed to take arguments of type short. Forcing the short type flag to be converted to the byte type causes some errors here.

For example, the equipment merge system will make the UNTRADEABLE flag become 520, combined with the Scissors of Karma 16, and finally become 536, this value is beyond the byte range, and the mandatory variable type will cause the flag error, the specific problem I encountered is that the MERGE_UNTRADEABLE flag is lost after using the Scissors of Karma.
2023-09-08 04:59:56 +08:00
Ponk
754e5e61f2 Merge pull request #185 from Arnuh/fix-client-local-address #patch
Fix masking of ip address when connecting locally
2023-08-20 18:26:59 +02:00
Ponk
afba85827a Merge pull request #186 from sashimi-yzh/fix-cats-eye-dropper #patch
fix the dropper of Cat's Eye
2023-08-20 18:21:20 +02:00
Zihao Yu
8cd5211b8b fix the dropper of Cat's Eye
* it was previously dropped from Scorpion, which is wrong
2023-08-20 22:55:43 +08:00
Arnah
2d7525f2b4 Fix cashshop exiting not using proper ip 2023-08-16 16:19:16 -06:00
Arnah
7adb25888f Stop masking ip address when connecting locally 2023-08-16 00:53:40 -06:00
Ponk
b46912afcb Merge pull request #181 from Silwhoon/fix-incorrect-orange-potion-id #patch
Changes an incorrect Orange Potion ID to the correct one
2023-08-15 19:34:44 +02:00
Ponk
ed3d4823b2 Merge pull request #184 from noamyoyo/master #patch
Expose database container to allow access from MySQL client such as Workbench.
2023-08-15 19:32:09 +02:00
noampfeifel
b8a360917e final fixes 2023-08-15 19:07:34 +03:00
noampfeifel
26dbe36a15 fixed ports to simple setup, added notes about DB_HOST 2023-08-15 19:06:05 +03:00
noampfeifel
396447519d fixing compose port and config string for db 2023-08-13 17:33:25 +03:00
pleb
83e436bbd2 Changes an incorrect Orange Potion ID to the correct one
Thorr in Mushroom Kingdom sold an untradable "Orange Potion for Beginners" instead of a "Orange Potion". This fixes that.
2023-07-27 09:03:39 -05:00
15 changed files with 57 additions and 208 deletions

View File

@@ -159,8 +159,8 @@ worlds:
server:
#Database Configuration
DB_URL_FORMAT: "jdbc:mysql://%s:3306/cosmic"
DB_HOST: "localhost"
DB_URL_FORMAT: "jdbc:mysql://%s:3306/cosmic" # If the docker ENV for DB_HOST is anything but "db", this string format should be changed from 3306 to 3307 (or whichever port it was changed to in docker)
DB_HOST: "localhost"
DB_USER: "cosmic_server"
DB_PASS: "snailshell"
INIT_CONNECTION_POOL_TIMEOUT: 90 # Seconds

View File

@@ -19993,7 +19993,7 @@ USE `cosmic`;
(8220015, 1452015, 1, 1, 0, 22000),
(8220015, 1472031, 1, 1, 0, 22000),
(8220015, 1482010, 1, 1, 0, 22000),
(2110301, 4031568, 1, 1, 3911, 80000),
(2100108, 4031568, 1, 1, 3911, 80000),
(9300150, 4031774, 1, 1, 3361, 100000),
(9300150, 4031796, 1, 1, 3362, 100000),
(9300105, 4001118, 1, 1, 3814, 200000),

View File

@@ -335,7 +335,7 @@ INSERT INTO `shopitems` ( `shopid`, `itemid`, `price`, `pitch`, `position`) VALU
(1301000, 2000006, 620, 0, 156),
(1301000, 2000003, 200, 0, 160),
(1301000, 2000002, 320, 0, 164),
(1301000, 2000015, 160, 0, 168),
(1301000, 2000001, 160, 0, 168),
(1301000, 2000000, 50, 0, 172);
# adding missing pirate items at Singapore npc's

View File

@@ -18,7 +18,7 @@ services:
- ./scripts:/opt/server/scripts
- ./wz:/opt/server/wz
environment:
DB_HOST: "db"
DB_HOST: "db" ## Remember if this is present it will OVERRIDE the host in the config.yaml, if you put here anything other than db, you'll need to change the config.yaml jdbc string to port 3307, and not port 3306
db:
image: mysql:8.0.23
@@ -27,6 +27,8 @@ services:
MYSQL_DATABASE: "cosmic"
MYSQL_USER: "cosmic_server"
MYSQL_PASSWORD: "snailshell"
ports:
- "3307:3306"
volumes:
- ./database/docker-db-data:/var/lib/mysql
- ./database/sql:/docker-entrypoint-initdb.d

View File

@@ -39,7 +39,6 @@ import net.server.Server;
import net.server.channel.Channel;
import net.server.coordinator.login.LoginBypassCoordinator;
import net.server.coordinator.session.Hwid;
import net.server.coordinator.session.IpAddresses;
import net.server.coordinator.session.SessionCoordinator;
import net.server.coordinator.session.SessionCoordinator.AntiMulticlientResult;
import net.server.guild.Guild;
@@ -176,10 +175,7 @@ public class Client extends ChannelInboundHandlerAdapter {
private static String getRemoteAddress(io.netty.channel.Channel channel) {
String remoteAddress = "null";
try {
String hostAddress = ((InetSocketAddress) channel.remoteAddress()).getAddress().getHostAddress();
if (hostAddress != null) {
remoteAddress = IpAddresses.evaluateRemoteAddress(hostAddress); // thanks dyz for noticing Local/LAN/WAN connections not interacting properly
}
remoteAddress = ((InetSocketAddress) channel.remoteAddress()).getAddress().getHostAddress();
} catch (NullPointerException npe) {
log.warn("Unable to get remote address for client", npe);
}

View File

@@ -43,7 +43,7 @@ public class KarmaManipulator {
flag ^= karmaFlag;
flag |= ItemConstants.UNTRADEABLE;
item.setFlag((byte) flag);
item.setFlag(flag);
}
}
@@ -53,6 +53,6 @@ public class KarmaManipulator {
flag |= karmaFlag;
flag &= (0xFFFFFFFF ^ ItemConstants.UNTRADEABLE);
item.setFlag((byte) flag);
item.setFlag(flag);
}
}

View File

@@ -15,7 +15,6 @@ import net.encryption.InitializationVector;
import net.encryption.PacketCodec;
import net.packet.logging.InPacketLogger;
import net.packet.logging.OutPacketLogger;
import net.server.coordinator.session.IpAddresses;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tools.PacketCreator;
@@ -35,10 +34,7 @@ public abstract class ServerChannelInitializer extends ChannelInitializer<Socket
String getRemoteAddress(Channel channel) {
String remoteAddress = "null";
try {
String hostAddress = ((InetSocketAddress) channel.remoteAddress()).getAddress().getHostAddress();
if (hostAddress != null) {
remoteAddress = IpAddresses.evaluateRemoteAddress(hostAddress); // thanks dyz for noticing Local/LAN/WAN connections not interacting properly
}
remoteAddress = ((InetSocketAddress) channel.remoteAddress()).getAddress().getHostAddress();
} catch (NullPointerException npe) {
log.warn("Unable to get remote address from netty Channel: {}", channel, npe);
}

View File

@@ -57,7 +57,7 @@ import server.SkillbookInformationProvider;
import server.ThreadManager;
import server.TimerManager;
import server.expeditions.ExpeditionBossLog;
import server.life.PlayerNPCFactory;
import server.life.PlayerNPC;
import server.quest.Quest;
import service.NoteService;
import tools.DatabaseConnection;
@@ -849,15 +849,15 @@ public class Server {
final ExecutorService initExecutor = Executors.newFixedThreadPool(10);
// Run slow operations asynchronously to make startup faster
final List<Future<?>> futures = new ArrayList<>();
futures.add(initExecutor.submit(() -> SkillFactory.loadAllSkills()));
futures.add(initExecutor.submit(() -> CashItemFactory.loadAllCashItems()));
futures.add(initExecutor.submit(() -> Quest.loadAllQuests()));
futures.add(initExecutor.submit(() -> SkillbookInformationProvider.loadAllSkillbookInformation()));
futures.add(initExecutor.submit(() -> PlayerNPCFactory.loadFactoryMetadata()));
futures.add(initExecutor.submit(SkillFactory::loadAllSkills));
futures.add(initExecutor.submit(CashItemFactory::loadAllCashItems));
futures.add(initExecutor.submit(Quest::loadAllQuests));
futures.add(initExecutor.submit(SkillbookInformationProvider::loadAllSkillbookInformation));
initExecutor.shutdown();
TimeZone.setDefault(TimeZone.getTimeZone(YamlConfig.config.server.TIMEZONE));
final int worldCount = Math.min(GameConstants.WORLD_NAMES.length, YamlConfig.config.server.WORLDS);
try (Connection con = DatabaseConnection.getConnection()) {
setAllLoggedOut(con);
setAllMerchantsInactive(con);
@@ -868,6 +868,7 @@ public class Server {
CashIdGenerator.loadExistentCashIdsFromDb(con);
applyAllNameChanges(con); // -- name changes can be missed by INSTANT_NAME_CHANGE --
applyAllWorldTransfers(con);
PlayerNPC.loadRunningRankData(con, worldCount);
} catch (SQLException sqle) {
log.error("Failed to run all startup-bound database tasks", sqle);
throw new IllegalStateException(sqle);
@@ -877,8 +878,6 @@ public class Server {
initializeTimelyTasks(channelDependencies); // aggregated method for timely tasks thanks to lxconan
try {
int worldCount = Math.min(GameConstants.WORLD_NAMES.length, YamlConfig.config.server.WORLDS);
for (int i = 0; i < worldCount; i++) {
initWorld();
}

View File

@@ -29,6 +29,7 @@ import constants.id.ItemId;
import constants.id.MapId;
import net.AbstractPacketHandler;
import net.packet.InPacket;
import net.server.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import server.Trade;
@@ -181,7 +182,11 @@ public final class ChangeMapHandler extends AbstractPacketHandler {
c.disconnect(false, false);
return;
}
String[] socket = c.getChannelServer().getIP().split(":");
String[] socket = Server.getInstance().getInetSocket(c, c.getWorld(), c.getChannel());
if (socket == null) {
c.enableCSActions();
return;
}
chr.getCashShop().open(false);
chr.setSessionTransitionState();

View File

@@ -45,6 +45,8 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
@@ -122,40 +124,12 @@ public final class MTSHandler extends AbstractPacketHandler {
return;
}
}
Calendar calendar = Calendar.getInstance();
int year;
int month;
int day;
int oldmax = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
int oldday = calendar.get(Calendar.DAY_OF_MONTH) + 7;
if (oldmax < oldday) {
if (calendar.get(Calendar.MONTH) + 2 > 12) {
year = calendar.get(Calendar.YEAR) + 1;
month = 1;
calendar.set(year, month, 1);
day = oldday - oldmax;
} else {
month = calendar.get(Calendar.MONTH) + 2;
year = calendar.get(Calendar.YEAR);
calendar.set(year, month, 1);
day = oldday - oldmax;
}
} else {
day = calendar.get(Calendar.DAY_OF_MONTH) + 7;
month = calendar.get(Calendar.MONTH);
year = calendar.get(Calendar.YEAR);
}
String date = year + "-";
if (month < 10) {
date += "0" + month + "-";
} else {
date += month + "-";
}
if (day < 10) {
date += "0" + day;
} else {
date += day + "";
}
LocalDate now = LocalDate.now();
LocalDate sellEnd = now.plusDays(7);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String date = sellEnd.format(formatter);
if (!i.getInventoryType().equals(InventoryType.EQUIP)) {
Item item = i;
try (PreparedStatement pse = con.prepareStatement("INSERT INTO mts_items (tab, type, itemid, quantity, expiration, giftFrom, seller, price, owner, sellername, sell_ends) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) {
@@ -761,7 +735,7 @@ public final class MTSHandler extends AbstractPacketHandler {
}
}
}
try (PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM mts_items WHERE tab = ? " + (type != 0 ? "AND type = ?" : "") + "AND transfer = 0")) {
try (PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM mts_items WHERE tab = ? " + (type != 0 ? "AND type = ?" : "") + " AND transfer = 0")) {
ps.setInt(1, tab);
if (type != 0) {
ps.setInt(2, type);

View File

@@ -1,7 +1,5 @@
package net.server.coordinator.session;
import config.YamlConfig;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -16,14 +14,6 @@ public class IpAddresses {
.collect(Collectors.toList());
}
public static String evaluateRemoteAddress(String inetAddress) {
if (isLocalAddress(inetAddress) || isLanAddress(inetAddress)) {
return YamlConfig.config.server.HOST;
} else {
return inetAddress;
}
}
public static boolean isLocalAddress(String inetAddress) {
return inetAddress.startsWith("127.");
}

View File

@@ -23,6 +23,8 @@ package server;
import client.inventory.Item;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
/**
@@ -38,13 +40,16 @@ public class MTSItemInfo {
private int day = 1;
public MTSItemInfo(Item item, int price, int id, int cid, String seller, String date) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate sellEnd = LocalDate.parse(date, formatter);
this.item = item;
this.price = price;
this.seller = seller;
this.id = id;
this.year = Integer.parseInt(date.substring(0, 4));
this.month = Integer.parseInt(date.substring(5, 7));
this.day = Integer.parseInt(date.substring(8, 10));
this.year = sellEnd.getYear();
this.month = sellEnd.getMonthValue();
this.day = sellEnd.getDayOfMonth();
}
public Item getItem() {

View File

@@ -53,6 +53,8 @@ import java.util.concurrent.atomic.AtomicInteger;
* @author XoticStory
* @author Ronan
*/
// TODO: remove dependency on custom Npc.wz. All NPCs with id 9901910 and above are custom additions for player npcs.
// In summary: NPCs 9901910-9906599 and 9977777 are custom additions to HeavenMS that should be removed.
public class PlayerNPC extends AbstractMapObject {
private static final Logger log = LoggerFactory.getLogger(PlayerNPC.class);
private static final Map<Byte, List<Integer>> availablePlayerNpcScriptIds = new HashMap<>();
@@ -67,10 +69,6 @@ public class PlayerNPC extends AbstractMapObject {
private int dir, FH, RX0, RX1, CY;
private int worldRank, overallRank, worldJobRank, overallJobRank;
static {
getRunningMetadata();
}
public PlayerNPC(String name, int scriptId, int face, int hair, int gender, byte skin, Map<Short, Integer> equips, int dir, int FH, int RX0, int RX1, int CX, int CY, int oid) {
this.equips = equips;
this.scriptId = scriptId;
@@ -128,6 +126,12 @@ public class PlayerNPC extends AbstractMapObject {
}
}
public static void loadRunningRankData(Connection con, int worlds) throws SQLException {
getRunningOverallRanks(con);
getRunningWorldRanks(con, worlds);
getRunningWorldJobRanks(con);
}
public Map<Short, Integer> getEquips() {
return equips;
}
@@ -213,16 +217,6 @@ public class PlayerNPC extends AbstractMapObject {
client.sendPacket(PacketCreator.removePlayerNPC(this.getObjectId()));
}
private static void getRunningMetadata() {
try (Connection con = DatabaseConnection.getConnection()) {
getRunningOverallRanks(con);
getRunningWorldRanks(con);
getRunningWorldJobRanks(con);
} catch (SQLException e) {
e.printStackTrace();
}
}
private static void getRunningOverallRanks(Connection con) throws SQLException {
try (PreparedStatement ps = con.prepareStatement("SELECT max(overallrank) FROM playernpcs");
ResultSet rs = ps.executeQuery()) {
@@ -235,9 +229,8 @@ public class PlayerNPC extends AbstractMapObject {
}
}
private static void getRunningWorldRanks(Connection con) throws SQLException {
int numWorlds = Server.getInstance().getWorldsSize();
for (int i = 0; i < numWorlds; i++) {
private static void getRunningWorldRanks(Connection con, int worlds) throws SQLException {
for (int i = 0; i < worlds; i++) {
runningWorldRank.add(new AtomicInteger(1));
}
@@ -246,7 +239,7 @@ public class PlayerNPC extends AbstractMapObject {
while (rs.next()) {
int wid = rs.getInt(1);
if (wid < numWorlds) {
if (wid < worlds) {
runningWorldRank.get(wid).set(rs.getInt(2) + 1);
}
}
@@ -649,4 +642,4 @@ public class PlayerNPC extends AbstractMapObject {
e.printStackTrace();
}
}
}
}

View File

@@ -19,124 +19,17 @@
*/
package server.life;
import constants.id.ItemId;
import constants.id.MapId;
import constants.id.NpcId;
import net.server.Server;
import provider.Data;
import provider.DataProvider;
import provider.DataProviderFactory;
import provider.DataTool;
import provider.wz.WZFiles;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* @author RonanLana
*/
public class PlayerNPCFactory {
private static final DataProvider npcData = DataProviderFactory.getDataProvider(WZFiles.NPC);
private static final Map<Integer, List<PlayerNPC>> dnpcMaps = new HashMap<>();
private static Integer runningDeveloperOid = 2147483000; // 647 slots, long enough
public synchronized static boolean isExistentScriptid(int scriptid) {
return npcData.getData(scriptid + ".img") != null;
}
private static void loadDeveloperRoomMetadata(DataProvider npc) {
Data thisData = npc.getData(NpcId.CUSTOM_DEV + ".img");
if (thisData != null) {
DataProvider map = DataProviderFactory.getDataProvider(WZFiles.MAP);
thisData = map.getData("Map/Map7/" + MapId.DEVELOPERS_HQ + ".img");
if (thisData != null) {
DataProvider sound = DataProviderFactory.getDataProvider(WZFiles.SOUND);
thisData = sound.getData("Field.img");
if (thisData != null) {
Data md = thisData.getChildByPath("anthem/brazil");
if (md != null) {
Server.getInstance().setAvailableDeveloperRoom();
}
}
}
}
}
public synchronized static void loadFactoryMetadata() {
DataProvider npc = npcData;
loadDeveloperRoomMetadata(npc);
DataProvider etc = DataProviderFactory.getDataProvider(WZFiles.ETC);
Data dnpcData = etc.getData("DeveloperNpc.img");
if (dnpcData != null) {
for (Data data : dnpcData.getChildren()) {
int scriptId = Integer.parseInt(data.getName());
String name = DataTool.getString("name", data, "");
int face = DataTool.getIntConvert("face", data, 20000);
int hair = DataTool.getIntConvert("hair", data, 30000);
int gender = DataTool.getIntConvert("gender", data, 0);
byte skin = (byte) DataTool.getIntConvert("skin", data, 0);
int dir = DataTool.getIntConvert("dir", data, 0);
int mapid = DataTool.getIntConvert("map", data, 0);
int FH = DataTool.getIntConvert("fh", data, 0);
int RX0 = DataTool.getIntConvert("rx0", data, 0);
int RX1 = DataTool.getIntConvert("rx1", data, 0);
int CX = DataTool.getIntConvert("cx", data, 0);
int CY = DataTool.getIntConvert("cy", data, 0);
Map<Short, Integer> equips = new HashMap<>();
for (Data edata : data.getChildByPath("equips").getChildren()) {
short equippos = (short) DataTool.getIntConvert("pos", edata);
int equipid = DataTool.getIntConvert("itemid", edata);
equips.put(equippos, equipid);
}
List<PlayerNPC> dnpcSet = dnpcMaps.get(mapid);
if (dnpcSet == null) {
dnpcSet = new LinkedList<>();
dnpcMaps.put(mapid, dnpcSet);
}
dnpcSet.add(new PlayerNPC(name, scriptId, face, hair, gender, skin, equips, dir, FH, RX0, RX1, CX, CY, runningDeveloperOid));
runningDeveloperOid++;
}
} else {
Data thisData = npc.getData(NpcId.CUSTOM_DEV + ".img");
if (thisData != null) {
byte[] encData = {0x52, 0x6F, 0x6E, 0x61, 0x6E};
String name = new String(encData);
int face = 20104, hair = 30215, gender = 0, skin = 0, dir = 0, mapid = MapId.DEVELOPERS_HQ;
int FH = 4, RX0 = -143, RX1 = -243, CX = -193, CY = 117, scriptId = NpcId.CUSTOM_DEV;
Map<Short, Integer> equips = new HashMap<>();
equips.put((short) -1, ItemId.GREEN_HEADBAND);
equips.put((short) -11, ItemId.TIMELESS_NIBLEHEIM);
equips.put((short) -8, ItemId.BLUE_KORBEN);
equips.put((short) -6, ItemId.MITHRIL_PLATINE_PANTS);
equips.put((short) -7, ItemId.BLUE_CARZEN_BOOTS);
equips.put((short) -5, ItemId.MITHRIL_PLATINE);
List<PlayerNPC> dnpcSet = dnpcMaps.get(mapid);
if (dnpcSet == null) {
dnpcSet = new LinkedList<>();
dnpcMaps.put(mapid, dnpcSet);
}
dnpcSet.add(new PlayerNPC(name, scriptId, face, hair, gender, (byte) skin, equips, dir, FH, RX0, RX1, CX, CY, runningDeveloperOid));
runningDeveloperOid++;
}
}
}
public synchronized static List<PlayerNPC> getDeveloperNpcsFromMapid(int mapid) {
return dnpcMaps.get(mapid);
}
}

View File

@@ -28,7 +28,10 @@ import provider.DataProviderFactory;
import provider.DataTool;
import provider.wz.WZFiles;
import scripting.event.EventInstanceManager;
import server.life.*;
import server.life.AbstractLoadedLife;
import server.life.LifeFactory;
import server.life.Monster;
import server.life.PlayerNPC;
import server.partyquest.GuardianSpawnPoint;
import tools.DatabaseConnection;
import tools.StringUtil;
@@ -249,13 +252,6 @@ public class MapFactory {
} catch (SQLException e) {
e.printStackTrace();
}
List<PlayerNPC> dnpcs = PlayerNPCFactory.getDeveloperNpcsFromMapid(mapid);
if (dnpcs != null) {
for (PlayerNPC dnpc : dnpcs) {
map.addPlayerNPCMapObject(dnpc);
}
}
}
loadLifeFromWz(map, mapData);