Mob banish on touch + GMS-like cosmetics + Clear missing names
Fixed erroneous clean slate scroll block on equipments having certain properties. Implemented a log for bought cash items from Cash Shop. Implemented mob's player banish by touch (e. g. used by mobs from the Hypnotize quest). Thoroughly revised stylist/surgeon NPCs, adding several missing GMS-like cosmetic contents. Thoroughly revised String.wz names having missing item content throughout the WZ files. Revised missing name info for several faces throughout the WZ files. Solved a possible deadlock case related with a player vision's spawn object method. Fixed an issue with "Movement allowed only within account" items being given as "Untradeable" by NPCs. Happy Holidays and Great New Year everyone!!!
This commit is contained in:
73
tools/MapleCashCosmeticsChecker/build.xml
Normal file
73
tools/MapleCashCosmeticsChecker/build.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- You may freely edit this file. See commented blocks below for -->
|
||||
<!-- some examples of how to customize the build. -->
|
||||
<!-- (If you delete it and reopen the project it will be recreated.) -->
|
||||
<!-- By default, only the Clean and Build commands use this build script. -->
|
||||
<!-- Commands such as Run, Debug, and Test only use this build script if -->
|
||||
<!-- the Compile on Save feature is turned off for the project. -->
|
||||
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
|
||||
<!-- in the project's Project Properties dialog box.-->
|
||||
<project name="MapleCashCosmeticsChecker" default="default" basedir=".">
|
||||
<description>Builds, tests, and runs the project MapleCashCosmeticsChecker.</description>
|
||||
<import file="nbproject/build-impl.xml"/>
|
||||
<!--
|
||||
|
||||
There exist several targets which are by default empty and which can be
|
||||
used for execution of your tasks. These targets are usually executed
|
||||
before and after some main targets. They are:
|
||||
|
||||
-pre-init: called before initialization of project properties
|
||||
-post-init: called after initialization of project properties
|
||||
-pre-compile: called before javac compilation
|
||||
-post-compile: called after javac compilation
|
||||
-pre-compile-single: called before javac compilation of single file
|
||||
-post-compile-single: called after javac compilation of single file
|
||||
-pre-compile-test: called before javac compilation of JUnit tests
|
||||
-post-compile-test: called after javac compilation of JUnit tests
|
||||
-pre-compile-test-single: called before javac compilation of single JUnit test
|
||||
-post-compile-test-single: called after javac compilation of single JUunit test
|
||||
-pre-jar: called before JAR building
|
||||
-post-jar: called after JAR building
|
||||
-post-clean: called after cleaning build products
|
||||
|
||||
(Targets beginning with '-' are not intended to be called on their own.)
|
||||
|
||||
Example of inserting an obfuscator after compilation could look like this:
|
||||
|
||||
<target name="-post-compile">
|
||||
<obfuscate>
|
||||
<fileset dir="${build.classes.dir}"/>
|
||||
</obfuscate>
|
||||
</target>
|
||||
|
||||
For list of available properties check the imported
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
|
||||
Another way to customize the build is by overriding existing main targets.
|
||||
The targets of interest are:
|
||||
|
||||
-init-macrodef-javac: defines macro for javac compilation
|
||||
-init-macrodef-junit: defines macro for junit execution
|
||||
-init-macrodef-debug: defines macro for class debugging
|
||||
-init-macrodef-java: defines macro for class execution
|
||||
-do-jar: JAR building
|
||||
run: execution of project
|
||||
-javadoc-build: Javadoc generation
|
||||
test-report: JUnit report generation
|
||||
|
||||
An example of overriding the target for project execution could look like this:
|
||||
|
||||
<target name="run" depends="MapleCashCosmeticsChecker-impl.jar">
|
||||
<exec dir="bin" executable="launcher.exe">
|
||||
<arg file="${dist.jar}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
Notice that the overridden target depends on the jar target and not only on
|
||||
the compile target as the regular run target does. Again, for a list of available
|
||||
properties which you can use, check the target you are overriding in the
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
-->
|
||||
</project>
|
||||
4
tools/MapleCashCosmeticsChecker/lib/care/amoria/face.txt
Normal file
4
tools/MapleCashCosmeticsChecker/lib/care/amoria/face.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Male VIP: Champion Focus, Irritable Face, Motivated Look, Perplexed Stare, Dramatic Face, Rebel's Fire, Alert Face, Babyface Pout, Sad Innocence, Worrisome Glare
|
||||
Male REG: Pensive Look, Shade of Cool, Alert Face, Cool Guy Gaze, Leisure Look, Sad Innocence, Look of Wonder
|
||||
Female VIP: Athena's Grace, Hera's Radiance, Fearful Stare, Leisure Look, Strong Stare, Angel Glow, Babyface Pout, Pucker Up Face, Dollface Look, Soul's Window
|
||||
Female REG: Glitzy Face, Demure Poise Eyes, Fearful Stare, Babyface Pout, Dollface Look, Gentle Glow, Athena's Grace
|
||||
4
tools/MapleCashCosmeticsChecker/lib/care/amoria/hair.txt
Normal file
4
tools/MapleCashCosmeticsChecker/lib/care/amoria/hair.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Male VIP: Casanova, Eternal Elegance, Fuzz, Jun Pyo Hair, Metro, Natural, Rockie, Romance, Saturday Special, Super Suave, Windy Hair
|
||||
Male EXP: Antagonist, Explosion, w/ Bald Spot, Bowl Cut, Trip Scratch, Rebel, Fireball, Toben, Monkey, Head
|
||||
Female VIP: Angelica, Ballroom Classic, Carla, Caspia, Daisy Do, The Honeybun, Victorian Wrap, Darling Diva, Cecelia Twist, Classy Sass, Lana
|
||||
Female EXP: Connie, Bridget, Sammy, Carla, Stella, Angelica, Polly, Housewife, Rollered Hair
|
||||
4
tools/MapleCashCosmeticsChecker/lib/care/ariant/face.txt
Normal file
4
tools/MapleCashCosmeticsChecker/lib/care/ariant/face.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Male VIP: Insomniac Daze, Motivated Look, Fearful Glance, Rebel's Fire, Alert Face, Curious Dog
|
||||
Male REG: Edge of Emotion, Fearful Glance, Anger's Blaze, Dramatic Face, Smart Aleck, Perplexed Stare
|
||||
Female VIP: Look of Death, Motivated Look, Keen Look, Strong Stare, Pucker Up Face, Soul's Window
|
||||
Female REG: Kitty Cat, Poker Face, Look of Death, Wide-eyed Girl, Beauty Stare, Hypnotized Look, Leisure Look
|
||||
4
tools/MapleCashCosmeticsChecker/lib/care/ariant/hair.txt
Normal file
4
tools/MapleCashCosmeticsChecker/lib/care/ariant/hair.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Male VIP: Afro (small), Cabana Boy, Dreadlocks, Kravitz Locks, Line Scratch, Mane, Matinee Idol, Natural, Tornade Hair
|
||||
Male REG: Afro (small), Cabana Boy, Dreadlocks, Dreamcatcher, Hobo, Kravitz Locks, Line Scratch, Mane, Matinee Idol, Natural, Tornade Hair
|
||||
Female VIP: Bridget, Celeb, Edgy, Lana, Penelope, Rae, Boyish, Desert Flower, Tighty Bun
|
||||
Female REG: Boyish, Bridget, Celeb, Curly Stream, Dashing Damsel, Desert Flower, Lana, Oh So Windy, Palm Tree Hair, Penelope, Rae, Tighty Bun
|
||||
4
tools/MapleCashCosmeticsChecker/lib/care/cbd/face.txt
Normal file
4
tools/MapleCashCosmeticsChecker/lib/care/cbd/face.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Male VIP: Fierce Edge, Insomniac Daze, Overjoyed Smile, Shuteye, Alert Face, Curious Dog
|
||||
Male REG: Intense Stare, Demure Poise, Leisure Look, Insomniac Daze, Alert Face, Babyface Pout, Overjoyed Smile
|
||||
Female VIP: Compassion Look, Hypnotized Look, Look of Death, Shuteye, Pucker Up Face, Soul's Window
|
||||
Female REG: Glamorous Edge, Demure Poise Eyes, Leisure Look, Strong Stare, Curious Look, Beauty Stare, Compassion Look
|
||||
4
tools/MapleCashCosmeticsChecker/lib/care/cbd/hair.txt
Normal file
4
tools/MapleCashCosmeticsChecker/lib/care/cbd/hair.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Male VIP: Acorn, w/ Bald Spot, Fireball, Julian Hair, Old Man 'Do, Preppy Spike, Rebel, Toben, Vincent
|
||||
Male REG: Astro, Fireball, Julian Hair, Mane, Metrosexual, Old Man 'Do, Romance, Slick Dean, Exotica
|
||||
Female VIP: Apple Hair, Bowlcut, Connie, Disheveled, Ellie, Grandma ma', Miru, Monica, Veronica
|
||||
Female REG: Apple Hair, Bowlcut, Ellie, Grandma ma', Holla' Back Do, Monica, Oh So Windy, Sonara Wave, Tall Bun, School Girl Hair
|
||||
@@ -0,0 +1,4 @@
|
||||
Male VIP: Motivated Look, Perplexed Stare, Fearful Glance, Dramatic Face, Rebel's Fire, Alert Face, Babyface Pout, Sad Innocence, Worrisome Glare, Curious Dog, Look of Wonder, Eye of the Lion, Child's Play, Sarcastic Face
|
||||
Male REG: Ghostface Stare, Undecided Face, Worrisome Glare, Curious Dog, Motivated Look, Child's Play, Alert Face
|
||||
Female VIP: Motivated Look, Fearful Stare, Leisure Look, Strong Stare, Angel Glow, Babyface Pout, Pucker Up Face, Dollface Look, Hopeless Gaze, Soul's Window, Curious Look, Wide-eyed Girl, Innocent Look, Tender Love
|
||||
Female REG: Gentle Glow, Kitty Cat, Motivated Look, Hopeless Gaze, Keen Look, Leisure Look, Curious Look
|
||||
@@ -0,0 +1,6 @@
|
||||
Male VIP: Aran Cut, Catalyst, Acorn, Topknot, Wind, Shaggy Wax, The Coco
|
||||
Male REG: Aran Cut, Catalyst, Evan Hair (M), Acorn, Shaggy Wax, The Coco, The Mo Rawk, Topknot, Wind
|
||||
Male EXP: Aran Cut, Acorn, Shaggy Wax, The Coco, The Mo Rawk, Topknot, Wind, Buzz
|
||||
Female VIP: Angelica, Aran Hair, Chantelle, Crazy Medusa, Fourtail Braids, Frizzle Dizzle, Full Bangs
|
||||
Female REG: Angelica, Aran Hair, Chantelle, Crazy Medusa, Evan Hair (F), Fourtail Braids, Full Bangs, Rainbow, Stella
|
||||
Female EXP: Angelica, Aran Hair, Chantelle, Crazy Medusa, Fourtail Braids, Full Bangs, Stella, Head
|
||||
@@ -0,0 +1,4 @@
|
||||
Male VIP:
|
||||
Male REG:
|
||||
Female VIP:
|
||||
Female REG:
|
||||
@@ -0,0 +1,6 @@
|
||||
Male VIP: Antagonist, Aran Cut, Cornrow, Dragon Tail, Rockstar, Short Top Tail, Male Runway Hair
|
||||
Male REG: Antagonist, Aran Cut, Cornrow, Dragon Tail, Dual Blade Hair, Hontas, Lucky Charms, Rockstar, Short Top Tail
|
||||
Male EXP: Antagonist, Aran Cut, Cornrow, Dragon Tail, Hontas, Lucky Charms, Short Top Tail, Head
|
||||
Female VIP: Aran Hair, Bridget, Gardener, Pei Pei, Penelope, Shaggy Dog, Ravishing Raven
|
||||
Female REG: Annie, Aran Hair, Curly Stream, Gardener, Pei Pei, Penelope, Ravishing Raven, Shaggy Dog, Super Diva
|
||||
Female EXP: Annie, Aran Hair, Curly Stream, Gardener, Pei Pei, Penelope, Shaggy Dog, Rollered Hair
|
||||
@@ -0,0 +1,4 @@
|
||||
Male VIP: Motivated Look, Perplexed Stare, Fearful Glance, Dramatic Face, Rebel's Fire, Alert Face, Babyface Pout, Sad Innocence, Worrisome Glare, Curious Dog, Look of Wonder, Cool Guy Gaze
|
||||
Male REG: Hypnotized Look, Edge of Emotion, Insomniac Daze, Dramatic Face, Perplexed Stare, Sad Innocence, Overjoyed Smile
|
||||
Female VIP: Motivated Look, Fearful Stare, Leisure Look, Strong Stare, Angel Glow, Babyface Pout, Pucker Up Face, Dollface Look, Hopeless Gaze, Soul's Window, Curious Look, Wisdom Glance
|
||||
Female REG: Glamorous Edge, Kitty Cat, Leisure Look, Hopeless Gaze, Angel Glow, Pucker Up Face, Glitzy Face
|
||||
@@ -0,0 +1,6 @@
|
||||
Male VIP: Afro (big), Bowl Cut, Fuzz, Hector Hair, Julian Hair, Tentacle Hair, Trip Scratch, Urban Dragon
|
||||
Male REG: Afro (big), Bowl Cut, Bubba GoaTee, Fuzz, Hector Hair, Grooovy Do, Julian Hair, Hip Hop Cut, Rise N Shine, Robot, Tentacle Hair, The Mo Rawk, Urban Dragon
|
||||
Male EXP: Afro (big), Bowl Cut, Bubba GoaTee, Fuzz, Grooovy Do, Julian Hair, Rise N Shine, Robot, Tentacle Hair, The Mo Rawk, Urban Dragon, Buzz
|
||||
Female VIP: Apple Hair, Candy Heart, Eye-skimming Bang, Female Runway Hair, Lovely Ladyhawk, Naomi, Pigtails, Ayu
|
||||
Female REG: Apple Hair, Ayu, Bohemian Hair, Candy Heart, Eye-skimming Bang, Female Runway Hair, Jean, Lovely Ladyhawk, Naomi, Pigtails, Rastafari, Sonara Wave, Tall Bun, Minnie
|
||||
Female EXP: Apple Hair, Ayu, Bohemian Hair, Candy Heart, Eye-skimming Bang, Female Runway Hair, Jean, Lovely Ladyhawk, Pigtails, Rastafari, Tall Bun, Minnie, Head
|
||||
@@ -0,0 +1,4 @@
|
||||
Male VIP: Motivated Look, Perplexed Stare, Fearful Glance, Rebel's Fire, Alert Face, Babyface Pout, Sad Innocence, Curious Dog, Smart Aleck, Child's Play, Sarcastic Face
|
||||
Male REG: Demure Poise, Shade of Cool, Sad Innocence, Look of Wonder, Leisure Look, Alert Face, Cool Guy Gaze
|
||||
Female VIP: Hypnotized Look, Motivated Look, Keen Look, Strong Stare, Babyface Pout, Pucker Up Face, Hopeless Gaze, Soul's Window, Look of Death, Innocent Look, Tender Love
|
||||
Female REG: Gentle Glow, Poker Face, Athena's Grace, Compassion Look, Fearful Stare, Wisdom Glance, Wide-eyed Girl
|
||||
@@ -0,0 +1,4 @@
|
||||
Male VIP: Buddha Fire, Cozy Amber, Dreadlocks, Gruff & Tough, Monkey, Puffy Fro, Shaggy Dragon, Urban Dragon
|
||||
Male EXP: Alex, Buddha Fire, Cozy Amber, Dreadlocks, Exotica, Gruff & Tough, Kongfu Braids, Monkey, Puffy Fro, Rising Rocker, Shaggy Dragon, The Curl, Urban Dragon, Buzz
|
||||
Female VIP: Chantelle, Cutey Doll, Housewife, Lady Mariko, Lori, Ming Ming, Pei Pei, Tighty Bun
|
||||
Female EXP: Chantelle, Cutey Doll, Demolishing Diva, Housewife, Lady Mariko, Lori, Ming Ming, Onna's Honor, Pei Pei, Perfect Stranger, Spunky Do, Tighty Bun, Short Twin Tails, Head
|
||||
4
tools/MapleCashCosmeticsChecker/lib/care/nlc/face.txt
Normal file
4
tools/MapleCashCosmeticsChecker/lib/care/nlc/face.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Male VIP: Curious Dog, Motivated Look, Perplexed Stare, Fearful Glance, Dramatic Face, Rebel's Fire, Alert Face, Babyface Pout, Worrisome Glare
|
||||
Male REG: Undecided Face, Shade of Cool, Intense Stare, Perplexed Stare, Worrisome Glare, Cool Guy Gaze, Insomniac Daze
|
||||
Female VIP: Beauty Stare, Fearful Stare, Leisure Look, Strong Stare, Angel Glow, Babyface Pout, Pucker Up Face, Hopeless Gaze, Soul's Window
|
||||
Female REG: Demure Poise Eyes, Glitzy Face, Hypnotized Look, Motivated Look, Gentle Glow, Dollface Look, Soul's Window
|
||||
4
tools/MapleCashCosmeticsChecker/lib/care/nlc/hair.txt
Normal file
4
tools/MapleCashCosmeticsChecker/lib/care/nlc/hair.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Male VIP: Afro (big), Hector Hair, Messy Spike, Roving Rockstar, Spiky Shag, The Coco, Unbalanced
|
||||
Male EXP: Afro (big), Alex, Evan Hair (M), Fury, Hector Hair, Messy Spike, Roving Rockstar, Spiky Shag, The Coco, Tribal Buzz, Unbalanced, Head
|
||||
Female VIP: Eye-skimming Bang, Fluffy Dolly, Low Cut Bob, Messy Pigtails, Model's Ambition, Roxy, Sunflower Power
|
||||
Female EXP: Demolishing Diva, Eye-skimming Bang, Evan Hair (F), Fluffy Dolly, Low Cut Bob, Maiden's Weave, Messy Pigtails, Model's Ambition, Roxy, Streaky Siren, Sunflower Power, Rollered Hair
|
||||
4
tools/MapleCashCosmeticsChecker/lib/care/orbis/face.txt
Normal file
4
tools/MapleCashCosmeticsChecker/lib/care/orbis/face.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Male VIP: Motivated Look, Perplexed Stare, Fearful Glance, Dramatic Face, Rebel's Fire, Alert Face, Babyface Pout, Sad Innocence, Worrisome Glare, Curious Dog, Look of Wonder, Child's Play, Sarcastic Face
|
||||
Male REG: Pensive Look, Fearful Glance, Cool Guy Gaze, Overjoyed Smile, Child's Play, Hypnotized Look, Dramatic Face
|
||||
Female VIP: Motivated Look, Fearful Stare, Leisure Look, Strong Stare, Angel Glow, Babyface Pout, Pucker Up Face, Dollface Look, Hopeless Gaze, Soul's Window, Curious Look, Innocent Look, Tender Love
|
||||
Female REG: Gentle Glow, Poker Face, Compassion Look, Angel Glow, Wisdom Glance, Soul's Window, Dollface Look
|
||||
6
tools/MapleCashCosmeticsChecker/lib/care/orbis/hair.txt
Normal file
6
tools/MapleCashCosmeticsChecker/lib/care/orbis/hair.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Male VIP: Clean-Cut Short Hair, Foil Perm, Messy Spike, Metrosexual, Mohecan Shaggy Do, Spiky Shag, Tristan
|
||||
Male REG: Baldie, Clean-Cut Short Hair, Foil Perm, Messy Spike, Metrosexual, Mohecan Shaggy Do, Neon Cactus, Receding Hair, Spiky Shag, Tristan, Updo
|
||||
Male EXP: Baldie, Clean-Cut Short Hair, Foil Perm, Messy Spike, Mohecan Shaggy Do, Receding Hair, Spiky Shag, Tristan, Updo
|
||||
Female VIP: Bow Hair, Caspia, Monica, Princessa, Rose, The Honeybun, Top Tied Hair
|
||||
Female REG: Bow Hair, Caspia, Dashing Damsel, Lilin Hair, Monica, Princess Warrior, Princessa, Rose, Short Twin Tails, The Honeybun, Top Tied Hair, Bowl Cut
|
||||
Female EXP: Bow Hair, Caspia, Lilin Hair, Monica, Princess Warrior, Princessa, Rose, Short Twin Tails, Top Tied Hair, Bowl Cut
|
||||
4
tools/MapleCashCosmeticsChecker/lib/care/showa/face.txt
Normal file
4
tools/MapleCashCosmeticsChecker/lib/care/showa/face.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Male VIP: Fierce Edge, Motivated Look, Fearful Glance, Rebel's Fire, Alert Face, Curious Dog
|
||||
Male REG: Ghostface Stare, Intense Stare, Shuteye, Motivated Look, Fierce Edge, Irritable Face, Overjoyed Smile
|
||||
Female VIP: Compassion Look, Motivated Look, Keen Look, Strong Stare, Pucker Up Face, Soul's Window
|
||||
Female REG: Glitzy Face, Glamorous Edge, Motivated Look, Leisure Look, Look of Death, Shuteye, Beauty Stare
|
||||
4
tools/MapleCashCosmeticsChecker/lib/care/showa/hair.txt
Normal file
4
tools/MapleCashCosmeticsChecker/lib/care/showa/hair.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Male VIP: Dreamcatcher, Clean-Cut Short Hair, Dragon Tail, Gruff & Tough, Matinee Idol, Metrosexual, Mohecan Shaggy Do, Puffy Fro, Short Top Tail, Tristan
|
||||
Male REG: Clean-Cut Short Hair, Dragon Tail, Dreamcatcher, Gruff & Tough, Lion Hair, Matinee Idol, Metrosexual, Mohecan Shaggy Do, Puffy Fro, Short Top Tail, Spiky Tail, Tristan
|
||||
Female VIP: Candy Heart, Dambi, Fourtail Braids, Lady Mariko, Mary, Polly, Princessa, Sammy, Short Shaggy Hair, Top Tied Hair
|
||||
Female REG: Candy Heart, Dambi, Fourtail Braids, Jean, Lady Mariko, Onna's Honor, Paula, Princess Warrior, Princessa, Short Shaggy Hair, Streaky Siren, Top Tied Hair, Palm Tree Hair
|
||||
10
tools/MapleCashCosmeticsChecker/lib/colors.txt
Normal file
10
tools/MapleCashCosmeticsChecker/lib/colors.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
amoria 0 1 3 4 5 7
|
||||
ariant 0 1 3 6 7
|
||||
cbd 2 3 4 7
|
||||
henesys 0 1 2 4 6 7
|
||||
kerning
|
||||
ludi 2 3 4 5 7
|
||||
mulung 0 1 3 5 6 7
|
||||
nlc 1 2 3 4 5 6 7
|
||||
orbis 1 3 4 7
|
||||
showa 0 1 2 3 4 5 7
|
||||
213
tools/MapleCashCosmeticsChecker/lib/result.txt
Normal file
213
tools/MapleCashCosmeticsChecker/lib/result.txt
Normal file
@@ -0,0 +1,213 @@
|
||||
# Report File autogenerated from the MapleCashCosmeticsChecker feature by Ronan Lana.
|
||||
# Generated data takes into account several data info from the server source files and the server-side WZ.xmls.
|
||||
|
||||
Found 42 entries with missing cosmetic entries.
|
||||
NPC 1012103:VIP
|
||||
30060, 30140, 30200, 30210, 30310, 33040, 33100
|
||||
31150, 31300, 31350, 31700, 31740, 34050, 34110
|
||||
|
||||
NPC 1012104:EXP
|
||||
30030, 30140, 30200, 30210, 30310, 30610, 33040, 33100
|
||||
31070, 31150, 31300, 31350, 31430, 31700, 34050, 34110
|
||||
|
||||
NPC 1012104:REG
|
||||
30060, 30140, 30200, 30210, 30310, 30610, 33040, 33100
|
||||
31070, 31080, 31150, 31300, 31350, 31700, 34050, 34110
|
||||
|
||||
NPC 1052004:VIP
|
||||
20000, 20001, 20003, 20004, 20005, 20006, 20007, 20008, 20012, 20014, 20015, 20022, 20028, 20031
|
||||
21000, 21001, 21002, 21003, 21004, 21005, 21006, 21007, 21008, 21012, 21013, 21014, 21023, 21026
|
||||
|
||||
NPC 1052005:REG
|
||||
20000, 20005, 20008, 20012, 20016, 20022, 20032
|
||||
21000, 21002, 21008, 21014, 21020, 21024, 21029
|
||||
|
||||
NPC 1052100:VIP
|
||||
30040, 30130, 30780, 30850, 30860, 30920, 33040
|
||||
31090, 31140, 31330, 31440, 31760, 31880, 34050
|
||||
|
||||
NPC 1052101:EXP
|
||||
30130, 30430, 30520, 30770, 30780, 30850, 30920, 33040
|
||||
31060, 31140, 31330, 31520, 31760, 31880, 34010, 34050
|
||||
|
||||
NPC 1052101:REG
|
||||
30040, 30130, 30520, 30770, 30780, 30850, 30920, 33040
|
||||
31060, 31140, 31330, 31440, 31520, 31750, 31760, 31880, 34050
|
||||
|
||||
NPC 2010001:VIP
|
||||
30230, 30260, 30280, 30340, 30490
|
||||
31110, 31220, 31230, 31630, 31790
|
||||
|
||||
NPC 2010002:VIP
|
||||
20000, 20001, 20003, 20004, 20005, 20006, 20007, 20008, 20012, 20014, 20022, 20028, 20031
|
||||
21000, 21001, 21002, 21003, 21004, 21005, 21006, 21007, 21008, 21012, 21014, 21023, 21026
|
||||
|
||||
NPC 2012007:EXP
|
||||
30230, 30280, 30340, 30490, 30530, 30740
|
||||
31110, 31220, 31230, 31710, 31790, 31890, 31930
|
||||
|
||||
NPC 2012007:REG
|
||||
30230, 30260, 30280, 30340, 30490, 30530, 30630, 30740
|
||||
31110, 31220, 31230, 31630, 31650, 31710, 31790, 31890, 31930
|
||||
|
||||
NPC 2012009:REG
|
||||
20003, 20011, 20021, 20022, 20023, 20027, 20031
|
||||
21004, 21007, 21010, 21012, 21020, 21021, 21030
|
||||
|
||||
NPC 2040019:REG
|
||||
20001, 20003, 20007, 20013, 20021, 20023, 20025
|
||||
21002, 21004, 21006, 21008, 21022, 21027, 21029
|
||||
|
||||
NPC 2041007:VIP
|
||||
30160, 30190, 30250, 30640, 30660, 30840, 30870, 30990
|
||||
31270, 31290, 31550, 31680, 31810, 31830, 31840, 31870
|
||||
|
||||
NPC 2041009:EXP
|
||||
30030, 30190, 30220, 30250, 30540, 30610, 30620, 30640, 30650, 30660, 30840, 30990
|
||||
31170, 31270, 31430, 31510, 31540, 31550, 31600, 31680, 31810, 31830, 31840, 31870
|
||||
|
||||
NPC 2041009:REG
|
||||
30190, 30220, 30250, 30540, 30610, 30620, 30640, 30650, 30660, 30840, 30870, 30940, 30990
|
||||
31170, 31270, 31290, 31510, 31540, 31550, 31600, 31640, 31680, 31810, 31830, 31840, 31870
|
||||
|
||||
NPC 2041010:VIP
|
||||
20000, 20001, 20003, 20004, 20005, 20006, 20007, 20008, 20011, 20012, 20014, 20031
|
||||
21000, 21001, 21002, 21003, 21004, 21005, 21006, 21007, 21008, 21010, 21012, 21014
|
||||
|
||||
NPC 2090100:VIP
|
||||
30150, 30240, 30370, 30420, 30640, 30710, 30750, 30810
|
||||
31140, 31160, 31180, 31300, 31460, 31470, 31660, 31910
|
||||
|
||||
NPC 2090101:EXP
|
||||
30030, 30150, 30240, 30370, 30420, 30550, 30600, 30640, 30700, 30710, 30720, 30750, 30810, 30830
|
||||
31140, 31160, 31180, 31210, 31300, 31430, 31460, 31470, 31660, 31690, 31800, 31890, 31910, 31940
|
||||
|
||||
NPC 2090104:REG
|
||||
20002, 20005, 20007, 20011, 20014, 20017, 20029
|
||||
21001, 21010, 21013, 21018, 21020, 21021, 21030
|
||||
|
||||
NPC 2090104:VIP
|
||||
20000, 20001, 20004, 20005, 20006, 20007, 20009, 20012, 20022, 20028, 20031
|
||||
21000, 21003, 21005, 21006, 21008, 21009, 21011, 21012, 21023, 21024, 21026
|
||||
|
||||
NPC 2100005:REG
|
||||
30150, 30170, 30180, 30320, 30330, 30410, 30460, 30680, 30800, 30820, 30900
|
||||
31090, 31190, 31330, 31340, 31400, 31420, 31520, 31620, 31650, 31660, 34000
|
||||
|
||||
NPC 2100006:VIP
|
||||
30150, 30170, 30180, 30320, 30330, 30410, 30460, 30820, 30900
|
||||
31040, 31090, 31190, 31330, 31340, 31400, 31420, 31620, 31660
|
||||
|
||||
NPC 2100008:VIP
|
||||
20000, 20004, 20005, 20012, 20013, 20031
|
||||
21000, 21003, 21006, 21009, 21012, 21024
|
||||
|
||||
NPC 2100009:REG
|
||||
20001, 20003, 20009, 20010, 20025, 20031
|
||||
21002, 21009, 21011, 21013, 21016, 21029, 21030
|
||||
|
||||
NPC 9120100:VIP
|
||||
30260, 30280, 30340, 30710, 30780, 30800, 30810, 30820, 30920
|
||||
31000, 31030, 31100, 31350, 31460, 31550, 31770, 31790, 31850
|
||||
|
||||
NPC 9120101:REG
|
||||
30260, 30280, 30340, 30360, 30710, 30780, 30790, 30800, 30810, 30820, 30920
|
||||
31350, 31410, 31460, 31540, 31550, 31710, 31720, 31770, 31790, 31800, 31850, 34000
|
||||
|
||||
NPC 9120102:VIP
|
||||
20000, 20004, 20005, 20012, 20020, 20031
|
||||
21000, 21003, 21006, 21012, 21021, 21024
|
||||
|
||||
NPC 9120103:REG
|
||||
20000, 20016, 20019, 20020, 20021, 20024, 20026
|
||||
21000, 21002, 21009, 21016, 21022, 21025, 21027
|
||||
|
||||
NPC 9201015:VIP
|
||||
30050, 30300, 30410, 30450, 30510, 30570, 30580, 30590, 30660, 30910
|
||||
31150, 31220, 31260, 31310, 31420, 31480, 31490, 31580, 31590, 31610, 31630
|
||||
|
||||
NPC 9201016:EXP
|
||||
30000, 30020, 30110, 30130, 30160, 30190, 30240, 30270, 30430
|
||||
31000, 31030, 31050, 31070, 31090, 31150, 31310, 31910, 34010
|
||||
|
||||
NPC 9201018:VIP
|
||||
20000, 20001, 20003, 20004, 20005, 20006, 20007, 20008, 20018, 20019
|
||||
21001, 21002, 21003, 21004, 21005, 21006, 21007, 21012, 21018, 21019
|
||||
|
||||
NPC 9201019:REG
|
||||
20002, 20005, 20007, 20011, 20014, 20027, 20029
|
||||
21001, 21005, 21007, 21017, 21018, 21020, 21022
|
||||
|
||||
NPC 9201063:EXP
|
||||
30250, 30400, 30430, 30440, 30490, 30730, 30830, 30870, 30880, 33100
|
||||
31320, 31450, 31560, 31570, 31690, 31720, 31730, 31830, 34010
|
||||
|
||||
NPC 9201064:VIP
|
||||
30250, 30490, 30730, 30870, 30880, 33100
|
||||
31320, 31450, 31560, 31730, 31830
|
||||
|
||||
NPC 9201069:VIP
|
||||
20000, 20001, 20003, 20004, 20005, 20006, 20008, 20012, 20031
|
||||
21001, 21002, 21003, 21004, 21005, 21006, 21008, 21012, 21016
|
||||
|
||||
NPC 9201070:REG
|
||||
20001, 20008, 20011, 20013, 20024, 20029, 20032
|
||||
21000, 21007, 21011, 21012, 21017, 21020, 21022
|
||||
|
||||
NPC 9270023:REG
|
||||
20002, 20005, 20006, 20013, 20017, 20021, 20024
|
||||
21002, 21003, 21014, 21016, 21017, 21021, 21027
|
||||
|
||||
NPC 9270024:VIP
|
||||
20005, 20012, 20013, 20020, 20021, 20026
|
||||
21006, 21009, 21011, 21012, 21021, 21025
|
||||
|
||||
NPC 9270036:VIP
|
||||
30000, 30020, 30110, 30120, 30270, 30290, 30310, 30670, 30840
|
||||
31010, 31050, 31110, 31120, 31240, 31250, 31280, 31670, 31810
|
||||
|
||||
NPC 9270037:REG
|
||||
30110, 30180, 30260, 30290, 30300, 30350, 30470, 30720, 30840
|
||||
31110, 31200, 31250, 31280, 31600, 31640, 31670, 31810, 34020
|
||||
|
||||
Unused cosmetics: 22
|
||||
30010 Zeta
|
||||
30070 Back
|
||||
30080 Buzzcut
|
||||
30090 Mohawk
|
||||
30100 Fantasy
|
||||
30480 Babby Cut
|
||||
30560 Grand Lionman
|
||||
30690 Metro Man
|
||||
30760 Bowling Ball
|
||||
30890 Eastern Mystery
|
||||
30930 Boy Band Cut
|
||||
30950 Volume Cut
|
||||
31020 Francesca
|
||||
31130 Jolie
|
||||
31530 Zessica
|
||||
31780 ???? ??
|
||||
31820 Grace
|
||||
31860 Laguna Beach
|
||||
31920 CL Hair
|
||||
31950 Vintage Flip
|
||||
33000 Prince Cut
|
||||
34030 Designer Hair
|
||||
|
||||
Missing cosmetic itemids: 15
|
||||
Bohemian Hair
|
||||
Bow Hair
|
||||
Clean-Cut Short Hair
|
||||
Dual Blade Hair
|
||||
Evan Hair (F)
|
||||
Evan Hair (M)
|
||||
Explosion
|
||||
Lilin Hair
|
||||
Low Cut Bob
|
||||
Messy Pigtails
|
||||
Oh So Windy
|
||||
Spiky Shag
|
||||
Top Tied Hair
|
||||
Updo
|
||||
Windy Hair
|
||||
|
||||
3
tools/MapleCashCosmeticsChecker/manifest.mf
Normal file
3
tools/MapleCashCosmeticsChecker/manifest.mf
Normal file
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
X-COMMENT: Main-Class will be added automatically by build
|
||||
|
||||
@@ -0,0 +1,722 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package maplecashcosmeticschecker;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
|
||||
This application parses the cosmetic recipes defined within "lib/care" folder, loads
|
||||
every present cosmetic itemid from the XML data, then checks the scripts for missed
|
||||
cosmetics within the stylist/surgeon. Results from the search are reported in a report
|
||||
file.
|
||||
|
||||
Note: to best make use of this feature, set ignoreCurrentScriptCosmetics = true. This
|
||||
way, every available cosmetic present on the recipes will be listed on the report.
|
||||
|
||||
Estimated parse time: 1 minute
|
||||
|
||||
*/
|
||||
public class MapleCashCosmeticsChecker {
|
||||
static String libPath = "lib";
|
||||
static String handbookPath = "../../handbook";
|
||||
static String wzPath = "../../wz";
|
||||
static String scriptPath = "../../scripts";
|
||||
|
||||
private static PrintWriter printWriter = null;
|
||||
static InputStreamReader fileReader = null;
|
||||
static BufferedReader bufferedReader = null;
|
||||
|
||||
static boolean ignoreCurrentScriptCosmetics = false;
|
||||
|
||||
static int initialStringLength = 50;
|
||||
|
||||
static byte status = 0;
|
||||
|
||||
static Map<Integer, Set<Integer>> scriptCosmetics = new HashMap<>();
|
||||
static Map<Integer, String> scriptEntries = new HashMap<>(500);
|
||||
|
||||
static Set<Integer> allCosmetics = new HashSet<>();
|
||||
|
||||
static Set<Integer> unusedCosmetics = new HashSet<>();
|
||||
static Map<Integer, List<Integer>> usedCosmetics = new HashMap<>();
|
||||
|
||||
static Map<Integer, String> couponNames = new HashMap<>();
|
||||
static Map<Integer, Integer> cosmeticNpcs = new HashMap<>(); // expected only 1 NPC per cosmetic coupon (town care/salon)
|
||||
static Map<List<String>, Integer> cosmeticNpcids = new HashMap<>();
|
||||
|
||||
static Set<String> missingCosmeticNames = new HashSet<>();
|
||||
static Map<String, Integer> cosmeticNameIds = new HashMap<>();
|
||||
static Map<Integer, String> cosmeticIdNames = new HashMap<>();
|
||||
|
||||
static Map<Pair<Integer, String>, Set<Integer>> missingCosmeticsNpcTypes = new HashMap<>();
|
||||
|
||||
private static String getName(String token) {
|
||||
int i, j;
|
||||
char[] dest;
|
||||
String d;
|
||||
|
||||
i = token.lastIndexOf("name");
|
||||
i = token.indexOf("\"", i) + 1; //lower bound of the string
|
||||
j = token.indexOf("\"", i); //upper bound
|
||||
|
||||
dest = new char[initialStringLength];
|
||||
token.getChars(i, j, dest, 0);
|
||||
|
||||
d = new String(dest);
|
||||
return(d.trim());
|
||||
}
|
||||
|
||||
private static String getValue(String token) {
|
||||
int i, j;
|
||||
char[] dest;
|
||||
String d;
|
||||
|
||||
i = token.lastIndexOf("value");
|
||||
i = token.indexOf("\"", i) + 1; //lower bound of the string
|
||||
j = token.indexOf("\"", i); //upper bound
|
||||
|
||||
dest = new char[initialStringLength];
|
||||
token.getChars(i, j, dest, 0);
|
||||
|
||||
d = new String(dest);
|
||||
return(d.trim());
|
||||
}
|
||||
|
||||
private static void forwardCursor(int st) {
|
||||
String line = null;
|
||||
|
||||
try {
|
||||
while(status >= st && (line = bufferedReader.readLine()) != null) {
|
||||
simpleToken(line);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void simpleToken(String token) {
|
||||
if(token.contains("/imgdir")) {
|
||||
status -= 1;
|
||||
}
|
||||
else if(token.contains("imgdir")) {
|
||||
status += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void translateToken(String token) {
|
||||
if(token.contains("/imgdir")) {
|
||||
status -= 1;
|
||||
}
|
||||
else if(token.contains("imgdir")) {
|
||||
status += 1;
|
||||
|
||||
if (status == 3) {
|
||||
String d = getName(token);
|
||||
|
||||
if (!(d.contentEquals("Face") || d.contentEquals("Hair"))) {
|
||||
forwardCursor(status);
|
||||
}
|
||||
} else if (status == 4) {
|
||||
String d = getName(token);
|
||||
int itemid = Integer.valueOf(d);
|
||||
|
||||
int cosmeticid;
|
||||
if (itemid >= 30000) {
|
||||
cosmeticid = (itemid / 10) * 10;
|
||||
} else {
|
||||
cosmeticid = itemid - ((itemid / 100) % 10) * 100;
|
||||
}
|
||||
|
||||
allCosmetics.add(cosmeticid);
|
||||
forwardCursor(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void readEqpStringData(String eqpStringDirectory) throws IOException {
|
||||
String line;
|
||||
|
||||
fileReader = new InputStreamReader(new FileInputStream(eqpStringDirectory), "UTF-8");
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
while((line = bufferedReader.readLine()) != null) {
|
||||
translateToken(line);
|
||||
}
|
||||
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
}
|
||||
|
||||
private static void loadCosmeticWzData() throws IOException {
|
||||
System.out.println("Reading String.wz ...");
|
||||
readEqpStringData(wzPath + "/String.wz/Eqp.img.xml");
|
||||
}
|
||||
|
||||
private static void setCosmeticUsage(List<Integer> usedByNpcids, int cosmeticid) {
|
||||
if (!usedByNpcids.isEmpty()) {
|
||||
usedCosmetics.put(cosmeticid, usedByNpcids);
|
||||
} else {
|
||||
unusedCosmetics.add(cosmeticid);
|
||||
}
|
||||
}
|
||||
|
||||
private static void listFiles(String directoryName, ArrayList<File> files) {
|
||||
File directory = new File(directoryName);
|
||||
|
||||
// get all the files from a directory
|
||||
File[] fList = directory.listFiles();
|
||||
for (File file : fList) {
|
||||
if (file.isFile()) {
|
||||
files.add(file);
|
||||
} else if (file.isDirectory()) {
|
||||
listFiles(file.getAbsolutePath(), files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int getNpcIdFromFilename(String name) {
|
||||
try {
|
||||
return Integer.valueOf(name.substring(0, name.indexOf('.')));
|
||||
} catch(Exception e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Integer> findCosmeticDataNpcids(int itemid) {
|
||||
List<Integer> npcids = new LinkedList<>();
|
||||
for (Entry<Integer, Set<Integer>> sc : scriptCosmetics.entrySet()) {
|
||||
if (sc.getValue().contains(itemid)) {
|
||||
npcids.add(itemid);
|
||||
}
|
||||
}
|
||||
|
||||
return npcids;
|
||||
}
|
||||
|
||||
private static void loadScripts() throws IOException {
|
||||
ArrayList<File> files = new ArrayList<>();
|
||||
listFiles(scriptPath + "/npc", files);
|
||||
|
||||
for(File f : files) {
|
||||
Integer npcid = getNpcIdFromFilename(f.getName());
|
||||
|
||||
//System.out.println("Parsing " + f.getAbsolutePath());
|
||||
fileReader = new InputStreamReader(new FileInputStream(f), "UTF-8");
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
String line;
|
||||
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
|
||||
boolean cosmeticNpc = false;
|
||||
Set<Integer> cosmeticids = new HashSet<>();
|
||||
while((line = bufferedReader.readLine())!=null){
|
||||
String[] s = line.split("hair_. = Array\\(", 2);
|
||||
|
||||
if (s.length > 1) {
|
||||
cosmeticNpc = true;
|
||||
s = s[1].split("\\)", 2);
|
||||
s = s[0].split(", ");
|
||||
|
||||
for (String st : s) {
|
||||
if (!st.isEmpty()) {
|
||||
int itemid = Integer.valueOf(st);
|
||||
cosmeticids.add(itemid);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s = line.split("face_. = Array\\(", 2);
|
||||
|
||||
if (s.length > 1) {
|
||||
cosmeticNpc = true;
|
||||
s = s[1].split("\\)", 2);
|
||||
s = s[0].split(", ");
|
||||
|
||||
for (String st : s) {
|
||||
if (!st.isEmpty()) {
|
||||
int itemid = Integer.valueOf(st);
|
||||
cosmeticids.add(itemid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stringBuffer.append(line).append("\n");
|
||||
}
|
||||
|
||||
scriptEntries.put(npcid, stringBuffer.toString());
|
||||
|
||||
if (cosmeticNpc) {
|
||||
scriptCosmetics.put(npcid, cosmeticids);
|
||||
}
|
||||
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void processCosmeticScriptData() throws IOException {
|
||||
System.out.println("Reading script files ...");
|
||||
loadScripts();
|
||||
|
||||
if (ignoreCurrentScriptCosmetics) {
|
||||
for (Set<Integer> npcCosmetics : scriptCosmetics.values()) {
|
||||
npcCosmetics.clear();
|
||||
}
|
||||
}
|
||||
|
||||
for (Integer itemid : allCosmetics) {
|
||||
List<Integer> npcids = findCosmeticDataNpcids(itemid);
|
||||
setCosmeticUsage(npcids, itemid);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Integer> loadCosmeticCouponids() throws IOException {
|
||||
List<Integer> couponItemids = new LinkedList<>();
|
||||
|
||||
fileReader = new InputStreamReader(new FileInputStream(handbookPath + "/Cash.txt"), "UTF-8");
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
String line;
|
||||
while((line = bufferedReader.readLine())!=null){
|
||||
if (line.isEmpty()) continue;
|
||||
String[] s = line.split(" - ", 3);
|
||||
|
||||
int itemid = Integer.valueOf(s[0]);
|
||||
if (itemid >= 5150000 && itemid < 5160000) {
|
||||
couponItemids.add(itemid);
|
||||
couponNames.put(itemid, s[1]);
|
||||
}
|
||||
}
|
||||
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
|
||||
return couponItemids;
|
||||
}
|
||||
|
||||
private static List<Integer> findItemidOnScript(int itemid) {
|
||||
List<Integer> files = new LinkedList<>();
|
||||
String t = String.valueOf(itemid);
|
||||
|
||||
for (Entry<Integer, String> text : scriptEntries.entrySet()) {
|
||||
if (text.getValue().contains(t)) {
|
||||
files.add(text.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
private static void loadCosmeticCouponNpcs() throws IOException {
|
||||
System.out.println("Locating cosmetic NPCs ...");
|
||||
|
||||
for (Integer itemid : loadCosmeticCouponids()) {
|
||||
List<Integer> npcids = findItemidOnScript(itemid);
|
||||
|
||||
if (!npcids.isEmpty()) {
|
||||
cosmeticNpcs.put(itemid, npcids.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum CosmeticType {
|
||||
HAIRSTYLE,
|
||||
HAIRCOLOR,
|
||||
DIRTYHAIR,
|
||||
FACE_SURGERY,
|
||||
EYE_COLOR,
|
||||
SKIN_CARE
|
||||
}
|
||||
|
||||
private static Pair<Integer, CosmeticType> parseCosmeticCoupon(String[] tokens) {
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
String s = tokens[i];
|
||||
|
||||
if (s.startsWith("Hair")) {
|
||||
if (s.contentEquals("Hairstyle")) {
|
||||
return new Pair<>(i, CosmeticType.HAIRSTYLE);
|
||||
} else {
|
||||
if (i - 1 >= 0 && tokens[i - 1].contentEquals("Dirty")) {
|
||||
return new Pair<>(i - 1, CosmeticType.DIRTYHAIR);
|
||||
} else if (i + 1 < tokens.length && tokens[i + 1].contentEquals("Color")) {
|
||||
return new Pair<>(i, CosmeticType.HAIRCOLOR);
|
||||
} else {
|
||||
return new Pair<>(i, CosmeticType.HAIRSTYLE);
|
||||
}
|
||||
}
|
||||
} else if (s.startsWith("Face")) {
|
||||
return new Pair<>(i, CosmeticType.FACE_SURGERY);
|
||||
} else if (s.startsWith("Cosmetic")) {
|
||||
return new Pair<>(i, CosmeticType.EYE_COLOR);
|
||||
} else if (s.startsWith("Plastic")) {
|
||||
return new Pair<>(i, CosmeticType.FACE_SURGERY);
|
||||
} else if (s.startsWith("Skin")) {
|
||||
return new Pair<>(i, CosmeticType.SKIN_CARE);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<String> getCosmeticCouponData(String town, String type, String subtype) {
|
||||
List<String> ret = new ArrayList<>(3);
|
||||
ret.add(town);
|
||||
ret.add(type);
|
||||
ret.add(subtype);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static List<String> parseCosmeticCoupon(String couponName) {
|
||||
String town, type, subtype = "EXP";
|
||||
|
||||
String[] s = couponName.split(" Coupon ", 2);
|
||||
|
||||
if (s.length > 1) {
|
||||
subtype = s[1].substring(1, s[1].length() - 1);
|
||||
}
|
||||
|
||||
String[] tokens = s[0].split(" ");
|
||||
Pair<Integer, CosmeticType> cosmeticData = parseCosmeticCoupon(tokens);
|
||||
if (cosmeticData == null) return null;
|
||||
|
||||
town = "";
|
||||
for (int i = 0; i < cosmeticData.left; i++) {
|
||||
town += (tokens[i] + "_");
|
||||
}
|
||||
town = town.substring(0, town.length() - 1).toLowerCase();
|
||||
|
||||
switch (cosmeticData.right) {
|
||||
case HAIRSTYLE:
|
||||
type = "hair";
|
||||
break;
|
||||
|
||||
case FACE_SURGERY:
|
||||
type = "face";
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return getCosmeticCouponData(town, type, subtype);
|
||||
}
|
||||
|
||||
private static void generateCosmeticPlaceNpcs() {
|
||||
for (Entry<Integer, String> e : couponNames.entrySet()) {
|
||||
Integer npcid = cosmeticNpcs.get(e.getKey());
|
||||
if (npcid == null) continue;
|
||||
|
||||
String couponName = e.getValue();
|
||||
List<String> couponData = parseCosmeticCoupon(couponName);
|
||||
|
||||
if (couponData == null) continue;
|
||||
cosmeticNpcids.put(couponData, npcid);
|
||||
}
|
||||
}
|
||||
|
||||
private static Integer getCosmeticNpcid(String townName, String typeCosmetic, String typeCoupon) {
|
||||
return cosmeticNpcids.get(getCosmeticCouponData(townName, typeCosmetic, typeCoupon));
|
||||
}
|
||||
|
||||
private static String getCosmeticName(String name, boolean gender) {
|
||||
String ret = name + " (" + (gender ? "F" : "M") + ")";
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void loadCosmeticNames(String cosmeticPath) throws IOException {
|
||||
fileReader = new InputStreamReader(new FileInputStream(cosmeticPath), "UTF-8");
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
String line;
|
||||
while((line = bufferedReader.readLine()) != null) {
|
||||
String[] s = line.split(" - ", 3);
|
||||
int itemid = Integer.valueOf(s[0]);
|
||||
|
||||
String name;
|
||||
if (itemid < 30000) {
|
||||
itemid = itemid - ((itemid / 100) % 10) * 100;
|
||||
|
||||
int idx = s[1].lastIndexOf(" ");
|
||||
if (idx > -1) {
|
||||
name = s[1].substring(0, idx);
|
||||
} else {
|
||||
name = s[1];
|
||||
}
|
||||
} else {
|
||||
itemid = (Integer.valueOf(s[0]) / 10) * 10;
|
||||
|
||||
int idx = s[1].indexOf(" ");
|
||||
if (idx > -1) {
|
||||
name = s[1].substring(idx + 1);
|
||||
} else {
|
||||
name = s[1];
|
||||
}
|
||||
}
|
||||
|
||||
name = name.trim();
|
||||
|
||||
String cname = getCosmeticName(name, (((itemid / 1000) % 10) % 3) != 0);
|
||||
|
||||
/*
|
||||
if (cosmeticNameIds.containsKey(cname) && Math.abs(cosmeticNameIds.get(cname) - itemid) > 50) {
|
||||
System.out.println("Clashing '" + name + "' " + itemid + "/" + cosmeticNameIds.get(cname));
|
||||
}
|
||||
*/
|
||||
|
||||
cosmeticNameIds.put(cname, itemid);
|
||||
cosmeticIdNames.put(itemid, name);
|
||||
}
|
||||
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
}
|
||||
|
||||
private static void loadCosmeticNames() throws IOException {
|
||||
System.out.println("Reading cosmetics from handbook ...");
|
||||
|
||||
loadCosmeticNames(handbookPath + "/Equip/Face.txt");
|
||||
loadCosmeticNames(handbookPath + "/Equip/Hair.txt");
|
||||
}
|
||||
|
||||
private static List<Integer> fetchExpectedCosmetics(String[] cosmeticList, boolean gender) {
|
||||
List<Integer> list = new LinkedList<>();
|
||||
|
||||
for (String cosmetic : cosmeticList) {
|
||||
String cname = getCosmeticName(cosmetic, gender);
|
||||
Integer itemid = cosmeticNameIds.get(cname);
|
||||
if (itemid != null) {
|
||||
list.add(itemid);
|
||||
} else {
|
||||
missingCosmeticNames.add(cosmetic);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static void verifyCosmeticExpectedFile(File f) throws IOException {
|
||||
String townName = f.getParent().substring(f.getParent().lastIndexOf("\\") + 1);
|
||||
String typeCosmetic = f.getName().substring(0, f.getName().indexOf("."));
|
||||
|
||||
fileReader = new InputStreamReader(new FileInputStream(f), "UTF-8");
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
String line;
|
||||
while((line = bufferedReader.readLine())!=null){
|
||||
String[] s = line.split(": ", 2);
|
||||
String[] t = s[0].split("ale ");
|
||||
|
||||
String typeCoupon = t[1];
|
||||
boolean gender = !t[0].contentEquals("M");
|
||||
|
||||
Integer npcid = getCosmeticNpcid(townName, typeCosmetic, typeCoupon);
|
||||
if (npcid != null) {
|
||||
String[] cosmetics = s[1].split(", ");
|
||||
List<Integer> cosmeticItemids = fetchExpectedCosmetics(cosmetics, gender);
|
||||
|
||||
Set<Integer> npcCosmetics = scriptCosmetics.get(npcid);
|
||||
Set<Integer> missingCosmetics = new HashSet<>();
|
||||
for (Integer itemid : cosmeticItemids) {
|
||||
if (!npcCosmetics.contains(itemid)) {
|
||||
missingCosmetics.add(itemid);
|
||||
}
|
||||
}
|
||||
|
||||
if (!missingCosmetics.isEmpty()) {
|
||||
Pair<Integer, String> key = new Pair<>(npcid, typeCoupon);
|
||||
|
||||
Set<Integer> list = missingCosmeticsNpcTypes.get(key);
|
||||
if (list == null) {
|
||||
missingCosmeticsNpcTypes.put(key, missingCosmetics);
|
||||
} else {
|
||||
list.addAll(missingCosmetics);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
}
|
||||
|
||||
private static void verifyCosmeticExpectedData() throws IOException {
|
||||
System.out.println("Analyzing cosmetic NPC scripts ...");
|
||||
|
||||
ArrayList<File> cosmeticRecipes = new ArrayList<>();
|
||||
listFiles(libPath + "/care", cosmeticRecipes);
|
||||
|
||||
for (File f : cosmeticRecipes) {
|
||||
verifyCosmeticExpectedFile(f);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Pair<Pair<Integer, String>, List<Integer>>> getSortedMapEntries(Map<Pair<Integer, String>, Set<Integer>> map) {
|
||||
List<Pair<Pair<Integer, String>, List<Integer>>> list = new ArrayList<>(map.size());
|
||||
for(Entry<Pair<Integer, String>, Set<Integer>> e : map.entrySet()) {
|
||||
List<Integer> il = new ArrayList<>(2);
|
||||
for(Integer i : e.getValue()) {
|
||||
il.add(i);
|
||||
}
|
||||
|
||||
Collections.sort(il, new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
return o1 - o2;
|
||||
}
|
||||
});
|
||||
|
||||
list.add(new Pair<>(e.getKey(), il));
|
||||
}
|
||||
|
||||
Collections.sort(list, new Comparator<Pair<Pair<Integer, String>, List<Integer>>>() {
|
||||
@Override
|
||||
public int compare(Pair<Pair<Integer, String>, List<Integer>> o1, Pair<Pair<Integer, String>, List<Integer>> o2) {
|
||||
int cmp = o1.getLeft().getLeft() - o2.getLeft().getLeft();
|
||||
if (cmp == 0) {
|
||||
return o1.getLeft().getRight().compareTo(o2.getLeft().getRight());
|
||||
} else {
|
||||
return cmp;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static void printReportFileHeader() {
|
||||
printWriter.println(" # Report File autogenerated from the MapleCashCosmeticsChecker feature by Ronan Lana.");
|
||||
printWriter.println(" # Generated data takes into account several data info from the server source files and the server-side WZ.xmls.");
|
||||
printWriter.println();
|
||||
}
|
||||
|
||||
private static Pair<List<Integer>, List<Integer>> getCosmeticReport(List<Integer> itemids) {
|
||||
List<Integer> maleItemids = new LinkedList<>();
|
||||
List<Integer> femaleItemids = new LinkedList<>();
|
||||
|
||||
for (Integer i : itemids) {
|
||||
if ((((i / 1000) % 10) % 3) == 0) {
|
||||
maleItemids.add(i);
|
||||
} else {
|
||||
femaleItemids.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
return new Pair<>(maleItemids, femaleItemids);
|
||||
}
|
||||
|
||||
private static void reportNpcCosmetics(List<Integer> itemids) {
|
||||
if (!itemids.isEmpty()) {
|
||||
String res = " ";
|
||||
for (Integer i : itemids) {
|
||||
res += (i + ", ");
|
||||
unusedCosmetics.remove(i);
|
||||
}
|
||||
|
||||
printWriter.println(res.substring(0, res.length() - 2));
|
||||
}
|
||||
}
|
||||
|
||||
private static void reportCosmeticResults() throws IOException {
|
||||
System.out.println("Reporting results ...");
|
||||
|
||||
printWriter = new PrintWriter("lib/result.txt", "UTF-8");
|
||||
|
||||
printReportFileHeader();
|
||||
|
||||
if (!missingCosmeticsNpcTypes.isEmpty()) {
|
||||
printWriter.println("Found " + missingCosmeticsNpcTypes.size() + " entries with missing cosmetic entries.");
|
||||
|
||||
for (Pair<Pair<Integer, String>, List<Integer>> mcn : getSortedMapEntries(missingCosmeticsNpcTypes)) {
|
||||
printWriter.println(" NPC " + mcn.getLeft());
|
||||
|
||||
Pair<List<Integer>, List<Integer>> genderItemids = getCosmeticReport(mcn.getRight());
|
||||
reportNpcCosmetics(genderItemids.getLeft());
|
||||
reportNpcCosmetics(genderItemids.getRight());
|
||||
printWriter.println();
|
||||
}
|
||||
}
|
||||
|
||||
if (!unusedCosmetics.isEmpty()) {
|
||||
printWriter.println("Unused cosmetics: " + unusedCosmetics.size());
|
||||
|
||||
List<Integer> list = new ArrayList<>(unusedCosmetics);
|
||||
Collections.sort(list);
|
||||
|
||||
for (Integer i : list) {
|
||||
printWriter.println(i + " " + cosmeticIdNames.get(i));
|
||||
}
|
||||
|
||||
printWriter.println();
|
||||
}
|
||||
|
||||
if (!missingCosmeticNames.isEmpty()) {
|
||||
printWriter.println("Missing cosmetic itemids: " + missingCosmeticNames.size());
|
||||
|
||||
List<String> listString = new ArrayList<>(missingCosmeticNames);
|
||||
Collections.sort(listString);
|
||||
|
||||
for (String c : listString) {
|
||||
printWriter.println(c);
|
||||
}
|
||||
|
||||
printWriter.println();
|
||||
}
|
||||
|
||||
printWriter.close();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
loadCosmeticWzData();
|
||||
processCosmeticScriptData();
|
||||
|
||||
loadCosmeticCouponNpcs();
|
||||
generateCosmeticPlaceNpcs();
|
||||
|
||||
loadCosmeticNames();
|
||||
verifyCosmeticExpectedData();
|
||||
|
||||
reportCosmeticResults();
|
||||
System.out.println("Done!");
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 ~ 2010 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License version 3
|
||||
as published by the Free Software Foundation. You may not use, modify
|
||||
or distribute this program under any other version of the
|
||||
GNU Affero General Public License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package maplecashcosmeticschecker;
|
||||
|
||||
/**
|
||||
* Represents a pair of values.
|
||||
*
|
||||
* @author Frz
|
||||
* @since Revision 333
|
||||
* @version 1.0
|
||||
*
|
||||
* @param <E> The type of the left value.
|
||||
* @param <F> The type of the right value.
|
||||
*/
|
||||
public class Pair<E, F> {
|
||||
|
||||
public E left;
|
||||
public F right;
|
||||
|
||||
/**
|
||||
* Class constructor - pairs two objects together.
|
||||
*
|
||||
* @param left The left object.
|
||||
* @param right The right object.
|
||||
*/
|
||||
public Pair(E left, F right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the left value.
|
||||
*
|
||||
* @return The left value.
|
||||
*/
|
||||
public E getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the right value.
|
||||
*
|
||||
* @return The right value.
|
||||
*/
|
||||
public F getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the pair into a string.
|
||||
*
|
||||
* @return Each value of the pair as a string joined by a colon.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return left.toString() + ":" + right.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hash code of this pair.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((left == null) ? 0 : left.hashCode());
|
||||
result = prime * result + ((right == null) ? 0 : right.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if two pairs are equal.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Pair other = (Pair) obj;
|
||||
if (left == null) {
|
||||
if (other.left != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!left.equals(other.left)) {
|
||||
return false;
|
||||
}
|
||||
if (right == null) {
|
||||
if (other.right != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!right.equals(other.right)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
73
tools/MapleCashCosmeticsFetcher/build.xml
Normal file
73
tools/MapleCashCosmeticsFetcher/build.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- You may freely edit this file. See commented blocks below for -->
|
||||
<!-- some examples of how to customize the build. -->
|
||||
<!-- (If you delete it and reopen the project it will be recreated.) -->
|
||||
<!-- By default, only the Clean and Build commands use this build script. -->
|
||||
<!-- Commands such as Run, Debug, and Test only use this build script if -->
|
||||
<!-- the Compile on Save feature is turned off for the project. -->
|
||||
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
|
||||
<!-- in the project's Project Properties dialog box.-->
|
||||
<project name="MapleCashCosmeticsFetcher" default="default" basedir=".">
|
||||
<description>Builds, tests, and runs the project MapleCashCosmeticsFetcher.</description>
|
||||
<import file="nbproject/build-impl.xml"/>
|
||||
<!--
|
||||
|
||||
There exist several targets which are by default empty and which can be
|
||||
used for execution of your tasks. These targets are usually executed
|
||||
before and after some main targets. They are:
|
||||
|
||||
-pre-init: called before initialization of project properties
|
||||
-post-init: called after initialization of project properties
|
||||
-pre-compile: called before javac compilation
|
||||
-post-compile: called after javac compilation
|
||||
-pre-compile-single: called before javac compilation of single file
|
||||
-post-compile-single: called after javac compilation of single file
|
||||
-pre-compile-test: called before javac compilation of JUnit tests
|
||||
-post-compile-test: called after javac compilation of JUnit tests
|
||||
-pre-compile-test-single: called before javac compilation of single JUnit test
|
||||
-post-compile-test-single: called after javac compilation of single JUunit test
|
||||
-pre-jar: called before JAR building
|
||||
-post-jar: called after JAR building
|
||||
-post-clean: called after cleaning build products
|
||||
|
||||
(Targets beginning with '-' are not intended to be called on their own.)
|
||||
|
||||
Example of inserting an obfuscator after compilation could look like this:
|
||||
|
||||
<target name="-post-compile">
|
||||
<obfuscate>
|
||||
<fileset dir="${build.classes.dir}"/>
|
||||
</obfuscate>
|
||||
</target>
|
||||
|
||||
For list of available properties check the imported
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
|
||||
Another way to customize the build is by overriding existing main targets.
|
||||
The targets of interest are:
|
||||
|
||||
-init-macrodef-javac: defines macro for javac compilation
|
||||
-init-macrodef-junit: defines macro for junit execution
|
||||
-init-macrodef-debug: defines macro for class debugging
|
||||
-init-macrodef-java: defines macro for class execution
|
||||
-do-jar: JAR building
|
||||
run: execution of project
|
||||
-javadoc-build: Javadoc generation
|
||||
test-report: JUnit report generation
|
||||
|
||||
An example of overriding the target for project execution could look like this:
|
||||
|
||||
<target name="run" depends="MapleCashCosmeticsFetcher-impl.jar">
|
||||
<exec dir="bin" executable="launcher.exe">
|
||||
<arg file="${dist.jar}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
Notice that the overridden target depends on the jar target and not only on
|
||||
the compile target as the regular run target does. Again, for a list of available
|
||||
properties which you can use, check the target you are overriding in the
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
-->
|
||||
</project>
|
||||
3
tools/MapleCashCosmeticsFetcher/manifest.mf
Normal file
3
tools/MapleCashCosmeticsFetcher/manifest.mf
Normal file
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
X-COMMENT: Main-Class will be added automatically by build
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package maplecashcosmeticsfetcher;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import tools.MapleItemInformationProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
|
||||
This application gathers info from the WZ.XML files, fetching all cosmetic coupons and tickets from there, and then
|
||||
searches the NPC script files, identifying the stylish NPCs that supposedly uses them. It will reports all NPCs that
|
||||
uses up a card, as well as report those currently unused.
|
||||
|
||||
Estimated parse time: 10 seconds
|
||||
|
||||
*/
|
||||
public class MapleCashCosmeticsFetcher {
|
||||
static MapleItemInformationProvider ii;
|
||||
|
||||
static String wzPath = "../../wz";
|
||||
static String scriptPath = "../../scripts";
|
||||
static InputStreamReader fileReader = null;
|
||||
static BufferedReader bufferedReader = null;
|
||||
|
||||
static Map<Integer, String> scriptEntries = new HashMap<>(500);
|
||||
|
||||
private static void listFiles(String directoryName, ArrayList<File> files) {
|
||||
File directory = new File(directoryName);
|
||||
|
||||
// get all the files from a directory
|
||||
File[] fList = directory.listFiles();
|
||||
for (File file : fList) {
|
||||
if (file.isFile()) {
|
||||
files.add(file);
|
||||
} else if (file.isDirectory()) {
|
||||
listFiles(file.getAbsolutePath(), files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int getNpcIdFromFilename(String name) {
|
||||
try {
|
||||
return Integer.valueOf(name.substring(0, name.indexOf('.')));
|
||||
} catch(Exception e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadScripts() throws Exception {
|
||||
ArrayList<File> files = new ArrayList<>();
|
||||
listFiles(scriptPath + "/npc", files);
|
||||
|
||||
for(File f : files) {
|
||||
Integer npcid = getNpcIdFromFilename(f.getName());
|
||||
|
||||
//System.out.println("Parsing " + f.getAbsolutePath());
|
||||
fileReader = new InputStreamReader(new FileInputStream(f), "UTF-8");
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while((line = bufferedReader.readLine())!=null){
|
||||
stringBuffer.append(line).append("\n");
|
||||
}
|
||||
|
||||
scriptEntries.put(npcid, stringBuffer.toString());
|
||||
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Integer> findItemidOnScript(int itemid) {
|
||||
List<Integer> files = new LinkedList<>();
|
||||
String t = String.valueOf(itemid);
|
||||
|
||||
for (Entry<Integer, String> text : scriptEntries.entrySet()) {
|
||||
if (text.getValue().contains(t)) {
|
||||
files.add(text.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
private static void reportCosmeticCouponResults() {
|
||||
for (int itemid = 5150000; itemid <= 5154000; itemid++) {
|
||||
String itemName = ii.getName(itemid);
|
||||
|
||||
if (itemName != null) {
|
||||
List<Integer> npcids = findItemidOnScript(itemid);
|
||||
|
||||
if (!npcids.isEmpty()) {
|
||||
System.out.println("Itemid " + itemid + " found on " + npcids + ". (" + itemName + ")");
|
||||
} else {
|
||||
System.out.println("NOT FOUND ITEMID " + itemid + " (" + itemName + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("wzpath", wzPath);
|
||||
ii = MapleItemInformationProvider.getInstance();
|
||||
|
||||
try {
|
||||
loadScripts();
|
||||
System.out.println("Loaded scripts");
|
||||
|
||||
reportCosmeticCouponResults();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public interface MapleCanvas {
|
||||
int getHeight();
|
||||
int getWidth();
|
||||
BufferedImage getImage();
|
||||
}
|
||||
34
tools/MapleCashCosmeticsFetcher/src/provider/MapleData.java
Normal file
34
tools/MapleCashCosmeticsFetcher/src/provider/MapleData.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider;
|
||||
|
||||
import java.util.List;
|
||||
import provider.wz.MapleDataType;
|
||||
|
||||
public interface MapleData extends MapleDataEntity, Iterable<MapleData> {
|
||||
@Override
|
||||
public String getName();
|
||||
public MapleDataType getType();
|
||||
public List<MapleData> getChildren();
|
||||
public MapleData getChildByPath(String path);
|
||||
public Object getData();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Matze
|
||||
*/
|
||||
public interface MapleDataDirectoryEntry extends MapleDataEntry {
|
||||
public List<MapleDataDirectoryEntry> getSubdirectories();
|
||||
public List<MapleDataFileEntry> getFiles();
|
||||
public MapleDataEntry getEntry(String name);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Matze
|
||||
*/
|
||||
public interface MapleDataEntity {
|
||||
public String getName();
|
||||
public MapleDataEntity getParent();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Matze
|
||||
*/
|
||||
public interface MapleDataEntry extends MapleDataEntity {
|
||||
public String getName();
|
||||
public int getSize();
|
||||
public int getChecksum();
|
||||
public int getOffset();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Matze
|
||||
*/
|
||||
public interface MapleDataFileEntry extends MapleDataEntry {
|
||||
public void setOffset(int offset);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider;
|
||||
|
||||
public interface MapleDataProvider {
|
||||
MapleData getData(String path);
|
||||
MapleDataDirectoryEntry getRoot();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import provider.wz.WZFile;
|
||||
import provider.wz.XMLWZFile;
|
||||
|
||||
public class MapleDataProviderFactory {
|
||||
private final static String wzPath = System.getProperty("wzpath");
|
||||
|
||||
private static MapleDataProvider getWZ(File in, boolean provideImages) {
|
||||
if (in.getName().toLowerCase().endsWith("wz") && !in.isDirectory()) {
|
||||
try {
|
||||
return new WZFile(in, provideImages);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Loading WZ File failed", e);
|
||||
}
|
||||
} else {
|
||||
return new XMLWZFile(in);
|
||||
}
|
||||
}
|
||||
|
||||
public static MapleDataProvider getDataProvider(File in) {
|
||||
return getWZ(in, false);
|
||||
}
|
||||
|
||||
public static MapleDataProvider getImageProvidingDataProvider(File in) {
|
||||
return getWZ(in, true);
|
||||
}
|
||||
|
||||
public static File fileInWZPath(String filename) {
|
||||
return new File(wzPath, filename);
|
||||
}
|
||||
}
|
||||
145
tools/MapleCashCosmeticsFetcher/src/provider/MapleDataTool.java
Normal file
145
tools/MapleCashCosmeticsFetcher/src/provider/MapleDataTool.java
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import provider.wz.MapleDataType;
|
||||
|
||||
public class MapleDataTool {
|
||||
public static String getString(MapleData data) {
|
||||
return ((String) data.getData());
|
||||
}
|
||||
|
||||
public static String getString(MapleData data, String def) {
|
||||
if (data == null || data.getData() == null) {
|
||||
return def;
|
||||
} else {
|
||||
return ((String) data.getData());
|
||||
}
|
||||
}
|
||||
|
||||
public static String getString(String path, MapleData data) {
|
||||
return getString(data.getChildByPath(path));
|
||||
}
|
||||
|
||||
public static String getString(String path, MapleData data, String def) {
|
||||
return getString(data.getChildByPath(path), def);
|
||||
}
|
||||
|
||||
public static double getDouble(MapleData data) {
|
||||
return ((Double) data.getData()).doubleValue();
|
||||
}
|
||||
|
||||
public static float getFloat(MapleData data) {
|
||||
return ((Float) data.getData()).floatValue();
|
||||
}
|
||||
|
||||
public static int getInt(MapleData data) {
|
||||
if (data == null || data.getData() == null) {
|
||||
return 0;// DEF?
|
||||
}
|
||||
return ((Integer) data.getData()).intValue();
|
||||
}
|
||||
|
||||
public static int getInt(String path, MapleData data) {
|
||||
return getInt(data.getChildByPath(path));
|
||||
}
|
||||
|
||||
public static int getIntConvert(MapleData data) {
|
||||
if (data.getType() == MapleDataType.STRING) {
|
||||
return Integer.parseInt(getString(data));
|
||||
} else {
|
||||
return getInt(data);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getIntConvert(String path, MapleData data) {
|
||||
MapleData d = data.getChildByPath(path);
|
||||
if (d.getType() == MapleDataType.STRING) {
|
||||
return Integer.parseInt(getString(d));
|
||||
} else {
|
||||
return getInt(d);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getInt(MapleData data, int def) {
|
||||
if (data == null || data.getData() == null) {
|
||||
return def;
|
||||
} else if (data.getType() == MapleDataType.STRING) {
|
||||
return Integer.parseInt(getString(data));
|
||||
} else {
|
||||
return ((Integer) data.getData()).intValue();
|
||||
}
|
||||
}
|
||||
|
||||
public static int getInt(String path, MapleData data, int def) {
|
||||
return getInt(data.getChildByPath(path), def);
|
||||
}
|
||||
|
||||
public static int getIntConvert(String path, MapleData data, int def) {
|
||||
MapleData d = data.getChildByPath(path);
|
||||
if (d == null) {
|
||||
return def;
|
||||
}
|
||||
if (d.getType() == MapleDataType.STRING) {
|
||||
try {
|
||||
return Integer.parseInt(getString(d));
|
||||
} catch (NumberFormatException nfe) {
|
||||
nfe.printStackTrace();
|
||||
return def;
|
||||
}
|
||||
} else {
|
||||
return getInt(d, def);
|
||||
}
|
||||
}
|
||||
|
||||
public static BufferedImage getImage(MapleData data) {
|
||||
return ((MapleCanvas) data.getData()).getImage();
|
||||
}
|
||||
|
||||
public static Point getPoint(MapleData data) {
|
||||
return ((Point) data.getData());
|
||||
}
|
||||
|
||||
public static Point getPoint(String path, MapleData data) {
|
||||
return getPoint(data.getChildByPath(path));
|
||||
}
|
||||
|
||||
public static Point getPoint(String path, MapleData data, Point def) {
|
||||
final MapleData pointData = data.getChildByPath(path);
|
||||
if (pointData == null) {
|
||||
return def;
|
||||
}
|
||||
return getPoint(pointData);
|
||||
}
|
||||
|
||||
public static String getFullDataPath(MapleData data) {
|
||||
String path = "";
|
||||
MapleDataEntity myData = data;
|
||||
while (myData != null) {
|
||||
path = myData.getName() + "/" + path;
|
||||
myData = myData.getParent();
|
||||
}
|
||||
return path.substring(0, path.length() - 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import provider.MapleCanvas;
|
||||
|
||||
public class FileStoredPngMapleCanvas implements MapleCanvas {
|
||||
private File file;
|
||||
private int width;
|
||||
private int height;
|
||||
private BufferedImage image;
|
||||
|
||||
public FileStoredPngMapleCanvas(int width, int height, File fileIn) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.file = fileIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getImage() {
|
||||
loadImageIfNecessary();
|
||||
return image;
|
||||
}
|
||||
|
||||
private void loadImageIfNecessary() {
|
||||
if (image == null) {
|
||||
try {
|
||||
image = ImageIO.read(file);
|
||||
// replace the dimensions loaded from the wz by the REAL dimensions from the image - should be equal tho
|
||||
width = image.getWidth();
|
||||
height = image.getHeight();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
public class ImgMapleSound {
|
||||
private int dataLength, offset;
|
||||
|
||||
public ImgMapleSound(int dataLength, int offset) {
|
||||
this.dataLength = dataLength;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public int getDataLength() {
|
||||
return dataLength;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import provider.MapleDataProviderFactory;
|
||||
import tools.data.input.GenericLittleEndianAccessor;
|
||||
import tools.data.input.InputStreamByteStream;
|
||||
import tools.data.input.LittleEndianAccessor;
|
||||
|
||||
public class ListWZFile {
|
||||
private LittleEndianAccessor lea;
|
||||
private List<String> entries = new ArrayList<String>();
|
||||
private static Collection<String> modernImgs = new HashSet<String>();
|
||||
|
||||
public static byte[] xorBytes(byte[] a, byte[] b) {
|
||||
byte[] wusched = new byte[a.length];
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
wusched[i] = (byte) (a[i] ^ b[i]);
|
||||
}
|
||||
return wusched;
|
||||
}
|
||||
|
||||
public ListWZFile(File listwz) throws FileNotFoundException {
|
||||
lea = new GenericLittleEndianAccessor(new InputStreamByteStream(new BufferedInputStream(new FileInputStream(listwz))));
|
||||
while (lea.available() > 0) {
|
||||
int l = lea.readInt() * 2;
|
||||
byte[] chunk = new byte[l];
|
||||
for (int i = 0; i < chunk.length; i++) {
|
||||
chunk[i] = lea.readByte();
|
||||
}
|
||||
lea.readChar();
|
||||
final String value = String.valueOf(WZTool.readListString(chunk));
|
||||
entries.add(value);
|
||||
}
|
||||
entries = Collections.unmodifiableList(entries);
|
||||
}
|
||||
|
||||
public List<String> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
final String listWz = System.getProperty("listwz");
|
||||
if (listWz != null) {
|
||||
ListWZFile listwz;
|
||||
try {
|
||||
listwz = new ListWZFile(MapleDataProviderFactory.fileInWZPath("List.wz"));
|
||||
modernImgs = new HashSet<String>(listwz.getEntries());
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isModernImgFile(String path) {
|
||||
return modernImgs.contains(path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
public enum MapleDataType {
|
||||
NONE, IMG_0x00, SHORT, INT, FLOAT, DOUBLE, STRING, EXTENDED, PROPERTY, CANVAS, VECTOR, CONVEX, SOUND, UOL, UNKNOWN_TYPE, UNKNOWN_EXTENDED_TYPE;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.DataBufferByte;
|
||||
import java.awt.image.PixelInterleavedSampleModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Inflater;
|
||||
import provider.MapleCanvas;
|
||||
|
||||
public class PNGMapleCanvas implements MapleCanvas {
|
||||
private static final int[] ZAHLEN = new int[]{2, 1, 0, 3};
|
||||
private int height;
|
||||
private int width;
|
||||
private int dataLength;
|
||||
private int format;
|
||||
private byte[] data;
|
||||
|
||||
public PNGMapleCanvas(int width, int height, int dataLength, int format, byte[] data) {
|
||||
super();
|
||||
this.height = height;
|
||||
this.width = width;
|
||||
this.dataLength = dataLength;
|
||||
this.format = format;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
private byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getImage() {
|
||||
int sizeUncompressed = 0;
|
||||
int size8888 = 0;
|
||||
int maxWriteBuf = 2;
|
||||
int maxHeight = 3;
|
||||
byte[] writeBuf = new byte[maxWriteBuf];
|
||||
@SuppressWarnings ("unused")
|
||||
byte[] rowPointers = new byte[maxHeight];
|
||||
switch (getFormat()) {
|
||||
case 1:
|
||||
case 513:
|
||||
sizeUncompressed = getHeight() * getWidth() * 4;
|
||||
break;
|
||||
case 2:
|
||||
sizeUncompressed = getHeight() * getWidth() * 8;
|
||||
break;
|
||||
case 517:
|
||||
sizeUncompressed = getHeight() * getWidth() / 128;
|
||||
break;
|
||||
}
|
||||
size8888 = getHeight() * getWidth() * 8;
|
||||
if (size8888 > maxWriteBuf) {
|
||||
maxWriteBuf = size8888;
|
||||
writeBuf = new byte[maxWriteBuf];
|
||||
}
|
||||
if (getHeight() > maxHeight) {
|
||||
maxHeight = getHeight();
|
||||
rowPointers = new byte[maxHeight];
|
||||
}
|
||||
Inflater dec = new Inflater();
|
||||
dec.setInput(getData(), 0, dataLength);
|
||||
int declen = 0;
|
||||
byte[] uc = new byte[sizeUncompressed];
|
||||
try {
|
||||
declen = dec.inflate(uc);
|
||||
} catch (DataFormatException ex) {
|
||||
throw new RuntimeException("zlib fucks", ex);
|
||||
}
|
||||
dec.end();
|
||||
if (getFormat() == 1) {
|
||||
for (int i = 0; i < sizeUncompressed; i++) {
|
||||
byte low = (byte) (uc[i] & 0x0F);
|
||||
byte high = (byte) (uc[i] & 0xF0);
|
||||
writeBuf[(i << 1)] = (byte) (((low << 4) | low) & 0xFF);
|
||||
writeBuf[(i << 1) + 1] = (byte) (high | ((high >>> 4) & 0xF));
|
||||
}
|
||||
} else if (getFormat() == 2) {
|
||||
writeBuf = uc;
|
||||
} else if (getFormat() == 513) {
|
||||
for (int i = 0; i < declen; i += 2) {
|
||||
byte bBits = (byte) ((uc[i] & 0x1F) << 3);
|
||||
byte gBits = (byte) (((uc[i + 1] & 0x07) << 5) | ((uc[i] & 0xE0) >> 3));
|
||||
byte rBits = (byte) (uc[i + 1] & 0xF8);
|
||||
writeBuf[(i << 1)] = (byte) (bBits | (bBits >> 5));
|
||||
writeBuf[(i << 1) + 1] = (byte) (gBits | (gBits >> 6));
|
||||
writeBuf[(i << 1) + 2] = (byte) (rBits | (rBits >> 5));
|
||||
writeBuf[(i << 1) + 3] = (byte) 0xFF;
|
||||
}
|
||||
} else if (getFormat() == 517) {
|
||||
byte b = 0x00;
|
||||
int pixelIndex = 0;
|
||||
for (int i = 0; i < declen; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
b = (byte) (((uc[i] & (0x01 << (7 - j))) >> (7 - j)) * 255);
|
||||
for (int k = 0; k < 16; k++) {
|
||||
pixelIndex = (i << 9) + (j << 6) + k * 2;
|
||||
writeBuf[pixelIndex] = b;
|
||||
writeBuf[pixelIndex + 1] = b;
|
||||
writeBuf[pixelIndex + 2] = b;
|
||||
writeBuf[pixelIndex + 3] = (byte) 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DataBufferByte imgData = new DataBufferByte(writeBuf, sizeUncompressed);
|
||||
SampleModel sm = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, getWidth(), getHeight(), 4, getWidth() * 4, ZAHLEN);
|
||||
WritableRaster imgRaster = Raster.createWritableRaster(sm, imgData, new Point(0, 0));
|
||||
BufferedImage aa = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
aa.setData(imgRaster);
|
||||
return aa;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import provider.MapleDataDirectoryEntry;
|
||||
import provider.MapleDataEntity;
|
||||
import provider.MapleDataEntry;
|
||||
import provider.MapleDataFileEntry;
|
||||
|
||||
public class WZDirectoryEntry extends WZEntry implements MapleDataDirectoryEntry {
|
||||
private List<MapleDataDirectoryEntry> subdirs = new ArrayList<MapleDataDirectoryEntry>();
|
||||
private List<MapleDataFileEntry> files = new ArrayList<MapleDataFileEntry>();
|
||||
private Map<String, MapleDataEntry> entries = new HashMap<String, MapleDataEntry>();
|
||||
|
||||
public WZDirectoryEntry(String name, int size, int checksum, MapleDataEntity parent) {
|
||||
super(name, size, checksum, parent);
|
||||
}
|
||||
|
||||
public WZDirectoryEntry() {
|
||||
super(null, 0, 0, null);
|
||||
}
|
||||
|
||||
public void addDirectory(MapleDataDirectoryEntry dir) {
|
||||
subdirs.add(dir);
|
||||
entries.put(dir.getName(), dir);
|
||||
}
|
||||
|
||||
public void addFile(MapleDataFileEntry fileEntry) {
|
||||
files.add(fileEntry);
|
||||
entries.put(fileEntry.getName(), fileEntry);
|
||||
}
|
||||
|
||||
public List<MapleDataDirectoryEntry> getSubdirectories() {
|
||||
return Collections.unmodifiableList(subdirs);
|
||||
}
|
||||
|
||||
public List<MapleDataFileEntry> getFiles() {
|
||||
return Collections.unmodifiableList(files);
|
||||
}
|
||||
|
||||
public MapleDataEntry getEntry(String name) {
|
||||
return entries.get(name);
|
||||
}
|
||||
}
|
||||
61
tools/MapleCashCosmeticsFetcher/src/provider/wz/WZEntry.java
Normal file
61
tools/MapleCashCosmeticsFetcher/src/provider/wz/WZEntry.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import provider.MapleDataEntity;
|
||||
import provider.MapleDataEntry;
|
||||
|
||||
public class WZEntry implements MapleDataEntry {
|
||||
private String name;
|
||||
private int size;
|
||||
private int checksum;
|
||||
private int offset;
|
||||
private MapleDataEntity parent;
|
||||
|
||||
public WZEntry(String name, int size, int checksum, MapleDataEntity parent) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.checksum = checksum;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public int getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public MapleDataEntity getParent() {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
154
tools/MapleCashCosmeticsFetcher/src/provider/wz/WZFile.java
Normal file
154
tools/MapleCashCosmeticsFetcher/src/provider/wz/WZFile.java
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataDirectoryEntry;
|
||||
import provider.MapleDataFileEntry;
|
||||
import provider.MapleDataProvider;
|
||||
import tools.data.input.GenericLittleEndianAccessor;
|
||||
import tools.data.input.GenericSeekableLittleEndianAccessor;
|
||||
import tools.data.input.InputStreamByteStream;
|
||||
import tools.data.input.LittleEndianAccessor;
|
||||
import tools.data.input.RandomAccessByteStream;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
public class WZFile implements MapleDataProvider {
|
||||
static {
|
||||
ListWZFile.init();
|
||||
}
|
||||
private File wzfile;
|
||||
private LittleEndianAccessor lea;
|
||||
private SeekableLittleEndianAccessor slea;
|
||||
private int headerSize;
|
||||
private WZDirectoryEntry root;
|
||||
private boolean provideImages;
|
||||
private int cOffset;
|
||||
|
||||
public WZFile(File wzfile, boolean provideImages) throws IOException {
|
||||
this.wzfile = wzfile;
|
||||
lea = new GenericLittleEndianAccessor(new InputStreamByteStream(new BufferedInputStream(new FileInputStream(wzfile))));
|
||||
RandomAccessFile raf = new RandomAccessFile(wzfile, "r");
|
||||
slea = new GenericSeekableLittleEndianAccessor(new RandomAccessByteStream(raf));
|
||||
root = new WZDirectoryEntry(wzfile.getName(), 0, 0, null);
|
||||
this.provideImages = provideImages;
|
||||
load();
|
||||
}
|
||||
|
||||
private void load() throws IOException {
|
||||
lea.readAsciiString(4);
|
||||
lea.readInt();
|
||||
lea.readInt();
|
||||
headerSize = lea.readInt();
|
||||
lea.readNullTerminatedAsciiString();
|
||||
lea.readShort();
|
||||
parseDirectory(root);
|
||||
cOffset = (int) lea.getBytesRead();
|
||||
getOffsets(root);
|
||||
}
|
||||
|
||||
private void getOffsets(MapleDataDirectoryEntry dir) {
|
||||
for (MapleDataFileEntry file : dir.getFiles()) {
|
||||
file.setOffset(cOffset);
|
||||
cOffset += file.getSize();
|
||||
}
|
||||
for (MapleDataDirectoryEntry sdir : dir.getSubdirectories()) {
|
||||
getOffsets(sdir);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseDirectory(WZDirectoryEntry dir) {
|
||||
int entries = WZTool.readValue(lea);
|
||||
for (int i = 0; i < entries; i++) {
|
||||
byte marker = lea.readByte();
|
||||
String name = null;
|
||||
int size, checksum;
|
||||
switch (marker) {
|
||||
case 0x02:
|
||||
name = WZTool.readDecodedStringAtOffsetAndReset(slea, lea.readInt() + this.headerSize + 1);
|
||||
size = WZTool.readValue(lea);
|
||||
checksum = WZTool.readValue(lea);
|
||||
lea.readInt(); //dummy int
|
||||
dir.addFile(new WZFileEntry(name, size, checksum, dir));
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
name = WZTool.readDecodedString(lea);
|
||||
size = WZTool.readValue(lea);
|
||||
checksum = WZTool.readValue(lea);
|
||||
lea.readInt(); //dummy int
|
||||
if (marker == 3) {
|
||||
dir.addDirectory(new WZDirectoryEntry(name, size, checksum, dir));
|
||||
} else {
|
||||
dir.addFile(new WZFileEntry(name, size, checksum, dir));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
for (MapleDataDirectoryEntry idir : dir.getSubdirectories()) {
|
||||
parseDirectory((WZDirectoryEntry) idir);
|
||||
}
|
||||
}
|
||||
|
||||
public WZIMGFile getImgFile(String path) throws IOException {
|
||||
String segments[] = path.split("/");
|
||||
WZDirectoryEntry dir = root;
|
||||
for (int x = 0; x < segments.length - 1; x++) {
|
||||
dir = (WZDirectoryEntry) dir.getEntry(segments[x]);
|
||||
if (dir == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
WZFileEntry entry = (WZFileEntry) dir.getEntry(segments[segments.length - 1]);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
String fullPath = wzfile.getName().substring(0, wzfile.getName().length() - 3).toLowerCase() + "/" + path;
|
||||
return new WZIMGFile(this.wzfile, entry, provideImages, ListWZFile.isModernImgFile(fullPath));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized MapleData getData(String path) {
|
||||
try {
|
||||
WZIMGFile imgFile = getImgFile(path);
|
||||
if (imgFile == null) {
|
||||
return null;
|
||||
}
|
||||
MapleData ret = imgFile.getRoot();
|
||||
return ret;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapleDataDirectoryEntry getRoot() {
|
||||
return root;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import provider.MapleDataEntity;
|
||||
import provider.MapleDataFileEntry;
|
||||
|
||||
public class WZFileEntry extends WZEntry implements MapleDataFileEntry {
|
||||
private int offset;
|
||||
|
||||
public WZFileEntry(String name, int size, int checksum, MapleDataEntity parent) {
|
||||
super(name, size, checksum, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void setOffset(int offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
118
tools/MapleCashCosmeticsFetcher/src/provider/wz/WZIMGEntry.java
Normal file
118
tools/MapleCashCosmeticsFetcher/src/provider/wz/WZIMGEntry.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataEntity;
|
||||
|
||||
public class WZIMGEntry implements MapleData {
|
||||
private String name;
|
||||
private MapleDataType type;
|
||||
private List<MapleData> children = new ArrayList<MapleData>(10);
|
||||
private Object data;
|
||||
private MapleDataEntity parent;
|
||||
|
||||
public WZIMGEntry(MapleDataEntity parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapleDataType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MapleData> getChildren() {
|
||||
return Collections.unmodifiableList(children);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapleData getChildByPath(String path) {
|
||||
String segments[] = path.split("/");
|
||||
if (segments[0].equals("..")) {
|
||||
return ((MapleData) getParent()).getChildByPath(path.substring(path.indexOf("/") + 1));
|
||||
}
|
||||
MapleData ret = this;
|
||||
for (int x = 0; x < segments.length; x++) {
|
||||
boolean foundChild = false;
|
||||
for (MapleData child : ret.getChildren()) {
|
||||
if (child.getName().equals(segments[x])) {
|
||||
ret = child;
|
||||
foundChild = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundChild) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setType(MapleDataType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setData(Object data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void addChild(WZIMGEntry entry) {
|
||||
children.add(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<MapleData> iterator() {
|
||||
return getChildren().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName() + ":" + getData();
|
||||
}
|
||||
|
||||
public MapleDataEntity getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
((ArrayList<MapleData>) children).trimToSize();
|
||||
}
|
||||
}
|
||||
227
tools/MapleCashCosmeticsFetcher/src/provider/wz/WZIMGFile.java
Normal file
227
tools/MapleCashCosmeticsFetcher/src/provider/wz/WZIMGFile.java
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import tools.data.input.GenericSeekableLittleEndianAccessor;
|
||||
import tools.data.input.RandomAccessByteStream;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
public class WZIMGFile {
|
||||
private WZFileEntry file;
|
||||
private WZIMGEntry root;
|
||||
private boolean provideImages;
|
||||
@SuppressWarnings ("unused")
|
||||
private boolean modernImg;
|
||||
|
||||
public WZIMGFile(File wzfile, WZFileEntry file, boolean provideImages, boolean modernImg) throws IOException {
|
||||
RandomAccessFile raf = new RandomAccessFile(wzfile, "r");
|
||||
SeekableLittleEndianAccessor slea = new GenericSeekableLittleEndianAccessor(new RandomAccessByteStream(raf));
|
||||
slea.seek(file.getOffset());
|
||||
this.file = file;
|
||||
this.provideImages = provideImages;
|
||||
root = new WZIMGEntry(file.getParent());
|
||||
root.setName(file.getName());
|
||||
root.setType(MapleDataType.EXTENDED);
|
||||
this.modernImg = modernImg;
|
||||
parseExtended(root, slea, 0);
|
||||
root.finish();
|
||||
raf.close();
|
||||
}
|
||||
|
||||
protected void dumpImg(OutputStream out, SeekableLittleEndianAccessor slea) throws IOException {
|
||||
DataOutputStream os = new DataOutputStream(out);
|
||||
long oldPos = slea.getPosition();
|
||||
slea.seek(file.getOffset());
|
||||
for (int x = 0; x < file.getSize(); x++) {
|
||||
os.write(slea.readByte());
|
||||
}
|
||||
slea.seek(oldPos);
|
||||
}
|
||||
|
||||
public WZIMGEntry getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
private void parse(WZIMGEntry entry, SeekableLittleEndianAccessor slea) {
|
||||
byte marker = slea.readByte();
|
||||
switch (marker) {
|
||||
case 0: {
|
||||
String name = WZTool.readDecodedString(slea);
|
||||
entry.setName(name);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
String name = WZTool.readDecodedStringAtOffsetAndReset(slea, file.getOffset() + slea.readInt());
|
||||
entry.setName(name);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
System.out.println("Unknown Image identifier: " + marker + " at offset " + (slea.getPosition() - file.getOffset()));
|
||||
}
|
||||
marker = slea.readByte();
|
||||
switch (marker) {
|
||||
case 0:
|
||||
entry.setType(MapleDataType.IMG_0x00);
|
||||
break;
|
||||
case 2:
|
||||
case 11: //??? no idea, since 0.49
|
||||
entry.setType(MapleDataType.SHORT);
|
||||
entry.setData(Short.valueOf(slea.readShort()));
|
||||
break;
|
||||
case 3:
|
||||
entry.setType(MapleDataType.INT);
|
||||
entry.setData(Integer.valueOf(WZTool.readValue(slea)));
|
||||
break;
|
||||
case 4:
|
||||
entry.setType(MapleDataType.FLOAT);
|
||||
entry.setData(Float.valueOf(WZTool.readFloatValue(slea)));
|
||||
break;
|
||||
case 5:
|
||||
entry.setType(MapleDataType.DOUBLE);
|
||||
entry.setData(Double.valueOf(slea.readDouble()));
|
||||
break;
|
||||
case 8:
|
||||
entry.setType(MapleDataType.STRING);
|
||||
byte iMarker = slea.readByte();
|
||||
if (iMarker == 0) {
|
||||
entry.setData(WZTool.readDecodedString(slea));
|
||||
} else if (iMarker == 1) {
|
||||
entry.setData(WZTool.readDecodedStringAtOffsetAndReset(slea, slea.readInt() + file.getOffset()));
|
||||
} else {
|
||||
System.out.println("Unknown String type " + iMarker);
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
entry.setType(MapleDataType.EXTENDED);
|
||||
long endOfExtendedBlock = slea.readInt();
|
||||
endOfExtendedBlock += slea.getPosition();
|
||||
parseExtended(entry, slea, endOfExtendedBlock);
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown Image type " + marker);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseExtended(WZIMGEntry entry, SeekableLittleEndianAccessor slea, long endOfExtendedBlock) {
|
||||
byte marker = slea.readByte();
|
||||
String type;
|
||||
switch (marker) {
|
||||
case 0x73:
|
||||
type = WZTool.readDecodedString(slea);
|
||||
break;
|
||||
case 0x1B:
|
||||
type = WZTool.readDecodedStringAtOffsetAndReset(slea, file.getOffset() + slea.readInt());
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unknown extended image identifier: " + marker + " at offset " +
|
||||
(slea.getPosition() - file.getOffset()));
|
||||
}
|
||||
if (type.equals("Property")) {
|
||||
entry.setType(MapleDataType.PROPERTY);
|
||||
slea.readByte();
|
||||
slea.readByte();
|
||||
int children = WZTool.readValue(slea);
|
||||
for (int i = 0; i < children; i++) {
|
||||
WZIMGEntry cEntry = new WZIMGEntry(entry);
|
||||
parse(cEntry, slea);
|
||||
cEntry.finish();
|
||||
entry.addChild(cEntry);
|
||||
}
|
||||
} else if (type.equals("Canvas")) {
|
||||
entry.setType(MapleDataType.CANVAS);
|
||||
slea.readByte();
|
||||
marker = slea.readByte();
|
||||
if (marker == 0) {
|
||||
// do nothing
|
||||
} else if (marker == 1) {
|
||||
slea.readByte();
|
||||
slea.readByte();
|
||||
int children = WZTool.readValue(slea);
|
||||
for (int i = 0; i < children; i++) {
|
||||
WZIMGEntry child = new WZIMGEntry(entry);
|
||||
parse(child, slea);
|
||||
child.finish();
|
||||
entry.addChild(child);
|
||||
}
|
||||
} else {
|
||||
System.out.println("Canvas marker != 1 (" + marker + ")");
|
||||
}
|
||||
int width = WZTool.readValue(slea);
|
||||
int height = WZTool.readValue(slea);
|
||||
int format = WZTool.readValue(slea);
|
||||
int format2 = slea.readByte();
|
||||
slea.readInt();
|
||||
int dataLength = slea.readInt() - 1;
|
||||
slea.readByte();
|
||||
if (provideImages) {
|
||||
byte[] pngdata = slea.read(dataLength);
|
||||
entry.setData(new PNGMapleCanvas(width, height, dataLength, format + format2, pngdata));
|
||||
} else {
|
||||
entry.setData(new PNGMapleCanvas(width, height, dataLength, format + format2, null));
|
||||
slea.skip(dataLength);
|
||||
}
|
||||
} else if (type.equals("Shape2D#Vector2D")) {
|
||||
entry.setType(MapleDataType.VECTOR);
|
||||
int x = WZTool.readValue(slea);
|
||||
int y = WZTool.readValue(slea);
|
||||
entry.setData(new Point(x, y));
|
||||
} else if (type.equals("Shape2D#Convex2D")) {
|
||||
int children = WZTool.readValue(slea);
|
||||
for (int i = 0; i < children; i++) {
|
||||
WZIMGEntry cEntry = new WZIMGEntry(entry);
|
||||
parseExtended(cEntry, slea, 0);
|
||||
cEntry.finish();
|
||||
entry.addChild(cEntry);
|
||||
}
|
||||
} else if (type.equals("Sound_DX8")) {
|
||||
entry.setType(MapleDataType.SOUND);
|
||||
slea.readByte();
|
||||
int dataLength = WZTool.readValue(slea);
|
||||
WZTool.readValue(slea); // no clue what this is
|
||||
int offset = (int) slea.getPosition();
|
||||
entry.setData(new ImgMapleSound(dataLength, offset - file.getOffset()));
|
||||
slea.seek(endOfExtendedBlock);
|
||||
} else if (type.equals("UOL")) {
|
||||
entry.setType(MapleDataType.UOL);
|
||||
slea.readByte();
|
||||
byte uolmarker = slea.readByte();
|
||||
switch (uolmarker) {
|
||||
case 0:
|
||||
entry.setData(WZTool.readDecodedString(slea));
|
||||
break;
|
||||
case 1:
|
||||
entry.setData(WZTool.readDecodedStringAtOffsetAndReset(slea, file.getOffset() + slea.readInt()));
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown UOL marker: " + uolmarker + " " + entry.getName());
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled extended type: " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
187
tools/MapleCashCosmeticsFetcher/src/provider/wz/WZTool.java
Normal file
187
tools/MapleCashCosmeticsFetcher/src/provider/wz/WZTool.java
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import tools.data.input.LittleEndianAccessor;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
/*
|
||||
* Ported Code, see WZFile.java for more info
|
||||
*/
|
||||
public class WZTool {
|
||||
private static byte[] encKey;
|
||||
|
||||
static {
|
||||
byte[] iv = new byte[]{(byte) 0x4d, (byte) 0x23, (byte) 0xc7, (byte) 0x2b,
|
||||
(byte) 0x4d, (byte) 0x23, (byte) 0xc7, (byte) 0x2b,
|
||||
(byte) 0x4d, (byte) 0x23, (byte) 0xc7, (byte) 0x2b,
|
||||
(byte) 0x4d, (byte) 0x23, (byte) 0xc7, (byte) 0x2b,};
|
||||
byte[] key = new byte[]{(byte) 0x13, 0x00, 0x00, 0x00,
|
||||
(byte) 0x08, 0x00, 0x00, 0x00,
|
||||
(byte) 0x06, 0x00, 0x00, 0x00,
|
||||
(byte) 0xB4, 0x00, 0x00, 0x00,
|
||||
(byte) 0x1B, 0x00, 0x00, 0x00,
|
||||
(byte) 0x0F, 0x00, 0x00, 0x00,
|
||||
(byte) 0x33, 0x00, 0x00, 0x00,
|
||||
(byte) 0x52, 0x00, 0x00, 0x00
|
||||
};
|
||||
Cipher cipher = null;
|
||||
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
|
||||
try {
|
||||
cipher = Cipher.getInstance("AES");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
|
||||
} catch (InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
encKey = new byte[0xFFFF];
|
||||
for (int i = 0; i < (0xFFFF / 16); i++) {
|
||||
try {
|
||||
iv = cipher.doFinal(iv);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.arraycopy(iv, 0, encKey, (i * 16), 16);
|
||||
}
|
||||
try {
|
||||
iv = cipher.doFinal(iv);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.arraycopy(iv, 0, encKey, 65520, 15);
|
||||
}
|
||||
|
||||
public static byte[] readListString(byte[] str) {
|
||||
for (int i = 0; i < str.length; i++) {
|
||||
str[i] = (byte) (str[i] ^ encKey[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public static String readDecodedString(LittleEndianAccessor llea) {
|
||||
int strLength;
|
||||
byte b = llea.readByte();
|
||||
if (b == 0x00) {
|
||||
return "";
|
||||
}
|
||||
if (b >= 0) {
|
||||
if (b == 0x7F) {
|
||||
strLength = llea.readInt();
|
||||
} else {
|
||||
strLength = (int) b;
|
||||
}
|
||||
if (strLength < 0) {
|
||||
return "";
|
||||
}
|
||||
byte str[] = new byte[strLength * 2];
|
||||
for (int i = 0; i < strLength * 2; i++) {
|
||||
str[i] = llea.readByte();
|
||||
}
|
||||
return DecryptUnicodeStr(str);
|
||||
} else {
|
||||
if (b == -128) {
|
||||
strLength = llea.readInt();
|
||||
} else {
|
||||
strLength = -b;
|
||||
}
|
||||
if (strLength < 0) {
|
||||
return "";
|
||||
}
|
||||
byte str[] = new byte[strLength];
|
||||
for (int i = 0; i < strLength; i++) {
|
||||
str[i] = llea.readByte();
|
||||
}
|
||||
return DecryptAsciiStr(str);
|
||||
}
|
||||
}
|
||||
|
||||
public static String DecryptAsciiStr(byte[] str) {
|
||||
byte xorByte = (byte) 0xAA;
|
||||
for (int i = 0; i < str.length; i++) {
|
||||
str[i] = (byte) (str[i] ^ xorByte ^ encKey[i]);
|
||||
xorByte++;
|
||||
}
|
||||
return new String(str);
|
||||
}
|
||||
|
||||
public static String DecryptUnicodeStr(byte[] str) {
|
||||
int xorByte = 0xAAAA;
|
||||
char[] charRet = new char[str.length / 2];
|
||||
for (int i = 0; i < str.length; i++) {
|
||||
str[i] = (byte) (str[i] ^ encKey[i]);
|
||||
}
|
||||
for (int i = 0; i < (str.length / 2); i++) {
|
||||
char toXor = (char) ((str[i] << 8) | str[i + 1]);
|
||||
charRet[i] = (char) (toXor ^ xorByte);
|
||||
xorByte++;
|
||||
}
|
||||
return String.valueOf(charRet);
|
||||
}
|
||||
|
||||
public static String readDecodedStringAtOffset(SeekableLittleEndianAccessor slea, int offset) {
|
||||
slea.seek(offset);
|
||||
return readDecodedString(slea);
|
||||
}
|
||||
|
||||
public static String readDecodedStringAtOffsetAndReset(SeekableLittleEndianAccessor slea, int offset) {
|
||||
long pos = 0;
|
||||
pos = slea.getPosition();
|
||||
slea.seek(offset);
|
||||
String ret = readDecodedString(slea);
|
||||
slea.seek(pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int readValue(LittleEndianAccessor lea) {
|
||||
byte b = lea.readByte();
|
||||
if (b == -128) {
|
||||
return lea.readInt();
|
||||
} else {
|
||||
return ((int) b);
|
||||
}
|
||||
}
|
||||
|
||||
public static float readFloatValue(LittleEndianAccessor lea) {
|
||||
byte b = lea.readByte();
|
||||
if (b == -128) {
|
||||
return lea.readFloat();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.text.NumberFormat;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataEntity;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public class XMLDomMapleData implements MapleData {
|
||||
private Node node;
|
||||
private File imageDataDir;
|
||||
private NumberFormat nf;
|
||||
|
||||
public XMLDomMapleData(FileInputStream fis, File imageDataDir) {
|
||||
try {
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
Document document = documentBuilder.parse(fis);
|
||||
this.node = document.getFirstChild();
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (SAXException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.imageDataDir = imageDataDir;
|
||||
this.nf = NumberFormat.getInstance(Locale.FRANCE);
|
||||
}
|
||||
|
||||
private XMLDomMapleData(Node node) {
|
||||
this.node = node;
|
||||
this.nf = NumberFormat.getInstance(Locale.FRANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapleData getChildByPath(String path) {
|
||||
String segments[] = path.split("/");
|
||||
if (segments[0].equals("..")) {
|
||||
return ((MapleData) getParent()).getChildByPath(path.substring(path.indexOf("/") + 1));
|
||||
}
|
||||
|
||||
Node myNode = node;
|
||||
for (int x = 0; x < segments.length; x++) {
|
||||
NodeList childNodes = myNode.getChildNodes();
|
||||
boolean foundChild = false;
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node childNode = childNodes.item(i);
|
||||
if (childNode.getNodeType() == Node.ELEMENT_NODE && childNode.getAttributes().getNamedItem("name").getNodeValue().equals(segments[x])) {
|
||||
myNode = childNode;
|
||||
foundChild = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundChild) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
XMLDomMapleData ret = new XMLDomMapleData(myNode);
|
||||
ret.imageDataDir = new File(imageDataDir, getName() + "/" + path).getParentFile();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MapleData> getChildren() {
|
||||
List<MapleData> ret = new ArrayList<MapleData>();
|
||||
NodeList childNodes = node.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node childNode = childNodes.item(i);
|
||||
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
|
||||
XMLDomMapleData child = new XMLDomMapleData(childNode);
|
||||
child.imageDataDir = new File(imageDataDir, getName());
|
||||
ret.add(child);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getData() {
|
||||
NamedNodeMap attributes = node.getAttributes();
|
||||
MapleDataType type = getType();
|
||||
switch (type) {
|
||||
case DOUBLE:
|
||||
case FLOAT:
|
||||
case INT:
|
||||
case SHORT: {
|
||||
String value = attributes.getNamedItem("value").getNodeValue();
|
||||
Number nval;
|
||||
|
||||
try {
|
||||
nval = nf.parse(value);
|
||||
}
|
||||
catch(java.text.ParseException pe) {
|
||||
pe.printStackTrace();
|
||||
nval = 0.0f;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case DOUBLE:
|
||||
return nval.doubleValue();
|
||||
case FLOAT:
|
||||
return nval.floatValue();
|
||||
case INT:
|
||||
return nval.intValue();
|
||||
case SHORT:
|
||||
return nval.shortValue();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
case STRING:
|
||||
case UOL: {
|
||||
String value = attributes.getNamedItem("value").getNodeValue();
|
||||
return value;
|
||||
}
|
||||
case VECTOR: {
|
||||
String x = attributes.getNamedItem("x").getNodeValue();
|
||||
String y = attributes.getNamedItem("y").getNodeValue();
|
||||
return new Point(Integer.parseInt(x), Integer.parseInt(y));
|
||||
}
|
||||
case CANVAS: {
|
||||
String width = attributes.getNamedItem("width").getNodeValue();
|
||||
String height = attributes.getNamedItem("height").getNodeValue();
|
||||
return new FileStoredPngMapleCanvas(Integer.parseInt(width), Integer.parseInt(height), new File(
|
||||
imageDataDir, getName() + ".png"));
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapleDataType getType() {
|
||||
String nodeName = node.getNodeName();
|
||||
if (nodeName.equals("imgdir")) {
|
||||
return MapleDataType.PROPERTY;
|
||||
} else if (nodeName.equals("canvas")) {
|
||||
return MapleDataType.CANVAS;
|
||||
} else if (nodeName.equals("convex")) {
|
||||
return MapleDataType.CONVEX;
|
||||
} else if (nodeName.equals("sound")) {
|
||||
return MapleDataType.SOUND;
|
||||
} else if (nodeName.equals("uol")) {
|
||||
return MapleDataType.UOL;
|
||||
} else if (nodeName.equals("double")) {
|
||||
return MapleDataType.DOUBLE;
|
||||
} else if (nodeName.equals("float")) {
|
||||
return MapleDataType.FLOAT;
|
||||
} else if (nodeName.equals("int")) {
|
||||
return MapleDataType.INT;
|
||||
} else if (nodeName.equals("short")) {
|
||||
return MapleDataType.SHORT;
|
||||
} else if (nodeName.equals("string")) {
|
||||
return MapleDataType.STRING;
|
||||
} else if (nodeName.equals("vector")) {
|
||||
return MapleDataType.VECTOR;
|
||||
} else if (nodeName.equals("null")) {
|
||||
return MapleDataType.IMG_0x00;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapleDataEntity getParent() {
|
||||
Node parentNode = node.getParentNode();
|
||||
if (parentNode.getNodeType() == Node.DOCUMENT_NODE) {
|
||||
return null;
|
||||
}
|
||||
XMLDomMapleData parentData = new XMLDomMapleData(parentNode);
|
||||
parentData.imageDataDir = imageDataDir.getParentFile();
|
||||
return parentData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return node.getAttributes().getNamedItem("name").getNodeValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<MapleData> iterator() {
|
||||
return getChildren().iterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package provider.wz;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataDirectoryEntry;
|
||||
import provider.MapleDataProvider;
|
||||
|
||||
public class XMLWZFile implements MapleDataProvider {
|
||||
private File root;
|
||||
private WZDirectoryEntry rootForNavigation;
|
||||
|
||||
public XMLWZFile(File fileIn) {
|
||||
root = fileIn;
|
||||
rootForNavigation = new WZDirectoryEntry(fileIn.getName(), 0, 0, null);
|
||||
fillMapleDataEntitys(root, rootForNavigation);
|
||||
}
|
||||
|
||||
private void fillMapleDataEntitys(File lroot, WZDirectoryEntry wzdir) {
|
||||
for (File file : lroot.listFiles()) {
|
||||
String fileName = file.getName();
|
||||
if (file.isDirectory() && !fileName.endsWith(".img")) {
|
||||
WZDirectoryEntry newDir = new WZDirectoryEntry(fileName, 0, 0, wzdir);
|
||||
wzdir.addDirectory(newDir);
|
||||
fillMapleDataEntitys(file, newDir);
|
||||
} else if (fileName.endsWith(".xml")) {
|
||||
wzdir.addFile(new WZFileEntry(fileName.substring(0, fileName.length() - 4), 0, 0, wzdir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapleData getData(String path) {
|
||||
File dataFile = new File(root, path + ".xml");
|
||||
File imageDataDir = new File(root, path);
|
||||
if (!dataFile.exists()) {
|
||||
return null;//bitches
|
||||
}
|
||||
FileInputStream fis;
|
||||
try {
|
||||
fis = new FileInputStream(dataFile);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException("Datafile " + path + " does not exist in " + root.getAbsolutePath());
|
||||
}
|
||||
final XMLDomMapleData domMapleData;
|
||||
try {
|
||||
domMapleData = new XMLDomMapleData(fis, imageDataDir.getParentFile());
|
||||
} finally {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return domMapleData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapleDataDirectoryEntry getRoot() {
|
||||
return rootForNavigation;
|
||||
}
|
||||
}
|
||||
149
tools/MapleCashCosmeticsFetcher/src/tools/ArrayMap.java
Normal file
149
tools/MapleCashCosmeticsFetcher/src/tools/ArrayMap.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ArrayMap<K, V> extends AbstractMap<K, V> {
|
||||
|
||||
static class Entry<K, V> implements Map.Entry<K, V> {
|
||||
protected K key;
|
||||
protected V value;
|
||||
|
||||
public Entry(K key, V value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V newValue) {
|
||||
V oldValue = value;
|
||||
value = newValue;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Map.Entry<?, ?>)) {
|
||||
return false;
|
||||
}
|
||||
Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
|
||||
return (key == null ? e.getKey() == null : key.equals(e.getKey())) && (value == null ? e.getValue() == null : value.equals(e.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int keyHash = (key == null ? 0 : key.hashCode());
|
||||
int valueHash = (value == null ? 0 : value.hashCode());
|
||||
return keyHash ^ valueHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return key + "=" + value;
|
||||
}
|
||||
}
|
||||
private Set<? extends java.util.Map.Entry<K, V>> entries = null;
|
||||
private ArrayList<Entry<K, V>> list;
|
||||
|
||||
public ArrayMap() {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
|
||||
public ArrayMap(Map<K, V> map) {
|
||||
list = new ArrayList<>();
|
||||
putAll(map);
|
||||
}
|
||||
|
||||
public ArrayMap(int initialCapacity) {
|
||||
list = new ArrayList<>(initialCapacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings ("unchecked")
|
||||
public Set<java.util.Map.Entry<K, V>> entrySet() {
|
||||
if (entries == null) {
|
||||
entries = new AbstractSet<Entry<K, V>>() {
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<K, V>> iterator() {
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
return (Set<java.util.Map.Entry<K, V>>) entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
int size = list.size();
|
||||
Entry<K, V> entry = null;
|
||||
int i;
|
||||
if (key == null) {
|
||||
for (i = 0; i < size; i++) {
|
||||
entry = (list.get(i));
|
||||
if (entry.getKey() == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < size; i++) {
|
||||
entry = (list.get(i));
|
||||
if (key.equals(entry.getKey())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
V oldValue = null;
|
||||
if (i < size) {
|
||||
oldValue = entry.getValue();
|
||||
entry.setValue(value);
|
||||
} else {
|
||||
list.add(new Entry<>(key, value));
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package tools;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* @author Frz (Big Daddy)
|
||||
* @author The Real Spookster (some modifications to this beautiful code)
|
||||
*/
|
||||
public class DatabaseConnection {
|
||||
private static String DB_URL = "jdbc:mysql://localhost:3306/heavenms";
|
||||
private static String DB_USER = "root";
|
||||
private static String DB_PASS = "";
|
||||
|
||||
public static final int RETURN_GENERATED_KEYS = 1;
|
||||
|
||||
private static ThreadLocal<Connection> con = new ThreadLocalConnection();
|
||||
|
||||
public static Connection getConnection() {
|
||||
Connection c = con.get();
|
||||
try {
|
||||
c.getMetaData();
|
||||
} catch (SQLException e) { // connection is dead, therefore discard old object 5ever
|
||||
con.remove();
|
||||
c = con.get();
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private static class ThreadLocalConnection extends ThreadLocal<Connection> {
|
||||
|
||||
@Override
|
||||
protected Connection initialValue() {
|
||||
try {
|
||||
Class.forName("com.mysql.jdbc.Driver"); // touch the mysql driver
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.out.println("[SEVERE] SQL Driver Not Found. Consider death by clams.");
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
|
||||
} catch (SQLException e) {
|
||||
System.out.println("[SEVERE] Unable to make database connection.");
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
188
tools/MapleCashCosmeticsFetcher/src/tools/FilePrinter.java
Normal file
188
tools/MapleCashCosmeticsFetcher/src/tools/FilePrinter.java
Normal file
@@ -0,0 +1,188 @@
|
||||
package tools;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class FilePrinter {
|
||||
|
||||
public static final String
|
||||
ACCOUNT_STUCK = "accountStuck.txt",
|
||||
EXCEPTION_CAUGHT = "exceptionCaught.txt",
|
||||
CLIENT_START = "clientStartError.txt",
|
||||
ADD_PLAYER = "addPlayer.txt",
|
||||
MAPLE_MAP = "mapleMap.txt",
|
||||
ERROR38 = "error38.txt",
|
||||
PACKET_LOG = "log.txt",
|
||||
EXCEPTION = "exceptions.txt",
|
||||
SQL_EXCEPTION = "sqlexceptions.txt",
|
||||
PACKET_HANDLER = "PacketHandler/",
|
||||
PORTAL = "portals/",
|
||||
NPC = "npcs/",
|
||||
INVOCABLE = "invocable/",
|
||||
REACTOR = "reactors/",
|
||||
QUEST = "quests/",
|
||||
ITEM = "items/",
|
||||
MOB_MOVEMENT = "mobmovement.txt",
|
||||
MAP_SCRIPT = "mapscript/",
|
||||
DIRECTION = "directions/",
|
||||
SAVE_CHAR = "saveToDB.txt",
|
||||
INSERT_CHAR = "insertCharacter.txt",
|
||||
LOAD_CHAR = "loadCharFromDB.txt",
|
||||
UNHANDLED_EVENT = "doesNotExist.txt",
|
||||
SESSION = "sessions.txt",
|
||||
EXPLOITS = "exploits/",
|
||||
STORAGE = "storage/",
|
||||
PACKET_LOGS = "packetlogs/",
|
||||
DELETED_CHARACTERS = "deletedchars/",
|
||||
FREDRICK = "fredrick/",
|
||||
NPC_UNCODED = "uncodedNPCs.txt",
|
||||
QUEST_UNCODED = "uncodedQuests.txt",
|
||||
AUTOSAVING_CHARACTER = "saveCharAuto.txt",
|
||||
SAVING_CHARACTER = "saveChar.txt",
|
||||
USED_COMMANDS = "usedCommands.txt";//more to come (maps)
|
||||
|
||||
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //for file system purposes, it's nice to use yyyy-MM-dd
|
||||
private static final String FILE_PATH = "logs/" + sdf.format(Calendar.getInstance().getTime()) + "/"; // + sdf.format(Calendar.getInstance().getTime()) + "/"
|
||||
private static final String ERROR = "error/";
|
||||
|
||||
public static void printError(final String name, final Throwable t) {
|
||||
System.out.println("Error thrown: " + name);
|
||||
System.out.println(getString(t));
|
||||
FileOutputStream out = null;
|
||||
final String file = FILE_PATH + ERROR + name;
|
||||
try {
|
||||
File outputFile = new File(file);
|
||||
if (outputFile.getParentFile() != null) {
|
||||
outputFile.getParentFile().mkdirs();
|
||||
}
|
||||
out = new FileOutputStream(file, true);
|
||||
out.write(getString(t).getBytes());
|
||||
out.write("\n---------------------------------\r\n".getBytes());
|
||||
} catch (IOException ess) {
|
||||
ess.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void printError(final String name, final Throwable t, final String info) {
|
||||
System.out.println("Error thrown: " + name);
|
||||
System.out.println(getString(t));
|
||||
FileOutputStream out = null;
|
||||
final String file = FILE_PATH + ERROR + name;
|
||||
try {
|
||||
File outputFile = new File(file);
|
||||
if (outputFile.getParentFile() != null) {
|
||||
outputFile.getParentFile().mkdirs();
|
||||
}
|
||||
out = new FileOutputStream(file, true);
|
||||
out.write((info + "\r\n").getBytes());
|
||||
out.write(getString(t).getBytes());
|
||||
out.write("\n---------------------------------\r\n".getBytes());
|
||||
} catch (IOException ess) {
|
||||
ess.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void printError(final String name, final String s) {
|
||||
System.out.println("Error thrown: " + name);
|
||||
System.out.println(s);
|
||||
FileOutputStream out = null;
|
||||
final String file = FILE_PATH + ERROR + name;
|
||||
try {
|
||||
File outputFile = new File(file);
|
||||
if (outputFile.getParentFile() != null) {
|
||||
outputFile.getParentFile().mkdirs();
|
||||
}
|
||||
out = new FileOutputStream(file, true);
|
||||
out.write(s.getBytes());
|
||||
//out.write("\n---------------------------------\n".getBytes());
|
||||
} catch (IOException ess) {
|
||||
ess.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void print(final String name, final String s) {
|
||||
print(name, s, true);
|
||||
}
|
||||
|
||||
public static void print(final String name, final String s, boolean line) {
|
||||
System.out.println("Log: " + name);
|
||||
System.out.println(s);
|
||||
FileOutputStream out = null;
|
||||
String file = FILE_PATH + name;
|
||||
try {
|
||||
File outputFile = new File(file);
|
||||
if (outputFile.getParentFile() != null) {
|
||||
outputFile.getParentFile().mkdirs();
|
||||
}
|
||||
out = new FileOutputStream(file, true);
|
||||
out.write(s.getBytes());
|
||||
out.write("\r\n".getBytes());
|
||||
if (line) {
|
||||
out.write("---------------------------------\r\n".getBytes());
|
||||
}
|
||||
} catch (IOException ess) {
|
||||
ess.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getString(final Throwable e) {
|
||||
String retValue = null;
|
||||
StringWriter sw = null;
|
||||
PrintWriter pw = null;
|
||||
try {
|
||||
sw = new StringWriter();
|
||||
pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
retValue = sw.toString();
|
||||
} finally {
|
||||
try {
|
||||
if (pw != null) {
|
||||
pw.close();
|
||||
}
|
||||
if (sw != null) {
|
||||
sw.close();
|
||||
}
|
||||
} catch (IOException ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
return retValue;
|
||||
}
|
||||
}
|
||||
79
tools/MapleCashCosmeticsFetcher/src/tools/HexTool.java
Normal file
79
tools/MapleCashCosmeticsFetcher/src/tools/HexTool.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
public class HexTool {
|
||||
private static final char[] HEX = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
private static String toString(byte byteValue) {
|
||||
int tmp = byteValue << 8;
|
||||
char[] retstr = new char[]{HEX[(tmp >> 12) & 0x0F], HEX[(tmp >> 8) & 0x0F]};
|
||||
return String.valueOf(retstr);
|
||||
}
|
||||
|
||||
public static String toString(byte[] bytes) {
|
||||
StringBuilder hexed = new StringBuilder();
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
hexed.append(toString(bytes[i]));
|
||||
hexed.append(' ');
|
||||
}
|
||||
return hexed.substring(0, hexed.length() - 1);
|
||||
}
|
||||
|
||||
public static byte[] getByteArrayFromHexString(String hex) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int nexti = 0;
|
||||
int nextb = 0;
|
||||
boolean highoc = true;
|
||||
outer:
|
||||
for (;;) {
|
||||
int number = -1;
|
||||
while (number == -1) {
|
||||
if (nexti == hex.length()) {
|
||||
break outer;
|
||||
}
|
||||
char chr = hex.charAt(nexti);
|
||||
if (chr >= '0' && chr <= '9') {
|
||||
number = chr - '0';
|
||||
} else if (chr >= 'a' && chr <= 'f') {
|
||||
number = chr - 'a' + 10;
|
||||
} else if (chr >= 'A' && chr <= 'F') {
|
||||
number = chr - 'A' + 10;
|
||||
} else {
|
||||
number = -1;
|
||||
}
|
||||
nexti++;
|
||||
}
|
||||
if (highoc) {
|
||||
nextb = number << 4;
|
||||
highoc = false;
|
||||
} else {
|
||||
nextb |= number;
|
||||
highoc = true;
|
||||
baos.write(nextb);
|
||||
}
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,664 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
//import net.server.Server;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataDirectoryEntry;
|
||||
import provider.MapleDataFileEntry;
|
||||
import provider.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
import provider.MapleDataTool;
|
||||
import tools.DatabaseConnection;
|
||||
//import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
//import client.MapleCharacter;
|
||||
//import client.MapleClient;
|
||||
//import client.MapleJob;
|
||||
//import client.Skill;
|
||||
//import client.SkillFactory;
|
||||
//import client.autoban.AutobanFactory;
|
||||
//import client.inventory.Equip;
|
||||
//import client.inventory.Item;
|
||||
//import client.inventory.MapleInventory;
|
||||
//import client.inventory.MapleInventoryType;
|
||||
//import client.inventory.MapleWeaponType;
|
||||
//import constants.ServerConstants;
|
||||
//import constants.EquipSlot;
|
||||
//import constants.ItemConstants;
|
||||
//import constants.skills.Assassin;
|
||||
//import constants.skills.Gunslinger;
|
||||
//import constants.skills.NightWalker;
|
||||
import java.sql.Connection;
|
||||
//import server.life.MapleMonsterInformationProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Matze
|
||||
*
|
||||
*/
|
||||
public class MapleItemInformationProvider {
|
||||
|
||||
private static MapleItemInformationProvider instance = null;
|
||||
protected MapleDataProvider itemData;
|
||||
protected MapleDataProvider equipData;
|
||||
protected MapleDataProvider stringData;
|
||||
protected MapleData cashStringData;
|
||||
protected MapleData consumeStringData;
|
||||
protected MapleData eqpStringData;
|
||||
protected MapleData etcStringData;
|
||||
protected MapleData insStringData;
|
||||
protected MapleData petStringData;
|
||||
protected Map<Integer, Short> slotMaxCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> itemEffects = new HashMap<>();
|
||||
protected Map<Integer, Map<String, Integer>> equipStatsCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> equipCache = new HashMap<>();
|
||||
protected Map<Integer, Double> priceCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> wholePriceCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> projectileWatkCache = new HashMap<>();
|
||||
protected Map<Integer, String> nameCache = new HashMap<>();
|
||||
protected Map<Integer, String> descCache = new HashMap<>();
|
||||
protected Map<Integer, String> msgCache = new HashMap<>();
|
||||
protected Map<Integer, Boolean> dropRestrictionCache = new HashMap<>();
|
||||
protected Map<Integer, Boolean> pickupRestrictionCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> getMesoCache = new HashMap<>();
|
||||
protected Map<Integer, Boolean> onEquipUntradableCache = new HashMap<>();
|
||||
protected Map<Integer, Boolean> karmaCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> triggerItemCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> expCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> levelCache = new HashMap<>();
|
||||
protected List<Pair<Integer, String>> itemNameCache = new ArrayList<>();
|
||||
protected Map<Integer, Boolean> consumeOnPickupCache = new HashMap<>();
|
||||
protected Map<Integer, Boolean> isQuestItemCache = new HashMap<>();
|
||||
protected Map<Integer, String> equipmentSlotCache = new HashMap<>();
|
||||
protected Map<Integer, Boolean> noCancelMouseCache = new HashMap<>();
|
||||
|
||||
private MapleItemInformationProvider() {
|
||||
itemData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Item.wz"));
|
||||
equipData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Character.wz"));
|
||||
stringData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/String.wz"));
|
||||
cashStringData = stringData.getData("Cash.img");
|
||||
consumeStringData = stringData.getData("Consume.img");
|
||||
eqpStringData = stringData.getData("Eqp.img");
|
||||
etcStringData = stringData.getData("Etc.img");
|
||||
insStringData = stringData.getData("Ins.img");
|
||||
petStringData = stringData.getData("Pet.img");
|
||||
}
|
||||
|
||||
public static MapleItemInformationProvider getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new MapleItemInformationProvider();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public List<Pair<Integer, String>> getAllItems() {
|
||||
if (!itemNameCache.isEmpty()) {
|
||||
return itemNameCache;
|
||||
}
|
||||
List<Pair<Integer, String>> itemPairs = new ArrayList<>();
|
||||
MapleData itemsData;
|
||||
itemsData = stringData.getData("Cash.img");
|
||||
for (MapleData itemFolder : itemsData.getChildren()) {
|
||||
itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
|
||||
}
|
||||
itemsData = stringData.getData("Consume.img");
|
||||
for (MapleData itemFolder : itemsData.getChildren()) {
|
||||
itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
|
||||
}
|
||||
itemsData = stringData.getData("Eqp.img").getChildByPath("Eqp");
|
||||
for (MapleData eqpType : itemsData.getChildren()) {
|
||||
for (MapleData itemFolder : eqpType.getChildren()) {
|
||||
itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
|
||||
}
|
||||
}
|
||||
itemsData = stringData.getData("Etc.img").getChildByPath("Etc");
|
||||
for (MapleData itemFolder : itemsData.getChildren()) {
|
||||
itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
|
||||
}
|
||||
itemsData = stringData.getData("Ins.img");
|
||||
for (MapleData itemFolder : itemsData.getChildren()) {
|
||||
itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
|
||||
}
|
||||
itemsData = stringData.getData("Pet.img");
|
||||
for (MapleData itemFolder : itemsData.getChildren()) {
|
||||
itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
|
||||
}
|
||||
return itemPairs;
|
||||
}
|
||||
|
||||
public List<Pair<Integer, String>> getAllEtcItems() {
|
||||
if (!itemNameCache.isEmpty()) {
|
||||
return itemNameCache;
|
||||
}
|
||||
|
||||
List<Pair<Integer, String>> itemPairs = new ArrayList<>();
|
||||
MapleData itemsData;
|
||||
|
||||
itemsData = stringData.getData("Etc.img").getChildByPath("Etc");
|
||||
for (MapleData itemFolder : itemsData.getChildren()) {
|
||||
itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
|
||||
}
|
||||
return itemPairs;
|
||||
}
|
||||
|
||||
private MapleData getStringData(int itemId) {
|
||||
String cat = "null";
|
||||
MapleData theData;
|
||||
if (itemId >= 5010000) {
|
||||
theData = cashStringData;
|
||||
} else if (itemId >= 2000000 && itemId < 3000000) {
|
||||
theData = consumeStringData;
|
||||
} else if ((itemId >= 1010000 && itemId < 1040000) || (itemId >= 1122000 && itemId < 1123000) || (itemId >= 1132000 && itemId < 1133000) || (itemId >= 1142000 && itemId < 1143000)) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Accessory";
|
||||
} else if (itemId >= 1000000 && itemId < 1010000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Cap";
|
||||
} else if (itemId >= 1102000 && itemId < 1103000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Cape";
|
||||
} else if (itemId >= 1040000 && itemId < 1050000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Coat";
|
||||
} else if (itemId >= 20000 && itemId < 22000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Face";
|
||||
} else if (itemId >= 1080000 && itemId < 1090000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Glove";
|
||||
} else if (itemId >= 30000 && itemId < 35000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Hair";
|
||||
} else if (itemId >= 1050000 && itemId < 1060000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Longcoat";
|
||||
} else if (itemId >= 1060000 && itemId < 1070000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Pants";
|
||||
} else if (itemId >= 1802000 && itemId < 1842000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/PetEquip";
|
||||
} else if (itemId >= 1112000 && itemId < 1120000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Ring";
|
||||
} else if (itemId >= 1092000 && itemId < 1100000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Shield";
|
||||
} else if (itemId >= 1070000 && itemId < 1080000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Shoes";
|
||||
} else if (itemId >= 1900000 && itemId < 2000000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Taming";
|
||||
} else if (itemId >= 1300000 && itemId < 1800000) {
|
||||
theData = eqpStringData;
|
||||
cat = "Eqp/Weapon";
|
||||
} else if (itemId >= 4000000 && itemId < 5000000) {
|
||||
theData = etcStringData;
|
||||
cat = "Etc";
|
||||
} else if (itemId >= 3000000 && itemId < 4000000) {
|
||||
theData = insStringData;
|
||||
} else if (itemId / 1000 == 5000) {
|
||||
theData = petStringData;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (cat.equalsIgnoreCase("null")) {
|
||||
return theData.getChildByPath(String.valueOf(itemId));
|
||||
} else {
|
||||
return theData.getChildByPath(cat + "/" + itemId);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean noCancelMouse(int itemId) {
|
||||
if (noCancelMouseCache.containsKey(itemId)) {
|
||||
return noCancelMouseCache.get(itemId);
|
||||
}
|
||||
|
||||
MapleData item = getItemData(itemId);
|
||||
if (item == null) {
|
||||
noCancelMouseCache.put(itemId, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean blockMouse = MapleDataTool.getIntConvert("info/noCancelMouse", item, 0) == 1;
|
||||
noCancelMouseCache.put(itemId, blockMouse);
|
||||
return blockMouse;
|
||||
}
|
||||
|
||||
private MapleData getItemData(int itemId) {
|
||||
MapleData ret = null;
|
||||
String idStr = "0" + String.valueOf(itemId);
|
||||
MapleDataDirectoryEntry root = itemData.getRoot();
|
||||
for (MapleDataDirectoryEntry topDir : root.getSubdirectories()) {
|
||||
for (MapleDataFileEntry iFile : topDir.getFiles()) {
|
||||
if (iFile.getName().equals(idStr.substring(0, 4) + ".img")) {
|
||||
ret = itemData.getData(topDir.getName() + "/" + iFile.getName());
|
||||
if (ret == null) {
|
||||
return null;
|
||||
}
|
||||
ret = ret.getChildByPath(idStr);
|
||||
return ret;
|
||||
} else if (iFile.getName().equals(idStr.substring(1) + ".img")) {
|
||||
return itemData.getData(topDir.getName() + "/" + iFile.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
root = equipData.getRoot();
|
||||
for (MapleDataDirectoryEntry topDir : root.getSubdirectories()) {
|
||||
for (MapleDataFileEntry iFile : topDir.getFiles()) {
|
||||
if (iFile.getName().equals(idStr + ".img")) {
|
||||
return equipData.getData(topDir.getName() + "/" + iFile.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<Integer> getItemIdsInRange(int minId, int maxId, boolean ignoreCashItem) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
|
||||
if(ignoreCashItem) {
|
||||
for(int i = minId; i <= maxId; i++) {
|
||||
if(getItemData(i) != null && !isCash(i)) {
|
||||
list.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(int i = minId; i <= maxId; i++) {
|
||||
if(getItemData(i) != null) {
|
||||
list.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public short getSlotMax(int itemId) {
|
||||
Short slotMax = slotMaxCache.get(itemId);
|
||||
if (slotMax != null) {
|
||||
return (short)(slotMax);
|
||||
}
|
||||
short ret = 0;
|
||||
MapleData item = getItemData(itemId);
|
||||
if (item != null) {
|
||||
MapleData smEntry = item.getChildByPath("info/slotMax");
|
||||
if (smEntry == null) {
|
||||
ret = 100;
|
||||
} else {
|
||||
ret = (short) MapleDataTool.getInt(smEntry);
|
||||
}
|
||||
}
|
||||
|
||||
slotMaxCache.put(itemId, ret);
|
||||
return (short)(ret);
|
||||
}
|
||||
|
||||
public int getMeso(int itemId) {
|
||||
if (getMesoCache.containsKey(itemId)) {
|
||||
return getMesoCache.get(itemId);
|
||||
}
|
||||
MapleData item = getItemData(itemId);
|
||||
if (item == null) {
|
||||
return -1;
|
||||
}
|
||||
int pEntry;
|
||||
MapleData pData = item.getChildByPath("info/meso");
|
||||
if (pData == null) {
|
||||
return -1;
|
||||
}
|
||||
pEntry = MapleDataTool.getInt(pData);
|
||||
getMesoCache.put(itemId, pEntry);
|
||||
return pEntry;
|
||||
}
|
||||
|
||||
public int getWholePrice(int itemId) {
|
||||
if (wholePriceCache.containsKey(itemId)) {
|
||||
return wholePriceCache.get(itemId);
|
||||
}
|
||||
MapleData item = getItemData(itemId);
|
||||
if (item == null) {
|
||||
return -1;
|
||||
}
|
||||
int pEntry;
|
||||
MapleData pData = item.getChildByPath("info/price");
|
||||
if (pData == null) {
|
||||
return -1;
|
||||
}
|
||||
pEntry = MapleDataTool.getInt(pData);
|
||||
wholePriceCache.put(itemId, pEntry);
|
||||
return pEntry;
|
||||
}
|
||||
|
||||
public double getPrice(int itemId) {
|
||||
if (priceCache.containsKey(itemId)) {
|
||||
return priceCache.get(itemId);
|
||||
}
|
||||
MapleData item = getItemData(itemId);
|
||||
if (item == null) {
|
||||
return -1;
|
||||
}
|
||||
double pEntry;
|
||||
MapleData pData = item.getChildByPath("info/unitPrice");
|
||||
if (pData != null) {
|
||||
try {
|
||||
pEntry = MapleDataTool.getDouble(pData);
|
||||
} catch (Exception e) {
|
||||
pEntry = (double) MapleDataTool.getInt(pData);
|
||||
}
|
||||
} else {
|
||||
pData = item.getChildByPath("info/price");
|
||||
if (pData == null) {
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
pEntry = (double) MapleDataTool.getInt(pData);
|
||||
} catch(Exception e) {
|
||||
priceCache.put(itemId, 0.0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
priceCache.put(itemId, pEntry);
|
||||
return pEntry;
|
||||
}
|
||||
|
||||
protected String getEquipmentSlot(int itemId) {
|
||||
if (equipmentSlotCache.containsKey(itemId)) {
|
||||
return equipmentSlotCache.get(itemId);
|
||||
}
|
||||
|
||||
String ret = "";
|
||||
|
||||
MapleData item = getItemData(itemId);
|
||||
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MapleData info = item.getChildByPath("info");
|
||||
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ret = MapleDataTool.getString("islot", info, "");
|
||||
|
||||
equipmentSlotCache.put(itemId, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Map<String, Integer> getEquipStats(int itemId) {
|
||||
if (equipStatsCache.containsKey(itemId)) {
|
||||
return equipStatsCache.get(itemId);
|
||||
}
|
||||
Map<String, Integer> ret = new LinkedHashMap<>();
|
||||
MapleData item = getItemData(itemId);
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
MapleData info = item.getChildByPath("info");
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
for (MapleData data : info.getChildren()) {
|
||||
if (data.getName().startsWith("inc")) {
|
||||
ret.put(data.getName().substring(3), MapleDataTool.getIntConvert(data));
|
||||
}
|
||||
/*else if (data.getName().startsWith("req"))
|
||||
ret.put(data.getName(), MapleDataTool.getInt(data.getName(), info, 0));*/
|
||||
}
|
||||
ret.put("reqJob", MapleDataTool.getInt("reqJob", info, 0));
|
||||
ret.put("reqLevel", MapleDataTool.getInt("reqLevel", info, 0));
|
||||
ret.put("reqDEX", MapleDataTool.getInt("reqDEX", info, 0));
|
||||
ret.put("reqSTR", MapleDataTool.getInt("reqSTR", info, 0));
|
||||
ret.put("reqINT", MapleDataTool.getInt("reqINT", info, 0));
|
||||
ret.put("reqLUK", MapleDataTool.getInt("reqLUK", info, 0));
|
||||
ret.put("reqPOP", MapleDataTool.getInt("reqPOP", info, 0));
|
||||
ret.put("cash", MapleDataTool.getInt("cash", info, 0));
|
||||
ret.put("tuc", MapleDataTool.getInt("tuc", info, 0));
|
||||
ret.put("cursed", MapleDataTool.getInt("cursed", info, 0));
|
||||
ret.put("success", MapleDataTool.getInt("success", info, 0));
|
||||
ret.put("fs", MapleDataTool.getInt("fs", info, 0));
|
||||
equipStatsCache.put(itemId, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<Integer> getScrollReqs(int itemId) {
|
||||
List<Integer> ret = new ArrayList<>();
|
||||
MapleData data = getItemData(itemId);
|
||||
data = data.getChildByPath("req");
|
||||
if (data == null) {
|
||||
return ret;
|
||||
}
|
||||
for (MapleData req : data.getChildren()) {
|
||||
ret.add(MapleDataTool.getInt(req));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String getName(int itemId) {
|
||||
if (nameCache.containsKey(itemId)) {
|
||||
return nameCache.get(itemId);
|
||||
}
|
||||
MapleData strings = getStringData(itemId);
|
||||
if (strings == null) {
|
||||
return null;
|
||||
}
|
||||
String ret = MapleDataTool.getString("name", strings, null);
|
||||
nameCache.put(itemId, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String getMsg(int itemId) {
|
||||
if (msgCache.containsKey(itemId)) {
|
||||
return msgCache.get(itemId);
|
||||
}
|
||||
MapleData strings = getStringData(itemId);
|
||||
if (strings == null) {
|
||||
return null;
|
||||
}
|
||||
String ret = MapleDataTool.getString("msg", strings, null);
|
||||
msgCache.put(itemId, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean isDropRestricted(int itemId) {
|
||||
if (dropRestrictionCache.containsKey(itemId)) {
|
||||
return dropRestrictionCache.get(itemId);
|
||||
}
|
||||
MapleData data = getItemData(itemId);
|
||||
boolean bRestricted = MapleDataTool.getIntConvert("info/tradeBlock", data, 0) == 1;
|
||||
if (!bRestricted) {
|
||||
bRestricted = MapleDataTool.getIntConvert("info/accountSharable", data, 0) == 1;
|
||||
}
|
||||
if (!bRestricted) {
|
||||
bRestricted = MapleDataTool.getIntConvert("info/quest", data, 0) == 1;
|
||||
}
|
||||
dropRestrictionCache.put(itemId, bRestricted);
|
||||
return bRestricted;
|
||||
}
|
||||
|
||||
public boolean isPickupRestricted(int itemId) {
|
||||
if (pickupRestrictionCache.containsKey(itemId)) {
|
||||
return pickupRestrictionCache.get(itemId);
|
||||
}
|
||||
MapleData data = getItemData(itemId);
|
||||
boolean bRestricted = MapleDataTool.getIntConvert("info/only", data, 0) == 1;
|
||||
pickupRestrictionCache.put(itemId, bRestricted);
|
||||
return bRestricted;
|
||||
}
|
||||
|
||||
public Map<String, Integer> getSkillStats(int itemId, double playerJob) {
|
||||
Map<String, Integer> ret = new LinkedHashMap<>();
|
||||
MapleData item = getItemData(itemId);
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
MapleData info = item.getChildByPath("info");
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
for (MapleData data : info.getChildren()) {
|
||||
if (data.getName().startsWith("inc")) {
|
||||
ret.put(data.getName().substring(3), MapleDataTool.getIntConvert(data));
|
||||
}
|
||||
}
|
||||
ret.put("masterLevel", MapleDataTool.getInt("masterLevel", info, 0));
|
||||
ret.put("reqSkillLevel", MapleDataTool.getInt("reqSkillLevel", info, 0));
|
||||
ret.put("success", MapleDataTool.getInt("success", info, 0));
|
||||
MapleData skill = info.getChildByPath("skill");
|
||||
int curskill;
|
||||
for (int i = 0; i < skill.getChildren().size(); i++) {
|
||||
curskill = MapleDataTool.getInt(Integer.toString(i), skill, 0);
|
||||
if (curskill == 0) {
|
||||
break;
|
||||
}
|
||||
if (curskill / 10000 == playerJob) {
|
||||
ret.put("skillid", curskill);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret.get("skillid") == null) {
|
||||
ret.put("skillid", 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<Integer> petsCanConsume(int itemId) {
|
||||
List<Integer> ret = new ArrayList<>();
|
||||
MapleData data = getItemData(itemId);
|
||||
int curPetId;
|
||||
for (int i = 0; i < data.getChildren().size(); i++) {
|
||||
curPetId = MapleDataTool.getInt("spec/" + Integer.toString(i), data, 0);
|
||||
if (curPetId == 0) {
|
||||
break;
|
||||
}
|
||||
ret.add(Integer.valueOf(curPetId));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean isQuestItem(int itemId) {
|
||||
if (isQuestItemCache.containsKey(itemId)) {
|
||||
return isQuestItemCache.get(itemId);
|
||||
}
|
||||
MapleData data = getItemData(itemId);
|
||||
boolean questItem = MapleDataTool.getIntConvert("info/quest", data, 0) == 1;
|
||||
isQuestItemCache.put(itemId, questItem);
|
||||
return questItem;
|
||||
}
|
||||
|
||||
public int getQuestIdFromItem(int itemId) {
|
||||
MapleData data = getItemData(itemId);
|
||||
int questItem = MapleDataTool.getIntConvert("info/quest", data, 0);
|
||||
return questItem;
|
||||
}
|
||||
|
||||
public boolean isUntradeableOnEquip(int itemId) {
|
||||
if (onEquipUntradableCache.containsKey(itemId)) {
|
||||
return onEquipUntradableCache.get(itemId);
|
||||
}
|
||||
boolean untradableOnEquip = MapleDataTool.getIntConvert("info/equipTradeBlock", getItemData(itemId), 0) > 0;
|
||||
onEquipUntradableCache.put(itemId, untradableOnEquip);
|
||||
return untradableOnEquip;
|
||||
}
|
||||
|
||||
public boolean isKarmaAble(int itemId) {
|
||||
if (karmaCache.containsKey(itemId)) {
|
||||
return karmaCache.get(itemId);
|
||||
}
|
||||
boolean bRestricted = MapleDataTool.getIntConvert("info/tradeAvailable", getItemData(itemId), 0) > 0;
|
||||
karmaCache.put(itemId, bRestricted);
|
||||
return bRestricted;
|
||||
}
|
||||
|
||||
public int getStateChangeItem(int itemId) {
|
||||
if (triggerItemCache.containsKey(itemId)) {
|
||||
return triggerItemCache.get(itemId);
|
||||
} else {
|
||||
int triggerItem = MapleDataTool.getIntConvert("info/stateChangeItem", getItemData(itemId), 0);
|
||||
triggerItemCache.put(itemId, triggerItem);
|
||||
return triggerItem;
|
||||
}
|
||||
}
|
||||
|
||||
public int getExpById(int itemId) {
|
||||
if (expCache.containsKey(itemId)) {
|
||||
return expCache.get(itemId);
|
||||
} else {
|
||||
int exp = MapleDataTool.getIntConvert("spec/exp", getItemData(itemId), 0);
|
||||
expCache.put(itemId, exp);
|
||||
return exp;
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxLevelById(int itemId) {
|
||||
if (levelCache.containsKey(itemId)) {
|
||||
return levelCache.get(itemId);
|
||||
} else {
|
||||
int level = MapleDataTool.getIntConvert("info/maxLevel", getItemData(itemId), 256);
|
||||
levelCache.put(itemId, level);
|
||||
return level;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConsumeOnPickup(int itemId) {
|
||||
if (consumeOnPickupCache.containsKey(itemId)) {
|
||||
return consumeOnPickupCache.get(itemId);
|
||||
}
|
||||
MapleData data = getItemData(itemId);
|
||||
boolean consume = MapleDataTool.getIntConvert("spec/consumeOnPickup", data, 0) == 1 || MapleDataTool.getIntConvert("specEx/consumeOnPickup", data, 0) == 1;
|
||||
consumeOnPickupCache.put(itemId, consume);
|
||||
return consume;
|
||||
}
|
||||
|
||||
public boolean isCash(int itemId) {
|
||||
return itemId / 1000000 == 5 || getEquipStats(itemId).get("cash") == 1;
|
||||
}
|
||||
|
||||
public ArrayList<Pair<Integer, String>> getItemDataByName(String name)
|
||||
{
|
||||
ArrayList<Pair<Integer, String>> ret = new ArrayList<>();
|
||||
for (Pair<Integer, String> itemPair : MapleItemInformationProvider.getInstance().getAllItems()) {
|
||||
if (itemPair.getRight().toLowerCase().contains(name.toLowerCase())) {
|
||||
ret.add(itemPair);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
121
tools/MapleCashCosmeticsFetcher/src/tools/Pair.java
Normal file
121
tools/MapleCashCosmeticsFetcher/src/tools/Pair.java
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 ~ 2010 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License version 3
|
||||
as published by the Free Software Foundation. You may not use, modify
|
||||
or distribute this program under any other version of the
|
||||
GNU Affero General Public License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools;
|
||||
|
||||
/**
|
||||
* Represents a pair of values.
|
||||
*
|
||||
* @author Frz
|
||||
* @since Revision 333
|
||||
* @version 1.0
|
||||
*
|
||||
* @param <E> The type of the left value.
|
||||
* @param <F> The type of the right value.
|
||||
*/
|
||||
public class Pair<E, F> {
|
||||
|
||||
public E left;
|
||||
public F right;
|
||||
|
||||
/**
|
||||
* Class constructor - pairs two objects together.
|
||||
*
|
||||
* @param left The left object.
|
||||
* @param right The right object.
|
||||
*/
|
||||
public Pair(E left, F right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the left value.
|
||||
*
|
||||
* @return The left value.
|
||||
*/
|
||||
public E getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the right value.
|
||||
*
|
||||
* @return The right value.
|
||||
*/
|
||||
public F getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the pair into a string.
|
||||
*
|
||||
* @return Each value of the pair as a string joined by a colon.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return left.toString() + ":" + right.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hash code of this pair.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((left == null) ? 0 : left.hashCode());
|
||||
result = prime * result + ((right == null) ? 0 : right.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if two pairs are equal.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Pair other = (Pair) obj;
|
||||
if (left == null) {
|
||||
if (other.left != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!left.equals(other.left)) {
|
||||
return false;
|
||||
}
|
||||
if (right == null) {
|
||||
if (other.right != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!right.equals(other.right)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
128
tools/MapleCashCosmeticsFetcher/src/tools/StringUtil.java
Normal file
128
tools/MapleCashCosmeticsFetcher/src/tools/StringUtil.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools;
|
||||
|
||||
public class StringUtil {
|
||||
/**
|
||||
* Gets a string padded from the left to <code>length</code> by
|
||||
* <code>padchar</code>.
|
||||
*
|
||||
* @param in The input string to be padded.
|
||||
* @param padchar The character to pad with.
|
||||
* @param length The length to pad to.
|
||||
* @return The padded string.
|
||||
*/
|
||||
public static String getLeftPaddedStr(String in, char padchar, int length) {
|
||||
StringBuilder builder = new StringBuilder(length);
|
||||
for (int x = in.length(); x < length; x++) {
|
||||
builder.append(padchar);
|
||||
}
|
||||
builder.append(in);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string padded from the right to <code>length</code> by
|
||||
* <code>padchar</code>.
|
||||
*
|
||||
* @param in The input string to be padded.
|
||||
* @param padchar The character to pad with.
|
||||
* @param length The length to pad to.
|
||||
* @return The padded string.
|
||||
*/
|
||||
public static String getRightPaddedStr(String in, char padchar, int length) {
|
||||
StringBuilder builder = new StringBuilder(in);
|
||||
for (int x = in.length(); x < length; x++) {
|
||||
builder.append(padchar);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins an array of strings starting from string <code>start</code> with
|
||||
* a space.
|
||||
*
|
||||
* @param arr The array of strings to join.
|
||||
* @param start Starting from which string.
|
||||
* @return The joined strings.
|
||||
*/
|
||||
public static String joinStringFrom(String arr[], int start) {
|
||||
return joinStringFrom(arr, start, " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins an array of strings starting from string <code>start</code> with
|
||||
* <code>sep</code> as a seperator.
|
||||
*
|
||||
* @param arr The array of strings to join.
|
||||
* @param start Starting from which string.
|
||||
* @return The joined strings.
|
||||
*/
|
||||
public static String joinStringFrom(String arr[], int start, String sep) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = start; i < arr.length; i++) {
|
||||
builder.append(arr[i]);
|
||||
if (i != arr.length - 1) {
|
||||
builder.append(sep);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an enum name human readable (fixes spaces, capitalization, etc)
|
||||
*
|
||||
* @param enumName The name of the enum to neaten up.
|
||||
* @return The human-readable enum name.
|
||||
*/
|
||||
public static String makeEnumHumanReadable(String enumName) {
|
||||
StringBuilder builder = new StringBuilder(enumName.length() + 1);
|
||||
String[] words = enumName.split("_");
|
||||
for (String word : words) {
|
||||
if (word.length() <= 2) {
|
||||
builder.append(word); // assume that it's an abbrevation
|
||||
} else {
|
||||
builder.append(word.charAt(0));
|
||||
builder.append(word.substring(1).toLowerCase());
|
||||
}
|
||||
builder.append(' ');
|
||||
}
|
||||
return builder.substring(0, enumName.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of <code>chr</code>'s in <code>str</code>.
|
||||
*
|
||||
* @param str The string to check for instances of <code>chr</code>.
|
||||
* @param chr The character to check for.
|
||||
* @return The number of times <code>chr</code> occurs in <code>str</code>.
|
||||
*/
|
||||
public static int countCharacters(String str, char chr) {
|
||||
int ret = 0;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
if (str.charAt(i) == chr) {
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.input;
|
||||
|
||||
import java.io.IOException;
|
||||
import tools.HexTool;
|
||||
|
||||
public class ByteArrayByteStream implements SeekableInputStreamBytestream {
|
||||
private int pos = 0;
|
||||
private long bytesRead = 0;
|
||||
private byte[] arr;
|
||||
|
||||
public ByteArrayByteStream(byte[] arr) {
|
||||
this.arr = arr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPosition() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(long offset) throws IOException {
|
||||
pos = (int) offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBytesRead() {
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readByte() {
|
||||
bytesRead++;
|
||||
return ((int) arr[pos++]) & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String nows = "kevintjuh93 pwns";//I lol'd
|
||||
if (arr.length - pos > 0) {
|
||||
byte[] now = new byte[arr.length - pos];
|
||||
System.arraycopy(arr, pos, now, 0, arr.length - pos);
|
||||
nows = HexTool.toString(now);
|
||||
}
|
||||
return "All: " + HexTool.toString(arr) + "\nNow: " + nows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long available() {
|
||||
return arr.length - pos;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.input;
|
||||
|
||||
/**
|
||||
* Represents an abstract stream of bytes.
|
||||
*
|
||||
* @author Frz
|
||||
* @version 1.0
|
||||
* @since Revision 323
|
||||
*/
|
||||
public interface ByteInputStream {
|
||||
int readByte();
|
||||
long getBytesRead();
|
||||
long available();
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.input;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* Provides a generic interface to a Little Endian stream of bytes.
|
||||
*
|
||||
* @version 1.0
|
||||
* @author Frz
|
||||
* @since Revision 323
|
||||
*/
|
||||
public class GenericLittleEndianAccessor implements LittleEndianAccessor {
|
||||
private ByteInputStream bs;
|
||||
|
||||
/**
|
||||
* Class constructor - Wraps the accessor around a stream of bytes.
|
||||
*
|
||||
* @param bs The byte stream to wrap the accessor around.
|
||||
*/
|
||||
public GenericLittleEndianAccessor(ByteInputStream bs) {
|
||||
this.bs = bs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a single byte from the stream.
|
||||
*
|
||||
* @return The byte read.
|
||||
* @see tools.data.input.ByteInputStream#readByte
|
||||
*/
|
||||
@Override
|
||||
public byte readByte() {
|
||||
return (byte) bs.readByte();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an integer from the stream.
|
||||
*
|
||||
* @return The integer read.
|
||||
*/
|
||||
@Override
|
||||
public int readInt() {
|
||||
return bs.readByte() + (bs.readByte() << 8) + (bs.readByte() << 16) + (bs.readByte() << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a short integer from the stream.
|
||||
*
|
||||
* @return The short read.
|
||||
*/
|
||||
@Override
|
||||
public short readShort() {
|
||||
return (short) (bs.readByte() + (bs.readByte() << 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single character from the stream.
|
||||
*
|
||||
* @return The character read.
|
||||
*/
|
||||
@Override
|
||||
public char readChar() {
|
||||
return (char) readShort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a long integer from the stream.
|
||||
*
|
||||
* @return The long integer read.
|
||||
*/
|
||||
@Override
|
||||
public long readLong() {
|
||||
long byte1 = bs.readByte();
|
||||
long byte2 = bs.readByte();
|
||||
long byte3 = bs.readByte();
|
||||
long byte4 = bs.readByte();
|
||||
long byte5 = bs.readByte();
|
||||
long byte6 = bs.readByte();
|
||||
long byte7 = bs.readByte();
|
||||
long byte8 = bs.readByte();
|
||||
return (byte8 << 56) + (byte7 << 48) + (byte6 << 40) + (byte5 << 32) + (byte4 << 24) + (byte3 << 16) + (byte2 << 8) + byte1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a floating point integer from the stream.
|
||||
*
|
||||
* @return The float-type integer read.
|
||||
*/
|
||||
@Override
|
||||
public float readFloat() {
|
||||
return Float.intBitsToFloat(readInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a double-precision integer from the stream.
|
||||
*
|
||||
* @return The double-type integer read.
|
||||
*/
|
||||
@Override
|
||||
public double readDouble() {
|
||||
return Double.longBitsToDouble(readLong());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an ASCII string from the stream with length <code>n</code>.
|
||||
*
|
||||
* @param n Number of characters to read.
|
||||
* @return The string read.
|
||||
*/
|
||||
public final String readAsciiString(int n) {
|
||||
char ret[] = new char[n];
|
||||
for (int x = 0; x < n; x++) {
|
||||
ret[x] = (char) readByte();
|
||||
}
|
||||
return String.valueOf(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a null-terminated string from the stream.
|
||||
*
|
||||
* @return The string read.
|
||||
*/
|
||||
public final String readNullTerminatedAsciiString() {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte b;
|
||||
while (true) {
|
||||
b = readByte();
|
||||
if (b == 0) {
|
||||
break;
|
||||
}
|
||||
baos.write(b);
|
||||
}
|
||||
byte[] buf = baos.toByteArray();
|
||||
char[] chrBuf = new char[buf.length];
|
||||
for (int x = 0; x < buf.length; x++) {
|
||||
chrBuf[x] = (char) buf[x];
|
||||
}
|
||||
return String.valueOf(chrBuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of bytes read from the stream so far.
|
||||
*
|
||||
* @return A long integer representing the number of bytes read.
|
||||
* @see tools.data.input.ByteInputStream#getBytesRead()
|
||||
*/
|
||||
public long getBytesRead() {
|
||||
return bs.getBytesRead();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a MapleStory convention lengthed ASCII string.
|
||||
* This consists of a short integer telling the length of the string,
|
||||
* then the string itself.
|
||||
*
|
||||
* @return The string read.
|
||||
*/
|
||||
@Override
|
||||
public String readMapleAsciiString() {
|
||||
return readAsciiString(readShort());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads <code>num</code> bytes off the stream.
|
||||
*
|
||||
* @param num The number of bytes to read.
|
||||
* @return An array of bytes with the length of <code>num</code>
|
||||
*/
|
||||
@Override
|
||||
public byte[] read(int num) {
|
||||
byte[] ret = new byte[num];
|
||||
for (int x = 0; x < num; x++) {
|
||||
ret[x] = readByte();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a MapleStory Position information.
|
||||
* This consists of 2 short integer.
|
||||
*
|
||||
* @return The Position read.
|
||||
*/
|
||||
@Override
|
||||
public final Point readPos() {
|
||||
final int x = readShort();
|
||||
final int y = readShort();
|
||||
return new Point(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips the current position of the stream <code>num</code> bytes ahead.
|
||||
*
|
||||
* @param num Number of bytes to skip.
|
||||
*/
|
||||
@Override
|
||||
public void skip(int num) {
|
||||
for (int x = 0; x < num; x++) {
|
||||
readByte();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see tools.data.input.ByteInputStream#available
|
||||
*/
|
||||
@Override
|
||||
public long available() {
|
||||
return bs.available();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return bs.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.input;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Provides an abstract accessor to a generic Little Endian byte stream. This
|
||||
* accessor is seekable.
|
||||
*
|
||||
* @author Frz
|
||||
* @version 1.0
|
||||
* @since Revision 323
|
||||
* @see tools.data.input.GenericLittleEndianAccessor
|
||||
*/
|
||||
public class GenericSeekableLittleEndianAccessor extends GenericLittleEndianAccessor implements SeekableLittleEndianAccessor {
|
||||
private SeekableInputStreamBytestream bs;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
* Provide a seekable input stream to wrap this object around.
|
||||
*
|
||||
* @param bs The byte stream to wrap this around.
|
||||
*/
|
||||
public GenericSeekableLittleEndianAccessor(SeekableInputStreamBytestream bs) {
|
||||
super(bs);
|
||||
this.bs = bs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek the pointer to <code>offset</code>
|
||||
*
|
||||
* @param offset The offset to seek to.
|
||||
* @see tools.data.input.SeekableInputStreamBytestream#seek
|
||||
*/
|
||||
@Override
|
||||
public void seek(long offset) {
|
||||
try {
|
||||
bs.seek(offset);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Seek failed " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current position of the pointer.
|
||||
*
|
||||
* @return The current position of the pointer as a long integer.
|
||||
* @see tools.data.input.SeekableInputStreamBytestream#getPosition
|
||||
*/
|
||||
@Override
|
||||
public long getPosition() {
|
||||
try {
|
||||
return bs.getPosition();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("getPosition failed" + e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip <code>num</code> number of bytes in the stream.
|
||||
*
|
||||
* @param num The number of bytes to skip.
|
||||
*/
|
||||
@Override
|
||||
public void skip(int num) {
|
||||
seek(getPosition() + num);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.input;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Provides an abstract wrapper to a stream of bytes.
|
||||
*
|
||||
* @author Frz
|
||||
* @version 1.0
|
||||
* @since Revision 323
|
||||
*/
|
||||
public class InputStreamByteStream implements ByteInputStream {
|
||||
private InputStream is;
|
||||
private long read = 0;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
* Provide an input stream to wrap this around.
|
||||
*
|
||||
* @param is The input stream to wrap this object around.
|
||||
*/
|
||||
public InputStreamByteStream(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next byte from the stream.
|
||||
*
|
||||
* @return Then next byte in the stream.
|
||||
*/
|
||||
@Override
|
||||
public int readByte() {
|
||||
int temp;
|
||||
try {
|
||||
temp = is.read();
|
||||
if (temp == -1) {
|
||||
throw new RuntimeException("EOF");
|
||||
}
|
||||
read++;
|
||||
return temp;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of bytes read from the stream.
|
||||
*
|
||||
* @return The number of bytes read as a long integer.
|
||||
*/
|
||||
@Override
|
||||
public long getBytesRead() {
|
||||
return read;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes left in the stream.
|
||||
*
|
||||
* @return The number of bytes available for reading as a long integer.
|
||||
*/
|
||||
@Override
|
||||
public long available() {
|
||||
try {
|
||||
return is.available();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("ERROR" + e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.input;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
/**
|
||||
* @author Frz
|
||||
*/
|
||||
public interface LittleEndianAccessor {
|
||||
byte readByte();
|
||||
char readChar();
|
||||
short readShort();
|
||||
int readInt();
|
||||
Point readPos();
|
||||
long readLong();
|
||||
void skip(int num);
|
||||
byte[] read(int num);
|
||||
float readFloat();
|
||||
double readDouble();
|
||||
String readAsciiString(int n);
|
||||
String readNullTerminatedAsciiString();
|
||||
String readMapleAsciiString();
|
||||
long getBytesRead();
|
||||
long available();
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.input;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
/**
|
||||
* Provides an abstract layer to a byte stream. This layer can be accessed
|
||||
* randomly.
|
||||
*
|
||||
* @author Frz
|
||||
* @version 1.0
|
||||
* @since Revision 323
|
||||
*/
|
||||
public class RandomAccessByteStream implements SeekableInputStreamBytestream {
|
||||
private RandomAccessFile raf;
|
||||
private long read = 0;
|
||||
|
||||
public RandomAccessByteStream(RandomAccessFile raf) {
|
||||
super();
|
||||
this.raf = raf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readByte() {
|
||||
int temp;
|
||||
try {
|
||||
temp = raf.read();
|
||||
if (temp == -1) {
|
||||
throw new RuntimeException("EOF");
|
||||
}
|
||||
read++;
|
||||
return temp;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(long offset) throws IOException {
|
||||
raf.seek(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPosition() throws IOException {
|
||||
return raf.getFilePointer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBytesRead() {
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long available() {
|
||||
try {
|
||||
return raf.length() - raf.getFilePointer();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("ERROR " + e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.input;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Provides an abstract interface to a stream of bytes. This stream can be
|
||||
* seeked.
|
||||
*
|
||||
* @author Frz
|
||||
* @version 1.0
|
||||
* @since 299
|
||||
*/
|
||||
public interface SeekableInputStreamBytestream extends ByteInputStream {
|
||||
/**
|
||||
* Seeks the stream by the specified offset.
|
||||
*
|
||||
* @param offset
|
||||
* Number of bytes to seek.
|
||||
* @throws IOException
|
||||
*/
|
||||
void seek(long offset) throws IOException;
|
||||
|
||||
/**
|
||||
* Gets the current position of the stream.
|
||||
*
|
||||
* @return The stream position as a long integer.
|
||||
* @throws IOException
|
||||
*/
|
||||
long getPosition() throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.input;
|
||||
|
||||
public interface SeekableLittleEndianAccessor extends LittleEndianAccessor {
|
||||
void seek(long offset);
|
||||
long getPosition();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.output;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* Uses a byte array to output a stream of bytes.
|
||||
*
|
||||
* @author Frz
|
||||
* @version 1.0
|
||||
* @since Revision 352
|
||||
*/
|
||||
class BAOSByteOutputStream implements ByteOutputStream {
|
||||
private ByteArrayOutputStream baos;
|
||||
|
||||
/**
|
||||
* Class constructor - Wraps the stream around a Java BAOS.
|
||||
*
|
||||
* @param baos <code>The ByteArrayOutputStream</code> to wrap this around.
|
||||
*/
|
||||
BAOSByteOutputStream(ByteArrayOutputStream baos) {
|
||||
super();
|
||||
this.baos = baos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte to the stream.
|
||||
*
|
||||
* @param b The byte to write to the stream.
|
||||
* @see tools.data.output.ByteOutputStream#writeByte(byte)
|
||||
*/
|
||||
@Override
|
||||
public void writeByte(byte b) {
|
||||
baos.write(b);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.output;
|
||||
|
||||
/**
|
||||
* Provides an interface to an output stream of bytes.
|
||||
*
|
||||
* @author Frz
|
||||
* @since Revision 323
|
||||
* @version 1.0
|
||||
*/
|
||||
interface ByteOutputStream {
|
||||
/**
|
||||
* Writes a byte to the stream.
|
||||
*
|
||||
* @param b The byte to write.
|
||||
*/
|
||||
void writeByte(byte b);
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.output;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Provides a generic writer of a little-endian sequence of bytes.
|
||||
*
|
||||
* @author Frz
|
||||
* @version 1.0
|
||||
* @since Revision 323
|
||||
*/
|
||||
public class GenericLittleEndianWriter implements LittleEndianWriter {
|
||||
private static Charset ASCII = Charset.forName("US-ASCII");
|
||||
private ByteOutputStream bos;
|
||||
|
||||
/**
|
||||
* Class constructor - Protected to prevent instantiation with no arguments.
|
||||
*/
|
||||
protected GenericLittleEndianWriter() {
|
||||
// Blah!
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the byte-output stream for this instance of the object.
|
||||
*
|
||||
* @param bos The new output stream to set.
|
||||
*/
|
||||
void setByteOutputStream(ByteOutputStream bos) {
|
||||
this.bos = bos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an array of bytes to the stream.
|
||||
*
|
||||
* @param b The bytes to write.
|
||||
*/
|
||||
@Override
|
||||
public void write(byte[] b) {
|
||||
for (int x = 0; x < b.length; x++) {
|
||||
bos.writeByte(b[x]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a byte to the stream.
|
||||
*
|
||||
* @param b The byte to write.
|
||||
*/
|
||||
@Override
|
||||
public void write(byte b) {
|
||||
bos.writeByte(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a byte in integer form to the stream.
|
||||
*
|
||||
* @param b The byte as an <code>Integer</code> to write.
|
||||
*/
|
||||
@Override
|
||||
public void write(int b) {
|
||||
bos.writeByte((byte) b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skip(int b) {
|
||||
write(new byte[b]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a short integer to the stream.
|
||||
*
|
||||
* @param i The short integer to write.
|
||||
*/
|
||||
@Override
|
||||
public void writeShort(int i) {
|
||||
bos.writeByte((byte) (i & 0xFF));
|
||||
bos.writeByte((byte) ((i >>> 8) & 0xFF));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an integer to the stream.
|
||||
*
|
||||
* @param i The integer to write.
|
||||
*/
|
||||
@Override
|
||||
public void writeInt(int i) {
|
||||
bos.writeByte((byte) (i & 0xFF));
|
||||
bos.writeByte((byte) ((i >>> 8) & 0xFF));
|
||||
bos.writeByte((byte) ((i >>> 16) & 0xFF));
|
||||
bos.writeByte((byte) ((i >>> 24) & 0xFF));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an ASCII string the the stream.
|
||||
*
|
||||
* @param s The ASCII string to write.
|
||||
*/
|
||||
@Override
|
||||
public void writeAsciiString(String s) {
|
||||
write(s.getBytes(ASCII));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a maple-convention ASCII string to the stream.
|
||||
*
|
||||
* @param s The ASCII string to use maple-convention to write.
|
||||
*/
|
||||
@Override
|
||||
public void writeMapleAsciiString(String s) {
|
||||
writeShort((short) s.length());
|
||||
writeAsciiString(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a null-terminated ASCII string to the stream.
|
||||
*
|
||||
* @param s The ASCII string to write.
|
||||
*/
|
||||
@Override
|
||||
public void writeNullTerminatedAsciiString(String s) {
|
||||
writeAsciiString(s);
|
||||
write(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a long integer to the stream.
|
||||
* @param l The long integer to write.
|
||||
*/
|
||||
@Override
|
||||
public void writeLong(long l) {
|
||||
bos.writeByte((byte) (l & 0xFF));
|
||||
bos.writeByte((byte) ((l >>> 8) & 0xFF));
|
||||
bos.writeByte((byte) ((l >>> 16) & 0xFF));
|
||||
bos.writeByte((byte) ((l >>> 24) & 0xFF));
|
||||
bos.writeByte((byte) ((l >>> 32) & 0xFF));
|
||||
bos.writeByte((byte) ((l >>> 40) & 0xFF));
|
||||
bos.writeByte((byte) ((l >>> 48) & 0xFF));
|
||||
bos.writeByte((byte) ((l >>> 56) & 0xFF));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a 2D 4 byte position information
|
||||
*
|
||||
* @param s The Point position to write.
|
||||
*/
|
||||
@Override
|
||||
public void writePos(Point s) {
|
||||
writeShort(s.x);
|
||||
writeShort(s.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a boolean true ? 1 : 0
|
||||
*
|
||||
* @param b The boolean to write.
|
||||
*/
|
||||
@Override
|
||||
public void writeBool(final boolean b) {
|
||||
write(b ? 1 : 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.output;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
/**
|
||||
* Provides an interface to a writer class that writes a little-endian sequence
|
||||
* of bytes.
|
||||
*
|
||||
* @author Frz
|
||||
* @version 1.0
|
||||
* @since Revision 323
|
||||
*/
|
||||
public interface LittleEndianWriter {
|
||||
|
||||
/**
|
||||
* Write an array of bytes to the sequence.
|
||||
*
|
||||
* @param b The bytes to write.
|
||||
*/
|
||||
public void write(byte b[]);
|
||||
|
||||
/**
|
||||
* Write a byte to the sequence.
|
||||
*
|
||||
* @param b The byte to write.
|
||||
*/
|
||||
public void write(byte b);
|
||||
|
||||
/**
|
||||
* Write a byte in integer form to the sequence.
|
||||
*
|
||||
* @param b The byte as an <code>Integer</code> to write.
|
||||
*/
|
||||
public void write(int b);
|
||||
|
||||
public void skip(int b);
|
||||
|
||||
/**
|
||||
* Writes an integer to the sequence.
|
||||
*
|
||||
* @param i The integer to write.
|
||||
*/
|
||||
public void writeInt(int i);
|
||||
|
||||
/**
|
||||
* Write a short integer to the sequence.
|
||||
*
|
||||
* @param s The short integer to write.
|
||||
*/
|
||||
public void writeShort(int s);
|
||||
|
||||
/**
|
||||
* Write a long integer to the sequence.
|
||||
*
|
||||
* @param l The long integer to write.
|
||||
*/
|
||||
public void writeLong(long l);
|
||||
|
||||
/**
|
||||
* Writes an ASCII string the the sequence.
|
||||
*
|
||||
* @param s The ASCII string to write.
|
||||
*/
|
||||
void writeAsciiString(String s);
|
||||
|
||||
/**
|
||||
* Writes a null-terminated ASCII string to the sequence.
|
||||
*
|
||||
* @param s The ASCII string to write.
|
||||
*/
|
||||
void writeNullTerminatedAsciiString(String s);
|
||||
|
||||
/**
|
||||
* Writes a maple-convention ASCII string to the sequence.
|
||||
*
|
||||
* @param s The ASCII string to use maple-convention to write.
|
||||
*/
|
||||
void writeMapleAsciiString(String s);
|
||||
|
||||
/**
|
||||
* Writes a 2D 4 byte position information
|
||||
*
|
||||
* @param s The Point position to write.
|
||||
*/
|
||||
void writePos(Point s);
|
||||
|
||||
/**
|
||||
* Writes a boolean true ? 1 : 0
|
||||
*
|
||||
* @param b The boolean to write.
|
||||
*/
|
||||
void writeBool(final boolean b);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package tools.data.output;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import tools.HexTool;
|
||||
|
||||
/**
|
||||
* Writes a maplestory-packet little-endian stream of bytes.
|
||||
*
|
||||
* @author Frz
|
||||
* @version 1.0
|
||||
* @since Revision 352
|
||||
*/
|
||||
public class MaplePacketLittleEndianWriter extends GenericLittleEndianWriter {
|
||||
private ByteArrayOutputStream baos;
|
||||
|
||||
/**
|
||||
* Constructor - initializes this stream with a default size.
|
||||
*/
|
||||
public MaplePacketLittleEndianWriter() {
|
||||
this(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor - initializes this stream with size <code>size</code>.
|
||||
*
|
||||
* @param size The size of the underlying stream.
|
||||
*/
|
||||
public MaplePacketLittleEndianWriter(int size) {
|
||||
this.baos = new ByteArrayOutputStream(size);
|
||||
setByteOutputStream(new BAOSByteOutputStream(baos));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a <code>MaplePacket</code> instance representing this
|
||||
* sequence of bytes.
|
||||
*
|
||||
* @return A <code>MaplePacket</code> with the bytes in this stream.
|
||||
*/
|
||||
public byte[] getPacket() {
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes this packet into a human-readable hexadecimal stream of bytes.
|
||||
*
|
||||
* @return This packet as hex digits.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return HexTool.toString(baos.toByteArray());
|
||||
}
|
||||
}
|
||||
73
tools/MapleEmptyItemWzChecker/build.xml
Normal file
73
tools/MapleEmptyItemWzChecker/build.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- You may freely edit this file. See commented blocks below for -->
|
||||
<!-- some examples of how to customize the build. -->
|
||||
<!-- (If you delete it and reopen the project it will be recreated.) -->
|
||||
<!-- By default, only the Clean and Build commands use this build script. -->
|
||||
<!-- Commands such as Run, Debug, and Test only use this build script if -->
|
||||
<!-- the Compile on Save feature is turned off for the project. -->
|
||||
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
|
||||
<!-- in the project's Project Properties dialog box.-->
|
||||
<project name="MapleEmptyItemWzChecker" default="default" basedir=".">
|
||||
<description>Builds, tests, and runs the project MapleEmptyItemWzChecker.</description>
|
||||
<import file="nbproject/build-impl.xml"/>
|
||||
<!--
|
||||
|
||||
There exist several targets which are by default empty and which can be
|
||||
used for execution of your tasks. These targets are usually executed
|
||||
before and after some main targets. They are:
|
||||
|
||||
-pre-init: called before initialization of project properties
|
||||
-post-init: called after initialization of project properties
|
||||
-pre-compile: called before javac compilation
|
||||
-post-compile: called after javac compilation
|
||||
-pre-compile-single: called before javac compilation of single file
|
||||
-post-compile-single: called after javac compilation of single file
|
||||
-pre-compile-test: called before javac compilation of JUnit tests
|
||||
-post-compile-test: called after javac compilation of JUnit tests
|
||||
-pre-compile-test-single: called before javac compilation of single JUnit test
|
||||
-post-compile-test-single: called after javac compilation of single JUunit test
|
||||
-pre-jar: called before JAR building
|
||||
-post-jar: called after JAR building
|
||||
-post-clean: called after cleaning build products
|
||||
|
||||
(Targets beginning with '-' are not intended to be called on their own.)
|
||||
|
||||
Example of inserting an obfuscator after compilation could look like this:
|
||||
|
||||
<target name="-post-compile">
|
||||
<obfuscate>
|
||||
<fileset dir="${build.classes.dir}"/>
|
||||
</obfuscate>
|
||||
</target>
|
||||
|
||||
For list of available properties check the imported
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
|
||||
Another way to customize the build is by overriding existing main targets.
|
||||
The targets of interest are:
|
||||
|
||||
-init-macrodef-javac: defines macro for javac compilation
|
||||
-init-macrodef-junit: defines macro for junit execution
|
||||
-init-macrodef-debug: defines macro for class debugging
|
||||
-init-macrodef-java: defines macro for class execution
|
||||
-do-jar: JAR building
|
||||
run: execution of project
|
||||
-javadoc-build: Javadoc generation
|
||||
test-report: JUnit report generation
|
||||
|
||||
An example of overriding the target for project execution could look like this:
|
||||
|
||||
<target name="run" depends="MapleEmptyItemWzChecker-impl.jar">
|
||||
<exec dir="bin" executable="launcher.exe">
|
||||
<arg file="${dist.jar}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
Notice that the overridden target depends on the jar target and not only on
|
||||
the compile target as the regular run target does. Again, for a list of available
|
||||
properties which you can use, check the target you are overriding in the
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
-->
|
||||
</project>
|
||||
149
tools/MapleEmptyItemWzChecker/lib/Report.txt
Normal file
149
tools/MapleEmptyItemWzChecker/lib/Report.txt
Normal file
@@ -0,0 +1,149 @@
|
||||
# Report File autogenerated from the MapleEmptyItemWzChecker feature by Ronan Lana.
|
||||
# Generated data takes into account several data info from the server-side WZ.xmls.
|
||||
|
||||
String.wz NAMES with no Item.wz node, 130 entries:
|
||||
20816 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Face\
|
||||
20817 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Face\
|
||||
21817 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Face\
|
||||
21820 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Face\
|
||||
1002655 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Cap\
|
||||
1002657 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Cap\
|
||||
1002658 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Cap\
|
||||
1003028 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Cap\
|
||||
1003029 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Cap\
|
||||
1003030 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Cap\
|
||||
1003043 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Cap\
|
||||
1022096 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Accessory\
|
||||
1042180 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Coat\
|
||||
1052226 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Longcoat\
|
||||
1060115 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Pants\
|
||||
1060138 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Pants\
|
||||
1061125 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Pants\
|
||||
1061160 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Pants\
|
||||
1062036 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Pants\
|
||||
1062037 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Pants\
|
||||
1072248 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Shoes\
|
||||
1072249 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Shoes\
|
||||
1072418 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Shoes\
|
||||
1072425 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Shoes\
|
||||
1080002 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Glove\
|
||||
1082217 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Glove\
|
||||
1082221 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Glove\
|
||||
1082261 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Glove\
|
||||
1142152 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Accessory\
|
||||
1142155 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Accessory\
|
||||
1302032 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Weapon\
|
||||
1302069 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Weapon\
|
||||
1322030 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Weapon\
|
||||
1322034 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Weapon\
|
||||
1332058 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Weapon\
|
||||
1382013 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Weapon\
|
||||
1452047 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Weapon\
|
||||
1462020 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Weapon\
|
||||
1462042 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Weapon\
|
||||
1472057 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Weapon\
|
||||
1702113 ../../wz/String.wz/Eqp.img.xml -> Eqp.img\Eqp\Weapon\
|
||||
2002012 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2002013 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2002014 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2012004 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2022034 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2022036 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2022046 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2022114 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2070014 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2083000 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2084000 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2101016 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2101017 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2101018 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2101019 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2101022 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2101058 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2210023 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2210024 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240004 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240005 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240006 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240007 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240008 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240009 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240010 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240011 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240012 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240013 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240014 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2240015 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2290109 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
2390000 ../../wz/String.wz/Consume.img.xml -> Consume.img\
|
||||
3010044 ../../wz/String.wz/Ins.img.xml -> Ins.img\
|
||||
3994016 ../../wz/String.wz/Ins.img.xml -> Ins.img\
|
||||
4000275 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4001150 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031294 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031627 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031628 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031629 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031630 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031631 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031632 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031633 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031634 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031635 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031636 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031637 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031638 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031639 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031640 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031641 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031642 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031643 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031644 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031645 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031646 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031647 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031648 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031795 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4031867 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
4032526 ../../wz/String.wz/Etc.img.xml -> Etc.img\Etc\
|
||||
5000040 ../../wz/String.wz/Pet.img.xml -> Pet.img\
|
||||
5000043 ../../wz/String.wz/Pet.img.xml -> Pet.img\
|
||||
5000046 ../../wz/String.wz/Pet.img.xml -> Pet.img\
|
||||
5201000 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5201001 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5210000 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5210001 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5210002 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5210003 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5210004 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5210005 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5211001 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5211002 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5211003 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5211047 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5240016 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5240019 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5251004 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5251005 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5251006 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5360009 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5360010 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5360011 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5360012 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5360013 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
5360014 ../../wz/String.wz/Cash.img.xml -> Cash.img\
|
||||
|
||||
Item.wz ITEMS with no String.wz node, 12 entries:
|
||||
1942000 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01942000.img.xml -> NOT FOUND
|
||||
1942001 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01942001.img.xml -> NOT FOUND
|
||||
1942002 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01942002.img.xml -> NOT FOUND
|
||||
1952000 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01952000.img.xml -> NOT FOUND
|
||||
1952001 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01952001.img.xml -> NOT FOUND
|
||||
1952002 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01952002.img.xml -> NOT FOUND
|
||||
1962000 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01962000.img.xml -> NOT FOUND
|
||||
1962001 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01962001.img.xml -> NOT FOUND
|
||||
1962002 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01962002.img.xml -> NOT FOUND
|
||||
1972000 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01972000.img.xml -> NOT FOUND
|
||||
1972001 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01972001.img.xml -> NOT FOUND
|
||||
1972002 C:\Nexon\HeavenMS\wz\Character.wz\Dragon\01972002.img.xml -> NOT FOUND
|
||||
|
||||
3
tools/MapleEmptyItemWzChecker/manifest.mf
Normal file
3
tools/MapleEmptyItemWzChecker/manifest.mf
Normal file
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
X-COMMENT: Main-Class will be added automatically by build
|
||||
|
||||
@@ -0,0 +1,476 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package mapleemptyitemwzchecker;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*
|
||||
This application has two objectives: it reports in a detailed file all itemids which is
|
||||
currently missing either a name entry in the String.wz or an item entry in the Item.wz;
|
||||
And it removes from the String.wz XMLs all entries which misses properties on Item.wz.
|
||||
*/
|
||||
public class MapleEmptyItemWzChecker {
|
||||
|
||||
static String newFile = "lib/Report.txt";
|
||||
static String outputWzPath = "lib";
|
||||
static PrintWriter printWriter = null;
|
||||
static InputStreamReader fileReader = null;
|
||||
static BufferedReader bufferedReader = null;
|
||||
|
||||
static String wzPath = "../../wz";
|
||||
static String handbookPath = "../../handbook";
|
||||
static int initialStringLength = 50;
|
||||
static int itemFileNameSize = 13;
|
||||
|
||||
static byte status = 0;
|
||||
static int currentItemid = 0;
|
||||
static int currentDepth = 0;
|
||||
static Stack<String> currentPath = new Stack<>();
|
||||
static String currentFile;
|
||||
|
||||
static Map<Integer, String> stringWzItems = new HashMap<>();
|
||||
static Map<Integer, String> contentWzItems = new HashMap<>();
|
||||
|
||||
static Set<Integer> handbookItems = new HashSet<>();
|
||||
static Set<Integer> nonPropItems;
|
||||
|
||||
private static String getName(String token) {
|
||||
int i, j;
|
||||
char[] dest;
|
||||
String d;
|
||||
|
||||
i = token.lastIndexOf("name");
|
||||
i = token.indexOf("\"", i) + 1; //lower bound of the string
|
||||
j = token.indexOf("\"", i); //upper bound
|
||||
|
||||
dest = new char[initialStringLength];
|
||||
token.getChars(i, j, dest, 0);
|
||||
|
||||
d = new String(dest);
|
||||
return(d.trim());
|
||||
}
|
||||
|
||||
private static void forwardCursor(int st) {
|
||||
String line = null;
|
||||
|
||||
try {
|
||||
while(status >= st && (line = bufferedReader.readLine()) != null) {
|
||||
simpleToken(line);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void simpleToken(String token) {
|
||||
if(token.contains("/imgdir")) {
|
||||
status -= 1;
|
||||
}
|
||||
else if(token.contains("imgdir")) {
|
||||
status += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void listFiles(String directoryName, ArrayList<File> files) {
|
||||
File directory = new File(directoryName);
|
||||
|
||||
// get all the files from a directory
|
||||
File[] fList = directory.listFiles();
|
||||
for (File file : fList) {
|
||||
if (file.isFile()) {
|
||||
files.add(file);
|
||||
} else if (file.isDirectory()) {
|
||||
listFiles(file.getAbsolutePath(), files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int getItemIdFromFilename(String name) {
|
||||
try {
|
||||
return Integer.valueOf(name.substring(0, name.indexOf('.')));
|
||||
} catch(Exception e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void inspectItemWzEntry() {
|
||||
String line = null;
|
||||
|
||||
try {
|
||||
while((line = bufferedReader.readLine()) != null) {
|
||||
translateItemToken(line);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static String currentItemPath() {
|
||||
String s = currentFile + " -> ";
|
||||
|
||||
for (String p : currentPath) {
|
||||
s += (p + "\\");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private static void translateItemToken(String token) {
|
||||
if(token.contains("/imgdir")) {
|
||||
status -= 1;
|
||||
|
||||
currentPath.pop();
|
||||
}
|
||||
else if(token.contains("imgdir")) {
|
||||
status += 1;
|
||||
String d = getName(token);
|
||||
|
||||
if(status == 2) {
|
||||
currentItemid = Integer.valueOf(d);
|
||||
contentWzItems.put(currentItemid, currentItemPath());
|
||||
|
||||
forwardCursor(status);
|
||||
} else {
|
||||
currentPath.push(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void inspectStringWzEntry() {
|
||||
String line = null;
|
||||
|
||||
try {
|
||||
while((line = bufferedReader.readLine()) != null) {
|
||||
translateStringToken(line);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void translateStringToken(String token) {
|
||||
if(token.contains("/imgdir")) {
|
||||
status -= 1;
|
||||
currentPath.pop();
|
||||
}
|
||||
else if(token.contains("imgdir")) {
|
||||
status += 1;
|
||||
String d = getName(token);
|
||||
|
||||
if(status == currentDepth) {
|
||||
currentItemid = Integer.valueOf(d);
|
||||
stringWzItems.put(currentItemid, currentItemPath());
|
||||
//if (currentItemid >= 4000000) System.out.println(" " + currentItemid);
|
||||
|
||||
forwardCursor(status);
|
||||
} else {
|
||||
currentPath.push(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadStringWzFile(String filePath, int depth) throws IOException {
|
||||
fileReader = new InputStreamReader(new FileInputStream(filePath), "UTF-8");
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
currentFile = filePath;
|
||||
currentDepth = 2 + depth;
|
||||
//System.out.println(filePath + " depth " + depth);
|
||||
inspectStringWzEntry();
|
||||
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
}
|
||||
|
||||
private static void loadStringWz() throws IOException {
|
||||
System.out.println("Reading String.wz ...");
|
||||
String stringWzFiles[][] = {{"Cash", "Consume", "Ins", "Pet"}, {"Etc"}, {"Eqp"}};
|
||||
String stringWzPath = wzPath + "/String.wz/";
|
||||
|
||||
for (int i = 0; i < stringWzFiles.length; i++) {
|
||||
for (String dirFile : stringWzFiles[i]) {
|
||||
loadStringWzFile(stringWzPath + dirFile + ".img.xml", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadItemWz() throws IOException {
|
||||
System.out.println("Reading Item.wz ...");
|
||||
ArrayList<File> files = new ArrayList<>();
|
||||
listFiles(wzPath + "/Item.wz", files);
|
||||
|
||||
for(File f : files) {
|
||||
if (f.getParentFile().getName().contentEquals("Special")) continue;
|
||||
|
||||
//System.out.println("Parsing " + f.getAbsolutePath());
|
||||
fileReader = new InputStreamReader(new FileInputStream(f), "UTF-8");
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
currentFile = f.getCanonicalPath();
|
||||
|
||||
if(f.getName().length() <= itemFileNameSize) {
|
||||
inspectItemWzEntry();
|
||||
} else { // pet file structure is similar to equips, maybe there are other item-types following this behaviour?
|
||||
int itemid = getItemIdFromFilename(f.getName());
|
||||
if(itemid < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
currentItemid = itemid;
|
||||
contentWzItems.put(currentItemid, currentItemPath());
|
||||
}
|
||||
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadCharacterWz() throws IOException {
|
||||
System.out.println("Reading Character.wz ...");
|
||||
ArrayList<File> files = new ArrayList<>();
|
||||
listFiles(wzPath + "/Character.wz", files);
|
||||
|
||||
for(File f : files) {
|
||||
if (f.getParentFile().getName().contentEquals("Character.wz")) continue;
|
||||
|
||||
int itemid = getItemIdFromFilename(f.getName());
|
||||
if(itemid < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
currentFile = f.getCanonicalPath();
|
||||
currentItemid = itemid;
|
||||
contentWzItems.put(currentItemid, currentItemPath());
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculateItemNameDiff(Set<Integer> emptyItemNames, Set<Integer> emptyNameItems) {
|
||||
for (Integer i : contentWzItems.keySet()) {
|
||||
if (!stringWzItems.containsKey(i)) {
|
||||
emptyNameItems.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (Integer i : stringWzItems.keySet()) {
|
||||
if (!contentWzItems.containsKey(i)) {
|
||||
emptyItemNames.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void readHandbookItems() throws IOException {
|
||||
System.out.println("Reading handbook ...");
|
||||
String[] handbookPaths = {"Equip", "Cash.txt", "Etc.txt", "Pet.txt", "Setup.txt", "Use.txt"};
|
||||
|
||||
for (String path : handbookPaths) {
|
||||
readHandbookPath(handbookPath + "/" + path);
|
||||
}
|
||||
}
|
||||
|
||||
private static void readHandbookPath(String filePath) throws IOException {
|
||||
ArrayList<File> files = new ArrayList<>();
|
||||
|
||||
File testFile = new File(filePath);
|
||||
if (testFile.isDirectory()) {
|
||||
listFiles(filePath, files);
|
||||
} else {
|
||||
files.add(testFile);
|
||||
}
|
||||
|
||||
for (File f : files) {
|
||||
fileReader = new InputStreamReader(new FileInputStream(f), "UTF-8");
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
String line = null;
|
||||
|
||||
try {
|
||||
while((line = bufferedReader.readLine()) != null) {
|
||||
String[] tokens = line.split(" - ");
|
||||
|
||||
if (tokens[0].length() > 0) {
|
||||
int itemid = Integer.valueOf(tokens[0]);
|
||||
handbookItems.add(itemid);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void printReportFileHeader() {
|
||||
printWriter.println(" # Report File autogenerated from the MapleEmptyItemWzChecker feature by Ronan Lana.");
|
||||
printWriter.println(" # Generated data takes into account several data info from the server-side WZ.xmls.");
|
||||
printWriter.println();
|
||||
}
|
||||
|
||||
private static List<Integer> getSortedItems(Set<Integer> items) {
|
||||
List<Integer> sortedItems = new ArrayList<>(items);
|
||||
Collections.sort(sortedItems);
|
||||
|
||||
return sortedItems;
|
||||
}
|
||||
|
||||
private static void printReportFileResults(Set<Integer> emptyItemNames, Set<Integer> emptyNameItems) {
|
||||
if (!emptyItemNames.isEmpty()) {
|
||||
printWriter.println("String.wz NAMES with no Item.wz node, " + emptyItemNames.size() + " entries:");
|
||||
|
||||
for(Integer itemid : getSortedItems(emptyItemNames)) {
|
||||
printWriter.println(" " + itemid + " " + stringWzItems.get(itemid) + (handbookItems.contains(itemid) ? "" : " NOT FOUND"));
|
||||
}
|
||||
|
||||
printWriter.println();
|
||||
}
|
||||
|
||||
if (!emptyNameItems.isEmpty()) {
|
||||
printWriter.println("Item.wz ITEMS with no String.wz node, " + emptyNameItems.size() + " entries:");
|
||||
|
||||
for(Integer itemid : getSortedItems(emptyNameItems)) {
|
||||
printWriter.println(" " + itemid + " " + contentWzItems.get(itemid) + (handbookItems.contains(itemid) ? "" : " NOT FOUND"));
|
||||
}
|
||||
|
||||
printWriter.println();
|
||||
}
|
||||
}
|
||||
|
||||
private static void reportItemNameDiff(Set<Integer> emptyItemNames, Set<Integer> emptyNameItems) throws IOException {
|
||||
System.out.println("Reporting results...");
|
||||
printWriter = new PrintWriter(newFile, "UTF-8");
|
||||
|
||||
printReportFileHeader();
|
||||
printReportFileResults(emptyItemNames, emptyNameItems);
|
||||
|
||||
printWriter.close();
|
||||
}
|
||||
|
||||
private static void locateItemStringWzDiff() throws IOException {
|
||||
Set<Integer> emptyItemNames = new HashSet<>(), emptyNameItems = new HashSet<>();
|
||||
calculateItemNameDiff(emptyItemNames, emptyNameItems);
|
||||
|
||||
reportItemNameDiff(emptyItemNames, emptyNameItems);
|
||||
nonPropItems = emptyItemNames;
|
||||
}
|
||||
|
||||
private static void runEmptyItemWzChecker() throws IOException {
|
||||
readHandbookItems();
|
||||
|
||||
loadCharacterWz();
|
||||
loadItemWz();
|
||||
loadStringWz();
|
||||
|
||||
locateItemStringWzDiff();
|
||||
}
|
||||
|
||||
private static void generateStringWzEntry() {
|
||||
String line = null;
|
||||
|
||||
try {
|
||||
while((line = bufferedReader.readLine()) != null) {
|
||||
updateStringToken(line);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateStringToken(String token) {
|
||||
if(token.contains("/imgdir")) {
|
||||
status -= 1;
|
||||
|
||||
}
|
||||
else if(token.contains("imgdir")) {
|
||||
status += 1;
|
||||
|
||||
if (status == currentDepth && nonPropItems.contains(Integer.valueOf(getName(token)))) {
|
||||
forwardCursor(status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printWriter.println(token);
|
||||
}
|
||||
|
||||
private static void generateStringWzFile(String filePath, int depth) throws IOException {
|
||||
fileReader = new InputStreamReader(new FileInputStream(wzPath + filePath), "UTF-8");
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
printWriter = new PrintWriter(outputWzPath + filePath, "UTF-8");
|
||||
currentDepth = 2 + depth;
|
||||
|
||||
//System.out.println(filePath + " depth " + depth);
|
||||
generateStringWzEntry();
|
||||
|
||||
printWriter.close();
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
}
|
||||
|
||||
private static void generateStringWz() throws IOException {
|
||||
System.out.println("Generating clean String.wz ...");
|
||||
String stringWzFiles[][] = {{"Cash", "Consume", "Ins", "Pet"}, {"Etc"}, {"Eqp"}};
|
||||
String stringWzPath = "/String.wz/";
|
||||
|
||||
File folder = new File(outputWzPath + "/String.wz/");
|
||||
if (!folder.exists()) {
|
||||
folder.mkdirs();
|
||||
}
|
||||
|
||||
for (int i = 0; i < stringWzFiles.length; i++) {
|
||||
for (String dirFile : stringWzFiles[i]) {
|
||||
generateStringWzFile(stringWzPath + dirFile + ".img.xml", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
runEmptyItemWzChecker();
|
||||
generateStringWz();
|
||||
|
||||
System.out.println("Done!");
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user