Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
ziqian zhang
Grasscutter
Commits
9b26426e
Commit
9b26426e
authored
May 12, 2022
by
Melledy
Browse files
Merge branch 'development' into dev-quests
parents
12318021
8c32438b
Changes
19
Expand all
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/Grasscutter.java
View file @
9b26426e
...
...
@@ -4,6 +4,7 @@ import java.io.*;
import
java.util.Calendar
;
import
emu.grasscutter.command.CommandMap
;
import
emu.grasscutter.game.managers.StaminaManager.StaminaManager
;
import
emu.grasscutter.plugin.PluginManager
;
import
emu.grasscutter.plugin.api.ServerHook
;
import
emu.grasscutter.scripts.ScriptLoader
;
...
...
@@ -110,6 +111,9 @@ public final class Grasscutter {
new
ServerHook
(
gameServer
,
dispatchServer
);
// Create plugin manager instance.
pluginManager
=
new
PluginManager
();
// TODO: find a better place?
StaminaManager
.
initialize
();
// Start servers.
var
runMode
=
SERVER
.
runMode
;
...
...
src/main/java/emu/grasscutter/game/gacha/GachaManager.java
View file @
9b26426e
...
...
@@ -13,6 +13,7 @@ import com.google.gson.reflect.TypeToken;
import
com.sun.nio.file.SensitivityWatchEventModifier
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.common.ItemParamData
;
import
emu.grasscutter.data.def.ItemData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.avatar.Avatar
;
...
...
@@ -127,13 +128,8 @@ public class GachaManager {
}
// Spend currency
if
(
banner
.
getCostItem
()
>
0
)
{
GameItem
costItem
=
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
banner
.
getCostItem
());
if
(
costItem
==
null
||
costItem
.
getCount
()
<
times
)
{
return
;
}
player
.
getInventory
().
removeItem
(
costItem
,
times
);
if
(
banner
.
getCostItem
()
>
0
&&
!
player
.
getInventory
().
payItem
(
banner
.
getCostItem
(),
times
))
{
return
;
}
// Roll
...
...
src/main/java/emu/grasscutter/game/inventory/Inventory.java
View file @
9b26426e
...
...
@@ -7,6 +7,7 @@ import java.util.List;
import
emu.grasscutter.GameConstants
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.common.ItemParamData
;
import
emu.grasscutter.data.def.AvatarCostumeData
;
import
emu.grasscutter.data.def.AvatarData
;
import
emu.grasscutter.data.def.AvatarFlycloakData
;
...
...
@@ -256,6 +257,64 @@ public class Inventory implements Iterable<GameItem> {
getPlayer
().
setCrystals
(
player
.
getCrystals
()
+
count
);
}
}
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
)
{
// TODO Bulk delete
...
...
src/main/java/emu/grasscutter/game/managers/InventoryManager.java
View file @
9b26426e
package
emu.grasscutter.game.managers
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.Map
;
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_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_2
=
104012
;
// Fine Enhancement Ore
...
...
@@ -85,6 +88,7 @@ public class InventoryManager {
int
moraCost
=
0
;
int
expGain
=
0
;
List
<
GameItem
>
foodRelics
=
new
ArrayList
<
GameItem
>();
for
(
long
guid
:
foodRelicList
)
{
// Add to delete queue
GameItem
food
=
player
.
getInventory
().
getItemByGuid
(
guid
);
...
...
@@ -96,23 +100,21 @@ public class InventoryManager {
expGain
+=
food
.
getItemData
().
getBaseConvExp
();
// Feeding artifact with exp already
if
(
food
.
getTotalExp
()
>
0
)
{
expGain
+=
(
int
)
Math
.
floor
(
food
.
getTotalExp
()
*
.
8
f
)
;
expGain
+=
(
food
.
getTotalExp
()
*
4
)
/
5
;
}
foodRelics
.
add
(
food
);
}
List
<
ItemParamData
>
payList
=
new
ArrayList
<
ItemParamData
>();
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
());
int
gain
=
0
;
if
(
food
.
getItemId
()
==
RELIC_MATERIAL_2
)
{
gain
=
10000
*
amount
;
}
else
if
(
food
.
getItemId
()
==
RELIC_MATERIAL_1
)
{
gain
=
2500
*
amount
;
}
int
amount
=
itemParam
.
getCount
();
// Previously this capped to inventory amount, but rejecting the payment makes more sense for an invalid order
int
gain
=
amount
*
switch
(
itemParam
.
getItemId
())
{
case
RELIC_MATERIAL_1
->
RELIC_MATERIAL_EXP_1
;
case
RELIC_MATERIAL_2
->
RELIC_MATERIAL_EXP_2
;
default
->
0
;
};
expGain
+=
gain
;
moraCost
+=
gain
;
payList
.
add
(
new
ItemParamData
(
itemParam
.
getItemId
(),
itemParam
.
getCount
()));
}
// Make sure exp gain is valid
...
...
@@ -120,28 +122,14 @@ public class InventoryManager {
return
;
}
// Check mora
if
(
player
.
getMora
()
<
moraCost
)
{
// Confirm payment of materials and mora (assume food relics are payable afterwards)
payList
.
add
(
new
ItemParamData
(
202
,
moraCost
));
if
(!
player
.
getInventory
().
payItems
(
payList
.
toArray
(
new
ItemParamData
[
0
])))
{
return
;
}
player
.
setMora
(
player
.
getMora
()
-
moraCost
);
// Consume food items
for
(
long
guid
:
foodRelicList
)
{
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
);
}
// Consume food relics
player
.
getInventory
().
removeItems
(
foodRelics
);
// Implement random rate boost
int
rate
=
1
;
...
...
@@ -231,22 +219,16 @@ public class InventoryManager {
}
expGain
+=
food
.
getItemData
().
getWeaponBaseExp
();
if
(
food
.
getTotalExp
()
>
0
)
{
expGain
+=
(
int
)
Math
.
floor
(
food
.
getTotalExp
()
*
.
8
f
)
;
expGain
+=
(
food
.
getTotalExp
()
*
4
)
/
5
;
}
}
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
());
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
;
}
expGain
+=
param
.
getCount
()
*
switch
(
param
.
getItemId
())
{
case
WEAPON_ORE_1
->
WEAPON_ORE_EXP_1
;
case
WEAPON_ORE_2
->
WEAPON_ORE_EXP_2
;
case
WEAPON_ORE_3
->
WEAPON_ORE_EXP_3
;
default
->
0
;
};
}
// Try
...
...
@@ -288,65 +270,45 @@ public class InventoryManager {
}
// Get exp gain
int
expGain
=
0
,
moraCost
=
0
;
int
expGain
=
0
,
expGainFree
=
0
;
List
<
GameItem
>
foodWeapons
=
new
ArrayList
<
GameItem
>();
for
(
long
guid
:
foodWeaponGuidList
)
{
GameItem
food
=
player
.
getInventory
().
getItemByGuid
(
guid
);
if
(
food
==
null
||
!
food
.
isDestroyable
())
{
continue
;
}
expGain
+=
food
.
getItemData
().
getWeaponBaseExp
();
moraCost
+=
(
int
)
Math
.
floor
(
food
.
getItemData
().
getWeaponBaseExp
()
*
.
1
f
);
if
(
food
.
getTotalExp
()
>
0
)
{
expGain
+=
(
int
)
Math
.
floor
(
food
.
getTotalExp
()
*
.
8
f
);
expGain
Free
+=
(
food
.
getTotalExp
()
*
4
)
/
5
;
// No tax :D
}
foodWeapons
.
add
(
food
);
}
List
<
ItemParamData
>
payList
=
new
ArrayList
<
ItemParamData
>();
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
());
int
gain
=
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
;
}
int
amount
=
param
.
getCount
();
// Previously this capped to inventory amount, but rejecting the payment makes more sense for an invalid order
int
gain
=
amount
*
switch
(
param
.
getItemId
())
{
case
WEAPON_ORE_1
->
WEAPON_ORE_EXP_1
;
case
WEAPON_ORE_2
->
WEAPON_ORE_EXP_2
;
case
WEAPON_ORE_3
->
WEAPON_ORE_EXP_3
;
default
->
0
;
};
expGain
+=
gain
;
moraCost
+=
(
int
)
Math
.
floor
(
gain
*
.
1
f
);
payList
.
add
(
new
ItemParamData
(
param
.
getItemId
(),
amount
)
);
}
// Make sure exp gain is valid
int
moraCost
=
expGain
/
10
;
expGain
+=
expGainFree
;
if
(
expGain
<=
0
)
{
return
;
}
// Mora check
if
(
player
.
getMora
()
>=
moraCost
)
{
player
.
setMora
(
player
.
getMora
()
-
moraCost
);
}
else
{
// Confirm payment of materials and mora (assume food weapons are payable afterwards)
payList
.
add
(
new
ItemParamData
(
202
,
moraCost
));
if
(!
player
.
getInventory
().
payItems
(
payList
.
toArray
(
new
ItemParamData
[
0
])))
{
return
;
}
// 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
);
}
player
.
getInventory
().
removeItems
(
foodWeapons
);
// Level up
int
maxLevel
=
promoteData
.
getUnlockMaxLevel
();
...
...
@@ -393,7 +355,7 @@ public class InventoryManager {
player
.
sendPacket
(
new
PacketWeaponUpgradeRsp
(
weapon
,
oldLevel
,
leftovers
));
}
private
List
<
ItemParam
>
getLeftoverOres
(
floa
t
leftover
)
{
private
List
<
ItemParam
>
getLeftoverOres
(
in
t
leftover
)
{
List
<
ItemParam
>
leftoverOreList
=
new
ArrayList
<>(
3
);
if
(
leftover
<
WEAPON_ORE_EXP_1
)
{
...
...
@@ -401,11 +363,11 @@ public class InventoryManager {
}
// 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
;
int
ore2
=
(
int
)
Math
.
floor
(
leftover
/
WEAPON_ORE_EXP_2
)
;
int
ore2
=
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
)
{
leftoverOreList
.
add
(
ItemParam
.
newBuilder
().
setItemId
(
WEAPON_ORE_3
).
setCount
(
ore3
).
build
());
...
...
@@ -496,27 +458,16 @@ public class InventoryManager {
return
;
}
// Make sure player has promote items
for
(
ItemParamData
cost
:
nextPromoteData
.
getCostItems
())
{
GameItem
feedItem
=
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
cost
.
getId
());
if
(
feedItem
==
null
||
feedItem
.
getCount
()
<
cost
.
getCount
())
{
return
;
}
// Pay materials and mora if possible
ItemParamData
[]
costs
=
nextPromoteData
.
getCostItems
();
// Can this be null?
if
(
nextPromoteData
.
getCoinCost
()
>
0
)
{
costs
=
Arrays
.
copyOf
(
costs
,
costs
.
length
+
1
);
costs
[
costs
.
length
-
1
]
=
new
ItemParamData
(
202
,
nextPromoteData
.
getCoinCost
());
}
// Mora check
if
(
player
.
getMora
()
>=
nextPromoteData
.
getCoinCost
())
{
player
.
setMora
(
player
.
getMora
()
-
nextPromoteData
.
getCoinCost
());
}
else
{
if
(!
player
.
getInventory
().
payItems
(
costs
))
{
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
();
weapon
.
setPromoteLevel
(
nextPromoteLevel
);
weapon
.
save
();
...
...
@@ -552,27 +503,16 @@ public class InventoryManager {
return
;
}
// Make sure player has cost items
for
(
ItemParamData
cost
:
nextPromoteData
.
getCostItems
())
{
GameItem
feedItem
=
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
cost
.
getId
());
if
(
feedItem
==
null
||
feedItem
.
getCount
()
<
cost
.
getCount
())
{
return
;
}
// Pay materials and mora if possible
ItemParamData
[]
costs
=
nextPromoteData
.
getCostItems
();
// Can this be null?
if
(
nextPromoteData
.
getCoinCost
()
>
0
)
{
costs
=
Arrays
.
copyOf
(
costs
,
costs
.
length
+
1
);
costs
[
costs
.
length
-
1
]
=
new
ItemParamData
(
202
,
nextPromoteData
.
getCoinCost
());
}
// Mora check
if
(
player
.
getMora
()
>=
nextPromoteData
.
getCoinCost
())
{
player
.
setMora
(
player
.
getMora
()
-
nextPromoteData
.
getCoinCost
());
}
else
{
if
(!
player
.
getInventory
().
payItems
(
costs
))
{
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
avatar
.
setPromoteLevel
(
nextPromoteLevel
);
...
...
@@ -616,35 +556,26 @@ public class InventoryManager {
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
int
expGain
=
0
,
moraCost
=
0
;
// TODO clean up
if
(
itemId
==
AVATAR_BOOK_3
)
{
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
;
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
;
};
// Sanity check
if
(
expGain
<=
0
)
{
return
;
}
moraCost
=
(
int
)
Math
.
floor
(
expGain
*
.
2
f
);
// Mora check
if
(
player
.
getMora
()
>=
moraCost
)
{
player
.
setMora
(
player
.
getMora
()
-
moraCost
);
}
else
{
// Payment check
int
moraCost
=
expGain
/
5
;
ItemParamData
[]
costItems
=
new
ItemParamData
[]
{
new
ItemParamData
(
itemId
,
count
),
new
ItemParamData
(
202
,
moraCost
)};
if
(!
player
.
getInventory
().
payItems
(
costItems
))
{
return
;
}
// Consume items
player
.
getInventory
().
removeItem
(
feedItem
,
count
);
// Level up
upgradeAvatar
(
player
,
avatar
,
promoteData
,
expGain
);
}
...
...
@@ -764,33 +695,15 @@ public class InventoryManager {
return
;
}
// Make sure player has cost items
for
(
ItemParamData
cost
:
proudSkill
.
getCostItems
())
{
if
(
cost
.
getId
()
==
0
)
{
continue
;
}
GameItem
feedItem
=
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
cost
.
getId
());
if
(
feedItem
==
null
||
feedItem
.
getCount
()
<
cost
.
getCount
())
{
return
;
}
// Pay materials and mora if possible
List
<
ItemParamData
>
costs
=
new
ArrayList
<
ItemParamData
>(
proudSkill
.
getCostItems
());
// Can this be null?
if
(
proudSkill
.
getCoinCost
()
>
0
)
{
costs
.
add
(
new
ItemParamData
(
202
,
proudSkill
.
getCoinCost
()));
}
// Mora check
if
(
player
.
getMora
()
>=
proudSkill
.
getCoinCost
())
{
player
.
setMora
(
player
.
getMora
()
-
proudSkill
.
getCoinCost
());
}
else
{
if
(!
player
.
getInventory
().
payItems
(
costs
.
toArray
(
new
ItemParamData
[
0
])))
{
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
avatar
.
getSkillLevelMap
().
put
(
skillId
,
nextLevel
);
avatar
.
save
();
...
...
@@ -822,14 +735,11 @@ public class InventoryManager {
return
;
}
GameItem
cost
Item
=
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
talentData
.
getMainCostItemId
());
if
(
costItem
==
null
||
costItem
.
getCount
()
<
talentData
.
getMainCostItem
Count
(
))
{
// Pay
co
n
st
ellation item if possible
if
(
!
player
.
getInventory
().
payItem
(
talentData
.
getMainCostItem
Id
(),
1
))
{
return
;
}
// Consume item
player
.
getInventory
().
removeItem
(
costItem
,
talentData
.
getMainCostItemCount
());
// Apply + recalc
avatar
.
getTalentIdList
().
add
(
talentData
.
getId
());
avatar
.
setCoreProudSkillLevel
(
currentTalentLevel
+
1
);
...
...
src/main/java/emu/grasscutter/game/managers/StaminaManager/AfterUpdateStaminaListener.java
View file @
9b26426e
...
...
@@ -8,5 +8,5 @@ public interface AfterUpdateStaminaListener {
* @param reason Why updating stamina.
* @param newStamina New Stamina value.
*/
void
onAfterUpdateStamina
(
String
reason
,
int
newStamina
);
void
onAfterUpdateStamina
(
String
reason
,
int
newStamina
,
boolean
isCharacterStamina
);
}
src/main/java/emu/grasscutter/game/managers/StaminaManager/BeforeUpdateStaminaListener.java
View file @
9b26426e
...
...
@@ -8,7 +8,7 @@ public interface BeforeUpdateStaminaListener {
* @param newStamina New ABSOLUTE stamina value.
* @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.
* This gives listeners a chance to intercept this update.
...
...
@@ -16,5 +16,5 @@ public interface BeforeUpdateStaminaListener {
* @param consumption ConsumptionType and RELATIVE stamina change amount.
* @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
);
}
\ No newline at end of file
src/main/java/emu/grasscutter/game/managers/StaminaManager/ConsumptionType.java
View file @
9b26426e
...
...
@@ -13,18 +13,19 @@ public enum ConsumptionType {
// Slow swimming is handled per movement, not per second.
// Arm movement frequency depends on gender/age/height.
// 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
),
SWIM_DASH_START
(-
20
),
SWIM_DASH_START
(-
20
00
),
SWIM_DASH
(-
204
),
// -10.2 per second, 5Hz = -204 each tick
SWIMMING
(-
80
),
TALENT_DASH
(-
300
),
// -1500 per second, 5Hz = -300 each tick
TALENT_DASH_START
(-
1000
),
// restore
POWERED_FLY
(
500
),
// TODO: Get real value
POWERED_SKIFF
(
20
00
),
// TODO: Get real value
POWERED_FLY
(
500
),
POWERED_SKIFF
(
5
00
),
RUN
(
500
),
SKIFF
(
500
),
STANDBY
(
500
),
WALK
(
500
);
...
...
src/main/java/emu/grasscutter/game/managers/StaminaManager/StaminaManager.java
View file @
9b26426e
This diff is collapsed.
Click to expand it.
src/main/java/emu/grasscutter/game/player/Player.java
View file @
9b26426e
...
...
@@ -85,6 +85,8 @@ public class Player {
private
Set
<
Integer
>
flyCloakList
;
private
Set
<
Integer
>
costumeList
;
private
Integer
widgetId
;
@Transient
private
long
nextGuid
=
0
;
@Transient
private
int
peerId
;
@Transient
private
World
world
;
...
...
@@ -302,6 +304,14 @@ public class Player {
this
.
updateProfile
();
}
public
Integer
getWidgetId
()
{
return
widgetId
;
}
public
void
setWidgetId
(
Integer
widgetId
)
{
this
.
widgetId
=
widgetId
;
}
public
Position
getPos
()
{
return
pos
;
}
...
...
@@ -1170,7 +1180,9 @@ public class Player {
session
.
send
(
new
PacketFinishedParentQuestNotify
(
this
));
session
.
send
(
new
PacketQuestListNotify
(
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.
session
.
send
(
new
PacketPlayerEnterSceneNotify
(
this
));
// Enter game world
...
...
@@ -1267,7 +1279,7 @@ public class Player {
}
else
if
(
prop
==
PlayerProperty
.
PROP_IS_TRANSFERABLE
)
{
// 10009
if
(!(
0
<=
value
&&
value
<=
1
))
{
return
false
;
}
}
else
if
(
prop
==
PlayerProperty
.
PROP_MAX_STAMINA
)
{
// 10010
if
(!(
value
>=
0
&&
value
<=
StaminaManager
.
GlobalMaximumStamina
))
{
return
false
;
}
if
(!(
value
>=
0
&&
value
<=
StaminaManager
.
Global
Character
MaximumStamina
))
{
return
false
;
}
}
else
if
(
prop
==
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
)
{
// 10011
int
playerMaximumStamina
=
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
);
if
(!(
value
>=
0
&&
value
<=
playerMaximumStamina
))
{
return
false
;
}
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java
View file @
9b26426e
...
...
@@ -18,7 +18,7 @@ import emu.grasscutter.server.packet.send.PacketBuyGoodsRsp;
import
emu.grasscutter.server.packet.send.PacketStoreItemChangeNotify
;
import
emu.grasscutter.utils.Utils
;
import
java.util.
HashMap
;
import
java.util.
ArrayList
;
import
java.util.List
;
import
java.util.Optional
;
...
...
@@ -56,36 +56,13 @@ public class HandlerBuyGoodsReq extends PacketHandler {
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
;
}
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
));
GameItem
item
=
new
GameItem
(
GameData
.
getItemDataMap
().
get
(
sg
.
getGoodsItem
().
getId
()));
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerGetWidgetSlotReq.java
View file @
9b26426e
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketGetShopRsp
;
import
emu.grasscutter.server.packet.send.PacketGetWidgetSlotRsp
;
@Opcodes
(
PacketOpcodes
.
GetWidgetSlotReq
)
public
class
HandlerGetWidgetSlotReq
extends
PacketHandler
{
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
// Unhandled
Player
player
=
session
.
getPlayer
();
session
.
send
(
new
PacketGetWidgetSlotRsp
(
player
));
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerSetWidgetSlotReq.java
0 → 100644
View file @
9b26426e
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
()));
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerVehicleInteractReq.java
View file @
9b26426e
...
...
@@ -14,6 +14,7 @@ public class HandlerVehicleInteractReq extends PacketHandler {
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
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
()));
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketAllWidgetDataNotify.java
0 → 100644
View file @
9b26426e
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
);
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketGetWidgetSlotRsp.java
0 → 100644
View file @
9b26426e
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
);
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketSetWidgetSlotRsp.java
0 → 100644
View file @
9b26426e
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
);
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketVehicleStaminaNotify.java
0 → 100644
View file @
9b26426e
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
());
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketWidgetGadgetAllDataNotify.java
0 → 100644
View file @
9b26426e
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
);
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketWidgetSlotChangeNotify.java
0 → 100644
View file @
9b26426e
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
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment