Merge branch 'development' into unstable

# Conflicts:
#	src/generated/main/java/emu/grasscutter/net/proto/ResinChangeNotifyOuterClass.java
#	src/main/java/emu/grasscutter/game/managers/ResinManager.java
#	src/main/java/emu/grasscutter/game/player/Player.java
#	src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseAddItem.java
#	src/main/java/emu/grasscutter/server/packet/send/PacketResinChangeNotify.java
This commit is contained in:
KingRainbow44
2023-04-10 01:49:12 -04:00
13 changed files with 3313 additions and 940 deletions

View File

@@ -1,154 +1,179 @@
package emu.grasscutter.game.managers;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
import emu.grasscutter.game.player.BasePlayerManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.server.packet.send.PacketResinChangeNotify;
import emu.grasscutter.utils.Utils;
public class ResinManager extends BasePlayerManager {
public ResinManager(Player player) {
super(player);
}
/********************
* Change resin.
********************/
public synchronized boolean useResin(int amount) {
// Check if resin enabled.
if (!GAME_OPTIONS.resinOptions.resinUsage) {
return true;
}
int currentResin = this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
// Check if the player has sufficient resin.
if (currentResin < amount) {
return false;
}
// Deduct the resin from the player.
int newResin = currentResin - amount;
this.player.setProperty(PlayerProperty.PROP_PLAYER_RESIN, newResin);
// Check if this has taken the player under the recharge cap,
// starting the recharging process.
if (this.player.getNextResinRefresh() == 0 && newResin < GAME_OPTIONS.resinOptions.cap) {
int currentTime = Utils.getCurrentSeconds();
this.player.setNextResinRefresh(currentTime + GAME_OPTIONS.resinOptions.rechargeTime);
}
// Send packets.
this.player.sendPacket(new PacketResinChangeNotify(this.player));
// Battle Pass trigger
this.player
.getBattlePassManager()
.triggerMission(
WatcherTriggerType.TRIGGER_COST_MATERIAL, 106, amount); // Resin item id = 106
return true;
}
public synchronized boolean useCondensedResin(int amount) {
// Don't deduct if resin disabled.
if (!GAME_OPTIONS.resinOptions.resinUsage) return true;
return this.player.getInventory().payItem(220007, amount);
}
public synchronized void addResin(int amount) {
// Check if resin enabled.
if (!GAME_OPTIONS.resinOptions.resinUsage) {
return;
}
// Add resin.
int currentResin = this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
int newResin = currentResin + amount;
this.player.setProperty(PlayerProperty.PROP_PLAYER_RESIN, newResin);
// Stop recharging if player is now at or over the cap.
if (newResin >= GAME_OPTIONS.resinOptions.cap) {
this.player.setNextResinRefresh(0);
}
// Send packets.
this.player.sendPacket(new PacketResinChangeNotify(this.player));
}
/********************
* Recharge resin.
********************/
public synchronized void rechargeResin() {
// Check if resin enabled.
if (!GAME_OPTIONS.resinOptions.resinUsage) {
return;
}
int currentResin = this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
int currentTime = Utils.getCurrentSeconds();
// Make sure we are currently in "recharging mode".
// This is denoted by Player.nextResinRefresh being greater than 0.
if (this.player.getNextResinRefresh() <= 0) {
return;
}
// Determine if we actually need to recharge yet.
if (currentTime < this.player.getNextResinRefresh()) {
return;
}
// Calculate how much resin we need to refill and update player.
// Note that this can be more than one in case the player
// logged off with uncapped resin and is now logging in again.
int recharge =
1
+ ((currentTime - this.player.getNextResinRefresh())
/ GAME_OPTIONS.resinOptions.rechargeTime);
int newResin = Math.min(GAME_OPTIONS.resinOptions.cap, currentResin + recharge);
int resinChange = newResin - currentResin;
this.player.setProperty(PlayerProperty.PROP_PLAYER_RESIN, newResin);
// Calculate next recharge time.
// Set to zero to disable recharge (because on/over cap.)
if (newResin >= GAME_OPTIONS.resinOptions.cap) {
this.player.setNextResinRefresh(0);
} else {
int nextRecharge =
this.player.getNextResinRefresh() + resinChange * GAME_OPTIONS.resinOptions.rechargeTime;
this.player.setNextResinRefresh(nextRecharge);
}
// Send packets.
this.player.sendPacket(new PacketResinChangeNotify(this.player));
}
/********************
* Player login.
********************/
public synchronized void onPlayerLogin() {
// If resin usage is disabled, set resin to cap.
if (!GAME_OPTIONS.resinOptions.resinUsage) {
this.player.setProperty(PlayerProperty.PROP_PLAYER_RESIN, GAME_OPTIONS.resinOptions.cap);
this.player.setNextResinRefresh(0);
}
// In case server administrators change the resin cap while players are capped,
// we need to restart recharging here.
int currentResin = this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
int currentTime = Utils.getCurrentSeconds();
if (currentResin < GAME_OPTIONS.resinOptions.cap && this.player.getNextResinRefresh() == 0) {
this.player.setNextResinRefresh(currentTime + GAME_OPTIONS.resinOptions.rechargeTime);
}
// Send initial notifications on logon.
this.player.sendPacket(new PacketResinChangeNotify(this.player));
}
}
package emu.grasscutter.game.managers;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.BasePlayerManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.net.proto.RetcodeOuterClass;
import emu.grasscutter.server.packet.send.PacketItemAddHintNotify;
import emu.grasscutter.server.packet.send.PacketResinChangeNotify;
import emu.grasscutter.utils.Utils;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
public class ResinManager extends BasePlayerManager {
public static final int MAX_RESIN_BUYING_COUNT = 6;
public static final int AMOUNT_TO_ADD = 60;
public static final int[] HCOIN_NUM_TO_BUY_RESIN = new int[]{50, 100, 100, 150, 200, 200};
public ResinManager(Player player) {
super(player);
}
/********************
* Change resin.
********************/
public synchronized boolean useResin(int amount) {
// Check if resin enabled.
if (!GAME_OPTIONS.resinOptions.resinUsage) {
return true;
}
int currentResin = this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
// Check if the player has sufficient resin.
if (currentResin < amount) {
return false;
}
// Deduct the resin from the player.
int newResin = currentResin - amount;
this.player.setProperty(PlayerProperty.PROP_PLAYER_RESIN, newResin);
// Check if this has taken the player under the recharge cap,
// starting the recharging process.
if (this.player.getNextResinRefresh() == 0 && newResin < GAME_OPTIONS.resinOptions.cap) {
int currentTime = Utils.getCurrentSeconds();
this.player.setNextResinRefresh(currentTime + GAME_OPTIONS.resinOptions.rechargeTime);
}
// Send packets.
this.player.sendPacket(new PacketResinChangeNotify(this.player));
// Battle Pass trigger
this.player
.getBattlePassManager()
.triggerMission(
WatcherTriggerType.TRIGGER_COST_MATERIAL, 106, amount); // Resin item id = 106
return true;
}
public synchronized boolean useCondensedResin(int amount) {
// Don't deduct if resin disabled.
if (!GAME_OPTIONS.resinOptions.resinUsage) return true;
return this.player.getInventory().payItem(220007, amount);
}
public synchronized void addResin(int amount) {
// Check if resin enabled.
if (!GAME_OPTIONS.resinOptions.resinUsage) {
return;
}
// Add resin.
int currentResin = this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
int newResin = currentResin + amount;
this.player.setProperty(PlayerProperty.PROP_PLAYER_RESIN, newResin);
// Stop recharging if player is now at or over the cap.
if (newResin >= GAME_OPTIONS.resinOptions.cap) {
this.player.setNextResinRefresh(0);
}
// Send packets.
this.player.sendPacket(new PacketResinChangeNotify(this.player));
}
/********************
* Recharge resin.
********************/
public synchronized void rechargeResin() {
// Check if resin enabled.
if (!GAME_OPTIONS.resinOptions.resinUsage) {
return;
}
int currentResin = this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
int currentTime = Utils.getCurrentSeconds();
// Make sure we are currently in "recharging mode".
// This is denoted by Player.nextResinRefresh being greater than 0.
if (this.player.getNextResinRefresh() <= 0) {
return;
}
// Determine if we actually need to recharge yet.
if (currentTime < this.player.getNextResinRefresh()) {
return;
}
// Calculate how much resin we need to refill and update player.
// Note that this can be more than one in case the player
// logged off with uncapped resin and is now logging in again.
int recharge =
1
+ ((currentTime - this.player.getNextResinRefresh())
/ GAME_OPTIONS.resinOptions.rechargeTime);
int newResin = Math.min(GAME_OPTIONS.resinOptions.cap, currentResin + recharge);
int resinChange = newResin - currentResin;
this.player.setProperty(PlayerProperty.PROP_PLAYER_RESIN, newResin);
// Calculate next recharge time.
// Set to zero to disable recharge (because on/over cap.)
if (newResin >= GAME_OPTIONS.resinOptions.cap) {
this.player.setNextResinRefresh(0);
} else {
int nextRecharge =
this.player.getNextResinRefresh() + resinChange * GAME_OPTIONS.resinOptions.rechargeTime;
this.player.setNextResinRefresh(nextRecharge);
}
// Send packets.
this.player.sendPacket(new PacketResinChangeNotify(this.player));
}
/********************
* Player login.
********************/
public synchronized void onPlayerLogin() {
// If resin usage is disabled, set resin to cap.
if (!GAME_OPTIONS.resinOptions.resinUsage) {
this.player.setProperty(PlayerProperty.PROP_PLAYER_RESIN, GAME_OPTIONS.resinOptions.cap);
this.player.setNextResinRefresh(0);
}
// In case server administrators change the resin cap while players are capped,
// we need to restart recharging here.
int currentResin = this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
int currentTime = Utils.getCurrentSeconds();
if (currentResin < GAME_OPTIONS.resinOptions.cap && this.player.getNextResinRefresh() == 0) {
this.player.setNextResinRefresh(currentTime + GAME_OPTIONS.resinOptions.rechargeTime);
}
// Send initial notifications on logon.
this.player.sendPacket(new PacketResinChangeNotify(this.player));
}
public int buy() {
if (this.player.getResinBuyCount() >= MAX_RESIN_BUYING_COUNT) {
return RetcodeOuterClass.Retcode.RET_RESIN_BOUGHT_COUNT_EXCEEDED_VALUE;
}
var res = this.player.getInventory().payItem(201, HCOIN_NUM_TO_BUY_RESIN[this.player.getResinBuyCount()]);
if (!res) {
return RetcodeOuterClass.Retcode.RET_HCOIN_NOT_ENOUGH_VALUE;
}
this.player.setResinBuyCount(this.player.getResinBuyCount() + 1);
this.player.setProperty(PlayerProperty.PROP_PLAYER_WAIT_SUB_HCOIN, 0);
this.addResin(AMOUNT_TO_ADD);
this.player.sendPacket(new PacketItemAddHintNotify(new GameItem(106, AMOUNT_TO_ADD), ActionReason.BuyResin));
return 0;
}
}

