Commit a95002fd authored by zhaodice's avatar zhaodice Committed by GitHub
Browse files

Hunting and deforestation support. (#1083)



* add drops for animals wild pig,fishes,foxes,birds

* append fox

* Deforestation Support

implement drop woods when attacking tree

* Deforestation support (remove prints)

implement drop woods when attacking tree

* Deforestation support (remove prints)

implement drop woods when attacking tree

* add AutoRecycleHashMap

Map's KEY is automatic expire if key long time no use (query or modify from HashMap)

* use AutoRecycleHashMap in case of memory leak

* fix bug

* remove prints

* static AutoRecycleHashMap

* fix problems

* Delete AutoRecycleHashMap.java

* remove log

* fix build

* improve

* remove unnecessary information
Co-authored-by: default avatarAlbedo <105265570+arub3do@users.noreply.github.com>
Co-authored-by: default avatarAlbedo <105265570+arub3do@users.noreply.github.com>
parent 830ac793
package emu.grasscutter.game.managers.DeforestationManager;
import java.util.ArrayList;
import java.util.HashMap;
import dev.morphia.annotations.Transient;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.entity.EntityItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.HitTreeNotifyOuterClass;
import emu.grasscutter.net.proto.VectorOuterClass;
import emu.grasscutter.utils.Position;
public class DeforestationManager {
final static int RECORD_EXPIRED_SECONDS = 60*5; // 5 min
final static int RECORD_MAX_TIMES = 3; // max number of wood
final static int RECORD_MAX_TIMES_OTHER_HIT_TREE = 10; // if hit 10 times other trees, reset wood
@Transient private final Player player;
@Transient private final ArrayList<HitTreeRecord> currentRecord;
@Transient private final static HashMap<Integer, Integer> ColliderTypeToWoodItemID = new HashMap<>();
static {
/* define wood types which reflected to item id*/
ColliderTypeToWoodItemID.put(1,101301);
ColliderTypeToWoodItemID.put(2,101302);
ColliderTypeToWoodItemID.put(3,101303);
ColliderTypeToWoodItemID.put(4,101304);
ColliderTypeToWoodItemID.put(5,101305);
ColliderTypeToWoodItemID.put(6,101306);
ColliderTypeToWoodItemID.put(7,101307);
ColliderTypeToWoodItemID.put(8,101308);
ColliderTypeToWoodItemID.put(9,101309);
ColliderTypeToWoodItemID.put(10,101310);
ColliderTypeToWoodItemID.put(11,101311);
ColliderTypeToWoodItemID.put(12,101312);
}
public DeforestationManager(Player player){
this.player = player;
this.currentRecord = new ArrayList<>();
}
public void resetWood(){
synchronized (currentRecord) {
currentRecord.clear();
}
}
public void onDeforestationInvoke(HitTreeNotifyOuterClass.HitTreeNotify hit){
synchronized (currentRecord) {
//Grasscutter.getLogger().info("onDeforestationInvoke! Wood records {}", currentRecord);
VectorOuterClass.Vector hitPosition = hit.getHitPostion();
int woodType = hit.getWoodType();
if (ColliderTypeToWoodItemID.containsKey(woodType)) {// is a available wood type
Scene scene = player.getScene();
int itemId = ColliderTypeToWoodItemID.get(woodType);
int positionHash = hitPosition.hashCode();
HitTreeRecord record = searchRecord(positionHash);
if (record == null) {
record = new HitTreeRecord(positionHash);
}else{
currentRecord.remove(record);// move it to last position
}
currentRecord.add(record);
if(currentRecord.size()>RECORD_MAX_TIMES_OTHER_HIT_TREE){
currentRecord.remove(0);
}
if(record.record()) {
EntityItem entity = new EntityItem(scene,
null,
GameData.getItemDataMap().get(itemId),
new Position(hitPosition.getX(), hitPosition.getY(), hitPosition.getZ()),
1,
false);
scene.addEntity(entity);
}
//record.record()=false : too many wood they have deforested, no more wood dropped!
} else {
Grasscutter.getLogger().warn("No wood type {} found.", woodType);
}
}
// unknown wood type
}
private HitTreeRecord searchRecord(int id){
for (HitTreeRecord record : currentRecord) {
if (record.getUnique() == id) {
return record;
}
}
return null;
}
}
package emu.grasscutter.game.managers.DeforestationManager;
public class HitTreeRecord {
private final int unique;
private short count; // hit this tree times
private long time; // last available hitting time
HitTreeRecord(int unique){
this.count = 0;
this.time = 0;
this.unique = unique;
}
/**
* reset hit time
*/
private void resetTime(){
this.time = System.currentTimeMillis();
}
/**
* commit hit behavior
*/
public boolean record(){
if (this.count < DeforestationManager.RECORD_MAX_TIMES) {
this.count++;
resetTime();
return true;
}
// check expired
boolean isWaiting = System.currentTimeMillis() - this.time < DeforestationManager.RECORD_EXPIRED_SECONDS * 1000L;
if(isWaiting){
return false;
}else{
this.count = 1;
resetTime();
return true;
}
}
/**
* get unique id
*/
public int getUnique(){
return unique;
}
@Override
public String toString() {
return "HitTreeRecord{" +
"unique=" + unique +
", count=" + count +
", time=" + time +
'}';
}
}
...@@ -11,6 +11,7 @@ import emu.grasscutter.game.ability.AbilityManager; ...@@ -11,6 +11,7 @@ import emu.grasscutter.game.ability.AbilityManager;
import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.avatar.AvatarProfileData; import emu.grasscutter.game.avatar.AvatarProfileData;
import emu.grasscutter.game.avatar.AvatarStorage; import emu.grasscutter.game.avatar.AvatarStorage;
import emu.grasscutter.game.managers.DeforestationManager.DeforestationManager;
import emu.grasscutter.game.entity.EntityGadget; import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityItem; import emu.grasscutter.game.entity.EntityItem;
import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.entity.GameEntity;
...@@ -145,11 +146,11 @@ public class Player { ...@@ -145,11 +146,11 @@ public class Player {
@Transient private MapMarksManager mapMarksManager; @Transient private MapMarksManager mapMarksManager;
@Transient private StaminaManager staminaManager; @Transient private StaminaManager staminaManager;
@Transient private EnergyManager energyManager; @Transient private EnergyManager energyManager;
@Transient private DeforestationManager deforestationManager;
private long springLastUsed; private long springLastUsed;
private HashMap<String, MapMark> mapMarks; private HashMap<String, MapMark> mapMarks;
@Deprecated @Deprecated
@SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only! @SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only!
public Player() { public Player() {
...@@ -159,6 +160,8 @@ public class Player { ...@@ -159,6 +160,8 @@ public class Player {
this.mailHandler = new MailHandler(this); this.mailHandler = new MailHandler(this);
this.towerManager = new TowerManager(this); this.towerManager = new TowerManager(this);
this.abilityManager = new AbilityManager(this); this.abilityManager = new AbilityManager(this);
this.deforestationManager = new DeforestationManager(this);
this.setQuestManager(new QuestManager(this)); this.setQuestManager(new QuestManager(this));
this.pos = new Position(); this.pos = new Position();
this.rotation = new Position(); this.rotation = new Position();
...@@ -227,6 +230,7 @@ public class Player { ...@@ -227,6 +230,7 @@ public class Player {
this.staminaManager = new StaminaManager(this); this.staminaManager = new StaminaManager(this);
this.sotsManager = new SotSManager(this); this.sotsManager = new SotSManager(this);
this.energyManager = new EnergyManager(this); this.energyManager = new EnergyManager(this);
this.deforestationManager = new DeforestationManager(this);
} }
public int getUid() { public int getUid() {
...@@ -923,7 +927,6 @@ public class Player { ...@@ -923,7 +927,6 @@ public class Player {
// Add to inventory // Add to inventory
boolean success = getInventory().addItem(item, ActionReason.SubfieldDrop); boolean success = getInventory().addItem(item, ActionReason.SubfieldDrop);
if (success) { if (success) {
if (!drop.isShare()) // not shared drop if (!drop.isShare()) // not shared drop
this.sendPacket(new PacketGadgetInteractRsp(drop, InteractType.INTERACT_PICK_ITEM)); this.sendPacket(new PacketGadgetInteractRsp(drop, InteractType.INTERACT_PICK_ITEM));
else else
...@@ -1109,6 +1112,10 @@ public class Player { ...@@ -1109,6 +1112,10 @@ public class Player {
return abilityManager; return abilityManager;
} }
public DeforestationManager getDeforestationManager() {
return deforestationManager;
}
public HashMap<String, MapMark> getMapMarks() { return mapMarks; } public HashMap<String, MapMark> getMapMarks() { return mapMarks; }
public void setMapMarks(HashMap<String, MapMark> newMarks) { mapMarks = newMarks; } public void setMapMarks(HashMap<String, MapMark> newMarks) { mapMarks = newMarks; }
...@@ -1294,6 +1301,9 @@ public class Player { ...@@ -1294,6 +1301,9 @@ public class Player {
// Call quit event. // Call quit event.
PlayerQuitEvent event = new PlayerQuitEvent(this); event.call(); PlayerQuitEvent event = new PlayerQuitEvent(this); event.call();
//reset wood
getDeforestationManager().resetWood();
} }
public enum SceneLoadState { public enum SceneLoadState {
......
package emu.grasscutter.server.packet.recv;
import java.math.BigInteger;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HitTreeNotifyOuterClass.HitTreeNotify;
import emu.grasscutter.server.game.GameSession;
/**
* Implement Deforestation Function
*/
@Opcodes(PacketOpcodes.HitTreeNotify)
public class HandlerHitTreeNotify extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
HitTreeNotify hit = HitTreeNotify.parseFrom(payload);
session.getPlayer().getDeforestationManager().onDeforestationInvoke(hit);
}
}
\ No newline at end of file
[ [
{"monsterId":28040101,"dropDataList":[{"itemId":100084,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28040102,"dropDataList":[{"itemId":100084,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28040103,"dropDataList":[{"itemId":100084,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28040104,"dropDataList":[{"itemId":100084,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28040105,"dropDataList":[{"itemId":100084,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28040106,"dropDataList":[{"itemId":100084,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28040107,"dropDataList":[{"itemId":100084,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28040108,"dropDataList":[{"itemId":100084,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020301,"dropDataList":[{"itemId":100061,"minCount":2,"maxCount":2,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020302,"dropDataList":[{"itemId":100061,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020101,"dropDataList":[{"itemId":100061,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020102,"dropDataList":[{"itemId":100061,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020103,"dropDataList":[{"itemId":100061,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020104,"dropDataList":[{"itemId":100061,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020105,"dropDataList":[{"itemId":100061,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020106,"dropDataList":[{"itemId":100061,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020701,"dropDataList":[{"itemId":100061,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020702,"dropDataList":[{"itemId":100061,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020303,"dropDataList":[{"itemId":100094,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28020304,"dropDataList":[{"itemId":100094,"minCount":2,"maxCount":3,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030401,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030402,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030403,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030404,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030405,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030406,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030407,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030408,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030409,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030301,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030302,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030303,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030304,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030305,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030306,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030307,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030308,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030309,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030310,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{"monsterId":28030311,"dropDataList":[{"itemId":100064,"minCount":1,"maxCount":1,"minWeight":0,"maxWeight":10000}]},
{ {
"monsterId": 21010101, "monsterId": 21010101,
"dropDataList": [ "dropDataList": [
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