mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-23 19:26:49 +00:00
Merge branch 'development' into dev-quests
This commit is contained in:
commit
0df4a076d7
8
proto/AbilityMixinWidgetMpSupport.proto
Normal file
8
proto/AbilityMixinWidgetMpSupport.proto
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message AbilityMixinWidgetMpSupport {
|
||||||
|
uint32 target_entity_id = 1;
|
||||||
|
}
|
29
proto/AllWidgetDataNotify.proto
Normal file
29
proto/AllWidgetDataNotify.proto
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "LunchBoxData.proto";
|
||||||
|
import "AnchorPointData.proto";
|
||||||
|
import "OneoffGatherPointDetectorData.proto";
|
||||||
|
import "ClientCollectorData.proto";
|
||||||
|
import "WidgetCoolDownData.proto";
|
||||||
|
import "WidgetSlotData.proto";
|
||||||
|
|
||||||
|
message AllWidgetDataNotify {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4260;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated AnchorPointData anchor_point_list = 2;
|
||||||
|
uint32 next_anchor_point_usable_time = 3;
|
||||||
|
LunchBoxData lunch_box_data = 5;
|
||||||
|
repeated OneoffGatherPointDetectorData oneoff_gather_point_detector_data_list = 6;
|
||||||
|
repeated ClientCollectorData client_collector_data_list = 7;
|
||||||
|
repeated WidgetCoolDownData cool_down_group_data_list = 8;
|
||||||
|
repeated WidgetCoolDownData normal_cool_down_data_list = 9;
|
||||||
|
repeated WidgetSlotData slot_list = 11;
|
||||||
|
}
|
12
proto/AnchorPointData.proto
Normal file
12
proto/AnchorPointData.proto
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "Vector.proto";
|
||||||
|
|
||||||
|
message AnchorPointData {
|
||||||
|
uint32 anchor_point_id = 1;
|
||||||
|
Vector pos = 2;
|
||||||
|
Vector rot = 3;
|
||||||
|
uint32 end_time = 4;
|
||||||
|
}
|
18
proto/AnchorPointDataNotify.proto
Normal file
18
proto/AnchorPointDataNotify.proto
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "AnchorPointData.proto";
|
||||||
|
|
||||||
|
message AnchorPointDataNotify {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4253;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated AnchorPointData anchor_point_list = 1;
|
||||||
|
uint32 next_usable_time = 2;
|
||||||
|
}
|
24
proto/AnchorPointOpReq.proto
Normal file
24
proto/AnchorPointOpReq.proto
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message AnchorPointOpReq {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
IS_ALLOW_CLIENT = 1;
|
||||||
|
CMD_ID = 4255;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AnchorPointOpType {
|
||||||
|
ANCHOR_POINT_OP_NONE = 0;
|
||||||
|
ANCHOR_POINT_OP_TELEPORT = 1;
|
||||||
|
ANCHOR_POINT_OP_REMOVE = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 anchor_point_op_type = 1;
|
||||||
|
uint32 anchor_point_id = 2;
|
||||||
|
}
|
18
proto/AnchorPointOpRsp.proto
Normal file
18
proto/AnchorPointOpRsp.proto
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message AnchorPointOpRsp {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4274;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 retcode = 1;
|
||||||
|
uint32 anchor_point_op_type = 2;
|
||||||
|
uint32 anchor_point_id = 3;
|
||||||
|
}
|
10
proto/ClientCollectorData.proto
Normal file
10
proto/ClientCollectorData.proto
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message ClientCollectorData {
|
||||||
|
uint32 material_id = 1;
|
||||||
|
uint32 max_points = 2;
|
||||||
|
uint32 curr_points = 3;
|
||||||
|
}
|
17
proto/ClientCollectorDataNotify.proto
Normal file
17
proto/ClientCollectorDataNotify.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "ClientCollectorData.proto";
|
||||||
|
|
||||||
|
message ClientCollectorDataNotify {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4280;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated ClientCollectorData client_collector_data_list = 1;
|
||||||
|
}
|
16
proto/GetWidgetSlotReq.proto
Normal file
16
proto/GetWidgetSlotReq.proto
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message GetWidgetSlotReq {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
IS_ALLOW_CLIENT = 1;
|
||||||
|
CMD_ID = 4285;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
18
proto/GetWidgetSlotRsp.proto
Normal file
18
proto/GetWidgetSlotRsp.proto
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetSlotData.proto";
|
||||||
|
|
||||||
|
message GetWidgetSlotRsp {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4291;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 retcode = 1;
|
||||||
|
repeated WidgetSlotData slot_list = 2;
|
||||||
|
}
|
8
proto/LunchBoxData.proto
Normal file
8
proto/LunchBoxData.proto
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message LunchBoxData {
|
||||||
|
map<uint32, uint32> slot_material_map = 1;
|
||||||
|
}
|
9
proto/LunchBoxSlotType.proto
Normal file
9
proto/LunchBoxSlotType.proto
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
enum LunchBoxSlotType {
|
||||||
|
LUNCH_BOX_SLOT_NONE = 0;
|
||||||
|
LUNCH_BOX_SLOT_REVIVE = 1;
|
||||||
|
LUNCH_BOX_SLOT_HEAL = 2;
|
||||||
|
}
|
15
proto/OneoffGatherPointDetectorData.proto
Normal file
15
proto/OneoffGatherPointDetectorData.proto
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "Vector.proto";
|
||||||
|
|
||||||
|
message OneoffGatherPointDetectorData {
|
||||||
|
uint32 material_id = 1;
|
||||||
|
bool is_all_collected = 2;
|
||||||
|
bool is_hint_valid = 3;
|
||||||
|
Vector hint_center_pos = 4;
|
||||||
|
uint32 hint_radius = 5;
|
||||||
|
uint32 group_id = 6;
|
||||||
|
uint32 config_id = 7;
|
||||||
|
}
|
17
proto/OneoffGatherPointDetectorDataNotify.proto
Normal file
17
proto/OneoffGatherPointDetectorDataNotify.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "OneoffGatherPointDetectorData.proto";
|
||||||
|
|
||||||
|
message OneoffGatherPointDetectorDataNotify {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4288;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated OneoffGatherPointDetectorData oneoff_gather_point_detector_data_list = 1;
|
||||||
|
}
|
26
proto/QuickUseWidgetReq.proto
Normal file
26
proto/QuickUseWidgetReq.proto
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetCreateLocationInfo.proto";
|
||||||
|
import "WidgetCameraInfo.proto";
|
||||||
|
import "WidgetCreatorInfo.proto";
|
||||||
|
import "WidgetThunderBirdFeatherInfo.proto";
|
||||||
|
|
||||||
|
message QuickUseWidgetReq {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
IS_ALLOW_CLIENT = 1;
|
||||||
|
CMD_ID = 4300;
|
||||||
|
}
|
||||||
|
|
||||||
|
oneof Param {
|
||||||
|
WidgetCreateLocationInfo location_info = 20;
|
||||||
|
WidgetCameraInfo camera_info = 21;
|
||||||
|
WidgetCreatorInfo creator_info = 22;
|
||||||
|
WidgetThunderBirdFeatherInfo thunder_bird_feather_info = 23;
|
||||||
|
}
|
||||||
|
}
|
21
proto/QuickUseWidgetRsp.proto
Normal file
21
proto/QuickUseWidgetRsp.proto
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "OneoffGatherPointDetectorData.proto";
|
||||||
|
import "ClientCollectorData.proto";
|
||||||
|
|
||||||
|
message QuickUseWidgetRsp {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4258;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 retcode = 1;
|
||||||
|
uint32 material_id = 2;
|
||||||
|
OneoffGatherPointDetectorData detector_data = 3;
|
||||||
|
ClientCollectorData client_collector_data = 4;
|
||||||
|
}
|
18
proto/SetUpLunchBoxWidgetReq.proto
Normal file
18
proto/SetUpLunchBoxWidgetReq.proto
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "LunchBoxData.proto";
|
||||||
|
|
||||||
|
message SetUpLunchBoxWidgetReq {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
IS_ALLOW_CLIENT = 1;
|
||||||
|
CMD_ID = 4265;
|
||||||
|
}
|
||||||
|
|
||||||
|
LunchBoxData lunch_box_data = 1;
|
||||||
|
}
|
18
proto/SetUpLunchBoxWidgetRsp.proto
Normal file
18
proto/SetUpLunchBoxWidgetRsp.proto
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "LunchBoxData.proto";
|
||||||
|
|
||||||
|
message SetUpLunchBoxWidgetRsp {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4297;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 retcode = 1;
|
||||||
|
LunchBoxData lunch_box_data = 2;
|
||||||
|
}
|
21
proto/SetWidgetSlotReq.proto
Normal file
21
proto/SetWidgetSlotReq.proto
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetSlotOp.proto";
|
||||||
|
import "WidgetSlotTag.proto";
|
||||||
|
|
||||||
|
message SetWidgetSlotReq {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
IS_ALLOW_CLIENT = 1;
|
||||||
|
CMD_ID = 4269;
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetSlotOp op = 2;
|
||||||
|
repeated WidgetSlotTag tag_list = 3;
|
||||||
|
uint32 material_id = 4;
|
||||||
|
}
|
21
proto/SetWidgetSlotRsp.proto
Normal file
21
proto/SetWidgetSlotRsp.proto
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetSlotOp.proto";
|
||||||
|
import "WidgetSlotTag.proto";
|
||||||
|
|
||||||
|
message SetWidgetSlotRsp {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4279;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 retcode = 1;
|
||||||
|
WidgetSlotOp op = 2;
|
||||||
|
repeated WidgetSlotTag tag_list = 3;
|
||||||
|
uint32 material_id = 4;
|
||||||
|
}
|
20
proto/UseWidgetCreateGadgetReq.proto
Normal file
20
proto/UseWidgetCreateGadgetReq.proto
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "Vector.proto";
|
||||||
|
|
||||||
|
message UseWidgetCreateGadgetReq {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
IS_ALLOW_CLIENT = 1;
|
||||||
|
CMD_ID = 4276;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 material_id = 1;
|
||||||
|
Vector pos = 2;
|
||||||
|
Vector rot = 3;
|
||||||
|
}
|
17
proto/UseWidgetCreateGadgetRsp.proto
Normal file
17
proto/UseWidgetCreateGadgetRsp.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message UseWidgetCreateGadgetRsp {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4270;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 retcode = 1;
|
||||||
|
uint32 material_id = 2;
|
||||||
|
}
|
17
proto/UseWidgetRetractGadgetReq.proto
Normal file
17
proto/UseWidgetRetractGadgetReq.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message UseWidgetRetractGadgetReq {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
IS_ALLOW_CLIENT = 1;
|
||||||
|
CMD_ID = 4273;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 entity_id = 1;
|
||||||
|
}
|
18
proto/UseWidgetRetractGadgetRsp.proto
Normal file
18
proto/UseWidgetRetractGadgetRsp.proto
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message UseWidgetRetractGadgetRsp {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
IS_ALLOW_CLIENT = 1;
|
||||||
|
CMD_ID = 4266;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 retcode = 1;
|
||||||
|
uint32 entity_id = 2;
|
||||||
|
}
|
17
proto/WidgetActiveChangeNotify.proto
Normal file
17
proto/WidgetActiveChangeNotify.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetSlotData.proto";
|
||||||
|
|
||||||
|
message WidgetActiveChangeNotify {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4264;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated WidgetSlotData widget_data_list = 1;
|
||||||
|
}
|
8
proto/WidgetCameraInfo.proto
Normal file
8
proto/WidgetCameraInfo.proto
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message WidgetCameraInfo {
|
||||||
|
uint32 target_entity_id = 1;
|
||||||
|
}
|
10
proto/WidgetCoolDownData.proto
Normal file
10
proto/WidgetCoolDownData.proto
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message WidgetCoolDownData {
|
||||||
|
uint32 id = 1;
|
||||||
|
uint64 cool_down_time = 2;
|
||||||
|
bool is_success = 3;
|
||||||
|
}
|
18
proto/WidgetCoolDownNotify.proto
Normal file
18
proto/WidgetCoolDownNotify.proto
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetCoolDownData.proto";
|
||||||
|
|
||||||
|
message WidgetCoolDownNotify {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4298;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated WidgetCoolDownData group_cool_down_data_list = 1;
|
||||||
|
repeated WidgetCoolDownData normal_cool_down_data_list = 2;
|
||||||
|
}
|
10
proto/WidgetCreateLocationInfo.proto
Normal file
10
proto/WidgetCreateLocationInfo.proto
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "Vector.proto";
|
||||||
|
|
||||||
|
message WidgetCreateLocationInfo {
|
||||||
|
Vector pos = 1;
|
||||||
|
Vector rot = 2;
|
||||||
|
}
|
12
proto/WidgetCreatorInfo.proto
Normal file
12
proto/WidgetCreatorInfo.proto
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetCreatorOpType.proto";
|
||||||
|
import "WidgetCreateLocationInfo.proto";
|
||||||
|
|
||||||
|
message WidgetCreatorInfo {
|
||||||
|
WidgetCreatorOpType op_type = 1;
|
||||||
|
uint32 entity_id = 2;
|
||||||
|
WidgetCreateLocationInfo location_info = 3;
|
||||||
|
}
|
9
proto/WidgetCreatorOpType.proto
Normal file
9
proto/WidgetCreatorOpType.proto
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
enum WidgetCreatorOpType {
|
||||||
|
WIDGET_CREATOR_TYPE_NONE = 0;
|
||||||
|
WIDGET_CREATOR_TYPE_RETRACT = 1;
|
||||||
|
WIDGET_CREATOR_TYPE_RETRACT_AND_CREATE = 2;
|
||||||
|
}
|
23
proto/WidgetDoBagReq.proto
Normal file
23
proto/WidgetDoBagReq.proto
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetCreateLocationInfo.proto";
|
||||||
|
import "WidgetCreatorInfo.proto";
|
||||||
|
|
||||||
|
message WidgetDoBagReq {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
IS_ALLOW_CLIENT = 1;
|
||||||
|
CMD_ID = 4290;
|
||||||
|
}
|
||||||
|
|
||||||
|
oneof OpInfo {
|
||||||
|
WidgetCreateLocationInfo location_info = 20;
|
||||||
|
WidgetCreatorInfo widget_creator_info = 21;
|
||||||
|
}
|
||||||
|
uint32 material_id = 1;
|
||||||
|
}
|
17
proto/WidgetDoBagRsp.proto
Normal file
17
proto/WidgetDoBagRsp.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message WidgetDoBagRsp {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4271;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 retcode = 1;
|
||||||
|
uint32 material_id = 2;
|
||||||
|
}
|
17
proto/WidgetGadgetAllDataNotify.proto
Normal file
17
proto/WidgetGadgetAllDataNotify.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetGadgetData.proto";
|
||||||
|
|
||||||
|
message WidgetGadgetAllDataNotify {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4262;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated WidgetGadgetData widget_gadget_data = 1;
|
||||||
|
}
|
9
proto/WidgetGadgetData.proto
Normal file
9
proto/WidgetGadgetData.proto
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message WidgetGadgetData {
|
||||||
|
uint32 gadget_id = 1;
|
||||||
|
repeated uint32 gadget_entity_id_list = 3;
|
||||||
|
}
|
17
proto/WidgetGadgetDataNotify.proto
Normal file
17
proto/WidgetGadgetDataNotify.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetGadgetData.proto";
|
||||||
|
|
||||||
|
message WidgetGadgetDataNotify {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4256;
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetGadgetData widget_gadget_data = 1;
|
||||||
|
}
|
16
proto/WidgetGadgetDestroyNotify.proto
Normal file
16
proto/WidgetGadgetDestroyNotify.proto
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message WidgetGadgetDestroyNotify {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4268;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 entity_id = 1;
|
||||||
|
}
|
19
proto/WidgetReportReq.proto
Normal file
19
proto/WidgetReportReq.proto
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message WidgetReportReq {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
IS_ALLOW_CLIENT = 1;
|
||||||
|
CMD_ID = 4294;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 material_id = 1;
|
||||||
|
bool is_clear_hint = 2;
|
||||||
|
bool is_client_collect = 3;
|
||||||
|
}
|
17
proto/WidgetReportRsp.proto
Normal file
17
proto/WidgetReportRsp.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message WidgetReportRsp {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4259;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 retcode = 1;
|
||||||
|
uint32 material_id = 2;
|
||||||
|
}
|
19
proto/WidgetSlotChangeNotify.proto
Normal file
19
proto/WidgetSlotChangeNotify.proto
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetSlotOp.proto";
|
||||||
|
import "WidgetSlotData.proto";
|
||||||
|
|
||||||
|
message WidgetSlotChangeNotify {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4289;
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetSlotOp op = 1;
|
||||||
|
WidgetSlotData slot = 2;
|
||||||
|
}
|
12
proto/WidgetSlotData.proto
Normal file
12
proto/WidgetSlotData.proto
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "WidgetSlotTag.proto";
|
||||||
|
|
||||||
|
message WidgetSlotData {
|
||||||
|
WidgetSlotTag tag = 1;
|
||||||
|
uint32 material_id = 2;
|
||||||
|
uint32 cd_over_time = 3;
|
||||||
|
bool is_active = 4;
|
||||||
|
}
|
8
proto/WidgetSlotOp.proto
Normal file
8
proto/WidgetSlotOp.proto
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
enum WidgetSlotOp {
|
||||||
|
ATTACH = 0;
|
||||||
|
DETACH = 1;
|
||||||
|
}
|
8
proto/WidgetSlotTag.proto
Normal file
8
proto/WidgetSlotTag.proto
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
enum WidgetSlotTag {
|
||||||
|
WIDGET_SLOT_QUICK_USE = 0;
|
||||||
|
WIDGET_SLOT_ATTACH_AVATAR = 1;
|
||||||
|
}
|
7
proto/WidgetSlotTagComparer.proto
Normal file
7
proto/WidgetSlotTagComparer.proto
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message WidgetSlotTagComparer {
|
||||||
|
}
|
8
proto/WidgetThunderBirdFeatherInfo.proto
Normal file
8
proto/WidgetThunderBirdFeatherInfo.proto
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message WidgetThunderBirdFeatherInfo {
|
||||||
|
repeated uint32 entity_id_list = 1;
|
||||||
|
}
|
17
proto/WidgetUseAttachAbilityGroupChangeNotify.proto
Normal file
17
proto/WidgetUseAttachAbilityGroupChangeNotify.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message WidgetUseAttachAbilityGroupChangeNotify {
|
||||||
|
enum CmdId {
|
||||||
|
option allow_alias = true;
|
||||||
|
NONE = 0;
|
||||||
|
ENET_CHANNEL_ID = 0;
|
||||||
|
ENET_IS_RELIABLE = 1;
|
||||||
|
CMD_ID = 4292;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 material_id = 1;
|
||||||
|
bool is_attach = 2;
|
||||||
|
}
|
@ -4,6 +4,7 @@ import java.io.*;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
import emu.grasscutter.command.CommandMap;
|
import emu.grasscutter.command.CommandMap;
|
||||||
|
import emu.grasscutter.game.managers.StaminaManager.StaminaManager;
|
||||||
import emu.grasscutter.plugin.PluginManager;
|
import emu.grasscutter.plugin.PluginManager;
|
||||||
import emu.grasscutter.plugin.api.ServerHook;
|
import emu.grasscutter.plugin.api.ServerHook;
|
||||||
import emu.grasscutter.scripts.ScriptLoader;
|
import emu.grasscutter.scripts.ScriptLoader;
|
||||||
@ -111,6 +112,9 @@ public final class Grasscutter {
|
|||||||
// Create plugin manager instance.
|
// Create plugin manager instance.
|
||||||
pluginManager = new PluginManager();
|
pluginManager = new PluginManager();
|
||||||
|
|
||||||
|
// TODO: find a better place?
|
||||||
|
StaminaManager.initialize();
|
||||||
|
|
||||||
// Start servers.
|
// Start servers.
|
||||||
var runMode = SERVER.runMode;
|
var runMode = SERVER.runMode;
|
||||||
if (runMode == ServerRunMode.HYBRID) {
|
if (runMode == ServerRunMode.HYBRID) {
|
||||||
|
@ -13,6 +13,7 @@ import com.google.gson.reflect.TypeToken;
|
|||||||
import com.sun.nio.file.SensitivityWatchEventModifier;
|
import com.sun.nio.file.SensitivityWatchEventModifier;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
|
import emu.grasscutter.data.common.ItemParamData;
|
||||||
import emu.grasscutter.data.def.ItemData;
|
import emu.grasscutter.data.def.ItemData;
|
||||||
import emu.grasscutter.database.DatabaseHelper;
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
@ -127,15 +128,10 @@ public class GachaManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Spend currency
|
// Spend currency
|
||||||
if (banner.getCostItem() > 0) {
|
if (banner.getCostItem() > 0 && !player.getInventory().payItem(banner.getCostItem(), times)) {
|
||||||
GameItem costItem = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(banner.getCostItem());
|
|
||||||
if (costItem == null || costItem.getCount() < times) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.getInventory().removeItem(costItem, times);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Roll
|
// Roll
|
||||||
PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(banner);
|
PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(banner);
|
||||||
IntList wonItems = new IntArrayList(times);
|
IntList wonItems = new IntArrayList(times);
|
||||||
|
@ -7,6 +7,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
|
import emu.grasscutter.data.common.ItemParamData;
|
||||||
import emu.grasscutter.data.def.AvatarCostumeData;
|
import emu.grasscutter.data.def.AvatarCostumeData;
|
||||||
import emu.grasscutter.data.def.AvatarData;
|
import emu.grasscutter.data.def.AvatarData;
|
||||||
import emu.grasscutter.data.def.AvatarFlycloakData;
|
import emu.grasscutter.data.def.AvatarFlycloakData;
|
||||||
@ -257,6 +258,64 @@ public class Inventory implements Iterable<GameItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getVirtualItemCount(int itemId) {
|
||||||
|
switch (itemId) {
|
||||||
|
case 201: // Primogem
|
||||||
|
return player.getPrimogems();
|
||||||
|
case 202: // Mora
|
||||||
|
return player.getMora();
|
||||||
|
case 203: // Genesis Crystals
|
||||||
|
return player.getCrystals();
|
||||||
|
default:
|
||||||
|
GameItem item = getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(itemId); // What if we ever want to operate on weapons/relics/furniture? :S
|
||||||
|
return (item == null) ? 0 : item.getCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean payItem(int id, int count) {
|
||||||
|
return payItem(new ItemParamData(id, count));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean payItem(ItemParamData costItem) {
|
||||||
|
return payItems(new ItemParamData[] {costItem}, 1, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean payItems(ItemParamData[] costItems) {
|
||||||
|
return payItems(costItems, 1, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean payItems(ItemParamData[] costItems, int quantity) {
|
||||||
|
return payItems(costItems, quantity, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean payItems(ItemParamData[] costItems, int quantity, ActionReason reason) {
|
||||||
|
// Make sure player has requisite items
|
||||||
|
for (ItemParamData cost : costItems) {
|
||||||
|
if (getVirtualItemCount(cost.getId()) < (cost.getCount() * quantity)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// All costs are satisfied, now remove them all
|
||||||
|
for (ItemParamData cost : costItems) {
|
||||||
|
switch (cost.getId()) {
|
||||||
|
case 201 -> // Primogem
|
||||||
|
player.setPrimogems(player.getPrimogems() - (cost.getCount() * quantity));
|
||||||
|
case 202 -> // Mora
|
||||||
|
player.setMora(player.getMora() - (cost.getCount() * quantity));
|
||||||
|
case 203 -> // Genesis Crystals
|
||||||
|
player.setCrystals(player.getCrystals() - (cost.getCount() * quantity));
|
||||||
|
default ->
|
||||||
|
removeItem(getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId()), cost.getCount() * quantity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reason != null) { // Do we need these?
|
||||||
|
// getPlayer().sendPacket(new PacketItemAddHintNotify(changedItems, reason));
|
||||||
|
}
|
||||||
|
// getPlayer().sendPacket(new PacketStoreItemChangeNotify(changedItems));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void removeItems(List<GameItem> items) {
|
public void removeItems(List<GameItem> items) {
|
||||||
// TODO Bulk delete
|
// TODO Bulk delete
|
||||||
for (GameItem item : items) {
|
for (GameItem item : items) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package emu.grasscutter.game.managers;
|
package emu.grasscutter.game.managers;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -38,6 +39,8 @@ public class InventoryManager {
|
|||||||
|
|
||||||
private final static int RELIC_MATERIAL_1 = 105002; // Sanctifying Unction
|
private final static int RELIC_MATERIAL_1 = 105002; // Sanctifying Unction
|
||||||
private final static int RELIC_MATERIAL_2 = 105003; // Sanctifying Essence
|
private final static int RELIC_MATERIAL_2 = 105003; // Sanctifying Essence
|
||||||
|
private final static int RELIC_MATERIAL_EXP_1 = 2500; // Sanctifying Unction
|
||||||
|
private final static int RELIC_MATERIAL_EXP_2 = 10000; // Sanctifying Essence
|
||||||
|
|
||||||
private final static int WEAPON_ORE_1 = 104011; // Enhancement Ore
|
private final static int WEAPON_ORE_1 = 104011; // Enhancement Ore
|
||||||
private final static int WEAPON_ORE_2 = 104012; // Fine Enhancement Ore
|
private final static int WEAPON_ORE_2 = 104012; // Fine Enhancement Ore
|
||||||
@ -85,6 +88,7 @@ public class InventoryManager {
|
|||||||
int moraCost = 0;
|
int moraCost = 0;
|
||||||
int expGain = 0;
|
int expGain = 0;
|
||||||
|
|
||||||
|
List<GameItem> foodRelics = new ArrayList<GameItem>();
|
||||||
for (long guid : foodRelicList) {
|
for (long guid : foodRelicList) {
|
||||||
// Add to delete queue
|
// Add to delete queue
|
||||||
GameItem food = player.getInventory().getItemByGuid(guid);
|
GameItem food = player.getInventory().getItemByGuid(guid);
|
||||||
@ -96,23 +100,21 @@ public class InventoryManager {
|
|||||||
expGain += food.getItemData().getBaseConvExp();
|
expGain += food.getItemData().getBaseConvExp();
|
||||||
// Feeding artifact with exp already
|
// Feeding artifact with exp already
|
||||||
if (food.getTotalExp() > 0) {
|
if (food.getTotalExp() > 0) {
|
||||||
expGain += (int) Math.floor(food.getTotalExp() * .8f);
|
expGain += (food.getTotalExp() * 4) / 5;
|
||||||
}
|
}
|
||||||
|
foodRelics.add(food);
|
||||||
}
|
}
|
||||||
|
List<ItemParamData> payList = new ArrayList<ItemParamData>();
|
||||||
for (ItemParam itemParam : list) {
|
for (ItemParam itemParam : list) {
|
||||||
GameItem food = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(itemParam.getItemId());
|
int amount = itemParam.getCount(); // Previously this capped to inventory amount, but rejecting the payment makes more sense for an invalid order
|
||||||
if (food == null || food.getItemData().getMaterialType() != MaterialType.MATERIAL_RELIQUARY_MATERIAL) {
|
int gain = amount * switch(itemParam.getItemId()) {
|
||||||
continue;
|
case RELIC_MATERIAL_1 -> RELIC_MATERIAL_EXP_1;
|
||||||
}
|
case RELIC_MATERIAL_2 -> RELIC_MATERIAL_EXP_2;
|
||||||
int amount = Math.min(food.getCount(), itemParam.getCount());
|
default -> 0;
|
||||||
int gain = 0;
|
};
|
||||||
if (food.getItemId() == RELIC_MATERIAL_2) {
|
|
||||||
gain = 10000 * amount;
|
|
||||||
} else if (food.getItemId() == RELIC_MATERIAL_1) {
|
|
||||||
gain = 2500 * amount;
|
|
||||||
}
|
|
||||||
expGain += gain;
|
expGain += gain;
|
||||||
moraCost += gain;
|
moraCost += gain;
|
||||||
|
payList.add(new ItemParamData(itemParam.getItemId(), itemParam.getCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure exp gain is valid
|
// Make sure exp gain is valid
|
||||||
@ -120,28 +122,14 @@ public class InventoryManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check mora
|
// Confirm payment of materials and mora (assume food relics are payable afterwards)
|
||||||
if (player.getMora() < moraCost) {
|
payList.add(new ItemParamData(202, moraCost));
|
||||||
|
if (!player.getInventory().payItems(payList.toArray(new ItemParamData[0]))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
player.setMora(player.getMora() - moraCost);
|
|
||||||
|
|
||||||
// Consume food items
|
// Consume food relics
|
||||||
for (long guid : foodRelicList) {
|
player.getInventory().removeItems(foodRelics);
|
||||||
GameItem food = player.getInventory().getItemByGuid(guid);
|
|
||||||
if (food == null || !food.isDestroyable()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
player.getInventory().removeItem(food);
|
|
||||||
}
|
|
||||||
for (ItemParam itemParam : list) {
|
|
||||||
GameItem food = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(itemParam.getItemId());
|
|
||||||
if (food == null || food.getItemData().getMaterialType() != MaterialType.MATERIAL_RELIQUARY_MATERIAL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int amount = Math.min(food.getCount(), itemParam.getCount());
|
|
||||||
player.getInventory().removeItem(food, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement random rate boost
|
// Implement random rate boost
|
||||||
int rate = 1;
|
int rate = 1;
|
||||||
@ -231,22 +219,16 @@ public class InventoryManager {
|
|||||||
}
|
}
|
||||||
expGain += food.getItemData().getWeaponBaseExp();
|
expGain += food.getItemData().getWeaponBaseExp();
|
||||||
if (food.getTotalExp() > 0) {
|
if (food.getTotalExp() > 0) {
|
||||||
expGain += (int) Math.floor(food.getTotalExp() * .8f);
|
expGain += (food.getTotalExp() * 4) / 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (ItemParam param : itemParamList) {
|
for (ItemParam param : itemParamList) {
|
||||||
GameItem food = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(param.getItemId());
|
expGain += param.getCount() * switch(param.getItemId()) {
|
||||||
if (food == null || food.getItemData().getMaterialType() != MaterialType.MATERIAL_WEAPON_EXP_STONE) {
|
case WEAPON_ORE_1 -> WEAPON_ORE_EXP_1;
|
||||||
continue;
|
case WEAPON_ORE_2 -> WEAPON_ORE_EXP_2;
|
||||||
}
|
case WEAPON_ORE_3 -> WEAPON_ORE_EXP_3;
|
||||||
int amount = Math.min(param.getCount(), food.getCount());
|
default -> 0;
|
||||||
if (food.getItemId() == WEAPON_ORE_3) {
|
};
|
||||||
expGain += 10000 * amount;
|
|
||||||
} else if (food.getItemId() == WEAPON_ORE_2) {
|
|
||||||
expGain += 2000 * amount;
|
|
||||||
} else if (food.getItemId() == WEAPON_ORE_1) {
|
|
||||||
expGain += 400 * amount;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try
|
// Try
|
||||||
@ -288,65 +270,45 @@ public class InventoryManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get exp gain
|
// Get exp gain
|
||||||
int expGain = 0, moraCost = 0;
|
int expGain = 0, expGainFree = 0;
|
||||||
|
List<GameItem> foodWeapons = new ArrayList<GameItem>();
|
||||||
for (long guid : foodWeaponGuidList) {
|
for (long guid : foodWeaponGuidList) {
|
||||||
GameItem food = player.getInventory().getItemByGuid(guid);
|
GameItem food = player.getInventory().getItemByGuid(guid);
|
||||||
if (food == null || !food.isDestroyable()) {
|
if (food == null || !food.isDestroyable()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
expGain += food.getItemData().getWeaponBaseExp();
|
expGain += food.getItemData().getWeaponBaseExp();
|
||||||
moraCost += (int) Math.floor(food.getItemData().getWeaponBaseExp() * .1f);
|
|
||||||
if (food.getTotalExp() > 0) {
|
if (food.getTotalExp() > 0) {
|
||||||
expGain += (int) Math.floor(food.getTotalExp() * .8f);
|
expGainFree += (food.getTotalExp() * 4) / 5; // No tax :D
|
||||||
}
|
}
|
||||||
|
foodWeapons.add(food);
|
||||||
}
|
}
|
||||||
|
List<ItemParamData> payList = new ArrayList<ItemParamData>();
|
||||||
for (ItemParam param : itemParamList) {
|
for (ItemParam param : itemParamList) {
|
||||||
GameItem food = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(param.getItemId());
|
int amount = param.getCount(); // Previously this capped to inventory amount, but rejecting the payment makes more sense for an invalid order
|
||||||
if (food == null || food.getItemData().getMaterialType() != MaterialType.MATERIAL_WEAPON_EXP_STONE) {
|
int gain = amount * switch(param.getItemId()) {
|
||||||
continue;
|
case WEAPON_ORE_1 -> WEAPON_ORE_EXP_1;
|
||||||
}
|
case WEAPON_ORE_2 -> WEAPON_ORE_EXP_2;
|
||||||
int amount = Math.min(param.getCount(), food.getCount());
|
case WEAPON_ORE_3 -> WEAPON_ORE_EXP_3;
|
||||||
int gain = 0;
|
default -> 0;
|
||||||
if (food.getItemId() == WEAPON_ORE_3) {
|
};
|
||||||
gain = 10000 * amount;
|
|
||||||
} else if (food.getItemId() == WEAPON_ORE_2) {
|
|
||||||
gain = 2000 * amount;
|
|
||||||
} else if (food.getItemId() == WEAPON_ORE_1) {
|
|
||||||
gain = 400 * amount;
|
|
||||||
}
|
|
||||||
expGain += gain;
|
expGain += gain;
|
||||||
moraCost += (int) Math.floor(gain * .1f);
|
payList.add(new ItemParamData(param.getItemId(), amount));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure exp gain is valid
|
// Make sure exp gain is valid
|
||||||
|
int moraCost = expGain / 10;
|
||||||
|
expGain += expGainFree;
|
||||||
if (expGain <= 0) {
|
if (expGain <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mora check
|
// Confirm payment of materials and mora (assume food weapons are payable afterwards)
|
||||||
if (player.getMora() >= moraCost) {
|
payList.add(new ItemParamData(202, moraCost));
|
||||||
player.setMora(player.getMora() - moraCost);
|
if (!player.getInventory().payItems(payList.toArray(new ItemParamData[0]))) {
|
||||||
} else {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
player.getInventory().removeItems(foodWeapons);
|
||||||
// Consume weapon/items used to feed
|
|
||||||
for (long guid : foodWeaponGuidList) {
|
|
||||||
GameItem food = player.getInventory().getItemByGuid(guid);
|
|
||||||
if (food == null || !food.isDestroyable()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
player.getInventory().removeItem(food);
|
|
||||||
}
|
|
||||||
for (ItemParam param : itemParamList) {
|
|
||||||
GameItem food = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(param.getItemId());
|
|
||||||
if (food == null || food.getItemData().getMaterialType() != MaterialType.MATERIAL_WEAPON_EXP_STONE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int amount = Math.min(param.getCount(), food.getCount());
|
|
||||||
player.getInventory().removeItem(food, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Level up
|
// Level up
|
||||||
int maxLevel = promoteData.getUnlockMaxLevel();
|
int maxLevel = promoteData.getUnlockMaxLevel();
|
||||||
@ -393,7 +355,7 @@ public class InventoryManager {
|
|||||||
player.sendPacket(new PacketWeaponUpgradeRsp(weapon, oldLevel, leftovers));
|
player.sendPacket(new PacketWeaponUpgradeRsp(weapon, oldLevel, leftovers));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ItemParam> getLeftoverOres(float leftover) {
|
private List<ItemParam> getLeftoverOres(int leftover) {
|
||||||
List<ItemParam> leftoverOreList = new ArrayList<>(3);
|
List<ItemParam> leftoverOreList = new ArrayList<>(3);
|
||||||
|
|
||||||
if (leftover < WEAPON_ORE_EXP_1) {
|
if (leftover < WEAPON_ORE_EXP_1) {
|
||||||
@ -401,11 +363,11 @@ public class InventoryManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get leftovers
|
// Get leftovers
|
||||||
int ore3 = (int) Math.floor(leftover / WEAPON_ORE_EXP_3);
|
int ore3 = leftover / WEAPON_ORE_EXP_3;
|
||||||
leftover = leftover % WEAPON_ORE_EXP_3;
|
leftover = leftover % WEAPON_ORE_EXP_3;
|
||||||
int ore2 = (int) Math.floor(leftover / WEAPON_ORE_EXP_2);
|
int ore2 = leftover / WEAPON_ORE_EXP_2;
|
||||||
leftover = leftover % WEAPON_ORE_EXP_2;
|
leftover = leftover % WEAPON_ORE_EXP_2;
|
||||||
int ore1 = (int) Math.floor(leftover / WEAPON_ORE_EXP_1);
|
int ore1 = leftover / WEAPON_ORE_EXP_1;
|
||||||
|
|
||||||
if (ore3 > 0) {
|
if (ore3 > 0) {
|
||||||
leftoverOreList.add(ItemParam.newBuilder().setItemId(WEAPON_ORE_3).setCount(ore3).build());
|
leftoverOreList.add(ItemParam.newBuilder().setItemId(WEAPON_ORE_3).setCount(ore3).build());
|
||||||
@ -496,26 +458,15 @@ public class InventoryManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure player has promote items
|
// Pay materials and mora if possible
|
||||||
for (ItemParamData cost : nextPromoteData.getCostItems()) {
|
ItemParamData[] costs = nextPromoteData.getCostItems(); // Can this be null?
|
||||||
GameItem feedItem = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId());
|
if (nextPromoteData.getCoinCost() > 0) {
|
||||||
if (feedItem == null || feedItem.getCount() < cost.getCount()) {
|
costs = Arrays.copyOf(costs, costs.length + 1);
|
||||||
|
costs[costs.length-1] = new ItemParamData(202, nextPromoteData.getCoinCost());
|
||||||
|
}
|
||||||
|
if (!player.getInventory().payItems(costs)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Mora check
|
|
||||||
if (player.getMora() >= nextPromoteData.getCoinCost()) {
|
|
||||||
player.setMora(player.getMora() - nextPromoteData.getCoinCost());
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume promote filler items
|
|
||||||
for (ItemParamData cost : nextPromoteData.getCostItems()) {
|
|
||||||
GameItem feedItem = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId());
|
|
||||||
player.getInventory().removeItem(feedItem, cost.getCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
int oldPromoteLevel = weapon.getPromoteLevel();
|
int oldPromoteLevel = weapon.getPromoteLevel();
|
||||||
weapon.setPromoteLevel(nextPromoteLevel);
|
weapon.setPromoteLevel(nextPromoteLevel);
|
||||||
@ -552,26 +503,15 @@ public class InventoryManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure player has cost items
|
// Pay materials and mora if possible
|
||||||
for (ItemParamData cost : nextPromoteData.getCostItems()) {
|
ItemParamData[] costs = nextPromoteData.getCostItems(); // Can this be null?
|
||||||
GameItem feedItem = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId());
|
if (nextPromoteData.getCoinCost() > 0) {
|
||||||
if (feedItem == null || feedItem.getCount() < cost.getCount()) {
|
costs = Arrays.copyOf(costs, costs.length + 1);
|
||||||
|
costs[costs.length-1] = new ItemParamData(202, nextPromoteData.getCoinCost());
|
||||||
|
}
|
||||||
|
if (!player.getInventory().payItems(costs)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Mora check
|
|
||||||
if (player.getMora() >= nextPromoteData.getCoinCost()) {
|
|
||||||
player.setMora(player.getMora() - nextPromoteData.getCoinCost());
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume promote filler items
|
|
||||||
for (ItemParamData cost : nextPromoteData.getCostItems()) {
|
|
||||||
GameItem feedItem = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId());
|
|
||||||
player.getInventory().removeItem(feedItem, cost.getCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update promote level
|
// Update promote level
|
||||||
avatar.setPromoteLevel(nextPromoteLevel);
|
avatar.setPromoteLevel(nextPromoteLevel);
|
||||||
@ -616,34 +556,25 @@ public class InventoryManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameItem feedItem = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(itemId);
|
|
||||||
|
|
||||||
if (feedItem == null || feedItem.getItemData().getMaterialType() != MaterialType.MATERIAL_EXP_FRUIT || feedItem.getCount() < count) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calc exp
|
// Calc exp
|
||||||
int expGain = 0, moraCost = 0;
|
int expGain = switch(itemId) {
|
||||||
|
case AVATAR_BOOK_1 -> AVATAR_BOOK_EXP_1 * count;
|
||||||
|
case AVATAR_BOOK_2 -> AVATAR_BOOK_EXP_2 * count;
|
||||||
|
case AVATAR_BOOK_3 -> AVATAR_BOOK_EXP_3 * count;
|
||||||
|
default -> 0;
|
||||||
|
};
|
||||||
|
|
||||||
// TODO clean up
|
// Sanity check
|
||||||
if (itemId == AVATAR_BOOK_3) {
|
if (expGain <= 0) {
|
||||||
expGain = AVATAR_BOOK_EXP_3 * count;
|
|
||||||
} else if (itemId == AVATAR_BOOK_2) {
|
|
||||||
expGain = AVATAR_BOOK_EXP_2 * count;
|
|
||||||
} else if (itemId == AVATAR_BOOK_1) {
|
|
||||||
expGain = AVATAR_BOOK_EXP_1 * count;
|
|
||||||
}
|
|
||||||
moraCost = (int) Math.floor(expGain * .2f);
|
|
||||||
|
|
||||||
// Mora check
|
|
||||||
if (player.getMora() >= moraCost) {
|
|
||||||
player.setMora(player.getMora() - moraCost);
|
|
||||||
} else {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consume items
|
// Payment check
|
||||||
player.getInventory().removeItem(feedItem, count);
|
int moraCost = expGain / 5;
|
||||||
|
ItemParamData[] costItems = new ItemParamData[] {new ItemParamData(itemId, count), new ItemParamData(202, moraCost)};
|
||||||
|
if (!player.getInventory().payItems(costItems)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Level up
|
// Level up
|
||||||
upgradeAvatar(player, avatar, promoteData, expGain);
|
upgradeAvatar(player, avatar, promoteData, expGain);
|
||||||
@ -764,32 +695,14 @@ public class InventoryManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure player has cost items
|
// Pay materials and mora if possible
|
||||||
for (ItemParamData cost : proudSkill.getCostItems()) {
|
List<ItemParamData> costs = new ArrayList<ItemParamData>(proudSkill.getCostItems()); // Can this be null?
|
||||||
if (cost.getId() == 0) {
|
if (proudSkill.getCoinCost() > 0) {
|
||||||
continue;
|
costs.add(new ItemParamData(202, proudSkill.getCoinCost()));
|
||||||
}
|
}
|
||||||
GameItem feedItem = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId());
|
if (!player.getInventory().payItems(costs.toArray(new ItemParamData[0]))) {
|
||||||
if (feedItem == null || feedItem.getCount() < cost.getCount()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Mora check
|
|
||||||
if (player.getMora() >= proudSkill.getCoinCost()) {
|
|
||||||
player.setMora(player.getMora() - proudSkill.getCoinCost());
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume promote filler items
|
|
||||||
for (ItemParamData cost : proudSkill.getCostItems()) {
|
|
||||||
if (cost.getId() == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
GameItem feedItem = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId());
|
|
||||||
player.getInventory().removeItem(feedItem, cost.getCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upgrade skill
|
// Upgrade skill
|
||||||
avatar.getSkillLevelMap().put(skillId, nextLevel);
|
avatar.getSkillLevelMap().put(skillId, nextLevel);
|
||||||
@ -822,14 +735,11 @@ public class InventoryManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameItem costItem = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(talentData.getMainCostItemId());
|
// Pay constellation item if possible
|
||||||
if (costItem == null || costItem.getCount() < talentData.getMainCostItemCount()) {
|
if (!player.getInventory().payItem(talentData.getMainCostItemId(), 1)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consume item
|
|
||||||
player.getInventory().removeItem(costItem, talentData.getMainCostItemCount());
|
|
||||||
|
|
||||||
// Apply + recalc
|
// Apply + recalc
|
||||||
avatar.getTalentIdList().add(talentData.getId());
|
avatar.getTalentIdList().add(talentData.getId());
|
||||||
avatar.setCoreProudSkillLevel(currentTalentLevel + 1);
|
avatar.setCoreProudSkillLevel(currentTalentLevel + 1);
|
||||||
|
@ -8,5 +8,5 @@ public interface AfterUpdateStaminaListener {
|
|||||||
* @param reason Why updating stamina.
|
* @param reason Why updating stamina.
|
||||||
* @param newStamina New Stamina value.
|
* @param newStamina New Stamina value.
|
||||||
*/
|
*/
|
||||||
void onAfterUpdateStamina(String reason, int newStamina);
|
void onAfterUpdateStamina(String reason, int newStamina, boolean isCharacterStamina);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ public interface BeforeUpdateStaminaListener {
|
|||||||
* @param newStamina New ABSOLUTE stamina value.
|
* @param newStamina New ABSOLUTE stamina value.
|
||||||
* @return true if you want to cancel this update, otherwise false.
|
* @return true if you want to cancel this update, otherwise false.
|
||||||
*/
|
*/
|
||||||
int onBeforeUpdateStamina(String reason, int newStamina);
|
int onBeforeUpdateStamina(String reason, int newStamina, boolean isCharacterStamina);
|
||||||
/**
|
/**
|
||||||
* onBeforeUpdateStamina() will be called before StaminaManager attempt to update the player's current stamina.
|
* onBeforeUpdateStamina() will be called before StaminaManager attempt to update the player's current stamina.
|
||||||
* This gives listeners a chance to intercept this update.
|
* This gives listeners a chance to intercept this update.
|
||||||
@ -16,5 +16,5 @@ public interface BeforeUpdateStaminaListener {
|
|||||||
* @param consumption ConsumptionType and RELATIVE stamina change amount.
|
* @param consumption ConsumptionType and RELATIVE stamina change amount.
|
||||||
* @return true if you want to cancel this update, otherwise false.
|
* @return true if you want to cancel this update, otherwise false.
|
||||||
*/
|
*/
|
||||||
Consumption onBeforeUpdateStamina(String reason, Consumption consumption);
|
Consumption onBeforeUpdateStamina(String reason, Consumption consumption, boolean isCharacterStamina);
|
||||||
}
|
}
|
@ -13,18 +13,19 @@ public enum ConsumptionType {
|
|||||||
// Slow swimming is handled per movement, not per second.
|
// Slow swimming is handled per movement, not per second.
|
||||||
// Arm movement frequency depends on gender/age/height.
|
// Arm movement frequency depends on gender/age/height.
|
||||||
// TODO: Instead of cost -80 per tick, find a proper way to calculate cost.
|
// TODO: Instead of cost -80 per tick, find a proper way to calculate cost.
|
||||||
SKIFF(-300), // TODO: Get real value
|
SKIFF_DASH(-204),
|
||||||
SPRINT(-1800),
|
SPRINT(-1800),
|
||||||
SWIM_DASH_START(-20),
|
SWIM_DASH_START(-2000),
|
||||||
SWIM_DASH(-204), // -10.2 per second, 5Hz = -204 each tick
|
SWIM_DASH(-204), // -10.2 per second, 5Hz = -204 each tick
|
||||||
SWIMMING(-80),
|
SWIMMING(-80),
|
||||||
TALENT_DASH(-300), // -1500 per second, 5Hz = -300 each tick
|
TALENT_DASH(-300), // -1500 per second, 5Hz = -300 each tick
|
||||||
TALENT_DASH_START(-1000),
|
TALENT_DASH_START(-1000),
|
||||||
|
|
||||||
// restore
|
// restore
|
||||||
POWERED_FLY(500), // TODO: Get real value
|
POWERED_FLY(500),
|
||||||
POWERED_SKIFF(2000), // TODO: Get real value
|
POWERED_SKIFF(500),
|
||||||
RUN(500),
|
RUN(500),
|
||||||
|
SKIFF(500),
|
||||||
STANDBY(500),
|
STANDBY(500),
|
||||||
WALK(500);
|
WALK(500);
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package emu.grasscutter.game.managers.StaminaManager;
|
|||||||
|
|
||||||
import ch.qos.logback.classic.Logger;
|
import ch.qos.logback.classic.Logger;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.game.entity.EntityAvatar;
|
import emu.grasscutter.game.entity.EntityAvatar;
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
@ -13,21 +14,21 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
|||||||
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
|
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
|
||||||
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType;
|
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType;
|
||||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||||
|
import emu.grasscutter.net.proto.VehicleInteractTypeOuterClass.VehicleInteractType;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.*;
|
import emu.grasscutter.server.packet.send.*;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.lang.Math;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static emu.grasscutter.Configuration.*;
|
import static emu.grasscutter.Configuration.GAME_OPTIONS;
|
||||||
|
|
||||||
public class StaminaManager {
|
public class StaminaManager {
|
||||||
|
|
||||||
// TODO: Skiff state detection?
|
// TODO: Skiff state detection?
|
||||||
private final Player player;
|
private final Player player;
|
||||||
private final HashMap<String, HashSet<MotionState>> MotionStatesCategorized = new HashMap<>() {{
|
private static final HashMap<String, HashSet<MotionState>> MotionStatesCategorized = new HashMap<>() {{
|
||||||
put("CLIMB", new HashSet<>(List.of(
|
put("CLIMB", new HashSet<>(List.of(
|
||||||
MotionState.MOTION_CLIMB, // sustained, when not moving no cost no recover
|
MotionState.MOTION_CLIMB, // sustained, when not moving no cost no recover
|
||||||
MotionState.MOTION_STANDBY_TO_CLIMB // NOT OBSERVED, see MOTION_JUMP_UP_WALL_FOR_STANDBY
|
MotionState.MOTION_STANDBY_TO_CLIMB // NOT OBSERVED, see MOTION_JUMP_UP_WALL_FOR_STANDBY
|
||||||
@ -48,7 +49,7 @@ public class StaminaManager {
|
|||||||
)));
|
)));
|
||||||
put("SKIFF", new HashSet<>(List.of(
|
put("SKIFF", new HashSet<>(List.of(
|
||||||
MotionState.MOTION_SKIFF_BOARDING, // NOT OBSERVED even when boarding
|
MotionState.MOTION_SKIFF_BOARDING, // NOT OBSERVED even when boarding
|
||||||
MotionState.MOTION_SKIFF_DASH, // NOT OBSERVED even when dashing
|
MotionState.MOTION_SKIFF_DASH, // sustained, observed with waverider entity ID.
|
||||||
MotionState.MOTION_SKIFF_NORMAL, // sustained, OBSERVED when both normal and dashing
|
MotionState.MOTION_SKIFF_NORMAL, // sustained, OBSERVED when both normal and dashing
|
||||||
MotionState.MOTION_SKIFF_POWERED_DASH // sustained, recover
|
MotionState.MOTION_SKIFF_POWERED_DASH // sustained, recover
|
||||||
)));
|
)));
|
||||||
@ -108,7 +109,8 @@ public class StaminaManager {
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
private final Logger logger = Grasscutter.getLogger();
|
private final Logger logger = Grasscutter.getLogger();
|
||||||
public final static int GlobalMaximumStamina = 24000;
|
public final static int GlobalCharacterMaximumStamina = 24000;
|
||||||
|
public final static int GlobalVehicleMaxStamina = 24000;
|
||||||
private Position currentCoordinates = new Position(0, 0, 0);
|
private Position currentCoordinates = new Position(0, 0, 0);
|
||||||
private Position previousCoordinates = new Position(0, 0, 0);
|
private Position previousCoordinates = new Position(0, 0, 0);
|
||||||
private MotionState currentState = MotionState.MOTION_STANDBY;
|
private MotionState currentState = MotionState.MOTION_STANDBY;
|
||||||
@ -122,74 +124,58 @@ public class StaminaManager {
|
|||||||
private int lastSkillId = 0;
|
private int lastSkillId = 0;
|
||||||
private int lastSkillCasterId = 0;
|
private int lastSkillCasterId = 0;
|
||||||
private boolean lastSkillFirstTick = true;
|
private boolean lastSkillFirstTick = true;
|
||||||
public static final HashSet<Integer> TalentMovements = new HashSet<>(List.of(
|
private int vehicleId = -1;
|
||||||
10013, // Kamisato Ayaka
|
private int vehicleStamina = GlobalVehicleMaxStamina;
|
||||||
10413 // Mona
|
private static final HashSet<Integer> TalentMovements = new HashSet<>(List.of(
|
||||||
|
10013, 10413
|
||||||
));
|
));
|
||||||
|
private static final HashMap<Integer, Float> ClimbFoodReductionMap = new HashMap<>() {{
|
||||||
|
// TODO: get real food id
|
||||||
|
put(0, 0.8f); // Sample food
|
||||||
|
}};
|
||||||
|
private static final HashMap<Integer, Float> DashFoodReductionMap = new HashMap<>() {{
|
||||||
|
// TODO: get real food id
|
||||||
|
put(0, 0.8f); // Sample food
|
||||||
|
}};
|
||||||
|
private static final HashMap<Integer, Float> FlyFoodReductionMap = new HashMap<>() {{
|
||||||
|
// TODO: get real food id
|
||||||
|
put(0, 0.8f); // Sample food
|
||||||
|
}};
|
||||||
|
private static final HashMap<Integer, Float> SwimFoodReductionMap = new HashMap<>() {{
|
||||||
|
// TODO: get real food id
|
||||||
|
put(0, 0.8f); // Sample food
|
||||||
|
}};
|
||||||
|
private static final HashMap<Integer, Float> ClimbTalentReductionMap = new HashMap<>() {{
|
||||||
|
put(262301, 0.8f);
|
||||||
|
}};
|
||||||
|
private static final HashMap<Integer, Float> FlyTalentReductionMap = new HashMap<>() {{
|
||||||
|
put(212301, 0.8f);
|
||||||
|
put(222301, 0.8f);
|
||||||
|
}};
|
||||||
|
private static final HashMap<Integer, Float> SwimTalentReductionMap = new HashMap<>() {{
|
||||||
|
put(242301, 0.8f);
|
||||||
|
put(542301, 0.8f);
|
||||||
|
}};
|
||||||
|
|
||||||
// TODO: Get from somewhere else, instead of hard-coded here?
|
public static final HashSet<Integer> BowAvatars = new HashSet<>();
|
||||||
public static final HashSet<Integer> ClaymoreSkills = new HashSet<>(List.of(
|
public static final HashSet<Integer> CatalystAvatars = new HashSet<>();
|
||||||
10160, // Diluc, /=2
|
public static final HashSet<Integer> ClaymoreAvatars = new HashSet<>();
|
||||||
10201, // Razor
|
public static final HashSet<Integer> PolearmAvatars = new HashSet<>();
|
||||||
10241, // Beidou
|
public static final HashSet<Integer> SwordAvatars = new HashSet<>();
|
||||||
10341, // Noelle
|
|
||||||
10401, // Chongyun
|
|
||||||
10441, // Xinyan
|
|
||||||
10511, // Eula
|
|
||||||
10531, // Sayu
|
|
||||||
10571 // Arataki Itto, = 0
|
|
||||||
));
|
|
||||||
public static final HashSet<Integer> CatalystSkills = new HashSet<>(List.of(
|
|
||||||
10060, // Lisa
|
|
||||||
10070, // Barbara
|
|
||||||
10271, // Ningguang
|
|
||||||
10291, // Klee
|
|
||||||
10411, // Mona
|
|
||||||
10431, // Sucrose
|
|
||||||
10481, // Yanfei
|
|
||||||
10541, // Sangonomoiya Kokomi
|
|
||||||
10581 // Yae Miko
|
|
||||||
));
|
|
||||||
public static final HashSet<Integer> PolearmSkills = new HashSet<>(List.of(
|
|
||||||
10231, // Xiangling
|
|
||||||
10261, // Xiao
|
|
||||||
10301, // Zhongli
|
|
||||||
10451, // Rosaria
|
|
||||||
10461, // Hu Tao
|
|
||||||
10501, // Thoma
|
|
||||||
10521, // Raiden Shogun
|
|
||||||
10631, // Shenhe
|
|
||||||
10641 // Yunjin
|
|
||||||
));
|
|
||||||
public static final HashSet<Integer> SwordSkills = new HashSet<>(List.of(
|
|
||||||
10024, // Kamisato Ayaka
|
|
||||||
10031, // Jean
|
|
||||||
10073, // Kaeya
|
|
||||||
10321, // Bennett
|
|
||||||
10337, // Tartaglia, melee stance (10332 switch to melee, 10336 switch to ranged stance)
|
|
||||||
10351, // Qiqi
|
|
||||||
10381, // Xingqiu
|
|
||||||
10386, // Albedo
|
|
||||||
10421, // Keqing, =-2500
|
|
||||||
10471, // Kaedehara Kazuha
|
|
||||||
10661, // Kamisato Ayato
|
|
||||||
100553, // Lumine
|
|
||||||
100540 // Aether
|
|
||||||
));
|
|
||||||
public static final HashSet<Integer> BowSkills = new HashSet<>(List.of(
|
|
||||||
10041, 10043, // Amber
|
|
||||||
10221, 10223,// Venti
|
|
||||||
10311, 10315, // Fischl
|
|
||||||
10331, 10335, // Tartaglia, ranged stance
|
|
||||||
10371, // Ganyu
|
|
||||||
10391, 10394, // Diona
|
|
||||||
10491, // Yoimiya
|
|
||||||
10551, 10554, // Gorou
|
|
||||||
10561, 10564, // Kojou Sara
|
|
||||||
10621, // Aloy
|
|
||||||
99998, 99999 // Yelan // TODO: get real values
|
|
||||||
));
|
|
||||||
|
|
||||||
|
public static void initialize() {
|
||||||
|
// Initialize skill categories
|
||||||
|
GameData.getAvatarDataMap().forEach((avatarId, avatarData) -> {
|
||||||
|
switch (avatarData.getWeaponType()) {
|
||||||
|
case "WEAPON_BOW" -> BowAvatars.add(avatarId);
|
||||||
|
case "WEAPON_CLAYMORE" -> ClaymoreAvatars.add(avatarId);
|
||||||
|
case "WEAPON_CATALYST" -> CatalystAvatars.add(avatarId);
|
||||||
|
case "WEAPON_POLE" -> PolearmAvatars.add(avatarId);
|
||||||
|
case "WEAPON_SWORD_ONE_HAND" -> SwordAvatars.add(avatarId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// TODO: Initialize foods etc.
|
||||||
|
}
|
||||||
|
|
||||||
public StaminaManager(Player player) {
|
public StaminaManager(Player player) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
@ -203,6 +189,22 @@ public class StaminaManager {
|
|||||||
lastSkillCasterId = skillCasterId;
|
lastSkillCasterId = skillCasterId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMaxCharacterStamina() {
|
||||||
|
return player.getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCurrentCharacterStamina() {
|
||||||
|
return player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxVehicleStamina() {
|
||||||
|
return GlobalVehicleMaxStamina;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCurrentVehicleStamina() {
|
||||||
|
return vehicleStamina;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean registerBeforeUpdateStaminaListener(String listenerName, BeforeUpdateStaminaListener listener) {
|
public boolean registerBeforeUpdateStaminaListener(String listenerName, BeforeUpdateStaminaListener listener) {
|
||||||
if (beforeUpdateStaminaListeners.containsKey(listenerName)) {
|
if (beforeUpdateStaminaListeners.containsKey(listenerName)) {
|
||||||
return false;
|
return false;
|
||||||
@ -244,67 +246,71 @@ public class StaminaManager {
|
|||||||
return Math.abs(diffX) > 0.3 || Math.abs(diffY) > 0.2 || Math.abs(diffZ) > 0.3;
|
return Math.abs(diffX) > 0.3 || Math.abs(diffY) > 0.2 || Math.abs(diffZ) > 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int updateStaminaRelative(GameSession session, Consumption consumption) {
|
public int updateStaminaRelative(GameSession session, Consumption consumption, boolean isCharacterStamina) {
|
||||||
int currentStamina = player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA);
|
int currentStamina = isCharacterStamina ? getCurrentCharacterStamina() : getCurrentVehicleStamina();
|
||||||
if (consumption.amount == 0) {
|
if (consumption.amount == 0) {
|
||||||
return currentStamina;
|
return currentStamina;
|
||||||
}
|
}
|
||||||
// notify will update
|
// notify will update
|
||||||
for (Map.Entry<String, BeforeUpdateStaminaListener> listener : beforeUpdateStaminaListeners.entrySet()) {
|
for (Map.Entry<String, BeforeUpdateStaminaListener> listener : beforeUpdateStaminaListeners.entrySet()) {
|
||||||
Consumption overriddenConsumption = listener.getValue().onBeforeUpdateStamina(consumption.type.toString(), consumption);
|
Consumption overriddenConsumption = listener.getValue().onBeforeUpdateStamina(consumption.type.toString(), consumption, isCharacterStamina);
|
||||||
if ((overriddenConsumption.type != consumption.type) && (overriddenConsumption.amount != consumption.amount)) {
|
if ((overriddenConsumption.type != consumption.type) && (overriddenConsumption.amount != consumption.amount)) {
|
||||||
logger.debug("[StaminaManager] Stamina update relative(" +
|
logger.debug("Stamina update relative(" +
|
||||||
consumption.type.toString() + ", " + consumption.amount + ") overridden to relative(" +
|
consumption.type.toString() + ", " + consumption.amount + ") overridden to relative(" +
|
||||||
consumption.type.toString() + ", " + consumption.amount + ") by: " + listener.getKey());
|
consumption.type.toString() + ", " + consumption.amount + ") by: " + listener.getKey());
|
||||||
return currentStamina;
|
return currentStamina;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int playerMaxStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
int maxStamina = isCharacterStamina ? getMaxCharacterStamina() : getMaxVehicleStamina();
|
||||||
logger.trace(currentStamina + "/" + playerMaxStamina + "\t" + currentState + "\t" +
|
logger.trace((isCharacterStamina ? "C " : "V ") + currentStamina + "/" + maxStamina + "\t" + currentState + "\t" +
|
||||||
(isPlayerMoving() ? "moving" : " ") + "\t(" + consumption.type + "," +
|
(isPlayerMoving() ? "moving" : " ") + "\t(" + consumption.type + "," +
|
||||||
consumption.amount + ")");
|
consumption.amount + ")");
|
||||||
int newStamina = currentStamina + consumption.amount;
|
int newStamina = currentStamina + consumption.amount;
|
||||||
if (newStamina < 0) {
|
if (newStamina < 0) {
|
||||||
newStamina = 0;
|
newStamina = 0;
|
||||||
} else if (newStamina > playerMaxStamina) {
|
} else if (newStamina > maxStamina) {
|
||||||
newStamina = playerMaxStamina;
|
newStamina = maxStamina;
|
||||||
}
|
}
|
||||||
return setStamina(session, consumption.type.toString(), newStamina);
|
return setStamina(session, consumption.type.toString(), newStamina, isCharacterStamina);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int updateStaminaAbsolute(GameSession session, String reason, int newStamina) {
|
public int updateStaminaAbsolute(GameSession session, String reason, int newStamina, boolean isCharacterStamina) {
|
||||||
int currentStamina = player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA);
|
int currentStamina = isCharacterStamina ? getCurrentCharacterStamina() : getCurrentVehicleStamina();
|
||||||
// notify will update
|
// notify will update
|
||||||
for (Map.Entry<String, BeforeUpdateStaminaListener> listener : beforeUpdateStaminaListeners.entrySet()) {
|
for (Map.Entry<String, BeforeUpdateStaminaListener> listener : beforeUpdateStaminaListeners.entrySet()) {
|
||||||
int overriddenNewStamina = listener.getValue().onBeforeUpdateStamina(reason, newStamina);
|
int overriddenNewStamina = listener.getValue().onBeforeUpdateStamina(reason, newStamina, isCharacterStamina);
|
||||||
if (overriddenNewStamina != newStamina) {
|
if (overriddenNewStamina != newStamina) {
|
||||||
logger.debug("[StaminaManager] Stamina update absolute(" +
|
logger.debug("Stamina update absolute(" +
|
||||||
reason + ", " + newStamina + ") overridden to absolute(" +
|
reason + ", " + newStamina + ") overridden to absolute(" +
|
||||||
reason + ", " + newStamina + ") by: " + listener.getKey());
|
reason + ", " + newStamina + ") by: " + listener.getKey());
|
||||||
return currentStamina;
|
return currentStamina;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int playerMaxStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
int maxStamina = isCharacterStamina ? getMaxCharacterStamina() : getMaxVehicleStamina();
|
||||||
if (newStamina < 0) {
|
if (newStamina < 0) {
|
||||||
newStamina = 0;
|
newStamina = 0;
|
||||||
} else if (newStamina > playerMaxStamina) {
|
} else if (newStamina > maxStamina) {
|
||||||
newStamina = playerMaxStamina;
|
newStamina = maxStamina;
|
||||||
}
|
}
|
||||||
return setStamina(session, reason, newStamina);
|
return setStamina(session, reason, newStamina, isCharacterStamina);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns new stamina and sends PlayerPropNotify
|
// Returns new stamina and sends PlayerPropNotify or VehicleStaminaNotify
|
||||||
public int setStamina(GameSession session, String reason, int newStamina) {
|
public int setStamina(GameSession session, String reason, int newStamina, boolean isCharacterStamina) {
|
||||||
if (!GAME_OPTIONS.staminaUsage) {
|
if (!GAME_OPTIONS.staminaUsage) {
|
||||||
newStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
newStamina = getMaxCharacterStamina();
|
||||||
}
|
}
|
||||||
|
// set stamina if is character stamina
|
||||||
// set stamina
|
if (isCharacterStamina) {
|
||||||
player.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina);
|
player.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina);
|
||||||
session.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
|
session.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
|
||||||
|
} else {
|
||||||
|
vehicleStamina = newStamina;
|
||||||
|
session.send(new PacketVehicleStaminaNotify(vehicleId, ((float) newStamina) / 100));
|
||||||
|
}
|
||||||
// notify updated
|
// notify updated
|
||||||
for (Map.Entry<String, AfterUpdateStaminaListener> listener : afterUpdateStaminaListeners.entrySet()) {
|
for (Map.Entry<String, AfterUpdateStaminaListener> listener : afterUpdateStaminaListeners.entrySet()) {
|
||||||
listener.getValue().onAfterUpdateStamina(reason, newStamina);
|
listener.getValue().onAfterUpdateStamina(reason, newStamina, isCharacterStamina);
|
||||||
}
|
}
|
||||||
return newStamina;
|
return newStamina;
|
||||||
}
|
}
|
||||||
@ -343,22 +349,23 @@ public class StaminaManager {
|
|||||||
// External trigger handler
|
// External trigger handler
|
||||||
|
|
||||||
public void handleEvtDoSkillSuccNotify(GameSession session, int skillId, int casterId) {
|
public void handleEvtDoSkillSuccNotify(GameSession session, int skillId, int casterId) {
|
||||||
// Ignore if skill not cast by not current active
|
// Ignore if skill not cast by not current active avatar
|
||||||
if (casterId != player.getTeamManager().getCurrentAvatarEntity().getId()) {
|
if (casterId != player.getTeamManager().getCurrentAvatarEntity().getId()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSkillCast(skillId, casterId);
|
setSkillCast(skillId, casterId);
|
||||||
// Handle immediate stamina cost
|
// Handle immediate stamina cost
|
||||||
if (ClaymoreSkills.contains(skillId)) {
|
int currentAvatarId = player.getTeamManager().getCurrentAvatarEntity().getAvatar().getAvatarId();
|
||||||
|
if (ClaymoreAvatars.contains(currentAvatarId)) {
|
||||||
// Exclude claymore as their stamina cost starts when MixinStaminaCost gets in
|
// Exclude claymore as their stamina cost starts when MixinStaminaCost gets in
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: Differentiate normal attacks from charged attacks and exclude
|
// TODO: Differentiate normal attacks from charged attacks and exclude
|
||||||
// TODO: Temporary: Exclude non-claymore attacks for now
|
// TODO: Temporary: Exclude non-claymore attacks for now
|
||||||
if (BowSkills.contains(skillId)
|
if (BowAvatars.contains(currentAvatarId)
|
||||||
|| SwordSkills.contains(skillId)
|
|| SwordAvatars.contains(currentAvatarId)
|
||||||
|| PolearmSkills.contains(skillId)
|
|| PolearmAvatars.contains(currentAvatarId)
|
||||||
|| CatalystSkills.contains(skillId)
|
|| CatalystAvatars.contains(currentAvatarId)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -367,7 +374,7 @@ public class StaminaManager {
|
|||||||
|
|
||||||
public void handleMixinCostStamina(boolean isSwim) {
|
public void handleMixinCostStamina(boolean isSwim) {
|
||||||
// Talent moving and claymore avatar charged attack duration
|
// Talent moving and claymore avatar charged attack duration
|
||||||
// logger.trace("abilityMixinCostStamina: isSwim: " + isSwim);
|
// logger.trace("abilityMixinCostStamina: isSwim: " + isSwim + "\tlastSkill: " + lastSkillId);
|
||||||
if (lastSkillCasterId == player.getTeamManager().getCurrentAvatarEntity().getId()) {
|
if (lastSkillCasterId == player.getTeamManager().getCurrentAvatarEntity().getId()) {
|
||||||
handleImmediateStamina(cachedSession, lastSkillId);
|
handleImmediateStamina(cachedSession, lastSkillId);
|
||||||
}
|
}
|
||||||
@ -381,11 +388,11 @@ public class StaminaManager {
|
|||||||
MotionState motionState = motionInfo.getState();
|
MotionState motionState = motionInfo.getState();
|
||||||
int notifyEntityId = entity.getId();
|
int notifyEntityId = entity.getId();
|
||||||
int currentAvatarEntityId = session.getPlayer().getTeamManager().getCurrentAvatarEntity().getId();
|
int currentAvatarEntityId = session.getPlayer().getTeamManager().getCurrentAvatarEntity().getId();
|
||||||
if (notifyEntityId != currentAvatarEntityId) {
|
if (notifyEntityId != currentAvatarEntityId && notifyEntityId != vehicleId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentState = motionState;
|
currentState = motionState;
|
||||||
// logger.trace("" + currentState);
|
// logger.trace(currentState + "\t" + (notifyEntityId == currentAvatarEntityId ? "character" : "vehicle"));
|
||||||
Vector posVector = motionInfo.getPos();
|
Vector posVector = motionInfo.getPos();
|
||||||
Position newPos = new Position(posVector.getX(), posVector.getY(), posVector.getZ());
|
Position newPos = new Position(posVector.getX(), posVector.getY(), posVector.getZ());
|
||||||
if (newPos.getX() != 0 && newPos.getY() != 0 && newPos.getZ() != 0) {
|
if (newPos.getX() != 0 && newPos.getY() != 0 && newPos.getZ() != 0) {
|
||||||
@ -395,28 +402,40 @@ public class StaminaManager {
|
|||||||
handleImmediateStamina(session, motionState);
|
handleImmediateStamina(session, motionState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handleVehicleInteractReq(GameSession session, int vehicleId, VehicleInteractType vehicleInteractType) {
|
||||||
|
if (vehicleInteractType == VehicleInteractType.VEHICLE_INTERACT_IN) {
|
||||||
|
this.vehicleId = vehicleId;
|
||||||
|
// Reset character stamina here to prevent falling into water immediately on ejection if char stamina is
|
||||||
|
// close to empty when boarding.
|
||||||
|
updateStaminaAbsolute(session, "board vehicle", getMaxCharacterStamina(), true);
|
||||||
|
updateStaminaAbsolute(session, "board vehicle", getMaxVehicleStamina(), false);
|
||||||
|
} else {
|
||||||
|
this.vehicleId = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Internal handler
|
// Internal handler
|
||||||
|
|
||||||
private void handleImmediateStamina(GameSession session, @NotNull MotionState motionState) {
|
private void handleImmediateStamina(GameSession session, @NotNull MotionState motionState) {
|
||||||
switch (motionState) {
|
switch (motionState) {
|
||||||
case MOTION_CLIMB:
|
case MOTION_CLIMB:
|
||||||
if (currentState != MotionState.MOTION_CLIMB) {
|
if (currentState != MotionState.MOTION_CLIMB) {
|
||||||
updateStaminaRelative(session, new Consumption(ConsumptionType.CLIMB_START));
|
updateStaminaRelative(session, new Consumption(ConsumptionType.CLIMB_START), true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MOTION_DASH_BEFORE_SHAKE:
|
case MOTION_DASH_BEFORE_SHAKE:
|
||||||
if (previousState != MotionState.MOTION_DASH_BEFORE_SHAKE) {
|
if (previousState != MotionState.MOTION_DASH_BEFORE_SHAKE) {
|
||||||
updateStaminaRelative(session, new Consumption(ConsumptionType.SPRINT));
|
updateStaminaRelative(session, new Consumption(ConsumptionType.SPRINT), true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MOTION_CLIMB_JUMP:
|
case MOTION_CLIMB_JUMP:
|
||||||
if (previousState != MotionState.MOTION_CLIMB_JUMP) {
|
if (previousState != MotionState.MOTION_CLIMB_JUMP) {
|
||||||
updateStaminaRelative(session, new Consumption(ConsumptionType.CLIMB_JUMP));
|
updateStaminaRelative(session, new Consumption(ConsumptionType.CLIMB_JUMP), true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MOTION_SWIM_DASH:
|
case MOTION_SWIM_DASH:
|
||||||
if (previousState != MotionState.MOTION_SWIM_DASH) {
|
if (previousState != MotionState.MOTION_SWIM_DASH) {
|
||||||
updateStaminaRelative(session, new Consumption(ConsumptionType.SWIM_DASH_START));
|
updateStaminaRelative(session, new Consumption(ConsumptionType.SWIM_DASH_START), true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -424,18 +443,20 @@ public class StaminaManager {
|
|||||||
|
|
||||||
private void handleImmediateStamina(GameSession session, int skillId) {
|
private void handleImmediateStamina(GameSession session, int skillId) {
|
||||||
Consumption consumption = getFightConsumption(skillId);
|
Consumption consumption = getFightConsumption(skillId);
|
||||||
updateStaminaRelative(session, consumption);
|
updateStaminaRelative(session, consumption, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SustainedStaminaHandler extends TimerTask {
|
private class SustainedStaminaHandler extends TimerTask {
|
||||||
public void run() {
|
public void run() {
|
||||||
boolean moving = isPlayerMoving();
|
boolean moving = isPlayerMoving();
|
||||||
int currentStamina = player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA);
|
int currentCharacterStamina = getCurrentCharacterStamina();
|
||||||
int maxStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
int maxCharacterStamina = getMaxCharacterStamina();
|
||||||
if (moving || (currentStamina < maxStamina)) {
|
int currentVehicleStamina = getCurrentVehicleStamina();
|
||||||
|
int maxVehicleStamina = getMaxVehicleStamina();
|
||||||
|
if (moving || (currentCharacterStamina < maxCharacterStamina) || (currentVehicleStamina < maxVehicleStamina)) {
|
||||||
logger.trace("Player moving: " + moving + ", stamina full: " +
|
logger.trace("Player moving: " + moving + ", stamina full: " +
|
||||||
(currentStamina >= maxStamina) + ", recalculate stamina");
|
(currentCharacterStamina >= maxCharacterStamina) + ", recalculate stamina");
|
||||||
|
boolean isCharacterStamina = true;
|
||||||
Consumption consumption;
|
Consumption consumption;
|
||||||
if (MotionStatesCategorized.get("CLIMB").contains(currentState)) {
|
if (MotionStatesCategorized.get("CLIMB").contains(currentState)) {
|
||||||
consumption = getClimbConsumption();
|
consumption = getClimbConsumption();
|
||||||
@ -447,43 +468,44 @@ public class StaminaManager {
|
|||||||
consumption = new Consumption(ConsumptionType.RUN);
|
consumption = new Consumption(ConsumptionType.RUN);
|
||||||
} else if (MotionStatesCategorized.get("SKIFF").contains(currentState)) {
|
} else if (MotionStatesCategorized.get("SKIFF").contains(currentState)) {
|
||||||
consumption = getSkiffConsumption();
|
consumption = getSkiffConsumption();
|
||||||
|
isCharacterStamina = false;
|
||||||
} else if (MotionStatesCategorized.get("STANDBY").contains(currentState)) {
|
} else if (MotionStatesCategorized.get("STANDBY").contains(currentState)) {
|
||||||
consumption = new Consumption(ConsumptionType.STANDBY);
|
consumption = new Consumption(ConsumptionType.STANDBY);
|
||||||
} else if (MotionStatesCategorized.get("SWIM").contains((currentState))) {
|
} else if (MotionStatesCategorized.get("SWIM").contains(currentState)) {
|
||||||
consumption = getSwimConsumptions();
|
consumption = getSwimConsumptions();
|
||||||
} else if (MotionStatesCategorized.get("WALK").contains((currentState))) {
|
} else if (MotionStatesCategorized.get("WALK").contains(currentState)) {
|
||||||
consumption = new Consumption(ConsumptionType.WALK);
|
consumption = new Consumption(ConsumptionType.WALK);
|
||||||
} else if (MotionStatesCategorized.get("OTHER").contains((currentState))) {
|
} else if (MotionStatesCategorized.get("NOCOST_NORECOVER").contains(currentState)) {
|
||||||
|
consumption = new Consumption();
|
||||||
|
} else if (MotionStatesCategorized.get("OTHER").contains(currentState)) {
|
||||||
consumption = getOtherConsumptions();
|
consumption = getOtherConsumptions();
|
||||||
} else {
|
} else { // ignore
|
||||||
// ignore
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (consumption.amount < 0) {
|
|
||||||
/* Do not apply reduction factor when recovering stamina
|
if (consumption.amount < 0 && isCharacterStamina) {
|
||||||
TODO: Reductions that apply to all motion types:
|
// Do not apply reduction factor when recovering stamina
|
||||||
Elemental Resonance
|
if (player.getTeamManager().getTeamResonances().contains(10301)) {
|
||||||
Wind: -15%
|
consumption.amount *= 0.85f;
|
||||||
Skills
|
|
||||||
Diona E: -10% while shield lasts - applies to SP+MP
|
|
||||||
Barbara E: -12% while lasts - applies to SP+MP
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
// Delay 2 seconds before starts recovering stamina
|
}
|
||||||
if (cachedSession != null) {
|
// Delay 1 seconds before starts recovering stamina
|
||||||
|
if (consumption.amount != 0 && cachedSession != null) {
|
||||||
if (consumption.amount < 0) {
|
if (consumption.amount < 0) {
|
||||||
staminaRecoverDelay = 0;
|
staminaRecoverDelay = 0;
|
||||||
}
|
}
|
||||||
if (consumption.amount > 0 && consumption.type != ConsumptionType.POWERED_FLY) {
|
if (consumption.amount > 0
|
||||||
// For POWERED_FLY recover immediately - things like Amber's gliding exam may require this.
|
&& consumption.type != ConsumptionType.POWERED_FLY
|
||||||
if (staminaRecoverDelay < 10) {
|
&& consumption.type != ConsumptionType.POWERED_SKIFF) {
|
||||||
// For others recover after 2 seconds (10 ticks) - as official server does.
|
// For POWERED_* recover immediately - things like Amber's gliding exam and skiff challenges may require this.
|
||||||
|
if (staminaRecoverDelay < 5) {
|
||||||
|
// For others recover after 1 seconds (5 ticks) - as official server does.
|
||||||
staminaRecoverDelay++;
|
staminaRecoverDelay++;
|
||||||
consumption.amount = 0;
|
consumption.amount = 0;
|
||||||
logger.trace("[StaminaManager] Delaying recovery: " + staminaRecoverDelay);
|
logger.trace("Delaying recovery: " + staminaRecoverDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateStaminaRelative(cachedSession, consumption);
|
updateStaminaRelative(cachedSession, consumption, isCharacterStamina);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
previousState = currentState;
|
previousState = currentState;
|
||||||
@ -496,10 +518,11 @@ public class StaminaManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleDrowning() {
|
private void handleDrowning() {
|
||||||
int stamina = player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA);
|
// TODO: fix drowning waverider entity
|
||||||
|
int stamina = getCurrentCharacterStamina();
|
||||||
if (stamina < 10) {
|
if (stamina < 10) {
|
||||||
logger.trace(player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA) + "/" +
|
logger.trace(getCurrentCharacterStamina() + "/" +
|
||||||
player.getProperty(PlayerProperty.PROP_MAX_STAMINA) + "\t" + currentState);
|
getMaxCharacterStamina() + "\t" + currentState);
|
||||||
if (currentState != MotionState.MOTION_SWIM_IDLE) {
|
if (currentState != MotionState.MOTION_SWIM_IDLE) {
|
||||||
killAvatar(cachedSession, cachedEntity, PlayerDieType.PLAYER_DIE_DRAWN);
|
killAvatar(cachedSession, cachedEntity, PlayerDieType.PLAYER_DIE_DRAWN);
|
||||||
}
|
}
|
||||||
@ -517,24 +540,25 @@ public class StaminaManager {
|
|||||||
return getTalentMovingSustainedCost(skillCasting);
|
return getTalentMovingSustainedCost(skillCasting);
|
||||||
}
|
}
|
||||||
// Bow avatar charged attack
|
// Bow avatar charged attack
|
||||||
if (BowSkills.contains(skillCasting)) {
|
int currentAvatarId = player.getTeamManager().getCurrentAvatarEntity().getAvatar().getAvatarId();
|
||||||
|
if (BowAvatars.contains(currentAvatarId)) {
|
||||||
return getBowSustainedCost(skillCasting);
|
return getBowSustainedCost(skillCasting);
|
||||||
}
|
}
|
||||||
// Claymore avatar charged attack
|
// Claymore avatar charged attack
|
||||||
if (ClaymoreSkills.contains(skillCasting)) {
|
if (ClaymoreAvatars.contains(currentAvatarId)) {
|
||||||
return getClaymoreSustainedCost(skillCasting);
|
return getClaymoreSustainedCost(skillCasting);
|
||||||
}
|
}
|
||||||
// Catalyst avatar charged attack
|
// Catalyst avatar charged attack
|
||||||
if (CatalystSkills.contains(skillCasting)) {
|
if (CatalystAvatars.contains(currentAvatarId)) {
|
||||||
return getCatalystSustainedCost(skillCasting);
|
return getCatalystCost(skillCasting);
|
||||||
}
|
}
|
||||||
// Polearm avatar charged attack
|
// Polearm avatar charged attack
|
||||||
if (PolearmSkills.contains(skillCasting)) {
|
if (PolearmAvatars.contains(currentAvatarId)) {
|
||||||
return getPolearmSustainedCost(skillCasting);
|
return getPolearmCost(skillCasting);
|
||||||
}
|
}
|
||||||
// Sword avatar charged attack
|
// Sword avatar charged attack
|
||||||
if (SwordSkills.contains(skillCasting)) {
|
if (SwordAvatars.contains(skillCasting)) {
|
||||||
return getSwordSustainedCost(skillCasting);
|
return getSwordCost(skillCasting);
|
||||||
}
|
}
|
||||||
return new Consumption();
|
return new Consumption();
|
||||||
}
|
}
|
||||||
@ -546,18 +570,8 @@ public class StaminaManager {
|
|||||||
consumption.amount = ConsumptionType.CLIMBING.amount;
|
consumption.amount = ConsumptionType.CLIMBING.amount;
|
||||||
}
|
}
|
||||||
// Climbing specific reductions
|
// Climbing specific reductions
|
||||||
// TODO: create a food cost reduction map
|
consumption.amount *= getFoodCostReductionFactor(ClimbFoodReductionMap);
|
||||||
HashMap<Integer, Float> foodReductionMap = new HashMap<>() {{
|
consumption.amount *= getTalentCostReductionFactor(ClimbTalentReductionMap);
|
||||||
// TODO: get real talent id
|
|
||||||
put(0, 0.8f); // Sample food
|
|
||||||
}};
|
|
||||||
consumption.amount *= getFoodCostReductionFactor(foodReductionMap);
|
|
||||||
|
|
||||||
HashMap<Integer, Float> talentReductionMap = new HashMap<>() {{
|
|
||||||
// TODO: get real talent id
|
|
||||||
put(0, 0.8f); // Xiao
|
|
||||||
}};
|
|
||||||
consumption.amount *= getTalentCostReductionFactor(talentReductionMap);
|
|
||||||
return consumption;
|
return consumption;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,13 +586,9 @@ public class StaminaManager {
|
|||||||
consumption.type = ConsumptionType.SWIM_DASH;
|
consumption.type = ConsumptionType.SWIM_DASH;
|
||||||
consumption.amount = ConsumptionType.SWIM_DASH.amount;
|
consumption.amount = ConsumptionType.SWIM_DASH.amount;
|
||||||
}
|
}
|
||||||
// Reductions
|
// Swimming specific reductions
|
||||||
HashMap<Integer, Float> talentReductionMap = new HashMap<>() {{
|
consumption.amount *= getFoodCostReductionFactor(SwimFoodReductionMap);
|
||||||
// TODO: get real talent id
|
consumption.amount *= getTalentCostReductionFactor(SwimTalentReductionMap);
|
||||||
put(0, 0.8f); // Beidou
|
|
||||||
put(1, 0.8f); // Sangonomiya Kokomi
|
|
||||||
}};
|
|
||||||
consumption.amount *= getTalentCostReductionFactor(talentReductionMap);
|
|
||||||
return consumption;
|
return consumption;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,8 +597,8 @@ public class StaminaManager {
|
|||||||
if (currentState == MotionState.MOTION_DASH) {
|
if (currentState == MotionState.MOTION_DASH) {
|
||||||
consumption.type = ConsumptionType.DASH;
|
consumption.type = ConsumptionType.DASH;
|
||||||
consumption.amount = ConsumptionType.DASH.amount;
|
consumption.amount = ConsumptionType.DASH.amount;
|
||||||
// TODO: Dashing specific reductions
|
// Dashing specific reductions
|
||||||
// Foods:
|
consumption.amount *= getFoodCostReductionFactor(DashFoodReductionMap);
|
||||||
}
|
}
|
||||||
return consumption;
|
return consumption;
|
||||||
}
|
}
|
||||||
@ -599,32 +609,34 @@ public class StaminaManager {
|
|||||||
return new Consumption(ConsumptionType.POWERED_FLY);
|
return new Consumption(ConsumptionType.POWERED_FLY);
|
||||||
}
|
}
|
||||||
Consumption consumption = new Consumption(ConsumptionType.FLY);
|
Consumption consumption = new Consumption(ConsumptionType.FLY);
|
||||||
// Passive Talents
|
// Flying specific reductions
|
||||||
HashMap<Integer, Float> talentReductionMap = new HashMap<>() {{
|
consumption.amount *= getFoodCostReductionFactor(FlyFoodReductionMap);
|
||||||
put(212301, 0.8f); // Amber
|
consumption.amount *= getTalentCostReductionFactor(FlyTalentReductionMap);
|
||||||
put(222301, 0.8f); // Venti
|
|
||||||
}};
|
|
||||||
consumption.amount *= getTalentCostReductionFactor(talentReductionMap);
|
|
||||||
// TODO: Foods
|
|
||||||
return consumption;
|
return consumption;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Consumption getSkiffConsumption() {
|
private Consumption getSkiffConsumption() {
|
||||||
// POWERED_SKIFF, e.g. wind tunnel
|
|
||||||
if (currentState == MotionState.MOTION_SKIFF_POWERED_DASH) {
|
|
||||||
return new Consumption(ConsumptionType.POWERED_SKIFF);
|
|
||||||
}
|
|
||||||
// No known reduction for skiffing.
|
// No known reduction for skiffing.
|
||||||
return new Consumption(ConsumptionType.SKIFF);
|
return switch (currentState) {
|
||||||
|
case MOTION_SKIFF_DASH -> new Consumption(ConsumptionType.SKIFF_DASH);
|
||||||
|
case MOTION_SKIFF_POWERED_DASH -> new Consumption(ConsumptionType.POWERED_SKIFF);
|
||||||
|
case MOTION_SKIFF_NORMAL -> new Consumption(ConsumptionType.SKIFF);
|
||||||
|
default -> new Consumption();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Consumption getOtherConsumptions() {
|
private Consumption getOtherConsumptions() {
|
||||||
if (currentState == MotionState.MOTION_NOTIFY) {
|
switch (currentState) {
|
||||||
if (BowSkills.contains(lastSkillId)) {
|
case MOTION_NOTIFY:
|
||||||
|
// if (BowSkills.contains(lastSkillId)) {
|
||||||
|
// return new Consumption(ConsumptionType.FIGHT, 500);
|
||||||
|
// }
|
||||||
|
break;
|
||||||
|
case MOTION_FIGHT:
|
||||||
|
// TODO: what if charged attack
|
||||||
return new Consumption(ConsumptionType.FIGHT, 500);
|
return new Consumption(ConsumptionType.FIGHT, 500);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// TODO: Add other logic
|
|
||||||
return new Consumption();
|
return new Consumption();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,11 +683,11 @@ public class StaminaManager {
|
|||||||
return new Consumption(ConsumptionType.FIGHT, +500);
|
return new Consumption(ConsumptionType.FIGHT, +500);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Consumption getCatalystSustainedCost(int skillId) {
|
private Consumption getCatalystCost(int skillId) {
|
||||||
Consumption consumption = new Consumption(ConsumptionType.FIGHT, -5000);
|
Consumption consumption = new Consumption(ConsumptionType.FIGHT, -5000);
|
||||||
// Character specific handling
|
// Character specific handling
|
||||||
switch (skillId) {
|
switch (skillId) {
|
||||||
// TODO: Yanfei
|
// TODO:
|
||||||
}
|
}
|
||||||
return consumption;
|
return consumption;
|
||||||
}
|
}
|
||||||
@ -684,18 +696,20 @@ public class StaminaManager {
|
|||||||
Consumption consumption = new Consumption(ConsumptionType.FIGHT, -1333); // 4000 / 3 = 1333
|
Consumption consumption = new Consumption(ConsumptionType.FIGHT, -1333); // 4000 / 3 = 1333
|
||||||
// Character specific handling
|
// Character specific handling
|
||||||
switch (skillId) {
|
switch (skillId) {
|
||||||
case 10571: // Arataki Itto, does not consume stamina at all.
|
case 10571:
|
||||||
|
case 10532:
|
||||||
consumption.amount = 0;
|
consumption.amount = 0;
|
||||||
break;
|
break;
|
||||||
case 10160: // Diluc, with talent "Relentless" stamina cost is decreased by 50%
|
case 10160:
|
||||||
// TODO: How to get talent status?
|
if (player.getTeamManager().getCurrentAvatarEntity().getAvatar().getProudSkillList().contains(162101)) {
|
||||||
consumption.amount /= 2;
|
consumption.amount /= 2;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return consumption;
|
return consumption;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Consumption getPolearmSustainedCost(int skillId) {
|
private Consumption getPolearmCost(int skillId) {
|
||||||
Consumption consumption = new Consumption(ConsumptionType.FIGHT, -2500);
|
Consumption consumption = new Consumption(ConsumptionType.FIGHT, -2500);
|
||||||
// Character specific handling
|
// Character specific handling
|
||||||
switch (skillId) {
|
switch (skillId) {
|
||||||
@ -704,11 +718,11 @@ public class StaminaManager {
|
|||||||
return consumption;
|
return consumption;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Consumption getSwordSustainedCost(int skillId) {
|
private Consumption getSwordCost(int skillId) {
|
||||||
Consumption consumption = new Consumption(ConsumptionType.FIGHT, -2000);
|
Consumption consumption = new Consumption(ConsumptionType.FIGHT, -2000);
|
||||||
// Character specific handling
|
// Character specific handling
|
||||||
switch (skillId) {
|
switch (skillId) {
|
||||||
case 10421: // Keqing, -2500
|
case 10421:
|
||||||
consumption.amount = -2500;
|
consumption.amount = -2500;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,8 @@ public class Player {
|
|||||||
private Set<Integer> flyCloakList;
|
private Set<Integer> flyCloakList;
|
||||||
private Set<Integer> costumeList;
|
private Set<Integer> costumeList;
|
||||||
|
|
||||||
|
private Integer widgetId;
|
||||||
|
|
||||||
@Transient private long nextGuid = 0;
|
@Transient private long nextGuid = 0;
|
||||||
@Transient private int peerId;
|
@Transient private int peerId;
|
||||||
@Transient private World world;
|
@Transient private World world;
|
||||||
@ -302,6 +304,14 @@ public class Player {
|
|||||||
this.updateProfile();
|
this.updateProfile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getWidgetId() {
|
||||||
|
return widgetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidgetId(Integer widgetId) {
|
||||||
|
this.widgetId = widgetId;
|
||||||
|
}
|
||||||
|
|
||||||
public Position getPos() {
|
public Position getPos() {
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
@ -1170,6 +1180,8 @@ public class Player {
|
|||||||
session.send(new PacketFinishedParentQuestNotify(this));
|
session.send(new PacketFinishedParentQuestNotify(this));
|
||||||
session.send(new PacketQuestListNotify(this));
|
session.send(new PacketQuestListNotify(this));
|
||||||
session.send(new PacketServerCondMeetQuestListUpdateNotify(this));
|
session.send(new PacketServerCondMeetQuestListUpdateNotify(this));
|
||||||
|
session.send(new PacketAllWidgetDataNotify(this));
|
||||||
|
session.send(new PacketWidgetGadgetAllDataNotify());
|
||||||
|
|
||||||
getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward.
|
getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward.
|
||||||
|
|
||||||
@ -1267,7 +1279,7 @@ public class Player {
|
|||||||
} else if (prop == PlayerProperty.PROP_IS_TRANSFERABLE) { // 10009
|
} else if (prop == PlayerProperty.PROP_IS_TRANSFERABLE) { // 10009
|
||||||
if (!(0 <= value && value <= 1)) { return false; }
|
if (!(0 <= value && value <= 1)) { return false; }
|
||||||
} else if (prop == PlayerProperty.PROP_MAX_STAMINA) { // 10010
|
} else if (prop == PlayerProperty.PROP_MAX_STAMINA) { // 10010
|
||||||
if (!(value >= 0 && value <= StaminaManager.GlobalMaximumStamina)) { return false; }
|
if (!(value >= 0 && value <= StaminaManager.GlobalCharacterMaximumStamina)) { return false; }
|
||||||
} else if (prop == PlayerProperty.PROP_CUR_PERSIST_STAMINA) { // 10011
|
} else if (prop == PlayerProperty.PROP_CUR_PERSIST_STAMINA) { // 10011
|
||||||
int playerMaximumStamina = getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
int playerMaximumStamina = getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
||||||
if (!(value >= 0 && value <= playerMaximumStamina)) { return false; }
|
if (!(value >= 0 && value <= playerMaximumStamina)) { return false; }
|
||||||
|
@ -18,7 +18,7 @@ import emu.grasscutter.server.packet.send.PacketBuyGoodsRsp;
|
|||||||
import emu.grasscutter.server.packet.send.PacketStoreItemChangeNotify;
|
import emu.grasscutter.server.packet.send.PacketStoreItemChangeNotify;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@ -56,36 +56,13 @@ public class HandlerBuyGoodsReq extends PacketHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sg.getScoin() > 0 && session.getPlayer().getMora() < buyGoodsReq.getBoughtNum() * sg.getScoin()) {
|
List<ItemParamData> costs = new ArrayList<ItemParamData>(sg.getCostItemList()); // Can this even be null?
|
||||||
|
costs.add(new ItemParamData(202, sg.getScoin()));
|
||||||
|
costs.add(new ItemParamData(201, sg.getHcoin()));
|
||||||
|
costs.add(new ItemParamData(203, sg.getMcoin()));
|
||||||
|
if (!session.getPlayer().getInventory().payItems(costs.toArray(new ItemParamData[0]), buyGoodsReq.getBoughtNum())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sg.getHcoin() > 0 && session.getPlayer().getPrimogems() < buyGoodsReq.getBoughtNum() * sg.getHcoin()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (sg.getMcoin() > 0 && session.getPlayer().getCrystals() < buyGoodsReq.getBoughtNum() * sg.getMcoin()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
HashMap<GameItem, Integer> itemsCache = new HashMap<>();
|
|
||||||
if (sg.getCostItemList() != null) {
|
|
||||||
for (ItemParamData p : sg.getCostItemList()) {
|
|
||||||
Optional<GameItem> invItem = session.getPlayer().getInventory().getItems().values().stream().filter(x -> x.getItemId() == p.getId()).findFirst();
|
|
||||||
if (invItem.isEmpty() || invItem.get().getCount() < p.getCount())
|
|
||||||
return;
|
|
||||||
itemsCache.put(invItem.get(), p.getCount() * buyGoodsReq.getBoughtNum());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
session.getPlayer().setMora(session.getPlayer().getMora() - buyGoodsReq.getBoughtNum() * sg.getScoin());
|
|
||||||
session.getPlayer().setPrimogems(session.getPlayer().getPrimogems() - buyGoodsReq.getBoughtNum() * sg.getHcoin());
|
|
||||||
session.getPlayer().setCrystals(session.getPlayer().getCrystals() - buyGoodsReq.getBoughtNum() * sg.getMcoin());
|
|
||||||
|
|
||||||
if (!itemsCache.isEmpty()) {
|
|
||||||
for (GameItem gi : itemsCache.keySet()) {
|
|
||||||
session.getPlayer().getInventory().removeItem(gi, itemsCache.get(gi));
|
|
||||||
}
|
|
||||||
itemsCache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
session.getPlayer().addShopLimit(sg.getGoodsId(), buyGoodsReq.getBoughtNum(), ShopManager.getShopNextRefreshTime(sg));
|
session.getPlayer().addShopLimit(sg.getGoodsId(), buyGoodsReq.getBoughtNum(), ShopManager.getShopNextRefreshTime(sg));
|
||||||
GameItem item = new GameItem(GameData.getItemDataMap().get(sg.getGoodsItem().getId()));
|
GameItem item = new GameItem(GameData.getItemDataMap().get(sg.getGoodsItem().getId()));
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketGetShopRsp;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketGetWidgetSlotRsp;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.GetWidgetSlotReq)
|
@Opcodes(PacketOpcodes.GetWidgetSlotReq)
|
||||||
public class HandlerGetWidgetSlotReq extends PacketHandler {
|
public class HandlerGetWidgetSlotReq extends PacketHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
// Unhandled
|
Player player = session.getPlayer();
|
||||||
|
session.send(new PacketGetWidgetSlotRsp(player));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
|
import emu.grasscutter.game.player.Player;
|
||||||
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.SetWidgetSlotReqOuterClass;
|
||||||
|
import emu.grasscutter.net.proto.WidgetSlotOpOuterClass;
|
||||||
|
import emu.grasscutter.server.game.GameSession;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketSetWidgetSlotRsp;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketWidgetSlotChangeNotify;
|
||||||
|
|
||||||
|
@Opcodes(PacketOpcodes.SetWidgetSlotReq)
|
||||||
|
public class HandlerSetWidgetSlotReq extends PacketHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
|
SetWidgetSlotReqOuterClass.SetWidgetSlotReq req = SetWidgetSlotReqOuterClass.SetWidgetSlotReq.parseFrom(payload);
|
||||||
|
|
||||||
|
Player player = session.getPlayer();
|
||||||
|
player.setWidgetId(req.getMaterialId());
|
||||||
|
|
||||||
|
// WidgetSlotChangeNotify op & slot key
|
||||||
|
session.send(new PacketWidgetSlotChangeNotify(WidgetSlotOpOuterClass.WidgetSlotOp.DETACH));
|
||||||
|
// WidgetSlotChangeNotify slot
|
||||||
|
session.send(new PacketWidgetSlotChangeNotify(req.getMaterialId()));
|
||||||
|
|
||||||
|
// SetWidgetSlotRsp
|
||||||
|
session.send(new PacketSetWidgetSlotRsp(req.getMaterialId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@ public class HandlerVehicleInteractReq extends PacketHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
VehicleInteractReqOuterClass.VehicleInteractReq req = VehicleInteractReqOuterClass.VehicleInteractReq.parseFrom(payload);
|
VehicleInteractReqOuterClass.VehicleInteractReq req = VehicleInteractReqOuterClass.VehicleInteractReq.parseFrom(payload);
|
||||||
|
session.getPlayer().getStaminaManager().handleVehicleInteractReq(session, req.getEntityId(), req.getInteractType());
|
||||||
session.send(new PacketVehicleInteractRsp(session.getPlayer(), req.getEntityId(), req.getInteractType()));
|
session.send(new PacketVehicleInteractRsp(session.getPlayer(), req.getEntityId(), req.getInteractType()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
|
import emu.grasscutter.game.player.Player;
|
||||||
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.AllWidgetDataNotifyOuterClass.AllWidgetDataNotify;
|
||||||
|
import emu.grasscutter.net.proto.LunchBoxDataOuterClass;
|
||||||
|
import emu.grasscutter.net.proto.WidgetSlotDataOuterClass;
|
||||||
|
import emu.grasscutter.net.proto.WidgetSlotTagOuterClass;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class PacketAllWidgetDataNotify extends BasePacket {
|
||||||
|
|
||||||
|
public PacketAllWidgetDataNotify(Player player) {
|
||||||
|
super(PacketOpcodes.AllWidgetDataNotify);
|
||||||
|
|
||||||
|
// TODO: Implement this
|
||||||
|
|
||||||
|
AllWidgetDataNotify.Builder proto = AllWidgetDataNotify.newBuilder()
|
||||||
|
// If you want to implement this, feel free to do so. :)
|
||||||
|
.setLunchBoxData(
|
||||||
|
LunchBoxDataOuterClass.LunchBoxData.newBuilder().build()
|
||||||
|
)
|
||||||
|
// Maybe it's a little difficult, or it makes you upset :(
|
||||||
|
.addAllOneoffGatherPointDetectorDataList(List.of())
|
||||||
|
// So, goodbye, and hopefully sometime in the future o(* ̄▽ ̄*)ブ
|
||||||
|
.addAllCoolDownGroupDataList(List.of())
|
||||||
|
// I'll see your PR with a title that says (・∀・(・∀・(・∀・*)
|
||||||
|
.addAllAnchorPointList(List.of())
|
||||||
|
// "Complete implementation of widget functionality" b( ̄▽ ̄)d
|
||||||
|
.addAllClientCollectorDataList(List.of())
|
||||||
|
// Good luck, my boy.
|
||||||
|
.addAllNormalCoolDownDataList(List.of());
|
||||||
|
|
||||||
|
if (player.getWidgetId() == null) {
|
||||||
|
proto.addAllSlotList(List.of());
|
||||||
|
} else {
|
||||||
|
proto.addSlotList(
|
||||||
|
WidgetSlotDataOuterClass.WidgetSlotData.newBuilder()
|
||||||
|
.setIsActive(true)
|
||||||
|
.setMaterialId(player.getWidgetId())
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
|
proto.addSlotList(
|
||||||
|
WidgetSlotDataOuterClass.WidgetSlotData.newBuilder()
|
||||||
|
.setTag(WidgetSlotTagOuterClass.WidgetSlotTag.WIDGET_SLOT_ATTACH_AVATAR)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
AllWidgetDataNotify protoData = proto.build();
|
||||||
|
|
||||||
|
this.setData(protoData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
|||||||
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
|
import emu.grasscutter.game.player.Player;
|
||||||
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.GetWidgetSlotRspOuterClass;
|
||||||
|
import emu.grasscutter.net.proto.WidgetSlotDataOuterClass;
|
||||||
|
import emu.grasscutter.net.proto.WidgetSlotTagOuterClass;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PacketGetWidgetSlotRsp extends BasePacket {
|
||||||
|
|
||||||
|
public PacketGetWidgetSlotRsp(Player player) {
|
||||||
|
super(PacketOpcodes.GetWidgetSlotRsp);
|
||||||
|
|
||||||
|
GetWidgetSlotRspOuterClass.GetWidgetSlotRsp.Builder proto =
|
||||||
|
GetWidgetSlotRspOuterClass.GetWidgetSlotRsp.newBuilder();
|
||||||
|
|
||||||
|
if (player.getWidgetId() == null) {
|
||||||
|
proto.addAllSlotList(List.of());
|
||||||
|
} else {
|
||||||
|
proto.addSlotList(
|
||||||
|
WidgetSlotDataOuterClass.WidgetSlotData.newBuilder()
|
||||||
|
.setIsActive(true)
|
||||||
|
.setMaterialId(player.getWidgetId())
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
|
proto.addSlotList(
|
||||||
|
WidgetSlotDataOuterClass.WidgetSlotData.newBuilder()
|
||||||
|
.setTag(WidgetSlotTagOuterClass.WidgetSlotTag.WIDGET_SLOT_ATTACH_AVATAR)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
GetWidgetSlotRspOuterClass.GetWidgetSlotRsp protoData = proto.build();
|
||||||
|
|
||||||
|
this.setData(protoData);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.SetWidgetSlotRspOuterClass;
|
||||||
|
|
||||||
|
public class PacketSetWidgetSlotRsp extends BasePacket {
|
||||||
|
|
||||||
|
public PacketSetWidgetSlotRsp(int materialId) {
|
||||||
|
super(PacketOpcodes.SetWidgetSlotRsp);
|
||||||
|
|
||||||
|
SetWidgetSlotRspOuterClass.SetWidgetSlotRsp proto = SetWidgetSlotRspOuterClass.SetWidgetSlotRsp.newBuilder()
|
||||||
|
.setMaterialId(materialId)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
this.setData(proto);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.VehicleStaminaNotifyOuterClass.VehicleStaminaNotify;
|
||||||
|
|
||||||
|
public class PacketVehicleStaminaNotify extends BasePacket {
|
||||||
|
|
||||||
|
public PacketVehicleStaminaNotify(int vehicleId, float newStamina) {
|
||||||
|
super(PacketOpcodes.VehicleStaminaNotify);
|
||||||
|
VehicleStaminaNotify.Builder proto = VehicleStaminaNotify.newBuilder();
|
||||||
|
|
||||||
|
proto.setEntityId(vehicleId);
|
||||||
|
proto.setCurStamina(newStamina);
|
||||||
|
|
||||||
|
this.setData(proto.build());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.WidgetGadgetAllDataNotifyOuterClass.WidgetGadgetAllDataNotify;
|
||||||
|
|
||||||
|
public class PacketWidgetGadgetAllDataNotify extends BasePacket {
|
||||||
|
|
||||||
|
public PacketWidgetGadgetAllDataNotify() {
|
||||||
|
super(PacketOpcodes.AllWidgetDataNotify);
|
||||||
|
|
||||||
|
WidgetGadgetAllDataNotify proto = WidgetGadgetAllDataNotify.newBuilder().build();
|
||||||
|
|
||||||
|
this.setData(proto);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.WidgetSlotChangeNotifyOuterClass;
|
||||||
|
import emu.grasscutter.net.proto.WidgetSlotDataOuterClass;
|
||||||
|
import emu.grasscutter.net.proto.WidgetSlotOpOuterClass;
|
||||||
|
|
||||||
|
public class PacketWidgetSlotChangeNotify extends BasePacket {
|
||||||
|
|
||||||
|
public PacketWidgetSlotChangeNotify(WidgetSlotChangeNotifyOuterClass.WidgetSlotChangeNotify proto) {
|
||||||
|
super(PacketOpcodes.WidgetSlotChangeNotify);
|
||||||
|
|
||||||
|
this.setData(proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketWidgetSlotChangeNotify(WidgetSlotOpOuterClass.WidgetSlotOp op) {
|
||||||
|
super(PacketOpcodes.WidgetSlotChangeNotify);
|
||||||
|
|
||||||
|
WidgetSlotChangeNotifyOuterClass.WidgetSlotChangeNotify proto = WidgetSlotChangeNotifyOuterClass.WidgetSlotChangeNotify.newBuilder()
|
||||||
|
.setOp(op)
|
||||||
|
.setSlot(
|
||||||
|
WidgetSlotDataOuterClass.WidgetSlotData.newBuilder()
|
||||||
|
.setIsActive(true)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
this.setData(proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketWidgetSlotChangeNotify(int materialId) {
|
||||||
|
super(PacketOpcodes.WidgetSlotChangeNotify);
|
||||||
|
|
||||||
|
WidgetSlotChangeNotifyOuterClass.WidgetSlotChangeNotify proto = WidgetSlotChangeNotifyOuterClass.WidgetSlotChangeNotify.newBuilder()
|
||||||
|
.setSlot(
|
||||||
|
WidgetSlotDataOuterClass.WidgetSlotData.newBuilder()
|
||||||
|
.setIsActive(true)
|
||||||
|
.setMaterialId(materialId)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
this.setData(proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user