View File

@@ -319,9 +319,12 @@ public class Player {
private int nextResinRefresh;
@Getter
@Setter
private int resinBuyCount;
@Getter
@Setter
private int lastDailyReset;
@Getter
private final transient MpSettingType mpSetting = MpSettingType.MP_SETTING_TYPE_ENTER_AFTER_APPLY; // TODO
private transient MpSettingType mpSetting = MpSettingType.MP_SETTING_TYPE_ENTER_AFTER_APPLY; // TODO
@Deprecated
@SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only!
@@ -1269,6 +1272,9 @@ public class Player {
this.getBattlePassManager().resetWeeklyMissions();
}
// Reset resin-buying count.
this.setResinBuyCount(0);
// Done. Update last reset time.
this.setLastDailyReset(currentTime);
}

View File

@@ -1,25 +1,25 @@
package emu.grasscutter.game.props.ItemUseAction;
import emu.grasscutter.game.props.ItemUseOp;
public class ItemUseAddItem extends ItemUseInt {
private int count = 0;
public ItemUseAddItem(String[] useParam) {
super(useParam);
try {
this.count = Integer.parseInt(useParam[1]);
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {
}
}
@Override
public ItemUseOp getItemUseOp() {
return ItemUseOp.ITEM_USE_ADD_ITEM;
}
@Override
public boolean useItem(UseItemParams params) {
return params.player.getInventory().addItem(this.i, this.count * params.count);
}
}
package emu.grasscutter.game.props.ItemUseAction;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.ItemUseOp;
public class ItemUseAddItem extends ItemUseInt {
private int count = 0;
@Override
public ItemUseOp getItemUseOp() {
return ItemUseOp.ITEM_USE_ADD_ITEM;
}
public ItemUseAddItem(String[] useParam) {
super(useParam);
try {
this.count = Integer.parseInt(useParam[1]);
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
}
@Override
public boolean useItem(UseItemParams params) {
return params.player.getInventory().addItem(this.i, this.count * params.count, ActionReason.PlayerUseItem);
}
}

View File

@@ -0,0 +1,16 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketBuyResinRsp;
@Opcodes(PacketOpcodes.BuyResinReq)
public class HandlerBuyResinReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var player = session.getPlayer();
session.send(new PacketBuyResinRsp(player, player.getResinManager().buy()));
}
}

