Commit 65861c3c authored by Akka's avatar Akka Committed by GitHub
Browse files

Merge pull request #7 from Grasscutters/development

Development
parents c2d2a37f 176f3e91
package emu.grasscutter.game.managers.StaminaManager;
public enum ConsumptionType {
None(0),
// consume
CLIMB_START(-500),
CLIMBING(-150),
CLIMB_JUMP(-2500),
SPRINT(-1800),
DASH(-360),
FLY(-60),
SWIM_DASH_START(-20),
SWIM_DASH(-204),
SWIMMING(-80), // TODO: Slow swimming is handled per movement, not per second. Movement frequency depends on gender/age/height.
FIGHT(0), // See StaminaManager.getFightConsumption()
// restore
STANDBY(500),
RUN(500),
WALK(500),
STANDBY_MOVE(500),
POWERED_FLY(500);
public final int amount;
ConsumptionType(int amount) {
this.amount = amount;
}
}
\ No newline at end of file
# Stamina Manager
---
## UpdateStamina
```java
// will use consumption.consumptionType as reason
public int updateStaminaRelative(GameSession session, Consumption consumption);
```
```java
public int updateStaminaAbsolute(GameSession session, String reason, int newStamina)
```
---
## Pause and Resume
```java
public void startSustainedStaminaHandler()
```
```java
public void stopSustainedStaminaHandler()
```
---
## Stamina change listeners and intercepting
### BeforeUpdateStaminaListener
```java
import emu.grasscutter.game.managers.StaminaManager.BeforeUpdateStaminaListener;
// Listener sample: plugin disable CLIMB_JUMP stamina cost.
private class MyClass implements BeforeUpdateStaminaListener {
// Make your class implement the listener, and pass in your class as a listener.
public MyClass() {
getStaminaManager().registerBeforeUpdateStaminaListener("myClass", this);
}
@Override
public boolean onBeforeUpdateStamina(String reason, int newStamina) {
// do not intercept this update
return false;
}
@Override
public boolean onBeforeUpdateStamina(String reason, Consumption consumption) {
// Try to intercept if this update is CLIMB_JUMP
if (consumption.consumptionType == ConsumptionType.CLIMB_JUMP) {
return true;
}
// If it is not CLIMB_JUMP, do not intercept.
return false;
}
}
```
### AfterUpdateStaminaListener
```java
import emu.grasscutter.game.managers.StaminaManager.AfterUpdateStaminaListener;
// Listener sample: plugin listens for changes already made.
private class MyClass implements AfterUpdateStaminaListener {
// Make your class implement the listener, and pass in your class as a listener.
public MyClass() {
registerAfterUpdateStaminaListener("myClass", this);
}
@Override
public void onAfterUpdateStamina(String reason, int newStamina) {
// ...
}
}
```
\ No newline at end of file
......@@ -557,7 +557,7 @@ public class TeamManager {
// return;
// }
// }
player.getMovementManager().resetTimer(); // prevent drowning immediately after respawn
player.getStaminaManager().stopSustainedStaminaHandler(); // prevent drowning immediately after respawn
// Revive all team members
for (EntityAvatar entity : getActiveTeam()) {
......
......@@ -4,13 +4,7 @@ import com.google.gson.reflect.TypeToken;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.def.ItemData;
import emu.grasscutter.data.def.ShopGoodsData;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.managers.InventoryManager;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.net.proto.ItemParamOuterClass;
import emu.grasscutter.net.proto.ShopGoodsOuterClass;
import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
......@@ -54,9 +48,9 @@ public class ShopManager {
public static int getShopNextRefreshTime(ShopInfo shopInfo) {
return switch (shopInfo.getShopRefreshType()) {
case SHOP_REFRESH_DAILY -> Utils.GetNextTimestampOfThisHour(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_WEEKLY -> Utils.GetNextTimestampOfThisHourInNextWeek(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_MONTHLY -> Utils.GetNextTimestampOfThisHourInNextMonth(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_DAILY -> Utils.getNextTimestampOfThisHour(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_WEEKLY -> Utils.getNextTimestampOfThisHourInNextWeek(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_MONTHLY -> Utils.getNextTimestampOfThisHourInNextMonth(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
default -> 0;
};
}
......
......@@ -7,6 +7,7 @@ import emu.grasscutter.data.def.TowerLevelData;
import emu.grasscutter.game.dungeons.DungeonSettleListener;
import emu.grasscutter.game.dungeons.TowerDungeonSettleListener;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify;
import emu.grasscutter.server.packet.send.PacketTowerCurLevelRecordChangeNotify;
import emu.grasscutter.server.packet.send.PacketTowerEnterLevelRsp;
......@@ -15,9 +16,7 @@ import java.util.List;
@Entity
public class TowerManager {
@Transient private final Player player;
@Transient private Player player;
public TowerManager(Player player) {
this.player = player;
......@@ -77,7 +76,8 @@ public class TowerManager {
player.getScene().setPrevScenePoint(enterPointId);
player.getSession().send(new PacketTowerEnterLevelRsp(currentFloorId, currentLevel));
// stop using skill
player.getSession().send(new PacketCanUseSkillNotify(false));
}
public void notifyCurLevelRecordChange(){
......
......@@ -105,7 +105,13 @@ public class Scene {
public GameEntity getEntityById(int id) {
return this.entities.get(id);
}
public GameEntity getEntityByConfigId(int configId) {
return this.entities.values().stream()
.filter(x -> x.getConfigId() == configId)
.findFirst()
.orElse(null);
}
/**
* @return the autoCloseTime
*/
......
This diff is collapsed.
......@@ -4,12 +4,12 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.server.event.Event;
import emu.grasscutter.server.event.EventHandler;
import emu.grasscutter.server.event.HandlerPriority;
import emu.grasscutter.utils.EventConsumer;
import emu.grasscutter.utils.Utils;
import java.io.File;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
......@@ -47,12 +47,23 @@ public final class PluginManager {
List<File> plugins = Arrays.stream(files)
.filter(file -> file.getName().endsWith(".jar"))
.toList();
URL[] pluginNames = new URL[plugins.size()];
plugins.forEach(plugin -> {
try {
pluginNames[plugins.indexOf(plugin)] = plugin.toURI().toURL();
} catch (MalformedURLException exception) {
Grasscutter.getLogger().warn("Unable to load plugin.", exception);
}
});
URLClassLoader classLoader = new URLClassLoader(pluginNames);
plugins.forEach(plugin -> {
try {
URL url = plugin.toURI().toURL();
try (URLClassLoader loader = new URLClassLoader(new URL[]{url})) {
URL configFile = loader.findResource("plugin.json");
URL configFile = loader.findResource("plugin.json"); // Find the plugin.json file for each plugin.
InputStreamReader fileReader = new InputStreamReader(configFile.openStream());
PluginConfig pluginConfig = Grasscutter.getGsonFactory().fromJson(fileReader, PluginConfig.class);
......@@ -68,10 +79,10 @@ public final class PluginManager {
JarEntry entry = entries.nextElement();
if(entry.isDirectory() || !entry.getName().endsWith(".class") || entry.getName().contains("module-info")) continue;
String className = entry.getName().replace(".class", "").replace("/", ".");
loader.loadClass(className);
classLoader.loadClass(className); // Use the same class loader for ALL plugins.
}
Class<?> pluginClass = loader.loadClass(pluginConfig.mainClass);
Class<?> pluginClass = classLoader.loadClass(pluginConfig.mainClass);
Plugin pluginInstance = (Plugin) pluginClass.getDeclaredConstructor().newInstance();
this.loadPlugin(pluginInstance, PluginIdentifier.fromPluginConfig(pluginConfig), loader);
......@@ -156,6 +167,10 @@ public final class PluginManager {
.toList().forEach(handler -> this.invokeHandler(event, handler));
}
public Plugin getPlugin(String name) {
return this.plugins.get(name);
}
/**
* Performs logic checks then invokes the provided event handler.
* @param event The event passed through to the handler.
......@@ -167,4 +182,4 @@ public final class PluginManager {
(event.isCanceled() && handler.ignoresCanceled())
) handler.getCallback().consume((T) event);
}
}
\ No newline at end of file
}
......@@ -28,6 +28,7 @@ public final class PlayerHook {
/**
* Kicks a player from the server.
* TODO: Refactor to kick using a packet.
*/
public void kick() {
this.player.getSession().close();
......
# Grasscutter Plugin API
**Warning!** As of now, this is a work in progress and isn't completely documented.
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment