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
fbc0219c
Commit
fbc0219c
authored
Sep 23, 2022
by
AnimeGitB
Browse files
Allow loading Resources from zip files
Move Resources loading from String filenames to Paths Add zip support
parent
a90455a7
Changes
9
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/Grasscutter.java
View file @
fbc0219c
...
...
@@ -45,7 +45,6 @@ import javax.annotation.Nullable;
import
java.io.*
;
import
java.util.Calendar
;
import
static
emu
.
grasscutter
.
config
.
Configuration
.
DATA
;
import
static
emu
.
grasscutter
.
config
.
Configuration
.
SERVER
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
...
...
@@ -203,7 +202,7 @@ public final class Grasscutter {
// If the file already exists, we attempt to load it.
try
{
config
=
JsonUtils
.
loadToClass
(
configFile
.
ge
tPath
(),
ConfigContainer
.
class
);
config
=
JsonUtils
.
loadToClass
(
configFile
.
t
o
Path
(),
ConfigContainer
.
class
);
}
catch
(
Exception
exception
)
{
getLogger
().
error
(
"There was an error while trying to load the configuration from config.json. Please make sure that there are no syntax errors. If you want to start with a default configuration, delete your existing config.json."
);
System
.
exit
(
1
);
...
...
src/main/java/emu/grasscutter/config/ConfigContainer.java
View file @
fbc0219c
...
...
@@ -26,7 +26,7 @@ public class ConfigContainer {
*/
public
static
void
updateConfig
()
{
try
{
// Check if the server is using a legacy config.
JsonObject
configObject
=
JsonUtils
.
loadToClass
(
Grasscutter
.
configFile
.
ge
tPath
(),
JsonObject
.
class
);
JsonObject
configObject
=
JsonUtils
.
loadToClass
(
Grasscutter
.
configFile
.
t
o
Path
(),
JsonObject
.
class
);
if
(!
configObject
.
has
(
"version"
))
{
Grasscutter
.
getLogger
().
info
(
"Updating legacy .."
);
Grasscutter
.
saveConfig
(
null
);
...
...
src/main/java/emu/grasscutter/config/Configuration.java
View file @
fbc0219c
package
emu.grasscutter.config
;
import
java.util.Locale
;
import
java.util.stream.Stream
;
import
emu.grasscutter.Grasscutter
;
import
java.io.IOException
;
import
java.nio.file.FileSystem
;
import
java.nio.file.FileSystems
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
static
emu
.
grasscutter
.
Grasscutter
.
config
;
...
...
@@ -30,6 +38,42 @@ public final class Configuration extends ConfigContainer {
private
static
final
String
PLUGINS_FOLDER
=
config
.
folderStructure
.
plugins
;
private
static
final
String
SCRIPTS_FOLDER
=
config
.
folderStructure
.
scripts
;
private
static
final
String
PACKETS_FOLDER
=
config
.
folderStructure
.
packets
;
private
static
final
FileSystem
RESOURCES_FILE_SYSTEM
;
// Not sure about lifetime rules on this one, might be safe to remove
private
static
final
Path
RESOURCES_PATH
;
static
{
FileSystem
fs
=
null
;
Path
path
=
Path
.
of
(
RESOURCES_FOLDER
);
if
(
RESOURCES_FOLDER
.
endsWith
(
".zip"
))
{
// Would be nice to support .tar.gz too at some point, but it doesn't come for free in Java
try
{
fs
=
FileSystems
.
newFileSystem
(
path
);
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Failed to load resources zip \""
+
RESOURCES_FOLDER
+
"\""
);
}
}
if
(
fs
!=
null
)
{
var
root
=
fs
.
getPath
(
""
);
try
(
Stream
<
Path
>
pathStream
=
java
.
nio
.
file
.
Files
.
find
(
root
,
3
,
(
p
,
a
)
->
{
var
filename
=
p
.
getFileName
();
if
(
filename
==
null
)
return
false
;
return
filename
.
toString
().
equals
(
"ExcelBinOutput"
);
}))
{
var
excelBinOutput
=
pathStream
.
findFirst
();
if
(
excelBinOutput
.
isPresent
())
{
path
=
excelBinOutput
.
get
().
getParent
();
if
(
path
==
null
)
path
=
root
;
Grasscutter
.
getLogger
().
debug
(
"Resources will be loaded from \""
+
RESOURCES_FOLDER
+
"/"
+
path
.
toString
()
+
"\""
);
}
else
{
Grasscutter
.
getLogger
().
error
(
"Failed to find ExcelBinOutput in resources zip \""
+
RESOURCES_FOLDER
+
"\""
);
}
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Failed to scan resources zip \""
+
RESOURCES_FOLDER
+
"\""
);
}
}
RESOURCES_FILE_SYSTEM
=
fs
;
RESOURCES_PATH
=
path
;
};
public
static
final
Server
SERVER
=
config
.
server
;
public
static
final
Database
DATABASE
=
config
.
databaseInfo
;
...
...
@@ -54,11 +98,15 @@ public final class Configuration extends ConfigContainer {
}
public
static
String
DATA
(
String
path
)
{
return
Paths
.
get
(
DATA_FOLDER
,
path
).
toString
();
return
Path
.
of
(
DATA_FOLDER
,
path
).
toString
();
}
public
static
Path
getResourcePath
(
String
path
)
{
return
RESOURCES_PATH
.
resolve
(
path
);
}
public
static
String
RESOURCE
(
String
path
)
{
return
Paths
.
get
(
RESOURCES_FOLDER
,
path
).
toString
();
return
getResourcePath
(
path
).
toString
();
}
public
static
String
PLUGIN
()
{
...
...
@@ -66,15 +114,15 @@ public final class Configuration extends ConfigContainer {
}
public
static
String
PLUGIN
(
String
path
)
{
return
Path
s
.
get
(
PLUGINS_FOLDER
,
path
).
toString
();
return
Path
.
of
(
PLUGINS_FOLDER
,
path
).
toString
();
}
public
static
String
SCRIPT
(
String
path
)
{
return
Path
s
.
get
(
SCRIPTS_FOLDER
,
path
).
toString
();
return
Path
.
of
(
SCRIPTS_FOLDER
,
path
).
toString
();
}
public
static
String
PACKET
(
String
path
)
{
return
Path
s
.
get
(
PACKETS_FOLDER
,
path
).
toString
();
return
Path
.
of
(
PACKETS_FOLDER
,
path
).
toString
();
}
/**
...
...
src/main/java/emu/grasscutter/data/ResourceLoader.java
View file @
fbc0219c
...
...
@@ -5,7 +5,6 @@ import com.google.gson.annotations.SerializedName;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.binout.*
;
import
emu.grasscutter.data.binout.AbilityModifier.AbilityConfigData
;
import
emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction
;
import
emu.grasscutter.data.binout.AbilityModifier.AbilityModifierActionType
;
import
emu.grasscutter.data.common.PointData
;
import
emu.grasscutter.data.common.ScenePointConfig
;
...
...
@@ -16,21 +15,19 @@ import emu.grasscutter.game.world.SpawnDataEntry.GridBlockId;
import
emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry
;
import
emu.grasscutter.scripts.SceneIndexManager
;
import
emu.grasscutter.utils.JsonUtils
;
import
emu.grasscutter.utils.Utils
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
lombok.SneakyThrows
;
import
lombok.val
;
import
org.reflections.Reflections
;
import
java.io.*
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.util.*
;
import
java.util.Map.Entry
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
java.util.stream.Stream
;
import
static
emu
.
grasscutter
.
config
.
Configuration
.
DATA
;
import
static
emu
.
grasscutter
.
config
.
Configuration
.
RESOURCE
;
import
static
emu
.
grasscutter
.
config
.
Configuration
.
getResourcePath
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
public
class
ResourceLoader
{
...
...
@@ -105,7 +102,7 @@ public class ResourceLoader {
try
{
loadFromResource
(
resourceDefinition
,
type
,
map
,
doReload
);
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading resource file: "
+
Arrays
.
toString
(
type
.
name
()),
e
);
Grasscutter
.
getLogger
().
error
(
"Error loading resource file: "
+
Arrays
.
toString
(
type
.
name
()),
e
.
getLocalizedMessage
()
);
}
}
}
...
...
@@ -123,7 +120,7 @@ public class ResourceLoader {
@SuppressWarnings
({
"rawtypes"
,
"unchecked"
})
protected
static
<
T
>
void
loadFromResource
(
Class
<
T
>
c
,
String
fileName
,
Int2ObjectMap
map
)
throws
Exception
{
List
<
T
>
list
=
JsonUtils
.
loadToList
(
RESOURCE
(
"ExcelBinOutput/"
+
fileName
),
c
);
List
<
T
>
list
=
JsonUtils
.
loadToList
(
getResourcePath
(
"ExcelBinOutput/"
+
fileName
),
c
);
for
(
T
o
:
list
)
{
GameResource
res
=
(
GameResource
)
o
;
...
...
@@ -133,50 +130,42 @@ public class ResourceLoader {
}
private
static
void
loadScenePoints
()
{
Pattern
pattern
=
Pattern
.
compile
(
"
(?<=
scene
)(.*?)(?=
_point.json
)
"
);
File
folder
=
new
File
(
RESOURCE
(
"BinOutput/Scene/Point"
));
if
(!
folder
.
isDirectory
()
||
!
folder
.
exists
()
||
folder
.
listFiles
()
==
null
)
{
Grasscutter
.
getLogger
().
error
(
"Scene point files cannot be found, you cannot use teleport waypoints!"
)
;
return
;
}
val
pattern
=
Pattern
.
compile
(
"scene
([0-9]+)
_point
\\
.json"
);
try
{
Files
.
newDirectoryStream
(
getResourcePath
(
"BinOutput/Scene/Point"
),
"scene*_point.json"
).
forEach
(
path
->
{
val
matcher
=
pattern
.
matcher
(
path
.
getFileName
().
toString
());
if
(!
matcher
.
find
())
return
;
int
sceneId
=
Integer
.
parseInt
(
matcher
.
group
(
1
))
;
ScenePointConfig
config
;
for
(
File
file
:
Objects
.
requireNonNull
(
folder
.
listFiles
()))
{
ScenePointConfig
config
;
Integer
sceneId
;
try
{
config
=
JsonUtils
.
loadToClass
(
path
,
ScenePointConfig
.
class
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
;
}
Matcher
matcher
=
pattern
.
matcher
(
file
.
getName
());
if
(
matcher
.
find
())
{
sceneId
=
Integer
.
parseInt
(
matcher
.
group
(
1
));
}
else
{
continue
;
}
if
(
config
.
points
==
null
)
return
;
try
{
config
=
JsonUtils
.
loadToClass
(
file
.
getPath
(),
ScenePointConfig
.
class
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
continue
;
}
List
<
Integer
>
scenePoints
=
new
ArrayList
<>();
for
(
Map
.
Entry
<
String
,
JsonElement
>
entry
:
config
.
points
.
entrySet
())
{
String
key
=
entry
.
getKey
();
String
name
=
sceneId
+
"_"
+
key
;
int
id
=
Integer
.
parseInt
(
key
);
PointData
pointData
=
JsonUtils
.
decode
(
entry
.
getValue
(),
PointData
.
class
);
pointData
.
setId
(
id
);
if
(
config
.
points
==
null
)
{
continue
;
}
GameData
.
getScenePointIdList
().
add
(
id
);
GameData
.
getScenePointEntries
().
put
(
name
,
new
ScenePointEntry
(
name
,
pointData
))
;
scenePoints
.
add
(
id
);
List
<
Integer
>
scenePoints
=
new
ArrayList
<>();
for
(
Map
.
Entry
<
String
,
JsonElement
>
entry
:
config
.
points
.
entrySet
())
{
int
id
=
Integer
.
parseInt
(
entry
.
getKey
());
String
name
=
sceneId
+
"_"
+
entry
.
getKey
();
PointData
pointData
=
JsonUtils
.
decode
(
entry
.
getValue
(),
PointData
.
class
);
pointData
.
setId
(
id
);
GameData
.
getScenePointIdList
().
add
(
id
);
GameData
.
getScenePointEntries
().
put
(
name
,
new
ScenePointEntry
(
name
,
pointData
));
scenePoints
.
add
(
id
);
pointData
.
updateDailyDungeon
();
}
GameData
.
getScenePointsPerScene
().
put
(
sceneId
,
scenePoints
);
pointData
.
updateDailyDungeon
();
}
GameData
.
getScenePointsPerScene
().
put
(
sceneId
,
scenePoints
);
});
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Scene point files cannot be found, you cannot use teleport waypoints!"
);
return
;
}
}
...
...
@@ -190,47 +179,40 @@ public class ResourceLoader {
if
(
embryoList
==
null
)
{
// Load from BinOutput
Pattern
pattern
=
Pattern
.
compile
(
"(?<=ConfigAvatar_)(.*?)(?=.json)"
);
embryoList
=
new
ArrayList
<>();
File
folder
=
new
File
(
Utils
.
toFilePath
(
RESOURCE
(
"BinOutput/Avatar/"
)));
File
[]
files
=
folder
.
listFiles
();
if
(
files
==
null
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading ability embryos: no files found in "
+
folder
.
getAbsolutePath
());
return
;
}
val
pattern
=
Pattern
.
compile
(
"ConfigAvatar_(.+?)\\.json"
);
for
(
File
file
:
files
)
{
AvatarConfig
config
;
String
avatarName
;
Matcher
matcher
=
pattern
.
matcher
(
file
.
getName
());
if
(
matcher
.
find
())
{
avatarName
=
matcher
.
group
(
0
);
}
else
{
continue
;
}
val
l
=
new
ArrayList
<
AbilityEmbryoEntry
>();
try
{
Files
.
newDirectoryStream
(
getResourcePath
(
"BinOutput/Avatar/"
),
"ConfigAvatar_*.json"
).
forEach
(
path
->
{
val
matcher
=
pattern
.
matcher
(
path
.
getFileName
().
toString
());
if
(!
matcher
.
find
())
return
;
String
avatarName
=
matcher
.
group
(
1
);
AvatarConfig
config
;
try
{
config
=
JsonUtils
.
loadToClass
(
file
.
getP
ath
()
,
AvatarConfig
.
class
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
(
);
continue
;
}
try
{
config
=
JsonUtils
.
loadToClass
(
p
ath
,
AvatarConfig
.
class
);
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading player ability embryos:"
,
e
);
return
;
}
if
(
config
.
abilities
==
null
)
{
continue
;
}
if
(
config
.
abilities
==
null
)
return
;
int
s
=
config
.
abilities
.
size
();
AbilityEmbryoEntry
al
=
new
AbilityEmbryoEntry
(
avatarName
,
config
.
abilities
.
stream
().
map
(
Object:
:
toString
).
toArray
(
size
->
new
String
[
s
]));
embryoList
.
add
(
al
);
int
s
=
config
.
abilities
.
size
();
AbilityEmbryoEntry
al
=
new
AbilityEmbryoEntry
(
avatarName
,
config
.
abilities
.
stream
().
map
(
Object:
:
toString
).
toArray
(
size
->
new
String
[
s
]));
l
.
add
(
al
);
});
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading ability embryos: no files found"
);
return
;
}
embryoList
=
l
;
try
{
GameDepot
.
setPlayerAbilities
(
JsonUtils
.
loadToMap
(
RESOURCE
(
"BinOutput/AbilityGroup/AbilityGroup_Other_PlayerElementAbility.json"
),
String
.
class
,
AvatarConfig
.
class
));
}
catch
(
Exception
e
)
{
e
.
printStackTrace
(
);
GameDepot
.
setPlayerAbilities
(
JsonUtils
.
loadToMap
(
getResourcePath
(
"BinOutput/AbilityGroup/AbilityGroup_Other_PlayerElementAbility.json"
),
String
.
class
,
AvatarConfig
.
class
));
}
catch
(
IO
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading player abilities:"
,
e
);
}
}
...
...
@@ -246,64 +228,54 @@ public class ResourceLoader {
private
static
void
loadAbilityModifiers
()
{
// Load from BinOutput
File
folder
=
new
File
(
Utils
.
toFilePath
(
RESOURCE
(
"BinOutput/Ability/Temp/AvatarAbilities/"
)));
File
[]
files
=
folder
.
listFiles
();
if
(
files
==
null
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading ability modifiers: no files found in "
+
folder
.
getAbsolutePath
());
return
;
}
for
(
File
file
:
files
)
{
List
<
AbilityConfigData
>
abilityConfigList
;
try
{
abilityConfigList
=
JsonUtils
.
loadToList
(
file
.
getPath
(),
AbilityConfigData
.
class
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
continue
;
}
try
{
Files
.
newDirectoryStream
(
getResourcePath
(
"BinOutput/Ability/Temp/AvatarAbilities/"
)).
forEach
(
path
->
{
List
<
AbilityConfigData
>
abilityConfigList
;
for
(
AbilityConfigData
data
:
abilityConfigList
)
{
if
(
data
.
Default
.
modifiers
==
null
||
data
.
Default
.
modifiers
.
size
()
==
0
)
{
continue
;
try
{
abilityConfigList
=
JsonUtils
.
loadToList
(
path
,
AbilityConfigData
.
class
);
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading ability modifiers from path "
+
path
.
toString
()
+
": "
,
e
);
return
;
}
A
bility
ModifierEntry
modifierEntry
=
new
AbilityModifierEntry
(
data
.
Default
.
abilityName
);
for
(
Entry
<
String
,
AbilityModifier
>
entry
:
data
.
Default
.
modifiers
.
entrySet
())
{
AbilityModifier
modifier
=
entry
.
getValue
();
a
bility
ConfigList
.
forEach
(
data
->
{
if
(
data
.
Default
.
modifiers
==
null
||
data
.
Default
.
modifiers
.
size
()
==
0
)
{
return
;
}
// Stare.
if
(
modifier
.
onAdded
!=
null
)
{
for
(
AbilityModifierAction
action
:
modifier
.
onAdded
)
{
if
(
action
.
$type
.
contains
(
"HealHP"
))
{
String
name
=
data
.
Default
.
abilityName
;
AbilityModifierEntry
modifierEntry
=
new
AbilityModifierEntry
(
name
);
data
.
Default
.
modifiers
.
forEach
((
key
,
modifier
)
->
{
Stream
.
ofNullable
(
modifier
.
onAdded
)
.
flatMap
(
Stream:
:
of
)
.
filter
(
action
->
action
.
$type
.
contains
(
"HealHP"
))
.
forEach
(
action
->
{
action
.
type
=
AbilityModifierActionType
.
HealHP
;
modifierEntry
.
getOnAdded
().
add
(
action
);
}
}
}
if
(
modifier
.
onThinkInterval
!=
null
)
{
for
(
AbilityModifierAction
action
:
modifier
.
onThinkInterval
)
{
if
(
action
.
$type
.
contains
(
"HealHP"
))
{
});
Stream
.
ofNullable
(
modifier
.
onThinkInterval
)
.
flatMap
(
Stream:
:
of
)
.
filter
(
action
->
action
.
$type
.
contains
(
"HealHP"
))
.
forEach
(
action
->
{
action
.
type
=
AbilityModifierActionType
.
HealHP
;
modifierEntry
.
getOnThinkInterval
().
add
(
action
);
}
}
}
if
(
modifier
.
onRemoved
!=
null
)
{
for
(
AbilityModifierAction
action
:
modifier
.
onRemoved
)
{
if
(
action
.
$type
.
contains
(
"HealHP"
))
{
});
Stream
.
ofNullable
(
modifier
.
onRemoved
)
.
flatMap
(
Stream:
:
of
)
.
filter
(
action
->
action
.
$type
.
contains
(
"HealHP"
))
.
forEach
(
action
->
{
action
.
type
=
AbilityModifierActionType
.
HealHP
;
modifierEntry
.
getOnRemoved
().
add
(
action
);
}
}
}
}
GameData
.
getAbilityModifiers
().
put
(
modifierEntry
.
getName
(),
modifierEntry
);
}
});
});
GameData
.
getAbilityModifiers
().
put
(
name
,
modifierEntry
);
});
});
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading ability modifiers: "
,
e
);
return
;
}
}
...
...
@@ -353,30 +325,20 @@ public class ResourceLoader {
Map
<
String
,
OpenConfigEntry
>
map
=
new
TreeMap
<>();
String
[]
folderNames
=
{
"BinOutput/Talent/EquipTalents/"
,
"BinOutput/Talent/AvatarTalents/"
};
for
(
String
name
:
folderNames
)
{
File
folder
=
new
File
(
Utils
.
toFilePath
(
RESOURCE
(
name
)));
File
[]
files
=
folder
.
listFiles
();
if
(
files
==
null
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading open config: no files found in "
+
folder
.
getAbsolutePath
());
return
;
}
for
(
File
file
:
files
)
{
if
(!
file
.
getName
().
endsWith
(
".json"
))
{
continue
;
}
Map
<
String
,
OpenConfigData
[]>
config
;
try
{
config
=
JsonUtils
.
loadToMap
(
file
.
getPath
(),
String
.
class
,
OpenConfigData
[].
class
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
continue
;
}
for
(
Entry
<
String
,
OpenConfigData
[]>
e
:
config
.
entrySet
())
{
OpenConfigEntry
entry
=
new
OpenConfigEntry
(
e
.
getKey
(),
e
.
getValue
());
map
.
put
(
entry
.
getName
(),
entry
);
}
for
(
String
folderName
:
folderNames
)
{
try
{
Files
.
newDirectoryStream
(
getResourcePath
(
folderName
),
"*.json"
).
forEach
(
path
->
{
try
{
JsonUtils
.
loadToMap
(
path
,
String
.
class
,
OpenConfigData
[].
class
)
.
forEach
((
name
,
data
)
->
map
.
put
(
name
,
new
OpenConfigEntry
(
name
,
data
)));
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
;
}
});
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading open config: no files found in "
+
folderName
);
return
;
}
}
...
...
@@ -394,37 +356,29 @@ public class ResourceLoader {
}
private
static
void
loadQuests
()
{
File
folder
=
new
File
(
RESOURCE
(
"BinOutput/Quest/"
));
try
{
Files
.
list
(
getResourcePath
(
"BinOutput/Quest/"
)).
forEach
(
path
->
{
try
{
val
mainQuest
=
JsonUtils
.
loadToClass
(
path
,
MainQuestData
.
class
);
GameData
.
getMainQuestDataMap
().
put
(
mainQuest
.
getId
(),
mainQuest
);
}
catch
(
IOException
e
)
{
if
(!
folder
.
exists
())
{
}
});
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Quest data missing"
);
return
;
}
for
(
File
file
:
folder
.
listFiles
())
{
MainQuestData
mainQuest
=
null
;
try
{
mainQuest
=
JsonUtils
.
loadToClass
(
file
.
getPath
(),
MainQuestData
.
class
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
continue
;
}
GameData
.
getMainQuestDataMap
().
put
(
mainQuest
.
getId
(),
mainQuest
);
}
try
{
List
<
QuestEncryptionKey
>
keys
;
Int2ObjectMap
<
QuestEncryptionKey
>
questEncryptionMap
=
GameData
.
getMainQuestEncryptionMap
();
val
questEncryptionMap
=
GameData
.
getMainQuestEncryptionMap
();
String
path
=
"QuestEncryptionKeys.json"
;
if
(
Utils
.
fileExists
(
RESOURCE
(
path
)))
{
keys
=
JsonUtils
.
loadToList
(
RESOURCE
(
path
),
QuestEncryptionKey
.
class
);
keys
.
forEach
(
key
->
questEncryptionMap
.
put
(
key
.
getMainQuestId
(),
key
));
}
if
(
Utils
.
fileExists
(
DATA
(
path
)))
{
keys
=
DataLoader
.
loadList
(
path
,
QuestEncryptionKey
.
class
);
keys
.
forEach
(
key
->
questEncryptionMap
.
put
(
key
.
getMainQuestId
(),
key
));
}
try
{
JsonUtils
.
loadToList
(
getResourcePath
(
path
),
QuestEncryptionKey
.
class
).
forEach
(
key
->
questEncryptionMap
.
put
(
key
.
getMainQuestId
(),
key
));
}
catch
(
IOException
|
NullPointerException
ignored
)
{}
try
{
DataLoader
.
loadList
(
path
,
QuestEncryptionKey
.
class
).
forEach
(
key
->
questEncryptionMap
.
put
(
key
.
getMainQuestId
(),
key
));
}
catch
(
IOException
|
NullPointerException
ignored
)
{}
Grasscutter
.
getLogger
().
debug
(
"Loaded {} quest keys."
,
questEncryptionMap
.
size
());
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"Unable to load quest keys."
,
e
);
...
...
@@ -434,95 +388,84 @@ public class ResourceLoader {
}
public
static
void
loadScriptSceneData
()
{
File
folder
=
new
File
(
RESOURCE
(
"ScriptSceneData/"
));
if
(!
folder
.
exists
())
{
try
{
Files
.
list
(
getResourcePath
(
"ScriptSceneData/"
)).
forEach
(
path
->
{
try
{
GameData
.
getScriptSceneDataMap
().
put
(
path
.
getFileName
().
toString
(),
JsonUtils
.
loadToClass
(
path
,
ScriptSceneData
.
class
));
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
return
;
}
});
Grasscutter
.
getLogger
().
debug
(
"Loaded "
+
GameData
.
getScriptSceneDataMap
().
size
()
+
" ScriptSceneDatas."
);
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
debug
(
"ScriptSceneData folder missing or empty."
);
return
;
}
for
(
File
file
:
folder
.
listFiles
())
{
ScriptSceneData
sceneData
;
try
{
sceneData
=
JsonUtils
.
loadToClass
(
file
.
getPath
(),
ScriptSceneData
.
class
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
continue
;
}
GameData
.
getScriptSceneDataMap
().
put
(
file
.
getName
(),
sceneData
);
}
Grasscutter
.
getLogger
().
debug
(
"Loaded "
+
GameData
.
getScriptSceneDataMap
().
size
()
+
" ScriptSceneDatas."
);
}
@SneakyThrows
private
static
void
loadHomeworldDefaultSaveData
()
{
var
pattern
=
Pattern
.
compile
(
"scene(.*)_home_config.json"
);
Files
.
list
(
Path
.
of
(
RESOURCE
(
"BinOutput/HomeworldDefaultSave"
))).
forEach
(
file
->
{
String
filename
=
file
.
getFileName
().
toString
();
var
matcher
=
pattern
.
matcher
(
filename
);
if
(!
matcher
.
find
())
{
return
;
}
try
{
var
sceneId
=
Integer
.
parseInt
(
matcher
.
group
(
1
));
var
data
=
JsonUtils
.
loadToClass
(
file
.
toString
(),
HomeworldDefaultSaveData
.
class
);
GameData
.
getHomeworldDefaultSaveData
().
put
(
sceneId
,
data
);
}
catch
(
Exception
ignored
)
{}
});
val
pattern
=
Pattern
.
compile
(
"scene([0-9]+)_home_config\\.json"
);
try
{
Files
.
newDirectoryStream
(
getResourcePath
(
"BinOutput/HomeworldDefaultSave"
),
"scene*_home_config.json"
).
forEach
(
path
->
{
val
matcher
=
pattern
.
matcher
(
path
.
getFileName
().
toString
());
if
(!
matcher
.
find
())
return
;
Grasscutter
.
getLogger
().
debug
(
"Loaded "
+
GameData
.
getHomeworldDefaultSaveData
().
size
()
+
" HomeworldDefaultSaveDatas."
);
try
{
val
sceneId
=
Integer
.
parseInt
(
matcher
.
group
(
1
));
val
data
=
JsonUtils
.
loadToClass
(
path
,
HomeworldDefaultSaveData
.
class
);
GameData
.
getHomeworldDefaultSaveData
().
put
(
sceneId
,
data
);
}
catch
(
Exception
ignored
)
{}
});
Grasscutter
.
getLogger
().
debug
(
"Loaded "
+
GameData
.
getHomeworldDefaultSaveData
().
size
()
+
" HomeworldDefaultSaveDatas."
);
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Failed to load HomeworldDefaultSave folder."
);
}
}
@SneakyThrows
private
static
void
loadNpcBornData
()
{
Files
.
list
(
Path
.
of
(
RESOURCE
(
"BinOutput/Scene/SceneNpcBorn"
))).
forEach
(
file
->
{
if
(
file
.
toFile
().
isDirectory
())
{
return
;
}
try
{
var
data
=
JsonUtils
.
loadToClass
(
file
.
toString
(),
SceneNpcBornData
.
class
);
if
(
data
.
getBornPosList
()
==
null
||
data
.
getBornPosList
().
size
()
==
0
)
{
return
;
}
data
.
setIndex
(
SceneIndexManager
.
buildIndex
(
3
,
data
.
getBornPosList
(),
item
->
item
.
getPos
().
toPoint
()));
GameData
.
getSceneNpcBornData
().
put
(
data
.
getSceneId
(),
data
);
}
catch
(
Exception
ignored
)
{}
});
try
{
Files
.
newDirectoryStream
(
getResourcePath
(
"BinOutput/Scene/SceneNpcBorn/"
),
"*.json"
).
forEach
(
path
->
{
try
{
val
data
=
JsonUtils
.
loadToClass
(
path
,
SceneNpcBornData
.
class
);
if
(
data
.
getBornPosList
()
==
null
||
data
.
getBornPosList
().
size
()
==
0
)
{
return
;
}
Grasscutter
.
getLogger
().
debug
(
"Loaded "
+
GameData
.
getSceneNpcBornData
().
size
()
+
" SceneNpcBornDatas."
);
data
.
setIndex
(
SceneIndexManager
.
buildIndex
(
3
,
data
.
getBornPosList
(),
item
->
item
.
getPos
().
toPoint
()));
GameData
.
getSceneNpcBornData
().
put
(
data
.
getSceneId
(),
data
);
}
catch
(
IOException
ignored
)
{}
});
Grasscutter
.
getLogger
().
debug
(
"Loaded "
+
GameData
.
getSceneNpcBornData
().
size
()
+
" SceneNpcBornDatas."
);
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Failed to load SceneNpcBorn folder."
);
}
}
@SneakyThrows
private
static
void
loadGadgetConfigData
()
{
Files
.
list
(
Path
.
of
(
RESOURCE
(
"BinOutput/Gadget/"
))).
forEach
(
filePath
->
{
var
file
=
filePath
.
toFile
();
if
(
file
.
isDirectory
()
||
!
file
.
getName
().
endsWith
(
"json"
))
{
return
;
}
Map
<
String
,
ConfigGadget
>
config
;
try
{
config
=
JsonUtils
.
loadToMap
(
filePath
.
toString
(),
String
.
class
,
ConfigGadget
.
class
);
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"failed to load ConfigGadget entries for "
+
filePath
,
e
);
return
;
}
for
(
Entry
<
String
,
ConfigGadget
>
e
:
config
.
entrySet
())
{
GameData
.
getGadgetConfigData
().
put
(
e
.
getKey
(),
e
.
getValue
());
}
});
try
{
Files
.
newDirectoryStream
(
getResourcePath
(
"BinOutput/Gadget/"
),
"*.json"
).
forEach
(
path
->
{
try
{
GameData
.
getGadgetConfigData
().
putAll
(
JsonUtils
.
loadToMap
(
path
,
String
.
class
,
ConfigGadget
.
class
));
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"failed to load ConfigGadget entries for "
+
path
.
toString
(),
e
);
return
;
}
});
Grasscutter
.
getLogger
().
debug
(
"Loaded {} ConfigGadget entries."
,
GameData
.
getGadgetConfigData
().
size
());
Grasscutter
.
getLogger
().
debug
(
"Loaded {} ConfigGadget entries."
,
GameData
.
getGadgetConfigData
().
size
());
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Failed to load ConfigGadget folder."
);
}
}
@SneakyThrows
private
static
void
loadBlossomResources
()
{
GameDepot
.
setBlossomConfig
(
DataLoader
.
loadClass
(
"BlossomConfig.json"
,
BlossomConfig
.
class
));
Grasscutter
.
getLogger
().
debug
(
"Loaded BlossomConfig."
);
try
{
GameDepot
.
setBlossomConfig
(
DataLoader
.
loadClass
(
"BlossomConfig.json"
,
BlossomConfig
.
class
));
Grasscutter
.
getLogger
().
debug
(
"Loaded BlossomConfig."
);
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
warn
(
"Failed to load BlossomConfig."
);
}
}
// BinOutput configs
...
...
src/main/java/emu/grasscutter/tools/Tools.java
View file @
fbc0219c
...
...
@@ -2,9 +2,11 @@ package emu.grasscutter.tools;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.OutputStreamWriter
;
import
java.io.PrintWriter
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.file.Files
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
java.util.*
;
...
...
@@ -215,11 +217,15 @@ public final class Tools {
}
public
static
List
<
String
>
getAvailableLanguage
()
{
File
textMapFolder
=
new
File
(
RESOURCE
(
"TextMap"
));
List
<
String
>
availableLangList
=
new
ArrayList
<>();
for
(
String
textMapFileName
:
Objects
.
requireNonNull
(
textMapFolder
.
list
((
dir
,
name
)
->
name
.
startsWith
(
"TextMap"
)
&&
name
.
endsWith
(
".json"
))))
{
availableLangList
.
add
(
textMapFileName
.
replace
(
"TextMap"
,
""
).
replace
(
".json"
,
""
).
toLowerCase
());
}
return
availableLangList
;
try
{
Files
.
newDirectoryStream
(
getResourcePath
(
"TextMap"
),
"TextMap*.json"
).
forEach
(
path
->
{
availableLangList
.
add
(
path
.
getFileName
().
toString
().
replace
(
"TextMap"
,
""
).
replace
(
".json"
,
""
).
toLowerCase
());
});
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Failed to get available languages:"
,
e
);
}
return
availableLangList
;
}
@Deprecated
(
forRemoval
=
true
,
since
=
"1.2.3"
)
...
...
src/main/java/emu/grasscutter/utils/FileUtils.java
View file @
fbc0219c
...
...
@@ -9,7 +9,6 @@ import java.net.URI;
import
java.net.URISyntaxException
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.file.*
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.List
;
...
...
@@ -17,7 +16,7 @@ import java.util.stream.Collectors;
public
final
class
FileUtils
{
public
static
void
write
(
String
dest
,
byte
[]
bytes
)
{
Path
path
=
Path
s
.
get
(
dest
);
Path
path
=
Path
.
of
(
dest
);
try
{
Files
.
write
(
path
,
bytes
);
...
...
@@ -27,7 +26,7 @@ public final class FileUtils {
}
public
static
byte
[]
read
(
String
dest
)
{
return
read
(
Path
s
.
get
(
dest
));
return
read
(
Path
.
of
(
dest
));
}
public
static
byte
[]
read
(
Path
path
)
{
...
...
src/main/java/emu/grasscutter/utils/JsonUtils.java
View file @
fbc0219c
...
...
@@ -3,7 +3,10 @@ package emu.grasscutter.utils;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.io.Reader
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.util.List
;
import
java.util.Map
;
...
...
@@ -32,36 +35,57 @@ public final class JsonUtils {
return
gson
.
fromJson
(
jsonElement
,
classType
);
}
public
static
<
T
>
T
loadToClass
(
InputStream
Reader
fileReader
,
Class
<
T
>
classType
)
throws
IOException
{
public
static
<
T
>
T
loadToClass
(
Reader
fileReader
,
Class
<
T
>
classType
)
throws
IOException
{
return
gson
.
fromJson
(
fileReader
,
classType
);
}
@Deprecated
public
static
<
T
>
T
loadToClass
(
String
filename
,
Class
<
T
>
classType
)
throws
IOException
{
try
(
InputStreamReader
fileReader
=
new
InputStreamReader
(
new
FileInputStream
(
Utils
.
toFilePath
(
filename
)),
StandardCharsets
.
UTF_8
))
{
return
loadToClass
(
fileReader
,
classType
);
}
}
public
static
<
T
>
List
<
T
>
loadToList
(
InputStreamReader
fileReader
,
Class
<
T
>
classType
)
throws
IOException
{
public
static
<
T
>
T
loadToClass
(
Path
filename
,
Class
<
T
>
classType
)
throws
IOException
{
try
(
var
fileReader
=
Files
.
newBufferedReader
(
filename
,
StandardCharsets
.
UTF_8
))
{
return
loadToClass
(
fileReader
,
classType
);
}
}
public
static
<
T
>
List
<
T
>
loadToList
(
Reader
fileReader
,
Class
<
T
>
classType
)
throws
IOException
{
return
gson
.
fromJson
(
fileReader
,
TypeToken
.
getParameterized
(
List
.
class
,
classType
).
getType
());
}
@Deprecated
public
static
<
T
>
List
<
T
>
loadToList
(
String
filename
,
Class
<
T
>
classType
)
throws
IOException
{
try
(
InputStreamReader
fileReader
=
new
InputStreamReader
(
new
FileInputStream
(
Utils
.
toFilePath
(
filename
)),
StandardCharsets
.
UTF_8
))
{
return
loadToList
(
fileReader
,
classType
);
}
}
public
static
<
T1
,
T2
>
Map
<
T1
,
T2
>
loadToMap
(
InputStreamReader
fileReader
,
Class
<
T1
>
keyType
,
Class
<
T2
>
valueType
)
throws
IOException
{
public
static
<
T
>
List
<
T
>
loadToList
(
Path
filename
,
Class
<
T
>
classType
)
throws
IOException
{
try
(
var
fileReader
=
Files
.
newBufferedReader
(
filename
,
StandardCharsets
.
UTF_8
))
{
return
loadToList
(
fileReader
,
classType
);
}
}
public
static
<
T1
,
T2
>
Map
<
T1
,
T2
>
loadToMap
(
Reader
fileReader
,
Class
<
T1
>
keyType
,
Class
<
T2
>
valueType
)
throws
IOException
{
return
gson
.
fromJson
(
fileReader
,
TypeToken
.
getParameterized
(
Map
.
class
,
keyType
,
valueType
).
getType
());
}
@Deprecated
public
static
<
T1
,
T2
>
Map
<
T1
,
T2
>
loadToMap
(
String
filename
,
Class
<
T1
>
keyType
,
Class
<
T2
>
valueType
)
throws
IOException
{
try
(
InputStreamReader
fileReader
=
new
InputStreamReader
(
new
FileInputStream
(
Utils
.
toFilePath
(
filename
)),
StandardCharsets
.
UTF_8
))
{
return
loadToMap
(
fileReader
,
keyType
,
valueType
);
}
}
public
static
<
T1
,
T2
>
Map
<
T1
,
T2
>
loadToMap
(
Path
filename
,
Class
<
T1
>
keyType
,
Class
<
T2
>
valueType
)
throws
IOException
{
try
(
var
fileReader
=
Files
.
newBufferedReader
(
filename
,
StandardCharsets
.
UTF_8
))
{
return
loadToMap
(
fileReader
,
keyType
,
valueType
);
}
}
/**
* Safely JSON decodes a given string.
* @param jsonData The JSON-encoded data.
...
...
src/main/java/emu/grasscutter/utils/Language.java
View file @
fbc0219c
...
...
@@ -325,7 +325,7 @@ public final class Language {
private
static
Int2ObjectMap
<
String
>
loadTextMapFile
(
String
language
,
IntSet
nameHashes
)
{
Int2ObjectMap
<
String
>
output
=
new
Int2ObjectOpenHashMap
<>();
try
(
BufferedReader
file
=
new
BufferedReader
(
new
FileReader
(
Utils
.
toFilePath
(
RESOURCE
(
"TextMap/TextMap"
+
language
+
".json"
)
)
,
StandardCharsets
.
UTF_8
))
)
{
try
(
BufferedReader
file
=
Files
.
newBufferedReader
(
getResourcePath
(
"TextMap/TextMap"
+
language
+
".json"
),
StandardCharsets
.
UTF_8
))
{
Matcher
matcher
=
textMapKeyValueRegex
.
matcher
(
""
);
return
new
Int2ObjectOpenHashMap
<>(
file
.
lines
()
...
...
@@ -406,7 +406,7 @@ public final class Language {
try
{
long
cacheModified
=
Files
.
getLastModifiedTime
(
TEXTMAP_CACHE_PATH
).
toMillis
();
long
textmapsModified
=
Files
.
list
(
Path
.
of
(
RESOURCE
(
"TextMap"
))
)
long
textmapsModified
=
Files
.
list
(
getResourcePath
(
"TextMap"
))
.
filter
(
path
->
path
.
toString
().
endsWith
(
".json"
))
.
map
(
path
->
{
try
{
...
...
src/main/java/emu/grasscutter/utils/Utils.java
View file @
fbc0219c
...
...
@@ -22,6 +22,7 @@ import org.slf4j.Logger;
import
javax.annotation.Nullable
;
import
static
emu
.
grasscutter
.
config
.
Configuration
.
getResourcePath
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
@SuppressWarnings
({
"UnusedReturnValue"
,
"BooleanMethodIsAlwaysInverted"
})
...
...
@@ -169,19 +170,18 @@ public final class Utils {
Logger
logger
=
Grasscutter
.
getLogger
();
boolean
exit
=
false
;
String
resourcesFolder
=
config
.
folderStructure
.
resources
;
String
dataFolder
=
config
.
folderStructure
.
data
;
// Check for resources folder.
if
(!
f
ile
E
xists
(
r
esource
sFolder
))
{
if
(!
F
ile
s
.
e
xists
(
getR
esource
Path
(
""
)
))
{
logger
.
info
(
translate
(
"messages.status.create_resources"
));
logger
.
info
(
translate
(
"messages.status.resources_error"
));
createFolder
(
resources
Folder
);
exit
=
true
;
createFolder
(
config
.
folderStructure
.
resources
);
exit
=
true
;
}
// Check for BinOutput + ExcelBinOutput.
if
(!
f
ile
E
xists
(
r
esource
sFolder
+
"BinOutput"
)
||
!
fileE
xists
(
r
esource
sFolder
+
"ExcelBinOutput"
))
{
if
(!
F
ile
s
.
e
xists
(
getR
esource
Path
(
"BinOutput"
)
)
||
!
Files
.
e
xists
(
getR
esource
Path
(
"ExcelBinOutput"
))
)
{
logger
.
info
(
translate
(
"messages.status.resources_error"
));
exit
=
true
;
}
...
...
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