View File

@@ -0,0 +1,31 @@
package emu.grasscutter.server.packet.recv;
import javax.lang.model.type.TypeMirror;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.SceneAudioNotifyOuterClass.SceneAudioNotify;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketSceneAudioNotify;
import java.util.List;
@Opcodes(PacketOpcodes.SceneAudioNotify)
public class HandlerSceneAudioNotify extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
SceneAudioNotify notify = SceneAudioNotify.parseFrom(payload);
int sourceUid = notify.getSourceUid();
List<Float> param2 = notify.getParam2List();
List<String> param3 = notify.getParam3List();
int type = notify.getType();
List<Integer> param1 = notify.getParam1List();
session.getPlayer().getScene().broadcastPacket(new PacketSceneAudioNotify(sourceUid, param2, param3, type, param1));
}
}

View File

@@ -0,0 +1,18 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.BuyResinRspOuterClass;
public class PacketBuyResinRsp extends BasePacket {
public PacketBuyResinRsp(Player player, int ret) {
super(PacketOpcodes.BuyResinRsp);
this.setData(BuyResinRspOuterClass.BuyResinRsp.newBuilder()
.setCurValue(player.getProperty(PlayerProperty.PROP_PLAYER_RESIN))
.setRetcode(ret)
.build());
}
}

View File

@@ -1,24 +1,22 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.ResinChangeNotifyOuterClass.ResinChangeNotify;
public class PacketResinChangeNotify extends BasePacket {
public PacketResinChangeNotify(Player player) {
super(PacketOpcodes.ResinChangeNotify);
ResinChangeNotify proto =
ResinChangeNotify.newBuilder()
.setCurValue(player.getProperty(PlayerProperty.PROP_PLAYER_RESIN))
.setNextAddTimestamp(player.getNextResinRefresh())
.build();
// ToDo: Add ability to buy resin with primogems, has to be included here.
this.setData(proto);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.ResinChangeNotifyOuterClass.ResinChangeNotify;
public class PacketResinChangeNotify extends BasePacket {
public PacketResinChangeNotify(Player player) {
super(PacketOpcodes.ResinChangeNotify);
ResinChangeNotify proto = ResinChangeNotify.newBuilder()
.setCurValue(player.getProperty(PlayerProperty.PROP_PLAYER_RESIN))
.setNextAddTimestamp(player.getNextResinRefresh())
.setCurBuyCount(player.getResinBuyCount())
.build();
this.setData(proto);
}
}

View File

@@ -0,0 +1,23 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.SceneAudioNotifyOuterClass;
import java.util.List;
public class PacketSceneAudioNotify extends BasePacket {
public PacketSceneAudioNotify(int sourceUid, List<Float> param2, List<String> param3, int type, List<Integer> param1) {
super(PacketOpcodes.SceneAudioNotify);
SceneAudioNotifyOuterClass.SceneAudioNotify proto = SceneAudioNotifyOuterClass.SceneAudioNotify.newBuilder()
.setSourceUid(sourceUid)
.addAllParam2(param2)
.addAllParam3(param3)
.setType(type)
.addAllParam1(param1)
.build();
this.setData(proto);
}
}