Compare commits

...

133 commits

Author SHA1 Message Date
f1ae5730d4
Merge remote-tracking branch '1211/1.21.4' into bk-original 2025-04-19 22:09:11 -04:00
051a2b2f27
fix: fall back to chat if above or below world Y limit 2025-04-19 18:46:56 +07:00
a6d6ed198c
feat: silently /fill core using place block core (finally !!!!!!!!!)
i was also attempting to fix tracked core, but it really seems like the server is checking the distance between you and the block (since we are using the query block NBT packet instead of tellraw), although i have checked the vanilla minecraft code, they don't seem to check for it. maybe it's just a skill issue on my part, but it used to work in the original version of chipmunkmod, if i remember correctly
anyway, now it's basically a silent fill. you can still do `.core runFillCommand false` to still disable the place block core
2025-04-19 18:31:23 +07:00
0cc74be280
fix: hopefully fix core using old position after receiving teleport packet from server 2025-04-19 10:02:48 +07:00
16131b2184
Merge remote-tracking branch '1211/1.21.4' into bk-original 2025-04-18 22:41:07 -04:00
ea16395c15
fix: try to fix maddy's spam (doesn't do much..)
yes i'm also planning to create deploy core, which should evade all cspy spams, but i'm not sure how well that will perform in a minecraft client
my another plan is to only fill the core only when it's needed, like only when the chat is open (for custom chat), or when there's a cloop running
2025-04-19 09:23:28 +07:00
e2a8217e37
Make it compile 2025-04-18 14:22:19 -04:00
dc4fad6506
Comment thjis oi8ut 2025-04-18 14:14:37 -04:00
63342f85b7
Merge remote-tracking branch '1211/1.21.4' into bk-original 2025-04-18 14:14:22 -04:00
3f1ef6d889
Make music command not broadcast to everyone by default 2025-04-18 13:56:57 -04:00
69909de327
fix: .customchat format not working
refactor: remove useless timer in CustomChat (not even sure why it's there)
2025-04-16 17:24:27 +07:00
0b31a366cb
style: also commit the styles and info in readme 2025-04-15 10:25:17 +07:00
7ed4d1ee84
refactor: remove 2025-04-15 10:08:53 +07:00
0f9b6f4cdb
style: use the same code style as chomens bot 2025-04-15 09:41:08 +07:00
1afb5583b4
refactor: use Wrap* for mixins
refactor: remove TransactionManager since it's unused
refactor: fix some warnings about ClientPlayNetworkHandler being nullable

and some more stuff i might have forgor to put here
more stuff coming in the next commits !!!
2025-04-15 09:31:54 +07:00
bb8bb88489
feat: configurable self cares 2025-04-14 09:29:06 +07:00
3e05e6b89d
refactor: don't use chomens bot teams 2025-04-13 17:13:43 +07:00
d6a93ffef9
refactor: remove the infamous icu self care ported from SMP 2025-04-13 15:24:10 +07:00
c9594fe248
fix: forgor register migration (chome NS moment)
my brain was not working at that time i also was doing some other thing too
2025-04-12 21:06:11 +07:00
ccf9600cf1
refactor: remove imposter format in chomens (the HASH thing) 2025-04-12 15:15:06 +07:00
792c9e6a97
a 2025-04-12 00:27:09 -04:00
497e8a1946
Revert "feat: uwu bot hashing (qilk)"
This reverts commit 4d536c5a24.
2025-04-12 00:20:08 -04:00
03af6e4917
Remove friday night bot 2025-04-12 00:17:53 -04:00
c908d903a9
Merge remote-tracking branch '1211/1.21.4' into bk-original 2025-04-12 00:12:42 -04:00
79589edc44
fix: more strict regex 2025-04-10 17:16:21 +07:00
a085756c7d
refactor: use our own LegacyComponentSerializer with builder extractUrls for url replacement instead of the extras one 2025-04-10 14:18:36 +07:00
fff76b9cc2 Merge pull request 'fix: use return inject for infinite chat' () from amy/chomensmod:1.21.4 into 1.21.4
Reviewed-on: 
2025-04-07 23:48:22 -04:00
e1eed2164e
fix: use return inject for infinite chat 2025-04-08 00:44:04 -03:00
657ae684ff
refactor: remove ChomeNSAuth
it's merged to ChomeNS Mod :D
2025-04-08 10:04:34 +07:00
4d536c5a24
feat: uwu bot hashing (qilk) 2025-04-06 15:48:30 +07:00
6aa61cf724 Merge pull request 'More mixin cleanups' () from amy/chomensmod:1.21.4 into 1.21.4
Reviewed-on: 
2025-04-06 00:23:47 -04:00
64df0af9a0
refactor: use ThreadLocal boolean for player chat
this is still a huge hack but it's better than before, i guess
2025-04-06 01:13:47 -03:00
73ac8983d1
refactor: remove intrusive TextFieldWidgetMixin
it affects way more things than it should
2025-04-06 01:13:47 -03:00
a97c047566
refactor: use ModifyConstant for infinite chat mixin 2025-04-06 01:13:47 -03:00
92867a6217
fix: update nbot hashing 2025-04-05 19:06:39 +07:00
1193bd0bb4
fix: also make .username set greedy since we have .username empty now 2025-03-30 11:25:50 +07:00
8662ee448a Merge pull request '.username random/blank/empty' () from amy/chomens-chipmunkmod:1.21.4 into 1.21.4
Reviewed-on: 
2025-03-30 00:20:56 -04:00
f3c4c6abdd
feat: add random/blank/empty option for username command 2025-03-30 01:05:27 -03:00
a8e3b67d92
refactor: some changes for chomens mod lol 2025-03-25 19:16:41 +07:00
9bbe885025
chore: bump loom 2025-03-24 17:39:47 +07:00
2723483b7b
feat: re-add ChomeNSAuth
refactor: improve the chat stuff in ClientPlayNetworkHandlerMixin a bit
2025-03-23 08:40:55 +07:00
aaf7a44d95
refactor: remove bots.chomens.authKey from config (migration V2 !!!) 2025-03-22 19:41:38 +07:00
c5fbd67510
refactor: make .username set <username> only a string instead of a greedy string so we can set our username to an empty string for the funnies 2025-03-21 17:51:51 +07:00
88cca61fe2
refactor: remove deprecation warning from manually chomens validating 2025-03-17 13:47:11 +07:00
8ec8dd7074
fix: music goto command output 2025-03-16 10:41:17 +07:00
b6d906228e
Merge remote-tracking branch '1211/1.21.4' into bk-original 2025-03-15 18:48:29 -04:00
6b7bfa5ac6
Readme changes 2025-03-15 18:42:02 -04:00
68fa7a871f
Change license 2025-03-15 18:38:19 -04:00
604a901399
fix: lazy fix for arabica coffee kaboom clone 2025-03-15 19:04:35 +07:00
88461b45d3
fix: icu self care memory leak 2025-03-15 19:04:23 +07:00
e088c1fec1
refactor: make core increment a bit faster (from chomens bot) 2025-03-15 19:04:14 +07:00
c2313ee650
refactor: finally remove the hclient scent 2025-03-15 18:47:06 +07:00
8b7545ac16
refactor: at least reduce a bit of the mess
also about the pitch issue, it actually was intended to be like that, the clamp bypass already works, i just thought it can go unlimited
2025-03-06 20:12:40 +07:00
c1c7907e49
refactor: remove useless cancel call 2025-03-06 19:57:32 +07:00
b3f5e4f633
fix: more fixes to song stuff 2025-03-04 20:26:46 +07:00
1034518f5f
refactor: improve a lot of stuff about music, and also stereo support for NBS 2025-03-03 16:05:10 +07:00
11d89993b2
refactor: improve the server has command function in ServerUtilities 2025-03-03 16:04:38 +07:00
3a5e4490ee
refactor: remove out-of-bounds location in LocationArgumentType since it's pointless 2025-03-03 15:21:07 +07:00
7f9d942754
refactor: remove TabComplete 2025-03-03 15:06:02 +07:00
50ae8ab300
Add commment to kick 2025-02-16 18:48:28 -05:00
40037e3798
ffgwgwaewegaewgwea 2025-02-12 19:14:04 -05:00
c66f98c306
Merge remote-tracking branch '1211/1.21.4' into bk-original 2025-02-12 19:07:05 -05:00
bc483e9223
atwwartwa 2025-02-12 18:59:28 -05:00
bba4e8337f
fix: FNF boyfriend bot hashing 1s -> 2s 2025-02-11 19:51:37 +07:00
fd9a0ef0cb
refactor: remove ChomeNSAuth since we already have IP authentication 2025-02-09 08:11:10 +07:00
50db974497
refactor: use LF line endings and use 4 spaces on all classes 2025-02-09 08:00:47 +07:00
92b83b4ca2
Merge remote-tracking branch '1211' into bk-original 2025-01-30 21:00:42 -05:00
43527d9e6e 3.141592653589793238462643383279502884197169399375105820974944592307816406286 208998628034825342117067982148086513282306647093844609550582231725359408128481 117450284102701938521105559644622948954930381964428810975665933446128475648233 786783165271201909145648566923460348610454326648213393607260249141273724587006 606315588174881520920962829254091715364367892590360011330530548820466521384146 951941511609433057270365759591953092186117381932611793105118548074462379962749 567351885752724891227938183011949129833673362440656643086021394946395224737190 702179860943702770539217176293176752384674818467669405132000568127145263560827 785771342757789609173637178721468440901224953430146549585371050792279689258923 542019956112129021960864034418159813629774771309960518707211349999998372978049 951059731732816096318595024459455346908302642522308253344685035261931188171010 003137838752886587533208381420617177669147303598253490428755468731159562863882 353787593751957781857780532171226806613001927876611195909216420198938095257201 065485863278865936153381827968230301952035301852968995773622599413891249721775 283479131515574857242454150695950829533116861727855889075098381754637464939319 255060400927701671139009848824012858361603563707660104710181942955596198946767 837449448255379774726847104047534646208046684259069491293313677028989152104752 162056966024058038150193511253382430035587640247496473263914199272604269922796 782354781636009341721641219924586315030286182974555706749838505494588586926995 690927210797509302955321165344987202755960236480665499119881834797753566369807 426542527862551818417574672890977772793800081647060016145249192173217214772350 141441973568548161361157352552133475741849468438523323907394143334547762416862 518983569485562099219222184272550254256887671790494601653466804988627232791786 085784383827967976681454100953883786360950680064225125205117392984896084128488 626945604241965285022210661186306744278622039194945047123713786960956364371917 287467764657573962413890865832645995813390478027590099465764078951269468398352 595709825822620522489407726719478268482601476990902640136394437455305068203496 252451749399651431429809190659250937221696461515709858387410597885959772975498 930161753928468138268683868942774155991855925245953959431049972524680845987273 644695848653836736222626099124608051243884390451244136549762780797715691435997 700129616089441694868555848406353422072225828488648158456028506016842739452267 467678895252138522549954666727823986456596116354886230577456498035593634568174 324112515076069479451096596094025228879710893145669136867228748940560101503308 617928680920874760917824938589009714909675985261365549781893129784821682998948 722658804857564014270477555132379641451523746234364542858444795265867821051141 354735739523113427166102135969536231442952484937187110145765403590279934403742 007310578539062198387447808478489683321445713868751943506430218453191048481005 370614680674919278191197939952061419663428754440643745123718192179998391015919 561814675142691239748940907186494231961567945208095146550225231603881930142093 762137855956638937787083039069792077346722182562599661501421503068038447734549 202605414665925201497442850732518666002132434088190710486331734649651453905796 268561005508106658796998163574736384052571459102897064140110971206280439039759 515677157700420337869936007230558763176359421873125147120532928191826186125867 321579198414848829164470609575270695722091756711672291098169091528017350671274 858322287183520935396572512108357915136988209144421006751033467110314126711136 990865851639831501970165151168517143765761835155650884909989859982387345528331 635507647918535893226185489632132933089857064204675259070915481416549859461637 180270981994309924488957571282890592323326097299712084433573265489382391193259 746366730583604142813883032038249037589852437441702913276561809377344403070746 921120191302033038019762110110044929321516084244485963766983895228684783123552 658213144957685726243344189303968642624341077322697802807318915441101044682325 271620105265227211166039666557309254711055785376346682065310989652691862056476 931257058635662018558100729360659876486117910453348850346113657686753249441668 039626579787718556084552965412665408530614344431858676975145661406800700237877 659134401712749470420562230538994561314071127000407854733269939081454664645880 797270826683063432858785698305235808933065757406795457163775254202114955761581 400250126228594130216471550979259230990796547376125517656751357517829666454779 174501129961489030463994713296210734043751895735961458901938971311179042978285 647503203198691514028708085990480109412147221317947647772622414254854540332157 185306142288137585043063321751829798662237172159160771669254748738986654949450 114654062843366393790039769265672146385306736096571209180763832716641627488880 078692560290228472104031721186082041900042296617119637792133757511495950156604 963186294726547364252308177036751590673502350728354056704038674351362222477158 915049530984448933309634087807693259939780541934144737744184263129860809988868 741326047215695162396586457302163159819319516735381297416772947867242292465436 680098067692823828068996400482435403701416314965897940924323789690706977942236 250822168895738379862300159377647165122893578601588161755782973523344604281512 627203734314653197777416031990665541876397929334419521541341899485444734567383 162499341913181480927777103863877343177207545654532207770921201905166096280490 926360197598828161332316663652861932668633606273567630354477628035045077723554 710585954870279081435624014517180624643626794561275318134078330336254232783944 975382437205835311477119926063813346776879695970309833913077109870408591337464 144282277263465947047458784778720192771528073176790770715721344473060570073349 243693113835049316312840425121925651798069411352801314701304781643788518529092 854520116583934196562134914341595625865865570552690496520985803385072242648293 972858478316305777756068887644624824685792603953527734803048029005876075825104 747091643961362676044925627420420832085661190625454337213153595845068772460290 161876679524061634252257719542916299193064553779914037340432875262888963995879 475729174642635745525407909145135711136941091193932519107602082520261879853188 770584297259167781314969900901921169717372784768472686084900337702424291651300 500516832336435038951702989392233451722013812806965011784408745196012122859937 162313017114448464090389064495444006198690754851602632750529834918740786680881 833851022833450850486082503930213321971551843063545500766828294930413776552793 975175461395398468339363830474611996653858153842056853386218672523340283087112 328278921250771262946322956398989893582116745627010218356462201349671518819097 303811980049734072396103685406643193950979019069963955245300545058068550195673 022921913933918568034490398205955100226353536192041994745538593810234395544959 778377902374216172711172364343543947822181852862408514006660443325888569867054 315470696574745855033232334210730154594051655379068662733379958511562578432298 827372319898757141595781119635833005940873068121602876496286744604774649159950 549737425626901049037781986835938146574126804925648798556145372347867330390468 838343634655379498641927056387293174872332083760112302991136793862708943879936 201629515413371424892830722012690147546684765357616477379467520049075715552781 965362132392640616013635815590742202020318727760527721900556148425551879253034 351398442532234157623361064250639049750086562710953591946589751413103482276930 624743536325691607815478181152843667957061108615331504452127473924544945423682 886061340841486377670096120715124914043027253860764823634143346235189757664521 641376796903149501910857598442391986291642193994907236234646844117394032659184 044378051333894525742399508296591228508555821572503107125701266830240292952522 011872676756220415420516184163484756516999811614101002996078386909291603028840 026910414079288621507842451670908700069928212066041837180653556725253256753286 129104248776182582976515795984703562226293486003415872298053498965022629174878 820273420922224533985626476691490556284250391275771028402799806636582548892648 802545661017296702664076559042909945681506526530537182941270336931378517860904 070866711496558343434769338578171138645587367812301458768712660348913909562009 939361031029161615288138437909904231747336394804575931493140529763475748119356 709110137751721008031559024853090669203767192203322909433467685142214477379393 751703443661991040337511173547191855046449026365512816228824462575916333039107 225383742182140883508657391771509682887478265699599574490661758344137522397096 834080053559849175417381883999446974867626551658276584835884531427756879002909 517028352971634456212964043523117600665101241200659755851276178583829204197484 423608007193045761893234922927965019875187212726750798125547095890455635792122 103334669749923563025494780249011419521238281530911407907386025152274299581807 247162591668545133312394804947079119153267343028244186041426363954800044800267 049624820179289647669758318327131425170296923488962766844032326092752496035799 646925650493681836090032380929345958897069536534940603402166544375589004563288 225054525564056448246515187547119621844396582533754388569094113031509526179378 002974120766514793942590298969594699556576121865619673378623625612521632086286 922210327488921865436480229678070576561514463204692790682120738837781423356282 360896320806822246801224826117718589638140918390367367222088832151375560037279 839400415297002878307667094447456013455641725437090697939612257142989467154357 846878861444581231459357198492252847160504922124247014121478057345510500801908 699603302763478708108175450119307141223390866393833952942578690507643100638351 983438934159613185434754649556978103829309716465143840700707360411237359984345 225161050702705623526601276484830840761183013052793205427462865403603674532865 105706587488225698157936789766974220575059683440869735020141020672358502007245 225632651341055924019027421624843914035998953539459094407046912091409387001264 560016237428802109276457931065792295524988727584610126483699989225695968815920 560010165525637567856672279661988578279484885583439751874454551296563443480396 642055798293680435220277098429423253302257634180703947699415979159453006975214 829336655566156787364005366656416547321704390352132954352916941459904160875320 186837937023488868947915107163785290234529244077365949563051007421087142613497 459561513849871375704710178795731042296906667021449863746459528082436944578977 233004876476524133907592043401963403911473202338071509522201068256342747164602 433544005152126693249341967397704159568375355516673027390074972973635496453328 886984406119649616277344951827369558822075735517665158985519098666539354948106 887320685990754079234240230092590070173196036225475647894064754834664776041146 323390565134330684495397907090302346046147096169688688501408347040546074295869 913829668246818571031887906528703665083243197440477185567893482308943106828702 722809736248093996270607472645539925399442808113736943388729406307926159599546 262462970706259484556903471197299640908941805953439325123623550813494900436427 852713831591256898929519642728757394691427253436694153236100453730488198551706 594121735246258954873016760029886592578662856124966552353382942878542534048308 330701653722856355915253478445981831341129001999205981352205117336585640782648 494276441137639386692480311836445369858917544264739988228462184490087776977631 279572267265556259628254276531830013407092233436577916012809317940171859859993 384923549564005709955856113498025249906698423301735035804408116855265311709957 089942732870925848789443646005041089226691783525870785951298344172953519537885 534573742608590290817651557803905946408735061232261120093731080485485263572282 576820341605048466277504500312620080079980492548534694146977516493270950493463 938243222718851597405470214828971117779237612257887347718819682546298126868581 705074027255026332904497627789442362167411918626943965067151577958675648239939 176042601763387045499017614364120469218237076488783419689686118155815873606293 860381017121585527266830082383404656475880405138080163363887421637140643549556 186896411228214075330265510042410489678352858829024367090488711819090949453314 421828766181031007354770549815968077200947469613436092861484941785017180779306 810854690009445899527942439813921350558642219648349151263901280383200109773868 066287792397180146134324457264009737425700735921003154150893679300816998053652 027600727749674584002836240534603726341655425902760183484030681138185510597970 566400750942608788573579603732451414678670368809880609716425849759513806930944 940151542222194329130217391253835591503100333032511174915696917450271494331515 588540392216409722910112903552181576282328318234254832611191280092825256190205 263016391147724733148573910777587442538761174657867116941477642144111126358355 387136101102326798775641024682403226483464176636980663785768134920453022408197 278564719839630878154322116691224641591177673225326433568614618654522268126887 268445968442416107854016768142080885028005414361314623082102594173756238994207 571362751674573189189456283525704413354375857534269869947254703165661399199968 262824727064133622217892390317608542894373393561889165125042440400895271983787 386480584726895462438823437517885201439560057104811949884239060613695734231559 079670346149143447886360410318235073650277859089757827273130504889398900992391 350337325085598265586708924261242947367019390772713070686917092646254842324074 855036608013604668951184009366860954632500214585293095000090715105823626729326 453738210493872499669933942468551648326113414611068026744663733437534076429402 668297386522093570162638464852851490362932019919968828517183953669134522244470 804592396602817156551565666111359823112250628905854914509715755390024393153519 090210711945730024388017661503527086260253788179751947806101371500448991721002 220133501310601639154158957803711779277522597874289191791552241718958536168059 474123419339842021874564925644346239253195313510331147639491199507285843065836 193536932969928983791494193940608572486396883690326556436421664425760791471086 998431573374964883529276932822076294728238153740996154559879825989109371712621 828302584811238901196822142945766758071865380650648702613389282299497257453033 283896381843944770779402284359883410035838542389735424395647555684095224844554 139239410001620769363684677641301781965937997155746854194633489374843912974239 143365936041003523437770658886778113949861647874714079326385873862473288964564 359877466763847946650407411182565837887845485814896296127399841344272608606187 245545236064315371011274680977870446409475828034876975894832824123929296058294 861919667091895808983320121031843034012849511620353428014412761728583024355983 003204202451207287253558119584014918096925339507577840006746552603144616705082 768277222353419110263416315714740612385042584598841990761128725805911393568960 143166828317632356732541707342081733223046298799280490851409479036887868789493 054695570307261900950207643349335910602454508645362893545686295853131533718386 826561786227363716975774183023986006591481616404944965011732131389574706208847 480236537103115089842799275442685327797431139514357417221975979935968525228574 526379628961269157235798662057340837576687388426640599099350500081337543245463 596750484423528487470144354541957625847356421619813407346854111766883118654489 377697956651727966232671481033864391375186594673002443450054499539974237232871 249483470604406347160632583064982979551010954183623503030945309733583446283947 630477564501500850757894954893139394489921612552559770143685894358587752637962 559708167764380012543650237141278346792610199558522471722017772370041780841942 394872540680155603599839054898572354674564239058585021671903139526294455439131 663134530893906204678438778505423939052473136201294769187497519101147231528932 677253391814660730008902776896311481090220972452075916729700785058071718638105 496797310016787085069420709223290807038326345345203802786099055690013413718236 837099194951648960075504934126787643674638490206396401976668559233565463913836 318574569814719621084108096188460545603903845534372914144651347494078488442377 217515433426030669883176833100113310869042193903108014378433415137092435301367 763108491351615642269847507430329716746964066653152703532546711266752246055119 958183196376370761799191920357958200759560530234626775794393630746305690108011 494271410093913691381072581378135789400559950018354251184172136055727522103526 803735726527922417373605751127887218190844900617801388971077082293100279766593 583875890939568814856026322439372656247277603789081445883785501970284377936240 782505270487581647032458129087839523245323789602984166922548964971560698119218 658492677040395648127810217991321741630581055459880130048456299765112124153637 451500563507012781592671424134210330156616535602473380784302865525722275304999 883701534879300806260180962381516136690334111138653851091936739383522934588832 255088706450753947395204396807906708680644509698654880168287434378612645381583 428075306184548590379821799459968115441974253634439960290251001588827216474500 682070419376158454712318346007262933955054823955713725684023226821301247679452 264482091023564775272308208106351889915269288910845557112660396503439789627825 001611015323516051965590421184494990778999200732947690586857787872098290135295 661397888486050978608595701773129815531495168146717695976099421003618355913877 781769845875810446628399880600616229848616935337386578773598336161338413385368 421197893890018529569196780455448285848370117096721253533875862158231013310387 766827211572694951817958975469399264219791552338576623167627547570354699414892 904130186386119439196283887054367774322427680913236544948536676800000106526248 547305586159899914017076983854831887501429389089950685453076511680333732226517 566220752695179144225280816517166776672793035485154204023817460892328391703275 425750867655117859395002793389592057668278967764453184040418554010435134838953 120132637836928358082719378312654961745997056745071833206503455664403449045362 756001125018433560736122276594927839370647842645676338818807565612168960504161 139039063960162022153684941092605387688714837989559999112099164646441191856827 700457424343402167227644558933012778158686952506949936461017568506016714535431 581480105458860564550133203758645485840324029871709348091055621167154684847780 394475697980426318099175642280987399876697323769573701580806822904599212366168 902596273043067931653114940176473769387351409336183321614280214976339918983548 487562529875242387307755955595546519639440182184099841248982623673771467226061 633643296406335728107078875816404381485018841143188598827694490119321296827158 884133869434682859006664080631407775772570563072940049294030242049841656547973 670548558044586572022763784046682337985282710578431975354179501134727362577408 021347682604502285157979579764746702284099956160156910890384582450267926594205 550395879229818526480070683765041836562094555434613513415257006597488191634135 955671964965403218727160264859304903978748958906612725079482827693895352175362 185079629778514618843271922322381015874445052866523802253284389137527384589238 442253547265309817157844783421582232702069028723233005386216347988509469547200 479523112015043293226628272763217790884008786148022147537657810581970222630971 749507212724847947816957296142365859578209083073323356034846531873029302665964 501371837542889755797144992465403868179921389346924474198509733462679332107268 687076806263991936196504409954216762784091466985692571507431574079380532392523 947755744159184582156251819215523370960748332923492103451462643744980559610330 799414534778457469999212859999939961228161521931488876938802228108300198601654 941654261696858678837260958774567618250727599295089318052187292461086763995891 614585505839727420980909781729323930106766386824040111304024700735085782872462 713494636853181546969046696869392547251941399291465242385776255004748529547681 479546700705034799958886769501612497228204030399546327883069597624936151010243 655535223069061294938859901573466102371223547891129254769617600504797492806072 126803922691102777226102544149221576504508120677173571202718024296810620377657 883716690910941807448781404907551782038565390991047759414132154328440625030180 275716965082096427348414695726397884256008453121406593580904127113592004197598 513625479616063228873618136737324450607924411763997597461938358457491598809766 744709300654634242346063423747466608043170126005205592849369594143408146852981 505394717890045183575515412522359059068726487863575254191128887737176637486027 660634960353679470269232297186832771739323619200777452212624751869833495151019 864269887847171939664976907082521742336566272592844062043021411371992278526998 469884770232382384005565551788908766136013047709843861168705231055314916251728 373272867600724817298763756981633541507460883866364069347043720668865127568826 614973078865701568501691864748854167915459650723428773069985371390430026653078 398776385032381821553559732353068604301067576083890862704984188859513809103042 359578249514398859011318583584066747237029714978508414585308578133915627076035 639076394731145549583226694570249413983163433237897595568085683629725386791327 505554252449194358912840504522695381217913191451350099384631177401797151228378 546011603595540286440590249646693070776905548102885020808580087811577381719174 177601733073855475800605601433774329901272867725304318251975791679296996504146 070664571258883469797964293162296552016879730003564630457930884032748077181155 533090988702550520768046303460865816539487695196004408482065967379473168086415 645650530049881616490578831154345485052660069823093157776500378070466126470602 145750579327096204782561524714591896522360839664562410519551052235723973951288 181640597859142791481654263289200428160913693777372229998332708208296995573772 737566761552711392258805520189887620114168005468736558063347160373429170390798 639652296131280178267971728982293607028806908776866059325274637840539769184808 204102194471971386925608416245112398062011318454124478205011079876071715568315 40788654390412108730324020106853419472304766667217498698685470767
Merge pull request 'More cleanups' () from amy/chomens-chipmunkmod:1.20.1 into 1.21.1

Reviewed-on: 
2025-01-30 03:55:43 -05:00
754f981390
refactor: misc rainbow name cleanups 2025-01-28 17:37:21 -03:00
754aa4a923
empty: test commit on 1.21.1 branch 2025-01-26 14:44:44 +07:00
1f8a05f189
refactor: use apache commons Hex instead of our own Hexadecimal class 2025-01-26 02:59:36 -03:00
0da0967d8a
refactor: cleanup mixins
TextSerializerMixin was completely unused
TextMixin was a fix for an exploit that no longer works on the latest version
truncateChat/stripTextFormat were already handled in CustomChat mixin
2025-01-26 02:29:15 -03:00
501b4d2d2c
fix: chomens bot command suggestions not suggesting commands without aliases 2025-01-26 12:26:04 +07:00
1d40be05a8 Merge pull request 'Rewrite chomensbot suggestion handling' () from amy/chomens-chipmunkmod:1.20.1 into 1.20.1
Reviewed-on: 
2025-01-25 23:13:16 -05:00
ef47598b78
refactor: rewrite chomensbot suggestion handling 2025-01-26 01:10:54 -03:00
a4a9fcf0b4 Merge pull request 'Rewrite KaboomCheck' () from amy/chomens-chipmunkmod:1.20.1 into 1.20.1
Reviewed-on: 
2025-01-25 21:21:27 -05:00
c5ead7d843
refactor: rewrite KaboomCheck 2025-01-25 20:37:28 -03:00
f62f6b8684 Merge pull request 'Dead code elimination' () from amy/md-chipmunkmod:bk-original into bk-original
Reviewed-on: 
2025-01-24 07:24:35 -05:00
7cc6f86090
refactor: remove dead code 2025-01-22 21:55:55 -03:00
cd3bc05a4c Merge pull request 'Merge upstream' () from amy/md-chipmunkmod:bk-original into bk-original
Reviewed-on: 
2025-01-22 19:49:55 -05:00
eb13622c8a
Merge remote-tracking branch 'upstream/1.20.1' into bk-original 2025-01-22 21:35:41 -03:00
94085378a3 Merge pull request 'Correctly style message component' () from amy/chomens-chipmunkmod:1.20.1 into 1.20.1
Reviewed-on: 
2025-01-22 07:13:50 -05:00
dea7909e4c
fix: correctly style message component 2025-01-22 09:12:31 -03:00
b88b2c8e3d Merge pull request 'Use custom ComponentRenderer for custom chat' () from amy/chomens-chipmunkmod:1.20.1 into 1.20.1
Reviewed-on: 
2025-01-22 04:14:35 -05:00
c39c65a2cc
fix: update default config 2025-01-21 03:10:39 -03:00
71927e060a
refactor: use custom ComponentRenderer for custom chat 2025-01-21 03:00:26 -03:00
10645c1cad
refactor: remove commented out brigadier crash patch
yes it doesn't work
2025-01-16 10:07:44 +07:00
af509b8455
refactor: don't request more ChomeNS Bot command suggestions when we already got one (it can still be forced through eval) 2025-01-14 19:42:48 +07:00
cad2bfc2ba
People can be thousands of ancestors of the species before him. He said that ordinary people have told some of the times. But this matter is not related to teachers and changes. Maybe it can. It is not related to these things for many years. Now it is only a comment. It is said that this phenomenon will appear in the future. It is a new phenomenon. It is reported by people. It is not expected that this phenomenon will appear sooner or later. It is not expected that this phenomenon will appear sooner or later. 2025-01-05 10:07:10 -05:00
5de0f84cb9
Firefox 69 on Windows 10 Technical Preview 2025-01-05 09:26:11 -05:00
671a0c958f
Remove blackilykat files 2025-01-05 09:24:06 -05:00
296431bc37
Remove blank files 2025-01-05 09:08:51 -05:00
5364fbd7e2
Revert to chomens file 2025-01-05 09:02:53 -05:00
c3a6f3fcc3
Merge remote-tracking branch '1211/1.20.1' into bk-original 2025-01-05 08:59:49 -05:00
c0d010acf1
refactor: logger name chipmunkmod -> ChipmunkMod 2025-01-05 14:44:06 +07:00
e84b975266
feat: (re-)add infinite chat 2025-01-05 14:42:58 +07:00
64a87a59d8
refactor: some stuff to the argument types (also fixes URL class deprecation) 2025-01-05 14:42:25 +07:00
3be587d815
refactor: check for core run command length if more than 32767 ignore & use ChipmunkMod.LOGGER for the core command log 2025-01-05 14:41:50 +07:00
72260f23ad
fix?: reduce limit (99% no work) 2025-01-03 20:07:14 +07:00
3a42970408 Merge pull request 'feat: name3 migrations' () from amy/md-chipmunkmod:bk-original into bk-original
Reviewed-on: 
2025-01-03 01:25:12 -05:00
e20d59f54d
feat: name3 migrations 2025-01-03 03:18:57 -03:00
91bf5cc891
Merge remote-tracking branch '1211/1.20.1' into bk-original 2025-01-03 01:10:08 -05:00
e570702901 Merge pull request 'feat: config migrations' () from amy/chomens-chipmunkmod:1.20.1 into 1.20.1
Reviewed-on: 
2025-01-03 00:44:07 -05:00
fea9e1946f
feat: config migrations 2025-01-02 01:23:29 -03:00
9ff2a7b549
Fix 2025-01-01 21:56:07 -05:00
3d0764e498
Change format 2025-01-01 21:47:13 -05:00
69881013c7
Merge remote-tracking branch '1211/1.20.1' into bk-original 2025-01-01 21:44:55 -05:00
275aca9d05
feat: URL clickies or something
refactor: some stuff with MESSAGE replacing (not sure if it will break some configs)
2025-01-02 08:58:33 +07:00
1d09eab935
refactor: use configurate for config 2024-12-31 20:54:07 -03:00
3c83eedd09 Merge pull request 'Small cleanups' () from amy/chomens-chipmunkmod:1.20.1 into 1.20.1
thank
2024-12-31 05:27:22 -05:00
7b388fb293
Updatre 2024-12-31 00:25:26 -05:00
2b4306f099 Merge pull request 'Small cleanups' () from amy/md-chipmunkmod:bk-original into bk-original
Reviewed-on: 
2024-12-31 00:23:45 -05:00
682dcb00d7
Merge remote-tracking branch 'upstream-pr/1.20.1' into bk-original 2024-12-31 02:20:48 -03:00
fc4e2d2ccc
feat: pass UUID placeholder to CustomChat 2024-12-31 02:12:26 -03:00
e14b30f8d0
Fix Username bug, by copying yet another file from ChomeNS. 2024-12-31 00:00:45 -05:00
c61773fb73
refactor: mixin cleanups 2024-12-31 01:46:52 -03:00
dba4bb2056
refactor: turn Listener into an interface 2024-12-31 01:22:17 -03:00
ec0596dcda
Mostly revert to Chomens ChipmunkMod.java file 2024-12-29 22:46:13 -05:00
fee16ad7d9
Remove GMS 2024-12-29 22:37:06 -05:00
6dc272a78c
Merge branch 'amy-bk-original' into bk-original 2024-12-28 20:59:04 -05:00
84c7ad673c zebra fix merge 2024-12-28 20:52:38 -05:00
eda0259a97
fix: use correct z in command core check 2024-12-28 22:51:25 -03:00
774500eba0
fix: use correct z in command core check 2024-12-28 22:47:27 -03:00
e9f6042069
変更をマージし、Forgejo で更新します。 2024-12-28 20:46:02 -05:00
b790b805d7
Merge branch 'amy-bk-original' into bk-original 2024-12-28 20:45:30 -05:00
d0a6d01e5b
I remove the wrong thjing 2024-12-28 20:39:47 -05:00
d62df2b511
Merge remote-tracking branch 'upstream/1.20.1' into bk-original 2024-12-28 22:39:19 -03:00
4026ef2664
fix: Dye Mention. 2024-12-29 08:26:19 +07:00
be0982431b refactor: use BlockBox for core 2024-12-28 19:56:35 -05:00
50229d8c10
refactor: use minecraft:tellraw in ChomeNSBotCommandSuggestions when in kaboom 2024-12-29 07:52:29 +07:00
422b67597f
fix: the previous commit 2024-12-29 07:51:43 +07:00
6264013c6b
refactor: remove racist filter 2024-12-29 07:32:34 +07:00
2ee26eedc2 Update README.md 2024-12-28 16:43:32 -05:00
117 changed files with 3833 additions and 4082 deletions
.gitignoreLICENSEREADME.mdbuild.gradlecodestyle.xmlinspections.xml
src/main/java/land/chipmunk/chipmunkmod
ChipmunkMod.javaConfiguration.java
command
commands
config
data
listeners
mixin
modules
song
util

1
.gitignore vendored
View file

@ -38,4 +38,3 @@ hs_err_*.log
replay_*.log
*.hprof
*.jfr
/buildAndSend.sh

120
LICENSE
View file

@ -1,121 +1,11 @@
Creative Commons Legal Code
MIT License
CC0 1.0 Universal
Copyright (c) 2024-2025 7cc5c4f330d47060
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Statement of Purpose
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View file

@ -3,23 +3,42 @@ My fork of [Blackilykat's fork of ChipmunkMod](https://code.chipmunk.land/Blacki
# Installation
Download the latest release from the Releases tab, make sure you have the Fabric loader and Fabric API installed for version 1.21.1, then copy the JAR file to your mods folder. Alternatively, you may follow the instructions below to get the latest code.
Download the JAR file (not the source code archive unless you want to build it) of the latest release from the Releases tab, ensure you have the Fabric loader and Fabric API installed for version 1.21.4, then copy the JAR file to your mods folder. Alternatively, you may follow the instructions below to get the latest code.
# Building
Download the code by clicking the 3 dots icon on the right of the screen below the repository info then `Download ZIP` or `Download TAR.GZ`, then extract it.
Alternatively, you can download using the Git client:
`git clone https://code.chipmunk.land/7cc5c4f330d47060/chipmunkmod.git`
Alternatively, you can download using the [Git client](https://git-scm.com/): `git clone https://code.chipmunk.land/7cc5c4f330d47060/chipmunkmod.git`
Make sure you have a Java 21 JDK installed (this may not work for newer JDK versions), then go to the ChipmunkMod directory and run `./gradlew build` for Unix(-like) OSes or `gradlew.bat build` for Windows. If the build was successful, the compiled JAR file should be in `build/libs`.
Ensure you have a Java 21 JDK installed (this may not work for other JDK versions), then go to the ChipmunkMod directory and run `./gradlew build` for Unix(-like) OSes or `gradlew.bat build` for Windows. If the build was successful, the compiled JAR file should be in `build/libs`.
Make sure you have the Fabric loader and Fabric API installed for version 1.21.4 (the main branch is on a newer game version than the release), and copy the JAR file to your mods folder.
Ensure you have the Fabric loader and Fabric API installed for version 1.21.4, and copy the JAR file to your mods folder.
If that's not clear enough, search how to install a Fabric mod on a search engine.
If errors appear that you don't understand, [create an issue](https://code.chipmunk.land/7cc5c4f330d47060/chipmunkmod/issues/new) about it.
# Extra information
The mod icon used (https://commons.wikimedia.org/wiki/File:Streifenhoernchen.jpg) is in the public domain.
# License
The mod icon used (https://commons.wikimedia.org/wiki/File:Streifenhoernchen.jpg) is in the public domain.
This project is licensed under the MIT License. Using, modifying, and distributing this software, whether in source or binary form, is allowed, even for commercial purposes. If you make any copies of this software, you MUST link back to this repository. See the LICENSE document for the full terms and conditions.
This software contains code from the following projects. See their commit histories for attribution.
Fabric Example Mod (https://github.com/FabricMC/fabric-example-mod)
Original ChipmunkMod (https://code.chipmunk.land/chipmunkmc/chipmunkmod)
ChomeNS' fork of ChipmunkMod (https://code.chipmunk.land/ChomeNS/chipmunkmod)
Blackilykat's fork of ChipmunkMod (https://code.chipmunk.land/Blackilykat/chipmunkmod)
<!--# Development
When commiting your changes, please use my code style.
In IntelliJ IDEA:
`Ctrl + Alt + S`, search `Code Style`, go to `Java`, click gear icon, `Import Scheme -> IntelliJ IDEA code style XML`,
use the `codestyle.xml` file in this repository
`Ctrl + Alt + Shift + H`, click `Configure Inspections...`, click gear icon, `Import Profile...`,
use the `inspections.xml` file in this repository -->

View file

@ -1,15 +1,11 @@
plugins {
id 'fabric-loom' version '1.9-SNAPSHOT'
id 'fabric-loom' version '1.10-SNAPSHOT'
}
base.archivesName = project.archives_base_name
version = project.mod_version
group = project.maven_group
loom {
accessWidenerPath = file("src/main/resources/chipmunkmod.accesswidener")
}
repositories {
mavenCentral()
}
@ -20,14 +16,21 @@ dependencies {
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
// Fabric API. This is technically optional, but you probably want it anyway.
// Fabric API
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
// LuaJ
include(implementation("org.luaj:luaj-jse:3.0.1"))
// Configurate
include(implementation("org.spongepowered:configurate-core:4.1.2"))
include(implementation("org.spongepowered:configurate-gson:4.1.2"))
include(implementation("io.leangen.geantyref:geantyref:1.3.16"))
// Adventure
include(modImplementation("net.kyori:adventure-platform-fabric:6.2.0"))
include(implementation("org.apache.commons:commons-text:1.13.0"))
include(implementation("net.kyori:adventure-text-serializer-gson:4.18.0"))
include(implementation("net.kyori:adventure-text-serializer-legacy:4.18.0"))
include(implementation("org.luaj:luaj-jse:3.0.1"))
}
processResources {

29
codestyle.xml Normal file
View file

@ -0,0 +1,29 @@
<code_scheme name="Project" version="173">
<JavaCodeStyleSettings>
<option name="GENERATE_FINAL_LOCALS" value="true" />
<option name="GENERATE_FINAL_PARAMETERS" value="true" />
<option name="VISIBILITY" value="protected" />
<option name="SPACE_BEFORE_OPENING_ANGLE_BRACKET_IN_TYPE_PARAMETER" value="true" />
<option name="SPACE_BEFORE_DECONSTRUCTION_LIST" value="true" />
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="RIGHT_MARGIN" value="120" />
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
<option name="SPACE_WITHIN_BRACES" value="true" />
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="true" />
<option name="SPACE_BEFORE_METHOD_PARENTHESES" value="true" />
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
<option name="KEEP_SIMPLE_BLOCKS_IN_ONE_LINE" value="true" />
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
<option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true" />
<option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="true" />
<option name="KEEP_MULTIPLE_EXPRESSIONS_IN_ONE_LINE" value="true" />
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings>
</code_scheme>

9
inspections.xml Normal file
View file

@ -0,0 +1,9 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="LocalCanBeFinal" enabled="true" level="WARNING" enabled_by_default="true">
<option name="REPORT_VARIABLES" value="true" />
<option name="REPORT_PARAMETERS" value="true" />
</inspection_tool>
</profile>
</component>

View file

@ -1,116 +1,86 @@
package land.chipmunk.chipmunkmod;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.GsonBuilder;
import land.chipmunk.chipmunkmod.util.SharedVariables;
import land.chipmunk.chipmunkmod.modules.KaboomCheck;
import land.chipmunk.chipmunkmod.modules.SelfCare;
import land.chipmunk.chipmunkmod.util.gson.BlockPosTypeAdapter;
import net.fabricmc.api.ModInitializer;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.math.BlockPos;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import java.nio.charset.Charset;
// what the fuck is this indentation who is responsible for this nightmare
public class ChipmunkMod implements ModInitializer {
// This logger is used to write text to the console and the log file.
// It is considered best practice to use your mod id as the logger's name.
// That way, it's clear which mod wrote info, warnings, and errors.
public static final Logger LOGGER = LoggerFactory.getLogger("chipmunkmod");
public static Configuration CONFIG = new Configuration();
public static final File CONFIG_DIR = new File("config");
private static final File CONFIG_FILE = new File(CONFIG_DIR, "chipmunkmod.json");
public static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
@Override
public void onInitialize () {
// This code runs as soon as Minecraft is in a mod-load-ready state.
// However, some things (like resources) may still be uninitialized.
// Proceed with mild caution.
try {
CONFIG = loadConfig();
} catch (IOException exception) {
throw new RuntimeException("Could not load the config", exception);
}
KaboomCheck.INSTANCE.init();
SelfCare.INSTANCE.init();
//save on quit owo
ClientLifecycleEvents.CLIENT_STOPPING.register(client -> {
try {
saveConfig();
} catch (IOException e) {
LOGGER.error("Failed to save config. Printing stacktrace.");
e.printStackTrace();
return;
}
LOGGER.info("Saved config!");
});
LOGGER.info("Loaded ChipmunkMod (name3's fork)");
}
public static Configuration loadConfig () throws IOException {
CONFIG_DIR.mkdirs();
final Gson gson = new GsonBuilder()
.registerTypeAdapter(BlockPos.class, new BlockPosTypeAdapter())
.serializeNulls()
.create();
final File file = CONFIG_FILE;
if (!file.exists()) {
saveConfig();
}
InputStream is = new FileInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF8")));
Configuration configuration = gson.fromJson(reader, Configuration.class);
if(configuration.bots.testbot.webhookUrl == null && configuration.testbotWebhook != null) {
LOGGER.info("Updating testbot auth url location in config!");
configuration.bots.testbot.webhookUrl = configuration.testbotWebhook;
configuration.testbotWebhook = null;
}
return configuration;
}
public static void saveConfig() throws IOException {
// to migrate old configs and avoid confusion on which field to use. Exclusion strategy should be removed once no one has the old auth location
// in their configs anymore
Gson otherGson = new GsonBuilder().serializeNulls().setLenient().setPrettyPrinting().addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getName().equals("testbotWebhook");
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}).create();
String defaultConfig = otherGson.toJson(CONFIG);
BufferedWriter configWriter = new BufferedWriter(new FileWriter(CONFIG_FILE, Charset.forName("UTF8")));
configWriter.write(defaultConfig);
configWriter.close();
}
}
package land.chipmunk.chipmunkmod;
import land.chipmunk.chipmunkmod.config.ChipmunkModMigrations;
import land.chipmunk.chipmunkmod.config.Name3ModMigrations;
import land.chipmunk.chipmunkmod.config.Configuration;
import land.chipmunk.chipmunkmod.modules.SelfCare;
import land.chipmunk.chipmunkmod.util.configurate.ConfigurateUtilities;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongepowered.configurate.BasicConfigurationNode;
import org.spongepowered.configurate.gson.GsonConfigurationLoader;
import org.spongepowered.configurate.objectmapping.ObjectMapper;
import org.spongepowered.configurate.util.NamingSchemes;
import java.io.IOException;
import java.nio.file.Path;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ChipmunkMod implements ModInitializer {
public static final Logger LOGGER = LoggerFactory.getLogger("ChipmunkMod");
private static final Path CONFIG_PATH = FabricLoader.getInstance()
.getConfigDir().resolve("chipmunkmod.json");
public static Configuration CONFIG;
public static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public static Configuration loadConfig () throws IOException {
final ChipmunkModMigrations migrations = new ChipmunkModMigrations();
final Name3ModMigrations name3Migrations = new Name3ModMigrations();
final ObjectMapper.Factory customFactory = ObjectMapper.factoryBuilder()
.defaultNamingScheme(NamingSchemes.CAMEL_CASE)
.build();
final GsonConfigurationLoader loader = GsonConfigurationLoader.builder()
.defaultOptions(options -> options
.serializers(build -> build
.registerAnnotatedObjects(customFactory)
.registerAll(ConfigurateUtilities.customSerializers()))
.shouldCopyDefaults(true))
.indent(4)
.path(CONFIG_PATH)
.build();
// Configurate will create parent directories for us, so we don't need to do it
final BasicConfigurationNode node = loader.load();
if (node.empty()) { // Config empty, fill it with defaults
final Configuration defaults = new Configuration();
node.set(Configuration.class, defaults);
migrations.setLatest(node);
name3Migrations.setLatest(node);
loader.save(node);
return defaults;
}
if (migrations.migrate(node)) { // Migrated, write new config
loader.save(node);
}
if (name3Migrations.migrate(node)) {
loader.save(node);
}
return node.get(Configuration.class);
}
@Override
public void onInitialize () {
// This code runs as soon as Minecraft is in a mod-load-ready state.
// However, some things (like resources) may still be uninitialized.
// Proceed with mild caution.
try {
CONFIG = loadConfig();
} catch (final IOException exception) {
throw new RuntimeException("Could not load the config", exception);
}
SelfCare.INSTANCE.init();
LOGGER.info("Loaded ChipmunkMod (name3's fork)");
}
}

View file

@ -1,78 +0,0 @@
package land.chipmunk.chipmunkmod;
import land.chipmunk.chipmunkmod.data.BlockArea;
import net.minecraft.util.math.BlockPos;
import com.google.gson.JsonObject;
import java.util.HashMap;
public class Configuration {
public CommandManager commands = new CommandManager();
public CommandCore core = new CommandCore();
public Bots bots = new Bots();
public CustomChat customChat = new CustomChat();
public String autoSkinUsername = "off";
// here so old configs can be migrated
public String testbotWebhook = null;
public static class CommandManager {
public String prefix = ".";
}
public static class CommandCore {
public BlockArea relativeArea = new BlockArea(new BlockPos(0, 0, 0), new BlockPos(15, 0, 15));
}
public static class Bots {
public BotInfo hbot = new BotInfo("#", null);
public BotInfo sbot = new BotInfo(":", null);
public BotInfo ubot = new BotInfo("\"", null);
public BotInfo ubotdev = new BotInfo("d\"", null);
public BotInfo chipmunk = new BotInfo("'", null);
public ChomeNSBotInfo chomens = new ChomeNSBotInfo("*", null, null, null);
public BotInfo fnfboyfriend = new BotInfo("~", null);
public BotInfo nbot = new BotInfo("?", null);
public BotInfo kittycorp = new BotInfo("^", null);
public TestBotInfo testbot = new TestBotInfo("-", null);
}
public static class ChomeNSBotInfo {
public String prefix;
public String key;
public String authKey;
public String formatKey;
public ChomeNSBotInfo (String prefix, String key, String authKey, String formatKey) {
this.prefix = prefix;
this.key = key;
this.authKey = authKey;
this.formatKey = formatKey;
}
}
public static class TestBotInfo {
public String prefix;
public String webhookUrl;
public TestBotInfo (String prefix, String webhookUrl) {
this.prefix = prefix;
this.webhookUrl = webhookUrl;
}
}
public static class BotInfo {
public String prefix;
public String key;
public BotInfo (String prefix, String key) {
this.prefix = prefix;
this.key = key;
}
}
public static class CustomChat {
public JsonObject format;
}
}

View file

@ -1,89 +1,91 @@
package land.chipmunk.chipmunkmod.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.Text;
import net.minecraft.text.Texts;
import net.minecraft.text.MutableText;
import net.minecraft.util.Formatting;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.client.MinecraftClient;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import land.chipmunk.chipmunkmod.commands.*;
public class CommandManager {
public CommandDispatcher<FabricClientCommandSource> dispatcher = new CommandDispatcher<>();
public String prefix;
public static CommandManager INSTANCE;
public CommandManager (String prefix, CommandRegistryAccess commandRegistryAccess) {
this.prefix = prefix;
TestCommand.register(this.dispatcher);
CoreCommand.register(this.dispatcher);
UsernameCommand.register(this.dispatcher);
CloopCommand.register(this.dispatcher);
ValidateCommand.register(this.dispatcher);
ItemCommand.register(this.dispatcher, commandRegistryAccess);
CustomChatCommand.register(this.dispatcher);
EvalCommand.register(this.dispatcher);
MusicCommand.register(this.dispatcher);
RainbowNameCommand.register(this.dispatcher);
SayCommand.register(this.dispatcher);
AutoSkinCommand.register(this.dispatcher);
ReloadConfigCommand.register(this.dispatcher);
DebugCommand.register(this.dispatcher);
SelfCareCommand.register(this.dispatcher);
ClearAntiChatSpamQueueCommand.register(this.dispatcher);
KickCommand.register(this.dispatcher);
}
public void executeCommand (String command) {
final MinecraftClient client = MinecraftClient.getInstance();
final FabricClientCommandSource commandSource = (FabricClientCommandSource) client.getNetworkHandler().getCommandSource();
try {
dispatcher.execute(command, commandSource);
} catch (CommandSyntaxException e) {
commandSource.sendError(Texts.toText(e.getRawMessage()));
final Text context = getContext(e);
if (context != null) commandSource.sendError(context);
} catch (Exception e) {
commandSource.sendError(Text.of(e.getMessage()));
}
}
public Text getContext (CommandSyntaxException exception) {
final int _cursor = exception.getCursor();
final String input = exception.getInput();
if (input == null || _cursor < 0) {
return null;
}
final MutableText text = Text.literal("")
.formatted(Formatting.GRAY);
text.setStyle(text.getStyle().withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, prefix + input)));
final int cursor = Math.min(input.length(), _cursor);
if (cursor > CommandSyntaxException.CONTEXT_AMOUNT) {
text.append(Text.literal("..."));
}
text
.append(Text.literal(input.substring(Math.max(0, cursor - CommandSyntaxException.CONTEXT_AMOUNT), cursor)))
.append(Text.literal(input.substring(cursor)).formatted(Formatting.RED, Formatting.UNDERLINE))
.append(Text.translatable("command.context.here").formatted(Formatting.RED, Formatting.ITALIC));
return text;
}
public static LiteralArgumentBuilder<FabricClientCommandSource> literal (String name) { return LiteralArgumentBuilder.literal(name); }
public static <T> RequiredArgumentBuilder<FabricClientCommandSource, T> argument (String name, ArgumentType<T> type) { return RequiredArgumentBuilder.argument(name, type); }
}
package land.chipmunk.chipmunkmod.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import land.chipmunk.chipmunkmod.commands.*;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.client.MinecraftClient;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.text.Texts;
import net.minecraft.util.Formatting;
public class CommandManager {
public static CommandManager INSTANCE;
public CommandDispatcher<FabricClientCommandSource> dispatcher = new CommandDispatcher<>();
public String prefix;
public CommandManager (final String prefix, final CommandRegistryAccess commandRegistryAccess) {
this.prefix = prefix;
TestCommand.register(this.dispatcher);
CoreCommand.register(this.dispatcher);
UsernameCommand.register(this.dispatcher);
CloopCommand.register(this.dispatcher);
ValidateCommand.register(this.dispatcher);
ItemCommand.register(this.dispatcher, commandRegistryAccess);
CustomChatCommand.register(this.dispatcher);
EvalCommand.register(this.dispatcher);
MusicCommand.register(this.dispatcher);
RainbowNameCommand.register(this.dispatcher);
SayCommand.register(this.dispatcher);
AutoSkinCommand.register(this.dispatcher);
ReloadConfigCommand.register(this.dispatcher);
SelfCareCommand.register(this.dispatcher);
KickCommand.register(this.dispatcher);
}
public static LiteralArgumentBuilder<FabricClientCommandSource> literal (final String name) {
return LiteralArgumentBuilder.literal(name);
}
public static <T> RequiredArgumentBuilder<FabricClientCommandSource, T> argument (final String name, final ArgumentType<T> type) {
return RequiredArgumentBuilder.argument(name, type);
}
public void executeCommand (final String command) {
final MinecraftClient client = MinecraftClient.getInstance();
final FabricClientCommandSource commandSource = (FabricClientCommandSource) client.getNetworkHandler().getCommandSource();
try {
dispatcher.execute(command, commandSource);
} catch (final CommandSyntaxException e) {
commandSource.sendError(Texts.toText(e.getRawMessage()));
final Text context = getContext(e);
if (context != null) commandSource.sendError(context);
} catch (final Exception e) {
commandSource.sendError(Text.of(e.getMessage()));
}
}
public Text getContext (final CommandSyntaxException exception) {
final int _cursor = exception.getCursor();
final String input = exception.getInput();
if (input == null || _cursor < 0) {
return null;
}
final MutableText text = Text.literal("")
.formatted(Formatting.GRAY);
text.setStyle(text.getStyle().withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, prefix + input)));
final int cursor = Math.min(input.length(), _cursor);
if (cursor > CommandSyntaxException.CONTEXT_AMOUNT) {
text.append(Text.literal("..."));
}
text
.append(Text.literal(input.substring(Math.max(0, cursor - CommandSyntaxException.CONTEXT_AMOUNT), cursor)))
.append(Text.literal(input.substring(cursor)).formatted(Formatting.RED, Formatting.UNDERLINE))
.append(Text.translatable("command.context.here").formatted(Formatting.RED, Formatting.ITALIC));
return text;
}
}

View file

@ -8,80 +8,81 @@ import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import net.minecraft.text.Text;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
public class LocationArgumentType implements ArgumentType<Object> {
private static final Collection<String> EXAMPLES = Arrays.<String>asList("songs/amogus.mid", "images/cat.jpg", "videos/badapple.mp4");
private static final Collection<String> EXAMPLES = Arrays.asList("songs/amogus.mid", "images/cat.jpg", "videos/badapple.mp4");
private static final SimpleCommandExceptionType OOB_FILEPATH = new SimpleCommandExceptionType(Text.translatable("The specified file path is outside of the allowed directory"));
private final boolean allowsUrls;
private final boolean allowsPaths;
private final Path root;
private boolean allowsUrls = false;
private boolean allowsPaths = false;
private Path root;
private LocationArgumentType (boolean allowsUrls, boolean allowsPaths, Path root) {
private LocationArgumentType (final boolean allowsUrls, final boolean allowsPaths, final Path root) {
this.allowsUrls = allowsUrls;
this.allowsPaths = allowsPaths;
this.root = root.toAbsolutePath().normalize();
}
public static LocationArgumentType location (Path rootPath) { return new LocationArgumentType(true, true, rootPath); }
public static LocationArgumentType location (final Path rootPath) { return new LocationArgumentType(true, true, rootPath); }
public static LocationArgumentType url () { return new LocationArgumentType(true, false, null); }
public static LocationArgumentType filepath (Path rootPath) { return new LocationArgumentType(false, true, rootPath); }
@Override
public Object parse (StringReader reader) throws CommandSyntaxException {
final String remaining = reader.getString().substring(reader.getCursor());
if (allowsUrls && isUrlStart(remaining)) return parseUrl(reader);
if (allowsPaths) return parsePath(reader);
return null;
}
public static LocationArgumentType filepath (final Path rootPath) { return new LocationArgumentType(false, true, rootPath); }
public boolean isUrlStart (String string) { return string.startsWith("http://") || string.startsWith("https://") || string.startsWith("ftp://"); }
public URL parseUrl (StringReader reader) throws CommandSyntaxException {
final StringBuilder sb = new StringBuilder();
while (reader.canRead() && reader.peek() != ' ') {
sb.append(reader.read());
}
try {
return new URL(sb.toString());
} catch (MalformedURLException exception) {
throw new SimpleCommandExceptionType(Text.literal(exception.getMessage())).create();
}
}
public Path parsePath (StringReader reader) throws CommandSyntaxException {
final String pathString = reader.readString();
final Path path = Path.of(root.toString(), pathString).toAbsolutePath().normalize();
return path;
}
private static Object getLocation (CommandContext<?> context, String name) {
private static Object getLocation (final CommandContext<?> context, final String name) {
return context.getArgument(name, Object.class);
}
public static URL getUrl (CommandContext<?> context, String name) {
public static URL getUrl (final CommandContext<?> context, final String name) {
final Object location = getLocation(context, name);
if (location instanceof URL) return (URL) location;
try {
if (location instanceof Path) return new URL("file", "", -1, location.toString());
} catch (MalformedURLException ignored) {
if (location instanceof Path) return new URI("file", "", "", -1, location.toString(), "", "").toURL();
} catch (final MalformedURLException | URISyntaxException ignored) {
return null; // The real question is whether this will actually ever get called
}
return null;
}
public static Path getPath (CommandContext<?> context, String name) {
public static Path getPath (final CommandContext<?> context, final String name) {
final Object location = getLocation(context, name);
if (location instanceof Path) return (Path) location;
return null;
}
@Override
public Object parse (final StringReader reader) throws CommandSyntaxException {
final String remaining = reader.getString().substring(reader.getCursor());
if (allowsUrls && isUrlStart(remaining)) return parseUrl(reader);
if (allowsPaths) return parsePath(reader);
return null;
}
public boolean isUrlStart (final String string) { return string.startsWith("http://") || string.startsWith("https://") || string.startsWith("ftp://"); }
public URL parseUrl (final StringReader reader) throws CommandSyntaxException {
final StringBuilder sb = new StringBuilder();
while (reader.canRead() && reader.peek() != ' ') {
sb.append(reader.read());
}
try {
return new URI(sb.toString()).toURL();
} catch (final MalformedURLException | URISyntaxException exception) {
throw new SimpleCommandExceptionType(Text.literal(exception.getMessage())).create();
}
}
public Path parsePath (final StringReader reader) throws CommandSyntaxException {
final String pathString = reader.readString();
return Path.of(root.toString(), pathString).toAbsolutePath().normalize();
}
@Override
public Collection<String> getExamples () { return EXAMPLES; }
}

View file

@ -1,13 +1,14 @@
package land.chipmunk.chipmunkmod.command.arguments;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import java.util.Collection;
import java.util.Arrays;
import java.util.Collection;
public class TimestampArgumentType implements ArgumentType<Long> {
private static final Collection<String> EXAMPLES = Arrays.<String>asList("0:01", "1:23", "6:09");
private static final Collection<String> EXAMPLES = Arrays.asList("0:01", "1:23", "6:09");
private TimestampArgumentType () {
}
@ -15,7 +16,7 @@ public class TimestampArgumentType implements ArgumentType<Long> {
public static TimestampArgumentType timestamp () { return new TimestampArgumentType(); }
@Override
public Long parse (StringReader reader) throws CommandSyntaxException {
public Long parse (final StringReader reader) throws CommandSyntaxException {
long seconds = 0L;
long minutes = 0L;

View file

@ -13,7 +13,7 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class AutoSkinCommand {
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("autoskin")
.then(
@ -23,7 +23,7 @@ public class AutoSkinCommand {
);
}
public static int execute(CommandContext<FabricClientCommandSource> context) {
public static int execute (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final String username = getString(context, "username");

View file

@ -1,30 +0,0 @@
package land.chipmunk.chipmunkmod.commands;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import land.chipmunk.chipmunkmod.util.Chat;
import land.chipmunk.chipmunkmod.util.Executor;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import java.util.List;
import java.util.concurrent.Executors;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class ClearAntiChatSpamQueueCommand {
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
final ClearAntiChatSpamQueueCommand instance = new ClearAntiChatSpamQueueCommand();
dispatcher.register(
literal("clearantichatspamqueue")
.executes(instance::run)
);
}
public int run(CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
List<Runnable> runnables = Executor.antiChatSpamService.shutdownNow();
Executor.antiChatSpamService = Executors.newFixedThreadPool(1);
Chat.sendGreen("Stopped " + runnables.size() + " chat messages from getting recieved!");
return 1;
}
}

View file

@ -5,23 +5,25 @@ import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static com.mojang.brigadier.arguments.LongArgumentType.longArg;
import static com.mojang.brigadier.arguments.LongArgumentType.getLong;
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
import land.chipmunk.chipmunkmod.modules.CommandLoopManager;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.text.Text;
import land.chipmunk.chipmunkmod.modules.CommandLoopManager;
import java.util.List;
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static com.mojang.brigadier.arguments.LongArgumentType.getLong;
import static com.mojang.brigadier.arguments.LongArgumentType.longArg;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class CloopCommand {
private static final DynamicCommandExceptionType INVALID_CLOOP_ID_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("Invalid cloop id: %s", Text.literal(String.valueOf(id))));
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("cloop")
.then(
@ -52,18 +54,18 @@ public class CloopCommand {
);
}
public static int addCloop (CommandContext<FabricClientCommandSource> context) {
public static int addCloop (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final long interval = getLong(context, "interval");
final String command = getString(context, "command");
int id = CommandLoopManager.INSTANCE.loopCommand(command, interval);
final int id = CommandLoopManager.INSTANCE.loopCommand(command, interval);
source.sendFeedback(Text.translatable("Successfully created a loop for command '%s' with id %s", Text.literal(command), Text.literal(String.valueOf(id))));
return Command.SINGLE_SUCCESS;
}
public static int removeCloop (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
public static int removeCloop (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
final FabricClientCommandSource source = context.getSource();
final CommandLoopManager manager = CommandLoopManager.INSTANCE;
final int id = getInteger(context, "id");
@ -76,7 +78,7 @@ public class CloopCommand {
return Command.SINGLE_SUCCESS;
}
public static int clearCloops (CommandContext<FabricClientCommandSource> context) {
public static int clearCloops (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final CommandLoopManager manager = CommandLoopManager.INSTANCE;
@ -86,13 +88,13 @@ public class CloopCommand {
return Command.SINGLE_SUCCESS;
}
public static int listCloops (CommandContext<FabricClientCommandSource> context) {
public static int listCloops (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final List<CommandLoopManager.CommandLoop> loops = CommandLoopManager.INSTANCE.commandLoops;
int id = 0;
for (CommandLoopManager.CommandLoop loop : loops) {
source.sendFeedback(Text.translatable("%s: %s (%s)", Text.literal(String.valueOf(id)), Text.literal(loop.command), Text.literal(String.valueOf(loop.interval))));
for (final CommandLoopManager.CommandLoop loop : loops) {
source.sendFeedback(Text.translatable("%s: %s (%s)", Text.literal(String.valueOf(id)), Text.literal(loop.command), Text.literal(String.valueOf(loop.interval))));
id++;
}

View file

@ -1,106 +1,105 @@
package land.chipmunk.chipmunkmod.commands;
import com.google.common.base.Suppliers;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import static com.mojang.brigadier.arguments.BoolArgumentType.bool;
import static com.mojang.brigadier.arguments.BoolArgumentType.getBool;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import land.chipmunk.chipmunkmod.util.TextUtilities;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.text.Text;
import net.minecraft.nbt.NbtCompound;
import java.util.concurrent.CompletableFuture;
import land.chipmunk.chipmunkmod.modules.CommandCore;
public class CoreCommand {
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("core")
.then(
literal("run")
.then(
argument("command", greedyString())
.executes(c -> run(c))
)
)
.then(
literal("runTracked")
.then(
argument("command", greedyString())
.executes(c -> runTracked(c))
)
)
.then(literal("refill").executes(c -> refill(c)))
.then(literal("move").executes(c -> move(c)))
.then(
literal("runFillCommand")
.then(
argument("enabled", bool())
.executes(c -> runFillCommand(c))
)
)
);
}
public static int run (CommandContext<FabricClientCommandSource> context) {
CommandCore.INSTANCE.run(getString(context, "command"));
return Command.SINGLE_SUCCESS;
}
public static int runTracked (CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final String command = getString(context, "command");
final CompletableFuture<NbtCompound> future = CommandCore.INSTANCE.runTracked(command);
future.thenApply(tag -> {
try {
final String output = tag.getString("LastOutput");
if (output != null) source.sendFeedback(TextUtilities.fromJson(output));
} catch (Exception e) {
e.printStackTrace();
}
return tag;
});
return Command.SINGLE_SUCCESS;
}
public static int refill (CommandContext<FabricClientCommandSource> context) {
CommandCore.INSTANCE.refill();
return Command.SINGLE_SUCCESS;
}
public static int move (CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
CommandCore.INSTANCE.move(source.getClient().player.getPos());
return Command.SINGLE_SUCCESS;
}
public static int runFillCommand(CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final boolean bool = getBool(context, "enabled");
CommandCore.INSTANCE.runFillCommand = bool;
source.sendFeedback(Text.literal("Running fill commands are now " + (bool ? "enabled" : "disabled")));
return Command.SINGLE_SUCCESS;
}
}
package land.chipmunk.chipmunkmod.commands;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import land.chipmunk.chipmunkmod.modules.CommandCore;
import land.chipmunk.chipmunkmod.util.TextUtilities;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.text.Text;
import java.util.concurrent.CompletableFuture;
import static com.mojang.brigadier.arguments.BoolArgumentType.bool;
import static com.mojang.brigadier.arguments.BoolArgumentType.getBool;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class CoreCommand {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("core")
.then(
literal("run")
.then(
argument("command", greedyString())
.executes(c -> run(c))
)
)
.then(
literal("runTracked")
.then(
argument("command", greedyString())
.executes(c -> runTracked(c))
)
)
.then(literal("refill").executes(c -> refill(c)))
.then(literal("move").executes(c -> move(c)))
.then(
literal("runFillCommand")
.then(
argument("enabled", bool())
.executes(c -> runFillCommand(c))
)
)
);
}
public static int run (final CommandContext<FabricClientCommandSource> context) {
CommandCore.INSTANCE.run(getString(context, "command"));
return Command.SINGLE_SUCCESS;
}
public static int runTracked (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final String command = getString(context, "command");
final CompletableFuture<NbtCompound> future = CommandCore.INSTANCE.runTracked(command);
future.thenApply(tag -> {
try {
final String output = tag.getString("LastOutput");
if (output != null) source.sendFeedback(TextUtilities.fromJson(output));
} catch (final Exception e) {
e.printStackTrace();
}
return tag;
});
return Command.SINGLE_SUCCESS;
}
public static int refill (final CommandContext<FabricClientCommandSource> context) {
CommandCore.INSTANCE.refill();
return Command.SINGLE_SUCCESS;
}
public static int move (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
CommandCore.INSTANCE.move(source.getClient().player.getPos());
return Command.SINGLE_SUCCESS;
}
public static int runFillCommand (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final boolean bool = getBool(context, "enabled");
CommandCore.INSTANCE.runFillCommand = bool;
source.sendFeedback(Text.literal("Running fill commands is now " + (bool ? "enabled" : "disabled")));
return Command.SINGLE_SUCCESS;
}
}

View file

@ -3,8 +3,10 @@ package land.chipmunk.chipmunkmod.commands;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import land.chipmunk.chipmunkmod.modules.CustomChat;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.modules.custom_chat.CustomChat;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minecraft.text.Text;
import static com.mojang.brigadier.arguments.BoolArgumentType.bool;
@ -15,15 +17,17 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class CustomChatCommand {
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
private static final GsonComponentSerializer GSON = GsonComponentSerializer.gson();
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("customchat")
.then(
literal("enabled")
.then(
argument("boolean", bool())
.executes(CustomChatCommand::enabled)
)
.then(
argument("boolean", bool())
.executes(CustomChatCommand::enabled)
)
)
.then(
literal("format")
@ -35,7 +39,7 @@ public class CustomChatCommand {
);
}
public static int enabled (CommandContext<FabricClientCommandSource> context) {
public static int enabled (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final boolean bool = getBool(context, "boolean");
CustomChat.INSTANCE.enabled = bool;
@ -44,10 +48,10 @@ public class CustomChatCommand {
return Command.SINGLE_SUCCESS;
}
public static int setFormat (CommandContext<FabricClientCommandSource> context) {
public static int setFormat (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final String format = getString(context, "format");
CustomChat.INSTANCE.format = format;
CustomChat.INSTANCE.format = GSON.deserializeOr(format, ChipmunkMod.CONFIG.customChat.format);
source.sendFeedback(Text.literal("Set the custom chat format to: " + format));
return Command.SINGLE_SUCCESS;

View file

@ -1,65 +0,0 @@
package land.chipmunk.chipmunkmod.commands;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import land.chipmunk.chipmunkmod.util.Debug;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import java.util.ArrayList;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
import static com.mojang.brigadier.arguments.StringArgumentType.string;
public class DebugCommand {
public static SuggestionProvider<FabricClientCommandSource> knownSuggestions = (context, builder) -> {
Debug.known.stream()
.filter(option -> option.startsWith(builder.getRemaining().toLowerCase()))
.forEach(builder::suggest);
return builder.buildFuture();
};
public static SuggestionProvider<FabricClientCommandSource> selectedSuggestions = (context, builder) -> {
Debug.selected.stream()
.filter(option -> option.startsWith(builder.getRemaining().toLowerCase()))
.forEach(builder::suggest);
return builder.buildFuture();
};
public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("debug")
.then(literal("add")
.then(argument("caller", string())
.suggests(knownSuggestions)
.executes(DebugCommand::add)))
.then(literal("remove")
.then(argument("caller", string())
.suggests(selectedSuggestions)
.executes(DebugCommand::remove)))
.then(literal("clear")
.executes(DebugCommand::clear))
);
}
public static int add(CommandContext<FabricClientCommandSource> context) {
String caller = context.getArgument("caller", String.class);
Debug.selected.add(caller);
context.getSource().sendFeedback(Text.literal("Added ").append(Text.literal(caller).formatted(Formatting.YELLOW)).append(Text.literal(" to the debug list!")));
return 0;
}
public static int remove(CommandContext<FabricClientCommandSource> context) {
String caller = context.getArgument("caller", String.class);
Debug.selected.remove(caller);
context.getSource().sendFeedback(Text.literal("Removed ").append(Text.literal(caller).formatted(Formatting.YELLOW)).append(Text.literal(" from the debug list!")));
return 0;
}
public static int clear(CommandContext<FabricClientCommandSource> context) {
Debug.selected = new ArrayList<>();
context.getSource().sendFeedback(Text.literal("Cleared the debug list!"));
return 0;
}
}

View file

@ -19,7 +19,7 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class EvalCommand {
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("eval")
.then(literal("java")
@ -47,10 +47,10 @@ public class EvalCommand {
globals.set("context", CoerceJavaToLua.coerce(context));
globals.set("class", CoerceJavaToLua.coerce(Class.class));
LuaValue chunk = globals.load(code);
final LuaValue chunk = globals.load(code);
context.getSource().sendFeedback(Text.literal(chunk.call().toString()).formatted(Formatting.GREEN));
} catch (Exception e) {
} catch (final Exception e) {
context.getSource().sendError(Text.literal(e.toString()));
}

View file

@ -4,21 +4,22 @@ import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
import static net.minecraft.command.argument.ItemStackArgumentType.itemStack;
import static net.minecraft.command.argument.ItemStackArgumentType.getItemStackArgument;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.client.MinecraftClient;
import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.item.ItemStack;
import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket;
import net.minecraft.text.Text;
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
import static net.minecraft.command.argument.ItemStackArgumentType.getItemStackArgument;
import static net.minecraft.command.argument.ItemStackArgumentType.itemStack;
public class ItemCommand {
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess commandRegistryAccess) {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher, final CommandRegistryAccess commandRegistryAccess) {
dispatcher.register(
literal("item")
.then(
@ -32,17 +33,17 @@ public class ItemCommand {
);
}
public static int setItem (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
public static int setItem (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
return setItem(context, getInteger(context, "count"));
}
public static int setItem (CommandContext<FabricClientCommandSource> context, int count) throws CommandSyntaxException {
public static int setItem (final CommandContext<FabricClientCommandSource> context, final int count) throws CommandSyntaxException {
final FabricClientCommandSource source = context.getSource();
final MinecraftClient client = source.getClient();
final ItemStack stack = getItemStackArgument(context, "item").createStack(count, false);
int slot = 36 + client.player.getInventory().selectedSlot;
final int slot = 36 + client.player.getInventory().selectedSlot;
client.getNetworkHandler().getConnection().send(new CreativeInventoryActionC2SPacket(slot, stack));

View file

@ -12,6 +12,7 @@ import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import land.chipmunk.chipmunkmod.modules.CommandCore;
public class KickCommand {
// All methods here are reverse engineered from bots or players who abused them.
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("kick")

View file

@ -8,12 +8,12 @@ import land.chipmunk.chipmunkmod.command.CommandManager;
import land.chipmunk.chipmunkmod.modules.SongPlayer;
import land.chipmunk.chipmunkmod.song.Song;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
@ -40,10 +40,10 @@ public class MusicCommand {
private static final SimpleCommandExceptionType OOB_TIMESTAMP = new SimpleCommandExceptionType(Text.translatable("Invalid timestamp for the current song"));
private static final SimpleCommandExceptionType DIRECTORY_DOES_NOT_EXIST = new SimpleCommandExceptionType(Text.translatable("The specified directory does not exist"));
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
final MusicCommand instance = new MusicCommand();
Path root = Path.of(SongPlayer.SONG_DIR.getPath());
final Path root = Path.of(SongPlayer.SONG_DIR.getPath());
dispatcher.register(
literal("music")
@ -111,7 +111,7 @@ public class MusicCommand {
);
}
public int play (CommandContext<FabricClientCommandSource> context) {
public int play (final CommandContext<FabricClientCommandSource> context) {
final SongPlayer songPlayer = SongPlayer.INSTANCE;
final Path path = getPath(context, "location");
@ -122,7 +122,7 @@ public class MusicCommand {
return 1;
}
public int stop (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
public int stop (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
final FabricClientCommandSource source = context.getSource();
final SongPlayer songPlayer = SongPlayer.INSTANCE;
@ -130,24 +130,24 @@ public class MusicCommand {
songPlayer.stopPlaying();
songPlayer.songQueue.clear();
source.sendFeedback(Text.literal("Stopped music playback").formatted(Formatting.GREEN));
source.sendFeedback(Text.literal("Stopped music playback").formatted(Formatting.WHITE));
return 1;
}
public int skip (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
public int skip (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
final FabricClientCommandSource source = context.getSource();
final SongPlayer songPlayer = SongPlayer.INSTANCE;
if (songPlayer.currentSong == null) throw NO_SONG_IS_CURRENTLY_PLAYING.create();
songPlayer.stopPlaying();
source.sendFeedback(Text.literal("Skipped the current song").formatted(Formatting.GREEN));
source.sendFeedback(Text.literal("Skipped the current song").formatted(Formatting.WHITE));
return 1;
}
public int pause (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
public int pause (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
final FabricClientCommandSource source = context.getSource();
final SongPlayer songPlayer = SongPlayer.INSTANCE;
final Song currentSong = songPlayer.currentSong;
@ -165,7 +165,7 @@ public class MusicCommand {
return 1;
}
public int list (Path path) throws CommandSyntaxException {
public int list (final Path path) throws CommandSyntaxException {
final CommandManager commandManager = CommandManager.INSTANCE;
final String prefix = commandManager.prefix;
@ -175,19 +175,20 @@ public class MusicCommand {
if (filenames == null) throw DIRECTORY_DOES_NOT_EXIST.create();
final Path root = Path.of(SongPlayer.SONG_DIR.getAbsoluteFile().getPath()).toAbsolutePath();
String relativePath;
if (path.getNameCount() - root.getNameCount() > 0) relativePath = path.subpath(root.getNameCount(), path.getNameCount()).toString();
final String relativePath;
if (path.getNameCount() - root.getNameCount() > 0)
relativePath = path.subpath(root.getNameCount(), path.getNameCount()).toString();
else relativePath = "";
final List<Component> directories = new ArrayList<>();
final List<Component> files = new ArrayList<>();
int i = 0;
for (String filename : filenames) {
for (final String filename : filenames) {
final File file = new File(directory, filename);
if (!file.isDirectory()) continue;
final NamedTextColor color = (i++ & 1) == 0 ? NamedTextColor.DARK_GREEN : NamedTextColor.GREEN;
final TextColor color = (i++ & 1) == 0 ? TextColor.fromHexString("#ffccee") : TextColor.fromHexString("#ff99dd");
final Path relativeFilepath = Path.of(relativePath, filename);
final String escapedPath = escapePath(relativeFilepath.toString());
@ -199,11 +200,11 @@ public class MusicCommand {
);
}
for (String filename : filenames) {
for (final String filename : filenames) {
final File file = new File(directory, filename);
if (file.isDirectory()) continue;
final NamedTextColor color = (i++ & 1) == 0 ? NamedTextColor.DARK_GREEN : NamedTextColor.GREEN;
final TextColor color = (i++ & 1) == 0 ? TextColor.fromHexString("#ffccee") : TextColor.fromHexString("#ff99dd");
final Path relativeFilepath = Path.of(relativePath, filename);
final String escapedPath = escapePath(relativeFilepath.toString());
@ -218,18 +219,18 @@ public class MusicCommand {
final ArrayList<Component> mergedList = new ArrayList<>();
mergedList.addAll(directories);
mergedList.addAll(files);
final Component component = Component.translatable("Songs - %s", Component.join(JoinConfiguration.separator(Component.space()), mergedList)).color(NamedTextColor.GREEN);
final Component component = Component.translatable("Songs - %s", Component.join(JoinConfiguration.separator(Component.space()), mergedList)).color(NamedTextColor.WHITE);
((Audience) MinecraftClient.getInstance().player).sendMessage(component);
MinecraftClient.getInstance().player.sendMessage(component);
return 1;
}
// TODO: Move this into some utility class, as it is more related to brigadier strings in general than to the list command in specific
private String escapePath (String path) {
private String escapePath (final String path) {
final StringBuilder sb = new StringBuilder("'");
for (char character : path.toCharArray()) {
for (final char character : path.toCharArray()) {
if (character == '\'' || character == '\\') sb.append('\\');
sb.append(character);
}
@ -238,7 +239,7 @@ public class MusicCommand {
return sb.toString();
}
public int toggleLoop (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
public int toggleLoop (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
final FabricClientCommandSource source = context.getSource();
final SongPlayer songPlayer = SongPlayer.INSTANCE;
final Song currentSong = songPlayer.currentSong;
@ -253,7 +254,7 @@ public class MusicCommand {
}
public int loop (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
public int loop (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
final FabricClientCommandSource source = context.getSource();
final SongPlayer songPlayer = SongPlayer.INSTANCE;
final Song currentSong = songPlayer.currentSong;
@ -269,7 +270,7 @@ public class MusicCommand {
return 1;
}
public int gotoCommand (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
public int gotoCommand (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
final FabricClientCommandSource source = context.getSource();
final SongPlayer songPlayer = SongPlayer.INSTANCE;
final Song currentSong = songPlayer.currentSong;
@ -281,12 +282,12 @@ public class MusicCommand {
currentSong.setTime(millis);
source.sendFeedback(Text.translatable("Set the current time of the song to %s", songPlayer.formatTime(millis)));
MinecraftClient.getInstance().player.sendMessage(Component.translatable("Set the current time of the song to %s", songPlayer.formatTime(millis)));
return 1;
}
public int useCore (CommandContext<FabricClientCommandSource> context) {
public int useCore (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final boolean enabled = getBool(context, "boolean");
@ -298,7 +299,7 @@ public class MusicCommand {
return 1;
}
public int actionbar (CommandContext<FabricClientCommandSource> context) {
public int actionbar (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final boolean enabled = getBool(context, "boolean");
@ -310,7 +311,7 @@ public class MusicCommand {
return 1;
}
public int pitch (CommandContext<FabricClientCommandSource> context) {
public int pitch (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final float pitch = getFloat(context, "pitch");
@ -321,7 +322,7 @@ public class MusicCommand {
Text.translatable(
"Set the pitch to: %s",
Text.literal(String.valueOf(pitch))
).formatted(Formatting.GREEN)
).formatted(Formatting.WHITE)
);
return 1;

View file

@ -15,7 +15,7 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class RainbowNameCommand {
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("rainbowname")
.then(
@ -35,7 +35,7 @@ public class RainbowNameCommand {
);
}
public static int enabled (CommandContext<FabricClientCommandSource> context) {
public static int enabled (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final boolean bool = getBool(context, "boolean");
@ -51,7 +51,7 @@ public class RainbowNameCommand {
return Command.SINGLE_SUCCESS;
}
public static int setName (CommandContext<FabricClientCommandSource> context) {
public static int setName (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
final String name = getString(context, "name");

View file

@ -5,7 +5,6 @@ import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.modules.CommandCore;
import land.chipmunk.chipmunkmod.modules.CustomChat;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.text.Text;
@ -14,24 +13,22 @@ import java.io.IOException;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class ReloadConfigCommand {
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("reloadconfig")
.executes(ReloadConfigCommand::reload)
);
}
public static int reload(CommandContext<FabricClientCommandSource> context) {
public static int reload (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
try {
ChipmunkMod.CONFIG = ChipmunkMod.loadConfig();
CustomChat.INSTANCE.reloadFormat();
CommandCore.INSTANCE.reloadRelativeArea();
source.sendFeedback(Text.literal("Successfully reloaded the config"));
} catch (IOException e) {
} catch (final IOException e) {
source.sendError(Text.literal("Could not load config, check the logs for stacktrace"));
e.printStackTrace();
}

View file

@ -12,7 +12,7 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class SayCommand {
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("say")
.then(
@ -22,7 +22,7 @@ public class SayCommand {
);
}
public static int say (CommandContext<FabricClientCommandSource> context) {
public static int say (final CommandContext<FabricClientCommandSource> context) {
Chat.sendChatMessage(getString(context, "message"), true);
return Command.SINGLE_SUCCESS;

View file

@ -2,20 +2,10 @@ package land.chipmunk.chipmunkmod.commands;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.modules.SelfCare;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.text.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import static com.mojang.brigadier.arguments.BoolArgumentType.bool;
import static com.mojang.brigadier.arguments.BoolArgumentType.getBool;
@ -23,9 +13,7 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class SelfCareCommand {
private static final Logger log = LoggerFactory.getLogger(SelfCareCommand.class);
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("selfcare")
.then(
@ -49,18 +37,10 @@ public class SelfCareCommand {
.executes(m -> setSelfCare(m, "cspy"))
)
)
.then(
literal("icu")
.then(
argument("boolean", bool())
.executes(m -> setSelfCare(m, "icu"))
)
)
);
}
// setSelfCare is probably not a good name for this
public static int setSelfCare (CommandContext<FabricClientCommandSource> context, String type) {
public static int setSelfCare (final CommandContext<FabricClientCommandSource> context, final String type) {
final FabricClientCommandSource source = context.getSource();
final boolean bool = getBool(context, "boolean");
@ -77,10 +57,6 @@ public class SelfCareCommand {
SelfCare.INSTANCE.cspyEnabled = bool;
source.sendFeedback(Text.literal("The CommandSpy self care is now " + (bool ? "enabled" : "disabled")));
}
case "icu" -> {
SelfCare.INSTANCE.icuEnabled = bool;
source.sendFeedback(Text.literal("The iControlU self care is now " + (bool ? "enabled" : "disabled")));
}
}
return Command.SINGLE_SUCCESS;

View file

@ -1,24 +1,25 @@
package land.chipmunk.chipmunkmod.commands;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.text.Text;
public class TestCommand {
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("test")
.executes(c -> helloWorld(c))
);
}
public static int helloWorld (CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
source.sendFeedback(Text.literal("Hello, world!"));
return Command.SINGLE_SUCCESS;
}
}
package land.chipmunk.chipmunkmod.commands;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.text.Text;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class TestCommand {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("test")
.executes(c -> helloWorld(c))
);
}
public static int helloWorld (final CommandContext<FabricClientCommandSource> context) {
final FabricClientCommandSource source = context.getSource();
source.sendFeedback(Text.literal("Hello, world!"));
return Command.SINGLE_SUCCESS;
}
}

View file

@ -1,61 +1,100 @@
package land.chipmunk.chipmunkmod.commands;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.util.SharedVariables;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.TitleScreen;
import net.minecraft.client.gui.screen.multiplayer.ConnectScreen;
import net.minecraft.client.network.ServerInfo;
import net.minecraft.client.network.ServerAddress;
import net.minecraft.client.session.Session;
import net.minecraft.text.Text;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import java.util.Optional;
import land.chipmunk.chipmunkmod.mixin.MinecraftClientAccessor;
public class UsernameCommand {
private static final SimpleCommandExceptionType USERNAME_TOO_LONG = new SimpleCommandExceptionType(Text.translatable("The specified username is longer than 16 characters"));
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("username")
.then(
literal("set")
.then(
argument("username", greedyString())
.executes(c -> updateUsername(c))
)
)
);
}
public static int updateUsername (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
final String username = getString(context, "username");
if (username.length() > 16) throw USERNAME_TOO_LONG.create();
return updateSession(context, username);
}
public static int updateSession (CommandContext<FabricClientCommandSource> context, String username) throws CommandSyntaxException {
final FabricClientCommandSource source = context.getSource();
final MinecraftClient client = source.getClient();
// TODO: Put this in a separate class
final ServerInfo info = client.getCurrentServerEntry();
client.world.disconnect();
client.disconnect();
ConnectScreen.connect(new TitleScreen(), client, ServerAddress.parse(info.address), info, false, null);
return Command.SINGLE_SUCCESS;
}
}
package land.chipmunk.chipmunkmod.commands;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import land.chipmunk.chipmunkmod.mixin.ClientCommonNetworkHandlerAccessor;
import land.chipmunk.chipmunkmod.mixin.MinecraftClientAccessor;
import land.chipmunk.chipmunkmod.util.RandomUtilities;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.TitleScreen;
import net.minecraft.client.gui.screen.multiplayer.ConnectScreen;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ServerAddress;
import net.minecraft.client.network.ServerInfo;
import net.minecraft.client.session.Session;
import net.minecraft.network.ClientConnection;
import net.minecraft.text.Text;
import net.minecraft.util.Uuids;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
public class UsernameCommand {
private static final SimpleCommandExceptionType USERNAME_TOO_LONG = new SimpleCommandExceptionType(Text.translatable("The specified username is longer than 16 characters"));
private static final char[] PREMIUM_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"
.toCharArray();
private static final char SECTION_CHAR = '§';
private static final Session ORIGINAL_SESSION = MinecraftClient.getInstance().getSession();
private static final Random RANDOM = new Random();
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(literal("username")
.then(literal("set")
.then(argument("username", greedyString())
.executes(c -> changeOffline(c, getString(c, "username")))))
.then(literal("revert")
.executes(c -> changeSession(c, ORIGINAL_SESSION)))
.then(literal("random")
.then(literal("blank")
.executes(c -> changeOffline(c, RandomUtilities.emptyUsername(RANDOM, SECTION_CHAR))))
.executes(c -> changeOffline(c, RandomUtilities.randomString(RANDOM, PREMIUM_CHARS, RANDOM.nextInt(3, 16)))))
.then(literal("empty")
.executes(c -> changeOffline(c, "")))
);
}
private static Session offline (final String username) {
// This is how Minecraft's Main class does it
return new Session(username, Uuids.getOfflinePlayerUuid(username),
"", Optional.empty(), Optional.empty(), Session.AccountType.LEGACY);
}
// TODO: Put this in a separate class
private static void reconnect (final MinecraftClient client) {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) return; // single-player?
final ServerInfo info = networkHandler.getServerInfo();
if (info == null) return; // definitely single-player
final ClientConnection connection = networkHandler.getConnection();
final Screen screen = Objects.requireNonNullElseGet(
((ClientCommonNetworkHandlerAccessor) networkHandler).getPostDisconnectScreen(),
TitleScreen::new);
// This stuff needs to run after we close chat, otherwise it kicks us to the title screen. Don't ask me why
client.send(() -> {
connection.disconnect(Text.translatable("disconnect.transfer"));
connection.tryDisableAutoRead();
connection.handleDisconnection();
ConnectScreen.connect(screen, client, ServerAddress.parse(info.address), info, false, null);
});
}
private static int changeSession (final CommandContext<FabricClientCommandSource> context, final Session session) {
final MinecraftClient client = context.getSource().getClient();
((MinecraftClientAccessor) client).session(session);
reconnect(client);
return Command.SINGLE_SUCCESS;
}
private static int changeOffline (final CommandContext<FabricClientCommandSource> context, final String username) throws CommandSyntaxException {
if (username.length() > 16) throw USERNAME_TOO_LONG.create();
return changeSession(context, offline(username));
}
}

View file

@ -1,32 +1,27 @@
package land.chipmunk.chipmunkmod.commands;
import com.mojang.brigadier.CommandDispatcher;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.text.Text;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
import static land.chipmunk.chipmunkmod.util.BotValidationUtilities.*;
public class ValidateCommand {
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("validate")
.then(literal("hbot").then(argument("command", greedyString()).executes(c -> hbot(getString(c, "command")))))
.then(literal("ubot").then(argument("command", greedyString()).executes(c -> ubot(getString(c, "command")))))
.then(literal("ubotdev").then(argument("command", greedyString()).executes(c -> ubotdev(getString(c, "command")))))
.then(literal("sbot").then(argument("command", greedyString()).executes(c -> sbot(getString(c, "command")))))
// .then(literal("chipmunk").then(argument("command", greedyString()).executes(c -> chipmunk(getString(c, "command")))))
.then(literal("chomens").then(argument("command", greedyString()).executes(c -> {
c.getSource().sendFeedback(Text.literal("Warning: Manual ChomeNS Bot validation is deprecated. Please use the completions from typing the bot's prefix."));
return chomens(getString(c, "command"));
})))
.then(literal("fnfboyfriend").then(argument("command", greedyString()).executes(c -> fnfboyfriend(getString(c, "command")))))
.then(literal("nbot").then(argument("command", greedyString()).executes(c -> nbot(getString(c, "command")))))
.then(literal("kittycorp").then(argument("command", greedyString()).executes(c -> kittycorp(getString(c, "command")))))
);
}
}
package land.chipmunk.chipmunkmod.commands;
import com.mojang.brigadier.CommandDispatcher;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
import static land.chipmunk.chipmunkmod.util.BotValidationUtilities.*;
public class ValidateCommand {
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(
literal("validate")
.then(literal("hbot").then(argument("command", greedyString()).executes(c -> hbot(getString(c, "command")))))
.then(literal("ubot").then(argument("command", greedyString()).executes(c -> ubot(getString(c, "command")))))
.then(literal("ubotdev").then(argument("command", greedyString()).executes(c -> ubotdev(getString(c, "command")))))
.then(literal("sbot").then(argument("command", greedyString()).executes(c -> sbot(getString(c, "command")))))
// .then(literal("chipmunk").then(argument("command", greedyString()).executes(c -> chipmunk(getString(c, "command")))))
.then(literal("chomens").then(argument("command", greedyString()).executes(c -> chomens(getString(c, "command")))))
.then(literal("nbot").then(argument("command", greedyString()).executes(c -> nbot(getString(c, "command")))))
.then(literal("kittycorp").then(argument("command", greedyString()).executes(c -> kittycorp(getString(c, "command")))))
);
}
}

View file

@ -0,0 +1,18 @@
package land.chipmunk.chipmunkmod.config;
import land.chipmunk.chipmunkmod.config.migration.AbstractMigrationManager;
import land.chipmunk.chipmunkmod.config.migrations.MigrationV0;
import land.chipmunk.chipmunkmod.config.migrations.MigrationV1;
import land.chipmunk.chipmunkmod.config.migrations.MigrationV2;
import land.chipmunk.chipmunkmod.config.migrations.MigrationV3;
public final class ChipmunkModMigrations extends AbstractMigrationManager {
public ChipmunkModMigrations () {
super("version");
this.register(new MigrationV0()); // unversioned -> v0
this.register(new MigrationV1());
this.register(new MigrationV2());
this.register(new MigrationV3());
}
}

View file

@ -0,0 +1,98 @@
package land.chipmunk.chipmunkmod.config;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.BlockPos;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
@ConfigSerializable
public class Configuration {
public CommandManager commands = new CommandManager();
public CommandCore core = new CommandCore();
public Bots bots = new Bots();
public CustomChat customChat = new CustomChat();
public SelfCare selfCare = new SelfCare();
public String autoSkinUsername = "off";
@ConfigSerializable
public static class CommandManager {
public String prefix = ".";
}
@ConfigSerializable
public static class CommandCore {
public BlockBox relativeArea = BlockBox.create(new BlockPos(0, 0, 0), new BlockPos(15, 0, 15));
}
@ConfigSerializable
public static class Bots {
public BotInfo hbot = new BotInfo("#", null);
public BotInfo sbot = new BotInfo(":", null);
public BotInfo ubot = new BotInfo("\"", null);
public BotInfo ubotdev = new BotInfo("d\"", null);
public BotInfo chipmunk = new BotInfo("'", null);
public BotInfo chomens = new BotInfo("*", null);
public BotInfo nbot = new BotInfo("?", null);
public BotInfo kittycorp = new BotInfo("^", null);
public TestBotInfo testbot = new TestBotInfo("-", null);
}
@ConfigSerializable
public static class TestBotInfo {
public String prefix;
public @Nullable String webhookUrl;
public TestBotInfo () {
}
public TestBotInfo (final String prefix, @Nullable final String webhookUrl) {
this.prefix = prefix;
this.webhookUrl = webhookUrl;
}
}
@ConfigSerializable
public static class BotInfo {
public String prefix;
public @Nullable String key;
public BotInfo () {
}
public BotInfo (final String prefix, @Nullable final String key) {
this.prefix = prefix;
this.key = key;
}
}
@ConfigSerializable
public static class SelfCare {
public boolean cspy = true;
public boolean gameMode = true;
public boolean op = true;
}
@ConfigSerializable
public static class CustomChat {
public @NotNull Component format = // From amyavi
Component.translatable("[%s] %s %s", TextColor.fromHexString("#ff99dd"),
Component.text("ChipmunkMod", TextColor.fromHexString("#ffccee"))
.hoverEvent(HoverEvent.showText(
Component.text("Click here to open the ChipmunkMod source code (7cc5c4f330d47060's fork)",
NamedTextColor.WHITE)))
.clickEvent(ClickEvent.openUrl("https://code.chipmunk.land/7cc5c4f330d47060/chipmunkmod")),
Component.selector("@s").color(TextColor.fromHexString("#ffccee")),
Component.text("MESSAGE", NamedTextColor.WHITE)
.hoverEvent(HoverEvent.showText(
Component.text("Click here to copy the message",
NamedTextColor.WHITE)))
.clickEvent(ClickEvent.copyToClipboard("MESSAGE"))
);
}
}

View file

@ -0,0 +1,16 @@
package land.chipmunk.chipmunkmod.config;
import land.chipmunk.chipmunkmod.config.migration.AbstractMigrationManager;
import land.chipmunk.chipmunkmod.config.migrations.MigrationName3V0;
import land.chipmunk.chipmunkmod.config.migrations.MigrationName3V1;
import land.chipmunk.chipmunkmod.config.migrations.MigrationName3V2;
public final class Name3ModMigrations extends AbstractMigrationManager {
public Name3ModMigrations() {
super("version_name3");
this.register(new MigrationName3V0()); // unversioned -> v0
this.register(new MigrationName3V1());
this.register(new MigrationName3V2());
}
}

View file

@ -0,0 +1,63 @@
package land.chipmunk.chipmunkmod.config.migration;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
// Makes it easier for forks to add their own config versioning structure
public abstract class AbstractMigrationManager {
private final List<ConfigMigration> migrations = new ArrayList<>();
private final Object[] versionKey;
public AbstractMigrationManager (final Object... versionKey) {
this.versionKey = versionKey;
}
protected void register (final ConfigMigration migration) {
this.migrations.add(migration);
}
protected void registerFrom (final int version, final Supplier<ConfigurationTransformation> supplier) {
this.migrations.add(ConfigMigration.from(version, supplier));
}
public ConfigurationTransformation.Versioned create () {
final ConfigurationTransformation.VersionedBuilder builder = ConfigurationTransformation.versionedBuilder()
.versionKey(versionKey);
this.migrations.forEach(migration -> builder.addVersion(migration.version(), migration.create()));
return builder.build();
}
public <N extends ConfigurationNode> void setLatest (final N config) throws ConfigurateException {
final ConfigurationTransformation.Versioned transforms = this.create();
config.node(transforms.versionKey()).set(Integer.class, transforms.latestVersion());
}
public <N extends ConfigurationNode> boolean migrate (final N config) throws ConfigurateException {
final ConfigurationTransformation.Versioned transforms = this.create();
final int version = transforms.version(config);
if (version > transforms.latestVersion()) {
ChipmunkMod.LOGGER.warn("Latest config version is {}, but yours is {}! Are you from the future?",
transforms.latestVersion(), version);
return false;
}
transforms.apply(config);
final int newVersion = transforms.version(config);
if (version != newVersion) {
ChipmunkMod.LOGGER.info("Migrated config from version {} to {}!", version, newVersion);
return true;
}
return false;
}
}

View file

@ -0,0 +1,22 @@
package land.chipmunk.chipmunkmod.config.migration;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import java.util.function.Supplier;
public interface ConfigMigration {
static ConfigMigration from (final int version, final Supplier<ConfigurationTransformation> supplier) {
return new ConfigMigrationImpl(version, supplier);
}
int version ();
ConfigurationTransformation create ();
record ConfigMigrationImpl(int version, Supplier<ConfigurationTransformation> supplier) implements ConfigMigration {
@Override
public ConfigurationTransformation create () {
return this.supplier.get();
}
}
}

View file

@ -0,0 +1,21 @@
package land.chipmunk.chipmunkmod.config.migrations;
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import org.spongepowered.configurate.transformation.TransformAction;
import static org.spongepowered.configurate.NodePath.path;
public final class MigrationName3V0 implements ConfigMigration {
@Override
public int version() {
return 0;
}
@Override
public ConfigurationTransformation create() {
return ConfigurationTransformation.builder()
.addAction(path("testbotWebhook"), TransformAction.remove())
.build();
}
}

View file

@ -0,0 +1,21 @@
package land.chipmunk.chipmunkmod.config.migrations;
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import org.spongepowered.configurate.transformation.TransformAction;
import static org.spongepowered.configurate.NodePath.path;
public final class MigrationName3V1 implements ConfigMigration {
@Override
public int version() {
return 1;
}
@Override
public ConfigurationTransformation create() {
return ConfigurationTransformation.builder()
.addAction(path("bots", "fnfboyfriend"), TransformAction.remove())
.build();
}
}

View file

@ -0,0 +1,21 @@
package land.chipmunk.chipmunkmod.config.migrations;
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import org.spongepowered.configurate.transformation.TransformAction;
import static org.spongepowered.configurate.NodePath.path;
public final class MigrationName3V2 implements ConfigMigration {
@Override
public int version() {
return 2;
}
@Override
public ConfigurationTransformation create() {
return ConfigurationTransformation.builder()
.addAction(path("bots", "qilk"), TransformAction.remove())
.build();
}
}

View file

@ -0,0 +1,21 @@
package land.chipmunk.chipmunkmod.config.migrations;
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import org.spongepowered.configurate.transformation.TransformAction;
import static org.spongepowered.configurate.NodePath.path;
public final class MigrationV0 implements ConfigMigration {
@Override
public int version () {
return 0;
}
@Override
public ConfigurationTransformation create () {
return ConfigurationTransformation.builder()
.addAction(path("fullbright"), TransformAction.remove())
.build();
}
}

View file

@ -0,0 +1,66 @@
package land.chipmunk.chipmunkmod.config.migrations;
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
import land.chipmunk.chipmunkmod.util.configurate.ConfigurateUtilities;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.SelectorComponent;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.renderer.TranslatableComponentRenderer;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import java.util.List;
import static org.spongepowered.configurate.NodePath.path;
public final class MigrationV1 implements ConfigMigration {
@Override
public int version () {
return 1;
}
@Override
public ConfigurationTransformation create () {
return ConfigurationTransformation.builder()
.addAction(path("customChat", "format"),
ConfigurateUtilities.componentTransformer(new CustomChatFormatMigrator(), null))
.build();
}
private static final class CustomChatFormatMigrator extends TranslatableComponentRenderer<Void> {
@Override
protected @NotNull Component renderSelector (final @NotNull SelectorComponent component,
final @NotNull Void context) {
final String pattern = component.pattern();
if (pattern.equals("USERNAME") || pattern.equals("UUID")) {
final SelectorComponent.Builder builder = Component.selector()
.pattern("@s");
return this.mergeStyleAndOptionallyDeepRender(component, builder, context);
}
return super.renderSelector(component, context);
}
// Older configs had things like: `{ "text": "", "extra": ["MESSAGE"] }`
// We don't need that anymore, transform it to `{ "text": "MESSAGE" }`
@Override
protected @NotNull Component renderText (@NotNull final TextComponent component, @NotNull final Void context) {
if (!component.content().isEmpty() || component.children().size() != 1) {
return super.renderText(component, context);
}
final Component onlyChild = component.children().getFirst();
if (!onlyChild.equals(Component.text("MESSAGE"))) {
return super.renderText(component, context);
}
final Component newComponent = component
.children(List.of()); // Clear children
final TextComponent.Builder builder = Component.text()
.content("MESSAGE");
return this.mergeStyleAndOptionallyDeepRender(newComponent, builder, context);
}
}
}

View file

@ -0,0 +1,21 @@
package land.chipmunk.chipmunkmod.config.migrations;
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import org.spongepowered.configurate.transformation.TransformAction;
import static org.spongepowered.configurate.NodePath.path;
public class MigrationV2 implements ConfigMigration {
@Override
public int version () {
return 2;
}
@Override
public ConfigurationTransformation create () {
return ConfigurationTransformation.builder()
.addAction(path("bots", "chomens", "authKey"), TransformAction.remove())
.build();
}
}

View file

@ -0,0 +1,21 @@
package land.chipmunk.chipmunkmod.config.migrations;
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import org.spongepowered.configurate.transformation.TransformAction;
import static org.spongepowered.configurate.NodePath.path;
public class MigrationV3 implements ConfigMigration {
@Override
public int version () {
return 3;
}
@Override
public ConfigurationTransformation create () {
return ConfigurationTransformation.builder()
.addAction(path("bots", "chomens", "formatKey"), TransformAction.remove())
.build();
}
}

View file

@ -1,14 +0,0 @@
package land.chipmunk.chipmunkmod.data;
import net.minecraft.util.math.BlockPos;
// ? Am I reinventing the wheel here?
public class BlockArea {
public BlockPos start;
public BlockPos end;
public BlockArea (BlockPos start, BlockPos end) {
this.start = start;
this.end = end;
}
}

View file

@ -1,25 +1,56 @@
package land.chipmunk.chipmunkmod.data;
import java.util.ArrayList;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.util.TextUtilities;
import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
public class ChomeNSBotCommand {
public final String name;
public final TrustLevel trustLevel;
public final List<String> aliases = new ArrayList<>();
public record ChomeNSBotCommand(String name, TrustLevel trustLevel, List<String> aliases) {
public static @Nullable ChomeNSBotCommand fromText (final Text component) {
final String name = TextUtilities.plainOrNull(component);
if (name == null) return null;
public ChomeNSBotCommand (
String name,
TrustLevel trustLevel
) {
this.name = name;
this.trustLevel = trustLevel;
final List<Text> children = component.getSiblings();
if (children.size() < 2) return null; // must have at least trust level and alias boolean
final TrustLevel trustLevel = TrustLevel.fromText(children.getFirst());
if (trustLevel == null) return null;
final String hasAliasesString = TextUtilities.plainOrNull(children.get(1));
if (hasAliasesString == null) return null;
final boolean hasAliases = Boolean.parseBoolean(hasAliasesString);
if (!hasAliases) return new ChomeNSBotCommand(
ChipmunkMod.CONFIG.bots.chomens.prefix + name, trustLevel, List.of());
final List<String> aliases = children.stream()
.skip(2)
.map(TextUtilities::plainOrNull)
.filter(Objects::nonNull)
.toList();
return new ChomeNSBotCommand(
ChipmunkMod.CONFIG.bots.chomens.prefix + name, trustLevel, aliases);
}
public enum TrustLevel {
PUBLIC,
TRUSTED,
ADMIN,
OWNER
OWNER;
public static TrustLevel fromText (final Text component) {
final String trustLevelString = TextUtilities.plainOrNull(component);
if (trustLevelString == null) return null;
try {
return TrustLevel.valueOf(trustLevelString);
} catch (final IllegalArgumentException ignored) {
}
return null;
}
}
}

View file

@ -11,14 +11,14 @@ public class MutablePlayerListEntry {
public int latency;
public Text displayName;
public MutablePlayerListEntry(GameProfile profile, GameMode gamemode, int latency, Text displayName) {
public MutablePlayerListEntry (final GameProfile profile, final GameMode gamemode, final int latency, final Text displayName) {
this.profile = profile;
this.gamemode = gamemode;
this.latency = latency;
this.displayName = displayName;
}
public MutablePlayerListEntry (PlayerListS2CPacket.Entry entry) {
public MutablePlayerListEntry (final PlayerListS2CPacket.Entry entry) {
this(entry.profile(), entry.gameMode(), entry.latency(), entry.displayName());
}
}

View file

@ -2,15 +2,20 @@ package land.chipmunk.chipmunkmod.listeners;
import net.minecraft.network.packet.Packet;
import net.minecraft.text.Text;
import net.minecraft.util.math.Vec3d;
public class Listener {
public void chatMessageReceived (Text message) {}
public interface Listener {
default void packetReceived (final Packet<?> packet) { }
public void packetReceived (Packet<?> packet) {}
default void packetSent (final Packet<?> packet) { }
public void packetSent (Packet<?> packet) {}
default void chatMessageReceived (final Text message) { }
public void coreReady () {}
default void overlayMessageReceived (final Text message) { }
public void coreMoved () {}
default void coreReady () { }
default void coreMoved () { }
default void positionChanged (final Vec3d newPosition) { }
}

View file

@ -6,7 +6,7 @@ import java.util.List;
public class ListenerManager {
public static List<Listener> listeners = new ArrayList<>();
public static void addListener (Listener listener) {
public static void addListener (final Listener listener) {
listeners.add(listener);
}
}

View file

@ -1,78 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import land.chipmunk.chipmunkmod.modules.RainbowName;
import land.chipmunk.chipmunkmod.util.Debug;
import land.chipmunk.chipmunkmod.util.Executor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.hud.ChatHudLine;
import net.minecraft.client.gui.hud.MessageIndicator;
import net.minecraft.network.message.MessageSignatureData;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
import net.minecraft.util.Nullables;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(net.minecraft.client.gui.hud.ChatHud.class)
public abstract class ChatHudMixin {
@Shadow
public abstract void addMessage(Text message, @Nullable MessageSignatureData signature, @Nullable MessageIndicator indicator);
@Shadow @Final private MinecraftClient client;
@Shadow @Final private static Logger LOGGER;
@Shadow protected abstract void logChatMessage(ChatHudLine message);
@Shadow protected abstract void addVisibleMessage(ChatHudLine message);
@Shadow protected abstract void addMessage(ChatHudLine message);
@Unique
private void customLogChatMessage(ChatHudLine message) {
String string = message.content().getString().replaceAll("\r", "\\\\r").replaceAll("\n", "\\\\n");
String string2 = Nullables.map(message.indicator(), MessageIndicator::loggedName);
if (string2 != null) {
LOGGER.info("[{}] [CHAT] {}", string2, string);
} else {
LOGGER.info("[CHAT] {}", string);
}
}
@Inject(at = @At("HEAD"), method = "addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;Lnet/minecraft/client/gui/hud/MessageIndicator;)V", cancellable = true)
public void chipmunkmod$generalAddMessageMixin(Text message, MessageSignatureData signatureData, MessageIndicator indicator, CallbackInfo ci) {
ChatHudLine chatHudLine = new ChatHudLine(this.client.inGameHud.getTicks(), message, signatureData, indicator);
try {
if (RainbowName.INSTANCE.enabled) {
if (message.getString().contains("Your nickname is now ") || message.getString().contains("Nickname changed.")) {
ci.cancel();
return;
}
}
if (((TranslatableTextContent) message.getContent()).getKey().equals("advMode.setCommand.success")) {
ci.cancel();
return;
}
} catch (ClassCastException ignored) {}
for (Listener listener : ListenerManager.listeners) {
listener.chatMessageReceived(message);
}
customLogChatMessage(chatHudLine);
addVisibleMessage(chatHudLine);
addMessage(chatHudLine);
ci.cancel();
}
}

View file

@ -1,98 +1,101 @@
package land.chipmunk.chipmunkmod.mixin;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.command.CommandManager;
import land.chipmunk.chipmunkmod.modules.ChomeNSBotCommandSuggestions;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.command.CommandSource;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Mixin(net.minecraft.client.gui.screen.ChatInputSuggestor.class)
public class ChatInputSuggestorMixin {
@Shadow
private CompletableFuture<Suggestions> pendingSuggestions;
@Shadow
public void show (boolean narrateFirstSuggestion) {}
@Shadow
private static int getStartOfCurrentWord (String input) {
return 0;
}
@Mutable
@Final
@Shadow
final TextFieldWidget textField;
public ChatInputSuggestorMixin () {
textField = null;
}
@Inject(at = @At("TAIL"), method = "refresh()V")
public void refresh (CallbackInfo ci) {
final CommandManager commandManager = CommandManager.INSTANCE;
final String text = this.textField.getText();
final int cursor = this.textField.getCursor();
final ClientPlayerEntity player = MinecraftClient.getInstance().player;
final String chomeNSPrefix = ChipmunkMod.CONFIG.bots.chomens.prefix;
if (!text.contains(" ") && text.startsWith(chomeNSPrefix) && player != null) {
final String textUpToCursor = text.substring(0, cursor);
final List<String> commands = ChomeNSBotCommandSuggestions.INSTANCE.commands
.stream()
.map((command) -> command.name)
.toList();
pendingSuggestions = CommandSource.suggestMatching(
commands,
new SuggestionsBuilder(
textUpToCursor,
getStartOfCurrentWord(textUpToCursor)
)
);
pendingSuggestions.thenRun(() -> {
if (!pendingSuggestions.isDone()) return;
show(true);
});
} else if (cursor >= commandManager.prefix.length() && text.startsWith(commandManager.prefix)) {
final StringReader reader = new StringReader(text);
reader.setCursor(commandManager.prefix.length()); // Skip the prefix
final MinecraftClient client = MinecraftClient.getInstance();
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) return;
final CommandDispatcher<FabricClientCommandSource> dispatcher = commandManager.dispatcher;
final FabricClientCommandSource commandSource = (FabricClientCommandSource) networkHandler.getCommandSource();
pendingSuggestions = dispatcher.getCompletionSuggestions(dispatcher.parse(reader, commandSource), cursor);
show(true);
}
}
}
package land.chipmunk.chipmunkmod.mixin;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.command.CommandManager;
import land.chipmunk.chipmunkmod.data.ChomeNSBotCommand;
import land.chipmunk.chipmunkmod.modules.ChomeNSBotCommandSuggestions;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.command.CommandSource;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Mixin(net.minecraft.client.gui.screen.ChatInputSuggestor.class)
public class ChatInputSuggestorMixin {
@Mutable
@Final
@Shadow
final TextFieldWidget textField;
@Shadow
private CompletableFuture<Suggestions> pendingSuggestions;
public ChatInputSuggestorMixin () {
textField = null;
}
@Shadow
private static int getStartOfCurrentWord (final String input) {
return 0;
}
@Shadow
public void show (final boolean narrateFirstSuggestion) {
}
@Inject(at = @At("TAIL"), method = "refresh()V")
public void refresh (final CallbackInfo ci) {
final CommandManager commandManager = CommandManager.INSTANCE;
if (this.textField == null) return;
final String text = this.textField.getText();
final int cursor = this.textField.getCursor();
final ClientPlayerEntity player = MinecraftClient.getInstance().player;
final String chomeNSPrefix = ChipmunkMod.CONFIG.bots.chomens.prefix;
if (!text.contains(" ") && text.startsWith(chomeNSPrefix) && player != null) {
final String textUpToCursor = text.substring(0, cursor);
final List<String> commands = ChomeNSBotCommandSuggestions.INSTANCE.commands
.stream()
.map(ChomeNSBotCommand::name)
.toList();
pendingSuggestions = CommandSource.suggestMatching(
commands,
new SuggestionsBuilder(
textUpToCursor,
getStartOfCurrentWord(textUpToCursor)
)
);
pendingSuggestions.thenRun(() -> {
if (!pendingSuggestions.isDone()) return;
show(true);
});
} else if (cursor >= commandManager.prefix.length() && text.startsWith(commandManager.prefix)) {
final StringReader reader = new StringReader(text);
reader.setCursor(commandManager.prefix.length()); // Skip the prefix
final MinecraftClient client = MinecraftClient.getInstance();
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) return;
final CommandDispatcher<FabricClientCommandSource> dispatcher = commandManager.dispatcher;
final FabricClientCommandSource commandSource = (FabricClientCommandSource) networkHandler.getCommandSource();
pendingSuggestions = dispatcher.getCompletionSuggestions(dispatcher.parse(reader, commandSource), cursor);
show(true);
}
}
}

View file

@ -1,127 +1,116 @@
package land.chipmunk.chipmunkmod.mixin;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.data.ChomeNSBotCommand;
import land.chipmunk.chipmunkmod.modules.ChomeNSBotCommandSuggestions;
import land.chipmunk.chipmunkmod.util.BotValidationUtilities;
import land.chipmunk.chipmunkmod.util.Executor;
import land.chipmunk.chipmunkmod.util.Webhook;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ChatInputSuggestor;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Mixin(value = net.minecraft.client.gui.screen.ChatScreen.class)
public class ChatScreenMixin extends Screen {
@Shadow protected TextFieldWidget chatField;
@Shadow private String originalChatText;
@Shadow ChatInputSuggestor chatInputSuggestor;
@Shadow private int messageHistoryIndex = -1;
public ChatScreenMixin(String originalChatText) {
super(Text.translatable("chat_screen.title"));
this.originalChatText = originalChatText;
}
@Inject(at = @At("TAIL"), method = "init", cancellable = true)
public void init (CallbackInfo ci) {
final MinecraftClient client = MinecraftClient.getInstance();
this.messageHistoryIndex = client.inGameHud.getChatHud().getMessageHistory().size();
this.chatField = new TextFieldWidget(client.advanceValidatingTextRenderer, 4, this.height - 12, this.width - 4, 12, Text.translatable("chat.editBox")) {
protected MutableText getNarrationMessage() {
return super.getNarrationMessage().append(ChatScreenMixin.this.chatInputSuggestor.getNarration());
}
};
this.chatField.setMaxLength(Integer.MAX_VALUE);
this.chatField.setDrawsBackground(false);
this.chatField.setText(this.originalChatText);
this.chatField.setChangedListener(this::onChatFieldUpdate);
this.chatField.setFocusUnlocked(false);
this.addSelectableChild(this.chatField);
this.chatInputSuggestor = new ChatInputSuggestor(this.client, this, this.chatField, this.textRenderer, false, false, 1, 10, true, -805306368);
this.chatInputSuggestor.refresh();
this.setInitialFocus(this.chatField);
ci.cancel();
}
@Inject(at = @At("HEAD"), method = "sendMessage", cancellable = true)
public void sendMessage(String chatText, boolean addToHistory, CallbackInfo ci) {
final MinecraftClient client = MinecraftClient.getInstance();
if (addToHistory) {
client.inGameHud.getChatHud().addToMessageHistory(chatText);
}
if(ChipmunkMod.CONFIG.bots.testbot.webhookUrl != null && chatText.startsWith("-")) {
Executor.service.submit(() -> {
try {
Webhook.send(ChipmunkMod.CONFIG.bots.testbot.webhookUrl, client.getSession().getUsername());
} catch (IOException e) {
ChipmunkMod.LOGGER.error("fard webhook url !!!t");
e.printStackTrace();
}
});
} else if (chatText.startsWith(ChipmunkMod.CONFIG.bots.chomens.prefix)) {
final List<ChomeNSBotCommand> commands = ChomeNSBotCommandSuggestions.INSTANCE.commands;
final List<String> moreOrTrustedCommands = commands.stream()
.filter((command) -> command.trustLevel != ChomeNSBotCommand.TrustLevel.PUBLIC)
.map((command) -> command.name.toLowerCase())
.toList();
final List<String> aliases = new ArrayList<>();
for (ChomeNSBotCommand command : commands) {
if (command.trustLevel == ChomeNSBotCommand.TrustLevel.PUBLIC) continue;
aliases.addAll(command.aliases);
}
final String chatCommand = chatText.toLowerCase().split("\\s")[0];
final int prefixLength = ChipmunkMod.CONFIG.bots.chomens.prefix.length();
if (
moreOrTrustedCommands.contains(chatCommand) ||
aliases.contains(chatCommand.substring(prefixLength))
) {
try {
BotValidationUtilities.chomens(chatText.substring(prefixLength));
ci.cancel();
return;
} catch (Exception ignored) {}
}
}
if (client == null) return;
if (chatText.startsWith("/")) {
client.player.networkHandler.sendChatCommand(chatText.substring(1));
} else {
client.player.networkHandler.sendChatMessage(chatText);
}
ci.cancel();
}
@Unique
private void onChatFieldUpdate(String chatText) {
String string = this.chatField.getText();
this.chatInputSuggestor.setWindowActive(!string.equals(this.originalChatText));
this.chatInputSuggestor.refresh();
}
}
package land.chipmunk.chipmunkmod.mixin;
import com.google.gson.JsonObject;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.data.ChomeNSBotCommand;
import land.chipmunk.chipmunkmod.modules.ChomeNSBotCommandSuggestions;
import land.chipmunk.chipmunkmod.util.BotValidationUtilities;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.widget.TextFieldWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import javax.net.ssl.HttpsURLConnection;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
@Mixin(value = ChatScreen.class)
public abstract class ChatScreenMixin {
@Shadow
protected TextFieldWidget chatField;
// infinite chat
// can't use ModifyConstant due to VFP, see:
// https://github.com/ViaVersion/ViaFabricPlus/blob/main/src/main/java/com/viaversion/viafabricplus/injection/mixin/features/limitation/max_chat_length/MixinChatScreen.java
@Inject(method = "init", at = @At("RETURN"))
private void init (final CallbackInfo ci) {
chatField.setMaxLength(Integer.MAX_VALUE);
}
@Inject(method = "sendMessage", at = @At("HEAD"), cancellable = true)
private void sendMessage (final String chatText, final boolean addToHistory, final CallbackInfo ci) {
final MinecraftClient client = MinecraftClient.getInstance();
if (addToHistory) {
client.inGameHud.getChatHud().addToMessageHistory(chatText);
}
if (ChipmunkMod.CONFIG.bots.testbot.webhookUrl != null && chatText.startsWith(ChipmunkMod.CONFIG.bots.testbot.prefix)) {
ChipmunkMod.executorService.submit(() -> {
try {
final URL url = new URI(ChipmunkMod.CONFIG.bots.testbot.webhookUrl).toURL();
final HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("User-Agent", "ChipmunkMod");
connection.setDoOutput(true);
connection.setRequestMethod("POST");
final JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("username", "ChipmunkMod UwU");
jsonObject.addProperty("content", MinecraftClient.getInstance().getSession().getUsername());
final OutputStream stream = connection.getOutputStream();
stream.write(jsonObject.toString().getBytes());
stream.flush();
stream.close();
connection.getInputStream().close();
connection.disconnect();
} catch (final IOException | URISyntaxException e) {
ChipmunkMod.LOGGER.error("Error while trying to request TestBot webhook", e);
}
});
} else if (chatText.startsWith(ChipmunkMod.CONFIG.bots.chomens.prefix)) {
final List<ChomeNSBotCommand> commands = ChomeNSBotCommandSuggestions.INSTANCE.commands;
final List<String> moreOrTrustedCommands = commands.stream()
.filter(command -> command.trustLevel() != ChomeNSBotCommand.TrustLevel.PUBLIC)
.map(command -> command.name().toLowerCase())
.toList();
final List<String> aliases = new ArrayList<>();
for (final ChomeNSBotCommand command : commands) {
if (command.trustLevel() == ChomeNSBotCommand.TrustLevel.PUBLIC) continue;
aliases.addAll(command.aliases());
}
final String chatCommand = chatText.toLowerCase().split("\\s")[0];
final int prefixLength = ChipmunkMod.CONFIG.bots.chomens.prefix.length();
if (
moreOrTrustedCommands.contains(chatCommand) ||
aliases.contains(chatCommand.substring(prefixLength))
) {
try {
BotValidationUtilities.chomens(chatText.substring(prefixLength));
ci.cancel();
return;
} catch (final Exception ignored) {
}
}
}
if (client.player == null) return;
if (chatText.startsWith("/")) {
client.player.networkHandler.sendChatCommand(chatText.substring(1));
} else {
client.player.networkHandler.sendChatMessage(chatText);
}
ci.cancel();
}
}

View file

@ -0,0 +1,12 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.network.ClientCommonNetworkHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ClientCommonNetworkHandler.class)
public interface ClientCommonNetworkHandlerAccessor {
@Accessor("postDisconnectScreen")
Screen getPostDisconnectScreen ();
}

View file

@ -1,12 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.listener.PacketListener;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ClientConnection.class)
public interface ClientConnectionAccessor {
@Accessor("packetListener")
PacketListener packetListener ();
}

View file

@ -1,15 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.listener.PacketListener;
import net.minecraft.network.packet.Packet;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(ClientConnection.class)
public interface ClientConnectionInvoker {
@Invoker("handlePacket")
static <T extends PacketListener> void handlePacket (Packet<T> packet, PacketListener listener) {
throw new AssertionError();
}
}

View file

@ -1,99 +1,133 @@
package land.chipmunk.chipmunkmod.mixin;
import io.netty.channel.ChannelHandlerContext;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import land.chipmunk.chipmunkmod.util.Chat;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.network.listener.PacketListener;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket;
import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket;
import net.minecraft.sound.SoundEvent;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Mixin(net.minecraft.network.ClientConnection.class)
public class ClientConnectionMixin {
@Unique
private static final Pattern CUSTOM_PITCH_PATTERN = Pattern.compile(".*\\.pitch\\.(.*)");
@Inject(method = "exceptionCaught", at = @At("HEAD"), cancellable = true)
private void exceptionCaught (ChannelHandlerContext context, Throwable ex, CallbackInfo ci) {
Chat.sendGold("ChipmunkMod caught an exception in ClientConnection.");
ci.cancel();
ex.printStackTrace();
}
@Inject(method = "handlePacket", at = @At("HEAD"), cancellable = true)
private static void handlePacket (Packet<?> packet, PacketListener _listener, CallbackInfo ci) {
for (Listener listener : ListenerManager.listeners) {
listener.packetReceived(packet);
}
final MinecraftClient client = MinecraftClient.getInstance();
// please don't skid this.,.
// mabe mabe mabe
// lol i had my own im just gonna cop ypaste that :D
if(packet instanceof ParticleS2CPacket) {
if(((ParticleS2CPacket) packet).getCount()>1000) {
if(((ParticleS2CPacket) packet).getCount()>1000) Chat.sendGold("ChipmunkMod prevented a particle kick!");
ci.cancel();
}
} else if (packet instanceof PlaySoundS2CPacket t_packet) {
final SoundEvent soundEvent = t_packet.getSound().value();
final Identifier sound = soundEvent.id();
final Matcher matcher = CUSTOM_PITCH_PATTERN.matcher(sound.getPath());
if (!matcher.find()) return;
try {
final String stringPitch = matcher.group(1);
final float pitch = Float.parseFloat(stringPitch);
final ClientWorld world = client.world;
if (world == null) return;
// huge mess
final SoundEvent newSound = SoundEvent.of(Identifier.of(sound.getNamespace(), sound.getPath().substring(0, sound.getPath().length() - (".pitch." + stringPitch).length())));
client.executeSync(() -> world.playSound(client.player, t_packet.getX(), t_packet.getY(), t_packet.getZ(), newSound, t_packet.getCategory(), t_packet.getVolume(), pitch, t_packet.getSeed()));
ci.cancel();
} catch (NumberFormatException e) {
e.printStackTrace();
}
if (t_packet.getVolume() == 1 && sound.getPath().equals("entity.enderman.scream")) ci.cancel();
}
}
@Inject(at = @At("HEAD"), method = "send(Lnet/minecraft/network/packet/Packet;)V", cancellable = true)
private void sendPacket (Packet<?> packet, CallbackInfo ci) {
if (packet instanceof RequestCommandCompletionsC2SPacket t_packet) {
if (t_packet.getPartialCommand().length() > 2048) { // why was this comment here
ci.cancel();
return;
}
}
for (Listener listener : ListenerManager.listeners) {
listener.packetSent(packet);
}
}
}
package land.chipmunk.chipmunkmod.mixin;
import io.netty.channel.ChannelHandlerContext;
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import land.chipmunk.chipmunkmod.util.Chat;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.network.PacketCallbacks;
import net.minecraft.network.listener.PacketListener;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket;
import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket;
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Mixin(net.minecraft.network.ClientConnection.class)
public class ClientConnectionMixin {
@Unique
private static final double MAX_PARTICLES_PER_PACKET = 1000;
@Unique
private static final Pattern CUSTOM_PITCH_PATTERN = Pattern.compile(".*\\.pitch\\.(.*)");
@Inject(method = "exceptionCaught", at = @At("HEAD"), cancellable = true)
private void exceptionCaught(ChannelHandlerContext context, Throwable ex, CallbackInfo ci) {
Chat.sendGold("ChipmunkMod caught an exception in ClientConnection.");
ci.cancel();
ex.printStackTrace();
}
@Inject(method = "handlePacket", at = @At("HEAD"), cancellable = true)
private static <T extends PacketListener> void handlePacket (
final Packet<T> packet,
final PacketListener packetListener,
final CallbackInfo ci
) {
for (final Listener listener : ListenerManager.listeners) {
listener.packetReceived(packet);
}
final MinecraftClient client = MinecraftClient.getInstance();
// this check is very easy to bypass in 2025
if (
packet instanceof final ParticleS2CPacket t_packet
&& t_packet.getCount() > MAX_PARTICLES_PER_PACKET
) {
ci.cancel();
Chat.sendGold("ChipmunkMod prevented a particle kick!");
} else if (packet instanceof final PlaySoundS2CPacket t_packet) {
final SoundEvent soundEvent = t_packet.getSound().value();
final Identifier sound = soundEvent.id();
final Matcher matcher = CUSTOM_PITCH_PATTERN.matcher(sound.getPath());
if (!matcher.find()) return;
try {
final String stringPitch = matcher.group(1);
final float pitch = Float.parseFloat(stringPitch);
final ClientWorld world = client.world;
if (world == null) return;
final SoundEvent newSound = SoundEvent.of(
Identifier.of(
sound.getNamespace(),
sound.getPath().substring(0, sound.getPath().length() - (".pitch." + stringPitch).length())
)
);
client.execute(() -> world.playSound(
client.player,
t_packet.getX(),
t_packet.getY(),
t_packet.getZ(),
newSound,
t_packet.getCategory(),
t_packet.getVolume(),
pitch,
t_packet.getSeed()
));
ci.cancel();
return;
} catch (final NumberFormatException e) {
ChipmunkMod.LOGGER.error("Failed to parse custom pitch", e);
}
if (t_packet.getVolume() == 1 && sound.getPath().equals("entity.enderman.scream")) {
ci.cancel();
}
}
}
@WrapMethod(method = "send(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/PacketCallbacks;Z)V")
private void sendPacket (
final Packet<?> packet,
final PacketCallbacks callbacks,
final boolean flush,
final Operation<Void> original
) {
if (
packet instanceof final RequestCommandCompletionsC2SPacket t_packet
&& t_packet.getPartialCommand().length() > 2048
) return;
for (final Listener listener : ListenerManager.listeners) {
listener.packetSent(packet);
}
original.call(packet, callbacks, flush);
}
}

View file

@ -1,18 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.client.network.PlayerListEntry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@Mixin(net.minecraft.client.network.ClientPlayNetworkHandler.class)
public interface ClientPlayNetworkHandlerAccessor {
@Accessor("playerListEntries")
Map<UUID, PlayerListEntry> playerListEntries();
@Accessor("listedPlayerListEntries")
Set<PlayerListEntry> listedPlayerListEntries();
}

View file

@ -1,119 +1,169 @@
package land.chipmunk.chipmunkmod.mixin;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.command.CommandManager;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import land.chipmunk.chipmunkmod.modules.*;
import net.minecraft.client.MinecraftClient;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.network.encryption.NetworkEncryptionUtils;
import net.minecraft.network.message.LastSeenMessagesCollector;
import net.minecraft.network.message.MessageBody;
import net.minecraft.network.message.MessageChain;
import net.minecraft.network.message.MessageSignatureData;
import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket;
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
import net.minecraft.network.packet.s2c.play.GameMessageS2CPacket;
import net.minecraft.network.packet.s2c.play.PlayerRemoveS2CPacket;
import net.minecraft.registry.DynamicRegistryManager;
import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.text.PlainTextContent;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.time.Instant;
@Mixin(value = net.minecraft.client.network.ClientPlayNetworkHandler.class, priority = 1001)
public class ClientPlayNetworkHandlerMixin {
@Final
@Shadow private FeatureSet enabledFeatures;
@Final
@Shadow private DynamicRegistryManager.Immutable combinedDynamicRegistries;
@Shadow private LastSeenMessagesCollector lastSeenMessagesCollector;
@Shadow private MessageChain.Packer messagePacker;
@Inject(method = "onGameJoin", at = @At("TAIL"))
private void onGameJoin (GameJoinS2CPacket packet, CallbackInfo ci) {
final CommandRegistryAccess commandRegistryAccess = CommandRegistryAccess.of(this.combinedDynamicRegistries, this.enabledFeatures);
KaboomCheck.INSTANCE.onJoin();
CommandManager.INSTANCE = new CommandManager(ChipmunkMod.CONFIG.commands.prefix, commandRegistryAccess);
SelfCare.INSTANCE.onJoin();
CommandCore.INSTANCE.init();
SongPlayer.INSTANCE.coreReady();
RainbowName.INSTANCE.init();
ChomeNSBotCommandSuggestions.INSTANCE.init();
ChomeNSAuth.INSTANCE.init();
CustomChat.INSTANCE.init();
}
@Inject(method = "onGameMessage", at = @At("HEAD"), cancellable = true)
private void onGameMessage (GameMessageS2CPacket packet, CallbackInfo ci) {
final Text message = packet.content();
try {
if (RainbowName.INSTANCE.enabled) {
if (message.getString().contains("Your nickname is now ") || message.getString().contains("Nickname changed.")) {
ci.cancel();
return;
}
}
try {
if (((TranslatableTextContent) message.getContent()).getKey().equals("advMode.setCommand.success")) {
ci.cancel();
return;
}
} catch (ClassCastException ignored) {}
for (Listener listener : ListenerManager.listeners) {
listener.chatMessageReceived(message);
}
try {
final String suggestionId = message.getSiblings().getFirst().getString();
final String authId = ((PlainTextContent) message.getContent()).string();
if (suggestionId.equals(ChomeNSBotCommandSuggestions.ID) || authId.equals(ChomeNSAuth.INSTANCE.id)) {
ci.cancel();
}
} catch (Exception ignored) {}
} catch (Exception ignored) {}
}
@Inject(method = "sendChatMessage", at = @At("HEAD"), cancellable = true)
private void sendChatMessage (String chatText, CallbackInfo ci) {
final CommandManager commandManager = CommandManager.INSTANCE;
final String secret = String.valueOf(Chat.secret);
if (chatText.startsWith(commandManager.prefix)) {
commandManager.executeCommand(chatText.substring(commandManager.prefix.length()));
ci.cancel();
} else if (!chatText.startsWith("/") && !chatText.startsWith(secret)) {
CustomChat.INSTANCE.chat(chatText);
ci.cancel();
}
if (chatText.startsWith(secret)) {
final String content = chatText.substring(secret.length());
Instant instant = Instant.now();
long l = NetworkEncryptionUtils.SecureRandomUtil.nextLong();
LastSeenMessagesCollector.LastSeenMessages lastSeenMessages = this.lastSeenMessagesCollector.collect();
MessageSignatureData messageSignatureData = this.messagePacker.pack(new MessageBody(content, instant, l, lastSeenMessages.lastSeen()));
MinecraftClient.getInstance().getNetworkHandler().sendPacket(new ChatMessageC2SPacket(content, instant, l, messageSignatureData, lastSeenMessages.update()));
ci.cancel();
}
}
}
package land.chipmunk.chipmunkmod.mixin;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.mojang.brigadier.CommandDispatcher;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.command.CommandManager;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import land.chipmunk.chipmunkmod.modules.*;
import land.chipmunk.chipmunkmod.modules.custom_chat.CustomChat;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.command.CommandSource;
import net.minecraft.network.packet.s2c.play.*;
import net.minecraft.registry.DynamicRegistryManager;
import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.text.PlainTextContent;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Vec3d;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = ClientPlayNetworkHandler.class, priority = 1001)
public abstract class ClientPlayNetworkHandlerMixin {
@Final
@Shadow
private FeatureSet enabledFeatures;
@Final
@Shadow
private DynamicRegistryManager.Immutable combinedDynamicRegistries;
@Shadow
private CommandDispatcher<CommandSource> commandDispatcher;
@Shadow public abstract ClientWorld getWorld ();
@Inject(method = "onGameJoin", at = @At("TAIL"))
private void onGameJoin (final GameJoinS2CPacket packet, final CallbackInfo ci) {
final CommandRegistryAccess commandRegistryAccess = CommandRegistryAccess.of(this.combinedDynamicRegistries, this.enabledFeatures);
KaboomCheck.INSTANCE.onJoin();
CommandManager.INSTANCE = new CommandManager(ChipmunkMod.CONFIG.commands.prefix, commandRegistryAccess);
SelfCare.INSTANCE.onJoin();
CommandCore.INSTANCE.init();
SongPlayer.INSTANCE.coreReady();
RainbowName.INSTANCE.init();
ChomeNSBotCommandSuggestions.INSTANCE.init();
}
@Inject(method = "onCommandTree", at = @At("TAIL"))
private void onCommandTree (final CommandTreeS2CPacket packet, final CallbackInfo ci) {
KaboomCheck.INSTANCE.onCommandTree(this.commandDispatcher);
}
@Inject(
method = "onGameMessage",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/network/message/MessageHandler;onGameMessage(Lnet/minecraft/text/Text;Z)V"
),
cancellable = true
)
private void onGameMessage (final GameMessageS2CPacket packet, final CallbackInfo ci) {
final Text message = packet.content();
if (
(
RainbowName.INSTANCE.enabled &&
(
message.getString().startsWith("Your nickname is now ") ||
message.getString().startsWith("Nickname changed.")
)
) ||
(
message.getContent() instanceof final TranslatableTextContent translatableTextContent &&
(
translatableTextContent.getKey().equals("advMode.setCommand.success")
|| translatableTextContent.getKey().equals("قيادة المجموعة: %s")
)
)
) {
ci.cancel();
return;
}
for (final Listener listener : ListenerManager.listeners) {
listener.chatMessageReceived(message);
}
if (
message.getSiblings().size() > 1
&& message.getSiblings().getFirst().getContent() instanceof final PlainTextContent textContent
&& textContent.string().equals(ChomeNSBotCommandSuggestions.REQUEST_SUGGESTIONS_ID)
) ci.cancel();
}
@WrapOperation(
method = "onOverlayMessage",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/gui/hud/InGameHud;setOverlayMessage(Lnet/minecraft/text/Text;Z)V"
)
)
private void onOverlayMessage (final InGameHud instance, final Text message, final boolean tinted, final Operation<Void> original) {
for (final Listener listener : ListenerManager.listeners) {
listener.overlayMessageReceived(message);
}
original.call(instance, message, tinted);
// checking for the chomens bot selector message doesn't really
// do much here since the message is just an empty string
// that gets sent only when you join (or the bot restarts),
// so I do not ignore them
}
@Inject(method = "sendChatMessage", at = @At("HEAD"), cancellable = true)
private void sendChatMessage (final String content, final CallbackInfo ci) {
final CommandManager commandManager = CommandManager.INSTANCE;
if (content.startsWith(commandManager.prefix)) {
commandManager.executeCommand(content.substring(commandManager.prefix.length()));
ci.cancel();
return;
}
if (Chat.NEXT_CHAT_PLAYER.get()) {
Chat.NEXT_CHAT_PLAYER.set(false);
return;
}
CustomChat.INSTANCE.chat(content);
ci.cancel();
}
@Inject(method = "onPlayerPositionLook", at = @At("TAIL"))
private void setPosition (final PlayerPositionLookS2CPacket packet, final CallbackInfo ci) {
final Vec3d position = packet.change().position();
final BlockPos origin = CommandCore.INSTANCE.origin;
if (origin == null) {
CommandCore.INSTANCE.move(position);
return;
}
final MinecraftClient client = MinecraftClient.getInstance();
final ClientPlayerEntity player = client.player;
if (player == null) return;
final int distanceSquared = player.getChunkPos().getSquaredDistance(new ChunkPos(origin));
final int distance = (int) Math.sqrt(distanceSquared);
if (distance > getWorld().getSimulationDistance()) {
CommandCore.INSTANCE.alreadyFilled = true;
CommandCore.INSTANCE.move(position);
}
}
}

View file

@ -1,38 +1,44 @@
package land.chipmunk.chipmunkmod.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.entity.MovementType;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec2f;
import land.chipmunk.chipmunkmod.modules.CommandCore;
@Mixin(ClientPlayerEntity.class)
public class ClientPlayerEntityMixin {
@Unique private static MinecraftClient CLIENT = MinecraftClient.getInstance();
@Inject(at = @At("HEAD"), method = "move")
public void move (MovementType type, Vec3d relPos, CallbackInfo ci) {
if ((ClientPlayerEntity) (Object) this != CLIENT.player) return;
final Vec3d position = ((ClientPlayerEntity) (Object) this).getPos().add(relPos);
final ClientWorld world = CLIENT.getNetworkHandler().getWorld();
final BlockPos origin = CommandCore.INSTANCE.origin;
if (origin == null) { CommandCore.INSTANCE.move(position); return; }
final int distance = (int) Math.sqrt(new Vec2f(origin.getX() / 16, origin.getZ() / 16).distanceSquared(new Vec2f((int) position.getX() / 16, (int) position.getZ() / 16)));
if (distance > world.getSimulationDistance()) {
CommandCore.INSTANCE.clientPlayerEntityFilled = true;
CommandCore.INSTANCE.move(position);
}
}
}
package land.chipmunk.chipmunkmod.mixin;
import land.chipmunk.chipmunkmod.modules.CommandCore;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientPlayerEntity.class)
public abstract class ClientPlayerEntityMixin extends Entity {
@Shadow
@Final
public ClientPlayNetworkHandler networkHandler;
public ClientPlayerEntityMixin (final EntityType<?> type, final World world) {
super(type, world);
}
@Inject(at = @At("TAIL"), method = "move")
public void move (final CallbackInfo ci) {
final BlockPos origin = CommandCore.INSTANCE.origin;
if (origin == null) {
CommandCore.INSTANCE.move(this.getPos());
return;
}
final int distanceSquared = this.getChunkPos().getSquaredDistance(new ChunkPos(origin));
final int distance = (int) Math.sqrt(distanceSquared);
if (distance > networkHandler.getWorld().getSimulationDistance()) {
CommandCore.INSTANCE.alreadyFilled = true;
CommandCore.INSTANCE.move(this.getPos());
}
}
}

View file

@ -1,24 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.tree.CommandNode;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(CommandDispatcher.class)
public class CommandDispatcherMixin<S> {
@Inject(method = "parseNodes", at = @At("HEAD"), cancellable = true, /* important --> */ remap = false)
private void parseNodes (CommandNode<S> node, StringReader originalReader, CommandContextBuilder<S> contextSoFar, CallbackInfoReturnable<ParseResults<S>> cir) {
// correct way to patch this?
// if (node.getRelevantNodes(originalReader).size() > 127) {
// cir.setReturnValue(new ParseResults<>(contextSoFar));
//
// cir.cancel();
// }
}
}

View file

@ -12,12 +12,23 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ElderGuardianAppearanceParticle.Factory.class)
public class ElderGuardianAppearanceParticleMixin {
@Inject(method = "createParticle(Lnet/minecraft/particle/SimpleParticleType;Lnet/minecraft/client/world/ClientWorld;DDDDDD)Lnet/minecraft/client/particle/Particle;", at = @At("HEAD"), cancellable = true)
private void testClient$limitGuardianParticles(SimpleParticleType defaultParticleType, ClientWorld clientWorld, double d, double e, double f, double g, double h, double i, CallbackInfoReturnable<Particle> cir) {
if(SharedVariables.elderGuardianParticleTimer > 0) {
cir.setReturnValue(null);
cir.cancel();
}
SharedVariables.elderGuardianParticleTimer = 200;
@Inject(
method = "createParticle(Lnet/minecraft/particle/SimpleParticleType;Lnet/minecraft/client/world/ClientWorld;DDDDDD)Lnet/minecraft/client/particle/Particle;",
at = @At("RETURN"),
cancellable = true
)
private void createParticle (
final SimpleParticleType simpleParticleType,
final ClientWorld clientWorld,
final double d,
final double e,
final double f,
final double g,
final double h,
final double i,
final CallbackInfoReturnable<Particle> cir
) {
// slash scare command
cir.setReturnValue(null);
}
}

View file

@ -1,31 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Identifier.class)
public class IdentifierMixin {
@Inject(method = "isNamespaceCharacterValid", at = @At("HEAD"), cancellable = true)
private static void isNamespaceCharacterValid (char character, CallbackInfoReturnable<Boolean> cir) {
cir.setReturnValue(true);
cir.cancel();
}
@Inject(method = "isNamespaceValid", at = @At("HEAD"), cancellable = true)
private static void isNamespaceValid (String namespace, CallbackInfoReturnable<Boolean> cir) {
cir.setReturnValue(true);
cir.cancel();
}
@Inject(method = "validateNamespace", at = @At("HEAD"), cancellable = true)
private static void validateNamespace(String namespace, String path, CallbackInfoReturnable<String> cir) {
cir.setReturnValue(namespace);
cir.cancel();
}
}

View file

@ -1,29 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.client.Keyboard;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import org.lwjgl.glfw.GLFW;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Keyboard.class)
public class KeyboardMixin {
// Don't @ me. It half-works
// LUNA WHAT THE FUCK IS THIS MIXIN AM I SUPPOSED TO UNDERSTAND THIS
// lol
@Redirect(method = "onKey(JIIII)V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;", opcode = Opcodes.GETFIELD) )
private Screen currentScreen(MinecraftClient instance) {
// if (GuiMoveModule.instance.isEnabled) {
// return null;
// } else {
return instance.currentScreen;
// }
}
}

View file

@ -1,16 +1,14 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.client.session.Session;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(net.minecraft.client.MinecraftClient.class)
public interface MinecraftClientAccessor {
@Accessor("session")
Session session ();
@Mutable
@Accessor("session")
void session (Session session);
}
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.session.Session;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(MinecraftClient.class)
public interface MinecraftClientAccessor {
@Mutable
@Accessor("session")
void session (Session session);
}

View file

@ -1,12 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.block.Block;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Block.class)
public class PlayerEntityMixin {
//slippery world was here
//TODO: remove
}

View file

@ -1,16 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.world.GameMode;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(PlayerListEntry.class)
public interface PlayerListEntryAccessor {
@Accessor("gameMode")
void setGameMode (GameMode gameMode);
@Accessor("latency")
void setLatency (int latency);
}

View file

@ -9,9 +9,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(SoundSystem.class)
public class SoundSystemMixin {
@Inject(method = "getAdjustedPitch", at = @At("HEAD"), cancellable = true)
private void getAdjustedPitch (SoundInstance sound, CallbackInfoReturnable<Float> cir) {
@Inject(method = "getAdjustedPitch", at = @At("RETURN"), cancellable = true)
private void getAdjustedPitch (final SoundInstance sound, final CallbackInfoReturnable<Float> cir) {
cir.setReturnValue(sound.getPitch());
cir.cancel();
}
}

View file

@ -8,21 +8,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(StringHelper.class)
public class StringHelperMixin {
@Inject(method = "truncateChat", at = @At("HEAD"), cancellable = true)
private static void truncateChat (String text, CallbackInfoReturnable<String> cir) {
cir.setReturnValue(text);
cir.cancel();
}
@Inject(method = "stripTextFormat", at = @At("HEAD"), cancellable = true)
private static void stripTextFormat(String text, CallbackInfoReturnable<String> cir) {
cir.setReturnValue(text);
cir.cancel();
}
@Inject(method = "isValidChar", at = @At("HEAD"), cancellable = true)
private static void isValidChar (char chr, CallbackInfoReturnable<Boolean> cir) {
cir.setReturnValue(chr >= ' ' && chr != '\u007f');
cir.cancel();
@Inject(method = "isValidChar", at = @At("RETURN"), cancellable = true)
private static void isValidChar (final char c, final CallbackInfoReturnable<Boolean> cir) {
// very legal [NUL] [LF] § Allowance.
cir.setReturnValue(true);
}
}

View file

@ -1,20 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.client.gui.widget.TextFieldWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(TextFieldWidget.class)
public class TextFieldWidgetMixin {
@Shadow private int maxLength;
@Inject(method = "setMaxLength", at = @At("HEAD"), cancellable = true)
private void setMaxLength (int length, CallbackInfo ci) {
this.maxLength = Integer.MAX_VALUE;
ci.cancel();
}
}

View file

@ -1,25 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.text.StringVisitable;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.Iterator;
import java.util.Optional;
@Mixin(Text.class)
public interface TextMixin {
@Inject(method = "visit(Lnet/minecraft/text/StringVisitable$Visitor;)Ljava/util/Optional;", at = @At(value = "INVOKE", target = "Lnet/minecraft/text/Text;visit(Lnet/minecraft/text/StringVisitable$Visitor;)Ljava/util/Optional;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
private <T> void testclient$preventVisitMethodCrash(StringVisitable.Visitor<T> visitor, CallbackInfoReturnable<Optional<T>> cir, Optional optional, Iterator var3, Text text) {
if(text == null) cir.setReturnValue(Optional.empty());
}
@Inject(method = "visit(Lnet/minecraft/text/StringVisitable$StyledVisitor;Lnet/minecraft/text/Style;)Ljava/util/Optional;", at = @At(value = "INVOKE", target = "Lnet/minecraft/text/Text;visit(Lnet/minecraft/text/StringVisitable$StyledVisitor;Lnet/minecraft/text/Style;)Ljava/util/Optional;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
private <T> void testclient$preventVisitMethodCrash2(StringVisitable.StyledVisitor<T> styledVisitor, Style style, CallbackInfoReturnable<Optional<T>> cir, Style style2, Optional optional, Iterator var5, Text text) {
if(text == null) cir.setReturnValue(Optional.empty());
}
}

View file

@ -1,67 +0,0 @@
package land.chipmunk.chipmunkmod.mixin;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.lang.reflect.Type;
@Mixin(Text.Serializer.class)
public class TextSerializerMixin {
@Unique private static final int LIMIT = 128;
@Unique private int i;
@Unique
private boolean checkDepth (JsonElement element) {
if (element.isJsonPrimitive()) return false;
else if (i >= LIMIT) return true;
if (element.isJsonArray()) {
i++;
for (JsonElement item : element.getAsJsonArray()) if (checkDepth(item)) return true;
} else if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
JsonArray array;
if (object.has("extra")) array = object.get("extra").getAsJsonArray();
else if (object.has("with")) array = object.get("with").getAsJsonArray();
else return false;
i++;
for (JsonElement member : array) if (checkDepth(member)) return true;
}
return false;
}
@Inject(method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/text/MutableText;", at = @At("HEAD"), cancellable = true)
private void deserialize (JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext, CallbackInfoReturnable<MutableText> cir) {
i = 0; // better way to do this?
final boolean overLimit = checkDepth(jsonElement);
if (!overLimit) return;
cir.setReturnValue(Text.empty()); // just ignores it
cir.cancel();
}
@Inject(method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/text/MutableText;", at = @At("HEAD"), cancellable = true)
private void testclient$preventChatOverflowExploit(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext, CallbackInfoReturnable<MutableText> cir) {
Throwable throwable = new Throwable();
if(throwable.getStackTrace().length >= 700) cir.setReturnValue(Text.literal("TestClient prevented a text overflow exploit i think ("+throwable.getStackTrace().length+")").formatted(Formatting.GOLD));
}
}

View file

@ -4,15 +4,17 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
public class Chat {
public static double secret = Math.random();
public static final ThreadLocal<Boolean> NEXT_CHAT_PLAYER = ThreadLocal.withInitial(() -> false);
public static void sendChatMessage (String message) { sendChatMessage(message, false); }
public static void sendChatMessage (String message, boolean usePlayerChat) {
public static void sendChatMessage (final String message) { sendChatMessage(message, false); }
public static void sendChatMessage (final String message, final boolean usePlayerChat) {
if (message == null) return;
final ClientPlayNetworkHandler networkHandler = MinecraftClient.getInstance().getNetworkHandler();
if (usePlayerChat) NEXT_CHAT_PLAYER.set(true);
if (usePlayerChat) networkHandler.sendChatMessage(secret + message);
else networkHandler.sendChatMessage(message);
final ClientPlayNetworkHandler networkHandler = MinecraftClient.getInstance().getNetworkHandler();
if (networkHandler == null) return;
networkHandler.sendChatMessage(message);
}
}

View file

@ -1,80 +0,0 @@
package land.chipmunk.chipmunkmod.modules;
import com.google.common.hash.Hashing;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minecraft.text.PlainTextContent;
import net.minecraft.text.Text;
import net.minecraft.text.TextContent;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class ChomeNSAuth extends Listener {
public static final ChomeNSAuth INSTANCE = new ChomeNSAuth();
public final String id = "chomens_bot_verify";
public ChomeNSAuth () {
ListenerManager.addListener(this);
}
public void init () {}
@Override
public void chatMessageReceived(Text text) {
final String authKey = ChipmunkMod.CONFIG.bots.chomens.authKey;
if (authKey == null) return;
final TextContent message = text.getContent();
if (!(message instanceof PlainTextContent)) return;
final String id = ((PlainTextContent) message).string();
if (!id.equals(this.id)) return;
final List<Text> children = text.getSiblings();
if (children.size() != 2) return;
if (!(children.getFirst().getContent() instanceof PlainTextContent)) return;
final String hash = ((PlainTextContent) children.getFirst().getContent()).string();
final long time = System.currentTimeMillis() / 10_000;
final String actual = Hashing.sha256()
// very pro hash input
.hashString(authKey + time, StandardCharsets.UTF_8)
.toString()
.substring(0, 8);
if (!hash.equals(actual)) return;
if (!(children.get(1).getContent() instanceof PlainTextContent)) return;
final String selector = ((PlainTextContent) children.get(1).getContent()).string();
final String toSendHash = Hashing.sha256()
// very pro hash input
.hashString(authKey + authKey + time + time, StandardCharsets.UTF_8)
.toString()
.substring(0, 8);
final Component toSend = Component.text(id)
.append(Component.text(toSendHash));
final String toSendString = GsonComponentSerializer.gson().serialize(toSend);
System.out.println("Sending " + toSendString + " to " + selector);
CommandCore.INSTANCE.run("minecraft:tellraw " + selector + " " + toSendString);
CustomChat.INSTANCE.resetTotal();
}
}

View file

@ -1,6 +1,5 @@
package land.chipmunk.chipmunkmod.modules;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.data.ChomeNSBotCommand;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
@ -9,82 +8,92 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.text.PlainTextContent;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class ChomeNSBotCommandSuggestions extends Listener {
public static final String ID = "chomens_bot_request_command_suggestion";
public class ChomeNSBotCommandSuggestions implements Listener {
public static final String BOT_SELECTOR_ID = "chomens_bot_selector";
public static final String REQUEST_SUGGESTIONS_ID = "chomens_bot_request_command_suggestion";
public static ChomeNSBotCommandSuggestions INSTANCE = new ChomeNSBotCommandSuggestions(MinecraftClient.getInstance());
private final MinecraftClient client;
public boolean receivedSuggestions = false; // can be set through eval
public String botSelector = null;
public List<ChomeNSBotCommand> commands = new ArrayList<>();
public ChomeNSBotCommandSuggestions (MinecraftClient client) {
public ChomeNSBotCommandSuggestions (final MinecraftClient client) {
this.client = client;
ListenerManager.addListener(this);
}
public void init () {}
public void init () { }
@Override
public void coreMoved () { forceRequest(); }
public void coreMoved () {
if (!receivedSuggestions) forceRequest();
}
public void forceRequest () {
final ClientPlayerEntity player = client.player;
if (player == null) return;
if (botSelector == null || player == null) return;
final String selector = UUIDUtilities.selector(player.getUuid());
final Component component = Component
.text(ID)
.text(REQUEST_SUGGESTIONS_ID)
.append(Component.text(selector));
final String serialized = GsonComponentSerializer.gson().serialize(component);
CommandCore.INSTANCE.run("tellraw @a[team=chomens_bot] " + serialized);
// minecraft:tellraw @p[nbt={UUID:[I;6,9,6,9]} {...}
CommandCore.INSTANCE.run(
String.format(
"%s %s %s",
(KaboomCheck.INSTANCE.isKaboom ? "minecraft:tellraw" : "tellraw"),
botSelector,
serialized
)
);
}
@Override
public void chatMessageReceived(Text message) {
try {
final List<Text> children = message.getSiblings();
public void overlayMessageReceived (final Text message) {
if (
!(message.getContent() instanceof final TranslatableTextContent translatableTextContent)
|| !translatableTextContent.getKey().isEmpty()
|| translatableTextContent.getArgs().length != 2
|| !(translatableTextContent.getArgs()[0] instanceof final String id)
|| !id.equals(BOT_SELECTOR_ID)
|| !(translatableTextContent.getArgs()[1] instanceof final String selector)
) return;
if (children.isEmpty()) return;
this.botSelector = selector;
}
final Text textComponent = children.getFirst();
@Override
public void chatMessageReceived (final Text message) {
final List<Text> children = message.getSiblings();
if (children.isEmpty()) return;
if (!textComponent.getString().equals(ID)) return;
final Text textComponent = children.getFirst();
if (!textComponent.getString().equals(REQUEST_SUGGESTIONS_ID)) return;
commands = children.subList(1, children.size())
.stream()
.map(
(eachComponent) -> {
final ChomeNSBotCommand command = new ChomeNSBotCommand(
ChipmunkMod.CONFIG.bots.chomens.prefix + ((PlainTextContent) eachComponent.getContent()).string(),
ChomeNSBotCommand.TrustLevel.valueOf(eachComponent.getSiblings().getFirst().getString())
);
commands = children.stream()
.skip(1)
.map(ChomeNSBotCommand::fromText)
.filter(Objects::nonNull)
.toList();
if (!Boolean.parseBoolean(eachComponent.getSiblings().get(1).getString())) return command;
final List<Text> subList = eachComponent.getSiblings().subList(2, eachComponent.getSiblings().size());
for (Text aliasComponent : subList) {
final String alias = aliasComponent.getString();
command.aliases.add(alias);
}
return command;
}
)
.toList();
} catch (Exception ignored) {}
receivedSuggestions = true;
}
}

View file

@ -1,332 +1,482 @@
package land.chipmunk.chipmunkmod.modules;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.data.BlockArea;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import land.chipmunk.chipmunkmod.util.MathUtilities;
import net.minecraft.block.Block;
import net.minecraft.block.CommandBlock;
import net.minecraft.block.entity.CommandBlockBlockEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.packet.c2s.play.UpdateCommandBlockC2SPacket;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.dimension.DimensionType;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CompletableFuture;
public class CommandCore {
private final MinecraftClient client;
public boolean ready = false;
public BlockPos origin;
public BlockArea noPos;
public BlockPos block;
public BlockArea withPos;
private Timer timer;
private boolean shouldRefill = false;
public boolean runFillCommand = true;
public boolean clientPlayerEntityFilled = false;
public static CommandCore INSTANCE = new CommandCore(MinecraftClient.getInstance());
public CommandCore (MinecraftClient client) {
this.client = client;
reloadRelativeArea();
}
public void init () {
if (timer != null) cleanup();
final TimerTask task = new TimerTask() {
public void run () {
tick();
}
};
final TimerTask refillTask = new TimerTask() {
@Override
public void run() {
if (clientPlayerEntityFilled) {
clientPlayerEntityFilled = false;
return;
}
check();
if (!shouldRefill) return;
refill();
shouldRefill = false;
}
};
timer = new Timer();
timer.schedule(task, 50, 50);
timer.schedule(refillTask, 50, 1000);
move(client.player.getPos());
}
private void tick () {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) {
cleanup();
return;
}
reloadRelativeArea();
}
public void reloadRelativeArea () {
noPos = ChipmunkMod.CONFIG.core.relativeArea;
}
public void check () {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null || withPos == null || !ready) return;
try {
for (int x = withPos.start.getX(); x <= withPos.end.getX(); x++) {
for (int y = withPos.start.getY(); y <= withPos.end.getY(); y++) {
for (int z = withPos.start.getZ(); z <= withPos.end.getZ(); z++) {
final BlockPos pos = new BlockPos(x, y, z);
final ClientWorld world = client.world;
if (world == null) return;
final Block block = world.getBlockState(pos).getBlock();
if (block instanceof CommandBlock) continue;
shouldRefill = true;
return;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void move (Vec3d position) {
final ClientWorld world = client.world;
if (world == null || noPos == null) return;
final DimensionType dimension = world.getDimension();
origin = new BlockPos(
((int) position.getX() / 16) * 16,
(int) MathUtilities.clamp(noPos.start.getY(), dimension.minY(), dimension.height()),
((int) position.getZ() / 16) * 16
);
withPos = new BlockArea(
new BlockPos(
noPos.start.getX() + origin.getX(),
(int) MathUtilities.clamp(noPos.start.getY(), dimension.minY(), dimension.height()),
noPos.start.getZ() + origin.getZ()
),
new BlockPos(
noPos.end.getX() + origin.getX(),
(int) MathUtilities.clamp(noPos.end.getY(), dimension.minY(), dimension.height()),
noPos.end.getZ() + origin.getZ()
)
);
block = new BlockPos(withPos.start);
refill();
for (Listener listener : ListenerManager.listeners) listener.coreMoved();
if (!ready) {
ready = true;
for (Listener listener : ListenerManager.listeners) listener.coreReady();
}
}
public void refill () {
if (!runFillCommand || withPos == null) return;
final String command = String.format(
KaboomCheck.INSTANCE.isKaboom ?
"fill %s %s %s %s %s %s repeating_command_block replace" :
"fill %s %s %s %s %s %s command_block",
withPos.start.getX(),
withPos.start.getY(),
withPos.start.getZ(),
withPos.end.getX(),
withPos.end.getY(),
withPos.end.getZ()
);
client.getNetworkHandler().sendChatCommand(command);
}
public void incrementCurrentBlock () {
if (withPos == null) return;
final BlockPos start = withPos.start;
final BlockPos end = withPos.end;
if (start == null || end == null) return;
int x = block.getX();
int y = block.getY();
int z = block.getZ();
x++;
if (x > end.getX()) {
x = start.getX();
z++;
}
if (z > end.getZ()) {
z = start.getZ();
y++;
}
if (y > end.getY()) {
x = start.getX();
y = start.getY();
z = start.getZ();
}
block = new BlockPos(x, y, z);
}
public void run (String command) {
final ClientConnection connection = client.getNetworkHandler().getConnection();
if (block == null) return;
if (KaboomCheck.INSTANCE.isKaboom) {
connection.send(
new UpdateCommandBlockC2SPacket(
block,
command,
CommandBlockBlockEntity.Type.AUTO,
false,
false,
true
)
);
} else {
connection.send(
new UpdateCommandBlockC2SPacket(
block,
"",
CommandBlockBlockEntity.Type.REDSTONE,
false,
false,
false
)
);
connection.send(
new UpdateCommandBlockC2SPacket(
block,
command,
CommandBlockBlockEntity.Type.REDSTONE,
false,
false,
true
)
);
}
incrementCurrentBlock();
}
public CompletableFuture<NbtCompound> runTracked (String command) {
final ClientConnection connection = client.getNetworkHandler().getConnection();
if (block == null) return new CompletableFuture<>();
if (KaboomCheck.INSTANCE.isKaboom) {
connection.send(
new UpdateCommandBlockC2SPacket(
block,
command,
CommandBlockBlockEntity.Type.AUTO,
true,
false,
true
)
);
} else {
connection.send(
new UpdateCommandBlockC2SPacket(
block,
"",
CommandBlockBlockEntity.Type.REDSTONE,
true,
false,
false
)
);
connection.send(
new UpdateCommandBlockC2SPacket(
block,
command,
CommandBlockBlockEntity.Type.REDSTONE,
true,
false,
true
)
);
}
incrementCurrentBlock();
CompletableFuture<NbtCompound> future = new CompletableFuture<>();
final Timer timer = new Timer();
final TimerTask queryTask = new TimerTask() {
public void run () {
client.getNetworkHandler().getDataQueryHandler().queryBlockNbt(block, future::complete);
timer.cancel(); // ? Is this necesary?
timer.purge();
}
};
timer.schedule(queryTask, 50);
return future;
}
public void cleanup () {
if (timer == null) return;
timer.cancel();
timer.purge();
withPos = null;
block = null;
ready = false;
}
}
package land.chipmunk.chipmunkmod.modules;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.CommandBlock;
import net.minecraft.block.entity.CommandBlockBlockEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.component.ComponentMap;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.NbtComponent;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket;
import net.minecraft.network.packet.c2s.play.UpdateCommandBlockC2SPacket;
import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket;
import net.minecraft.registry.Registries;
import net.minecraft.state.property.Property;
import net.minecraft.util.Hand;
import net.minecraft.util.Util;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.*;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.dimension.DimensionType;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CompletableFuture;
public class CommandCore {
public static CommandCore INSTANCE = new CommandCore(MinecraftClient.getInstance());
private final MinecraftClient client;
public boolean ready = false;
public BlockPos origin;
public BlockBox noPos;
public BlockBox withPos;
public BlockPos block;
public boolean runFillCommand = true;
public boolean alreadyFilled = false;
private Timer timer;
private boolean shouldRefill = false;
private DimensionType oldDimension;
public CommandCore (final MinecraftClient client) {
this.client = client;
reloadRelativeArea();
}
public void init () {
if (timer != null) cleanup();
final TimerTask task = new TimerTask() {
public void run () {
tick();
}
};
final TimerTask refillTask = new TimerTask() {
@Override
public void run () {
if (alreadyFilled) {
alreadyFilled = false;
return;
}
check();
if (!shouldRefill) return;
refill();
shouldRefill = false;
}
};
timer = new Timer();
timer.schedule(task, 50, 50);
timer.schedule(refillTask, 50, 1000);
if (client.player == null) return;
move(client.player.getPos());
}
private void tick () {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) {
cleanup();
return;
}
reloadRelativeArea();
}
public void reloadRelativeArea () {
noPos = ChipmunkMod.CONFIG.core.relativeArea;
}
public void check () {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null || withPos == null || !ready) return;
final ClientPlayerEntity player = client.player;
final ClientWorld world = client.world;
if (player == null || world == null) return;
if (oldDimension != null && !oldDimension.equals(world.getDimension())) move(client.player.getPos());
oldDimension = world.getDimension();
try {
for (int x = withPos.getMinX(); x <= withPos.getMaxX(); x++) {
for (int y = withPos.getMinY(); y <= withPos.getMaxY(); y++) {
for (int z = withPos.getMinZ(); z <= withPos.getMaxZ(); z++) {
final BlockPos pos = new BlockPos(x, y, z);
final Block block = world.getBlockState(pos).getBlock();
if (block instanceof CommandBlock) continue;
shouldRefill = true;
return;
}
}
}
} catch (final Exception e) {
ChipmunkMod.LOGGER.error("Error while checking if core needs refilling", e);
}
}
public void move (final Vec3d position) {
final ClientWorld world = client.world;
if (world == null || noPos == null) return;
final DimensionType dimension = world.getDimension();
final int dimMinY = dimension.minY();
final int dimMaxY = dimension.height() + dimMinY - 1; // -1 accounts for block at Y=0
int yOffset = 0;
if (noPos.getMinY() < dimMinY) {
yOffset = dimMinY - noPos.getMinY();
} else if (noPos.getMaxY() > dimMaxY) {
yOffset = dimMaxY - noPos.getMaxY();
}
origin = new BlockPos(
((int) position.getX() / 16) * 16,
noPos.getMinY() + yOffset,
((int) position.getZ() / 16) * 16
);
withPos = noPos.offset(origin.getX(), yOffset, origin.getZ());
block = new BlockPos(withPos.getMinX(), withPos.getMinY(), withPos.getMinZ());
refill();
final Timer timer = new Timer();
final TimerTask task = new TimerTask() {
@Override
public void run () {
for (final Listener listener : ListenerManager.listeners) listener.coreMoved();
if (!ready) {
ready = true;
for (final Listener listener : ListenerManager.listeners) listener.coreReady();
}
}
};
timer.schedule(task, 75);
}
public void refill () {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (!runFillCommand || client.world == null || networkHandler == null || withPos == null) return;
final Chunk chunk = client.world.getChunk(withPos.getCenter());
if (chunk == null) return;
final String command = String.format(
"fill %s %s %s %s %s %s command_block",
withPos.getMinX(),
withPos.getMinY(),
withPos.getMinZ(),
withPos.getMaxX(),
withPos.getMaxY(),
withPos.getMaxZ()
);
runPlaceBlock(command);
}
public void incrementCurrentBlock () {
if (withPos == null) return;
int x = block.getX() + 1;
int y = block.getY();
int z = block.getZ();
if (x > withPos.getMaxX()) {
x = withPos.getMinX();
z++;
if (z > withPos.getMaxZ()) {
z = withPos.getMinZ();
y++;
if (y > withPos.getMaxY()) {
y = withPos.getMinY();
}
}
}
block = new BlockPos(x, y, z);
}
public void run (final String command) {
if (command.length() > 32767) return;
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) return;
final ClientConnection connection = networkHandler.getConnection();
if (block == null) return;
ChipmunkMod.LOGGER.info("Executing core command: {}", command);
if (KaboomCheck.INSTANCE.isKaboom) {
connection.send(
new UpdateCommandBlockC2SPacket(
block,
command,
CommandBlockBlockEntity.Type.AUTO,
false,
false,
true
)
);
} else {
connection.send(
new UpdateCommandBlockC2SPacket(
block,
"",
CommandBlockBlockEntity.Type.REDSTONE,
false,
false,
false
)
);
connection.send(
new UpdateCommandBlockC2SPacket(
block,
command,
CommandBlockBlockEntity.Type.REDSTONE,
false,
false,
true
)
);
}
incrementCurrentBlock();
}
public CompletableFuture<NbtCompound> runTracked (final String command) {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) return new CompletableFuture<>();
final ClientConnection connection = networkHandler.getConnection();
if (block == null) return new CompletableFuture<>();
if (KaboomCheck.INSTANCE.isKaboom) {
connection.send(
new UpdateCommandBlockC2SPacket(
block,
command,
CommandBlockBlockEntity.Type.AUTO,
true,
false,
true
)
);
} else {
connection.send(
new UpdateCommandBlockC2SPacket(
block,
"",
CommandBlockBlockEntity.Type.REDSTONE,
true,
false,
false
)
);
connection.send(
new UpdateCommandBlockC2SPacket(
block,
command,
CommandBlockBlockEntity.Type.REDSTONE,
true,
false,
true
)
);
}
final CompletableFuture<NbtCompound> future = new CompletableFuture<>();
final Timer timer = new Timer();
final BlockPos oldBlock = block;
final TimerTask queryTask = new TimerTask() {
public void run () {
client.getNetworkHandler().getDataQueryHandler().queryBlockNbt(oldBlock, future::complete);
}
};
timer.schedule(queryTask, 50);
incrementCurrentBlock();
return future;
}
public void runPlaceBlock (final String command) {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) return;
final ClientConnection connection = networkHandler.getConnection();
final ClientPlayerEntity player = client.player;
final ClientWorld world = client.world;
if (player == null || world == null || !player.isInCreativeMode()) return;
final DimensionType dimensionType = world.getDimension();
if (
player.getPos().getY() < dimensionType.minY()
|| player.getPos().getY() > dimensionType.height() + dimensionType.minY()
) {
networkHandler.sendChatCommand(command);
return;
}
final ClientPlayerInteractionManager interactionManager = client.interactionManager;
if (interactionManager == null) return;
final float yaw = player.getYaw();
final float pitch = player.getPitch();
// Anti Block when flying around
final BlockPos position = player.getBlockPos().add(
(int) Math.round(3 * Math.cos(Math.toRadians(yaw))),
3 * (pitch < 0 ? -1 : 1),
(int) Math.round(3 * Math.sin(Math.toRadians(yaw)))
);
// stolen from two five hundred million dollars
final BlockState oldBlockState = world.getBlockState(position);
final int freeHotBarSlot = player.getInventory().getEmptySlot();
final int slot = 36 + freeHotBarSlot;
final int oldSelectedSlot = player.getInventory().selectedSlot;
final ItemStack oldStack = player.getInventory().getStack(slot).copy();
final ItemStack commandBlock = new ItemStack(Items.COMMAND_BLOCK);
final NbtCompound data = new NbtCompound();
data.putString("id", "minecraft:command_block");
data.putString("Command", command);
data.putBoolean("auto", true);
final NbtCompound blockEntityTag = new NbtCompound();
blockEntityTag.put("BlockEntityTag", data);
commandBlock.applyComponentsFrom(
ComponentMap.builder()
.add(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(blockEntityTag))
.add(DataComponentTypes.BLOCK_ENTITY_DATA, NbtComponent.of(data))
.build()
);
connection.send(new CreativeInventoryActionC2SPacket(slot, commandBlock));
if (oldSelectedSlot != freeHotBarSlot) {
connection.send(new UpdateSelectedSlotC2SPacket(freeHotBarSlot));
}
interactionManager.breakBlock(position);
interactionManager.interactBlock(
player,
Hand.MAIN_HAND,
new BlockHitResult(
new Vec3d(position),
Direction.UP,
position,
false
)
);
if (oldSelectedSlot != freeHotBarSlot) {
connection.send(new UpdateSelectedSlotC2SPacket(oldSelectedSlot));
}
connection.send(new CreativeInventoryActionC2SPacket(slot, oldStack));
final Timer timer = new Timer();
final TimerTask task = new TimerTask() {
@Override
public void run () {
final StringBuilder command = new StringBuilder(
String.format(
"setblock %d %d %d %s",
position.getX(),
position.getY(),
position.getZ(),
Registries.BLOCK.getId(oldBlockState.getBlock())
)
);
if (!oldBlockState.getProperties().isEmpty()) {
command.append('[');
for (final Property<?> property : oldBlockState.getProperties()) {
command.append(property.getName())
.append('=')
.append(Util.getValueAsString(property, property.getType()))
.append(',');
}
command.deleteCharAt(command.length() - 1);
command.append(']');
}
CommandCore.this.run(command.toString());
}
};
timer.schedule(task, 100); // assuming the core has already been filled at this point
}
public void cleanup () {
if (timer == null) return;
timer.cancel();
timer.purge();
withPos = null;
block = null;
ready = false;
}
}

View file

@ -1,39 +1,36 @@
package land.chipmunk.chipmunkmod.modules;
import java.util.List;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class CommandLoopManager {
public static final CommandLoopManager INSTANCE = new CommandLoopManager(CommandCore.INSTANCE);
private final CommandCore core;
public List<CommandLoop> commandLoops = new ArrayList<>();
public CommandLoopManager (CommandCore core) {
public CommandLoopManager (final CommandCore core) {
this.core = core;
}
public static final CommandLoopManager INSTANCE = new CommandLoopManager(CommandCore.INSTANCE);
public int loopCommand (String command, long interval) {
public int loopCommand (final String command, final long interval) {
final CommandLoop loop = new CommandLoop(this.core, command, interval);
if (!commandLoops.add(loop)) return -1;
commandLoops.add(loop);
return commandLoops.size() - 1;
}
public boolean removeAndStop (CommandLoop loop) {
public boolean removeAndStop (final CommandLoop loop) {
loop.stop();
return commandLoops.remove(loop);
}
public boolean removeAndStop (int id) {
public boolean removeAndStop (final int id) {
return removeAndStop(commandLoops.get(id));
}
public void clearLoops () {
for (CommandLoop loop : this.commandLoops) loop.stop();
for (final CommandLoop loop : this.commandLoops) loop.stop();
commandLoops.clear();
}
@ -45,7 +42,7 @@ public class CommandLoopManager {
public long interval;
private Timer timer;
public CommandLoop (CommandCore core, String command, long interval) {
public CommandLoop (final CommandCore core, final String command, final long interval) {
this.core = core;
this.command = command;
this.interval = interval;
@ -53,8 +50,9 @@ public class CommandLoopManager {
timer.schedule(this.createTimerTask(), interval, interval);
}
private long interval (long interval) {
if (timer == null) throw new IllegalStateException("Attempted to set the interval of a stopped command loop");
private long interval (final long interval) {
if (timer == null)
throw new IllegalStateException("Attempted to set the interval of a stopped command loop");
timer.cancel();
timer.purge();

View file

@ -1,140 +0,0 @@
package land.chipmunk.chipmunkmod.modules;
import com.google.common.hash.Hashing;
import com.google.gson.JsonElement;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.text.Text;
import java.nio.charset.StandardCharsets;
import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CustomChat {
private final MinecraftClient client;
public static final CustomChat INSTANCE = new CustomChat(MinecraftClient.getInstance());
public boolean enabled = true;
public String format;
private Timer timer;
private int total = 0;
public CustomChat (MinecraftClient client) {
this.client = client;
reloadFormat();
}
public void init () {
final TimerTask task = new TimerTask() {
public void run () {
tick();
}
};
resetTotal();
timer = new Timer();
timer.schedule(task, 0, 50);
}
private void tick () {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler != null) return;
resetTotal();
cleanup();
}
public void resetTotal() {
total = 0;
}
private void cleanup () {
if (timer == null) return;
timer.cancel();
timer.purge();
}
public void reloadFormat () {
final JsonElement formatString = ChipmunkMod.CONFIG.customChat.format;
if (formatString == null) format = "{\"translate\":\"chat.type.text\",\"with\":[\"USERNAME\",\"MESSAGE\"]}";
else format = formatString.toString();
}
public void chat (String message) {
final ClientPlayerEntity player = client.player;
if (!enabled || !player.hasPermissionLevel(2) || !player.isCreative()) {
Chat.sendChatMessage(message, true);
return;
}
final String username = MinecraftClient.getInstance().getSession().getUsername();
final String sanitizedMessage = message
.replace("\\", "\\\\")
.replace("\"", "\\\"");
final LegacyComponentSerializer serializer = LegacyComponentSerializer.legacyAmpersand();
final String randomized = String.valueOf(Math.random());
final Component deserialized = serializer.deserialize(message);
final String messageWithColor = GsonComponentSerializer.gson().serialize(deserialized).replace("MESSAGE", randomized);
final String key = ChipmunkMod.CONFIG.bots.chomens.formatKey;
final String hash = key != null ?
Hashing.sha256()
.hashString(key + total, StandardCharsets.UTF_8)
.toString()
.substring(0, 8) :
"";
total++;
try {
// final MutablePlayerListEntry entry = Players.INSTANCE.getEntry(client.getNetworkHandler().getProfile().getId());
// final Component displayNameComponent = entry.displayName().asComponent();
// final String prefix = GsonComponentSerializer.gson().serialize(Component.join(JoinConfiguration.separator(Component.empty()), displayNameComponent.children().get(0)));
// final String displayName = GsonComponentSerializer.gson().serialize(Component.join(JoinConfiguration.separator(Component.empty()), displayNameComponent.children().get(1)));
// TODO: make this code not ohio code.,.,
String sanitizedFormat = format
// .replace("\"PREFIX\"", prefix)
// .replace("\"DISPLAYNAME\"", displayName)
.replace("USERNAME", username)
.replace("HASH", hash)
.replace("{\"text\":\"MESSAGE\"}", messageWithColor)
.replace("\"extra\":[\"MESSAGE\"],\"color\":", "\"extra\":[" + messageWithColor + "],\"color\":")
.replace("MESSAGE", sanitizedMessage.replaceAll("&.", ""))
.replace(randomized, "MESSAGE"); // ohio ohio
CommandCore.INSTANCE.run((KaboomCheck.INSTANCE.isKaboom ? "minecraft:tellraw @a " : "tellraw @a ") + sanitizedFormat);
} catch (Exception e) {
if (client.player == null) return;
((Audience) client.player).sendMessage(Component.text(e.toString()).color(NamedTextColor.RED));
}
}
}

View file

@ -1,83 +1,25 @@
package land.chipmunk.chipmunkmod.modules;
import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.network.packet.s2c.play.CommandSuggestionsS2CPacket;
import net.minecraft.command.CommandSource;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CompletableFuture;
public class KaboomCheck extends Listener {
public class KaboomCheck {
public static final KaboomCheck INSTANCE = new KaboomCheck();
private static final String CHECKED_COMMAND_OP = "extras:prefix"; // Added circa 2018
private static final String CHECKED_COMMAND = "minecraft:op"; // It'd be a bit weird for non-Kaboom servers to allow /op without OP...
private final MinecraftClient client = MinecraftClient.getInstance();
public boolean isKaboom = false;
private Timer timer = null;
private final MinecraftClient client;
public static final KaboomCheck INSTANCE = new KaboomCheck(MinecraftClient.getInstance());
public KaboomCheck (MinecraftClient client) {
this.client = client;
ListenerManager.addListener(this);
}
public void init () {}
public void onJoin () {
final TimerTask task = new TimerTask() {
public void run () {
tick();
}
};
if (timer != null) cleanup();
timer = new Timer();
timer.schedule(task, 50, 50);
check();
this.isKaboom = false;
}
private void tick () {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
public void onCommandTree (final CommandDispatcher<CommandSource> dispatcher) {
assert client.player != null; // We can only receive this packet while in a server
final String checkedCommand = client.player.getPermissionLevel() == 4
? CHECKED_COMMAND_OP : CHECKED_COMMAND;
if (networkHandler == null) cleanup();
this.isKaboom = dispatcher.getRoot().getChild(checkedCommand) != null;
}
private void check () {
final CompletableFuture<CommandSuggestionsS2CPacket> future = TabComplete.INSTANCE.complete("/ver ");
future.thenApply((packet) -> {
final Suggestions suggestions = packet.getSuggestions();
for (int i = 0; i < suggestions.getList().size(); i++) {
final Suggestion suggestion = suggestions.getList().get(i);
if (suggestion.getText().equals("Extras")) {
isKaboom = true;
break;
}
}
return true;
});
}
private void cleanup () {
if (timer == null) return;
isKaboom = false;
timer.purge();
timer.cancel();
}
}

View file

@ -1,8 +1,10 @@
package land.chipmunk.chipmunkmod.modules;
import com.mojang.authlib.GameProfile;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.util.ColorUtilities;
import land.chipmunk.chipmunkmod.util.RandomUtilities;
import land.chipmunk.chipmunkmod.util.UUIDUtilities;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
@ -14,23 +16,21 @@ import java.util.Timer;
import java.util.TimerTask;
public class RainbowName {
private final MinecraftClient client;
public static final RainbowName INSTANCE = new RainbowName(MinecraftClient.getInstance());
private static final String BUKKIT_COLOR_CODES = "123456789abcdefklmorx";
private static final String TEAM_NAME_CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.+";
private Timer timer = null;
private final MinecraftClient client;
private final Random random = new Random();
public boolean enabled = false;
private String[] team;
public String displayName;
private Timer timer = null;
private String team;
private int startHue = 0;
public RainbowName (final MinecraftClient client) {
this.client = client;
this.displayName = client.getSession().getUsername();
}
public void init () {
final TimerTask task = new TimerTask() {
public void run () {
@ -44,80 +44,36 @@ public class RainbowName {
timer.schedule(task, 0, 50);
}
private String[] generateColorCodes(int length) {
String SALTCHARS = BUKKIT_COLOR_CODES;
StringBuilder salt = new StringBuilder();
Random rnd = new Random();
while (salt.length() < length) { // length of the random string.
int index = (int) (rnd.nextFloat() * SALTCHARS.length());
salt.append(SALTCHARS.charAt(index));
}
String saltStr = salt.toString();
return saltStr.split("");
}
private String generateUsername (String[] codes) {
StringBuilder string = new StringBuilder();
for (String code : codes) string.append("&").append(code);
return string.toString();
}
private String generateUsername (int _codes) {
StringBuilder string = new StringBuilder();
final String[] codes = generateColorCodes(_codes);
for (String code : codes) string.append("&").append(code);
return string.toString();
}
private String generateUsername (char[] codes, char character) {
StringBuilder string = new StringBuilder();
for (char code : codes) string.append(character + code);
return string.toString();
}
private String[] generateTeamName () {
String SALTCHARS = TEAM_NAME_CHARACTERS;
StringBuilder salt = new StringBuilder();
Random rnd = new Random();
while (salt.length() < TEAM_NAME_CHARACTERS.length()) { // length of the random string.
int index = (int) (rnd.nextFloat() * SALTCHARS.length());
salt.append(SALTCHARS.charAt(index));
}
String saltStr = salt.toString();
return saltStr.split("");
}
public void enable () {
final String[] colorCodes = generateColorCodes(8);
client.getNetworkHandler().sendChatCommand("extras:username " + generateUsername(colorCodes));
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) return;
final GameProfile profile = networkHandler.getProfile();
team = generateTeamName();
final String username = RandomUtilities.emptyUsername(random);
team = RandomUtilities.randomString(random, RandomUtilities.TEAM_ALLOWED_CHARS, 16);
final String selfSelector = UUIDUtilities.selector(profile.getId());
CommandCore.INSTANCE.run("minecraft:team add " + String.join("", team));
CommandCore.INSTANCE.run("minecraft:execute as " + client.getNetworkHandler().getProfile().getId() + " run team join " + String.join("", team));
networkHandler.sendChatCommand("extras:username " + username);
CommandCore.INSTANCE.run("minecraft:team add " + team);
CommandCore.INSTANCE.run("minecraft:team join " + team + " " + selfSelector);
enabled = true;
}
public void disable () {
client.getNetworkHandler().sendChatCommand("extras:username " + client.getSession().getUsername());
CommandCore.INSTANCE.run("minecraft:team remove " + String.join("", team));
team = null;
CommandCore.INSTANCE.run("essentials:nick " + client.getSession().getUsername() + " off");
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) {
enabled = false;
return;
}
final GameProfile profile = networkHandler.getProfile();
CommandCore.INSTANCE.run("essentials:nick " + profile.getId() + " off");
CommandCore.INSTANCE.run("minecraft:team remove " + team);
networkHandler.sendChatCommand("extras:username " + profile.getName());
enabled = false;
}
public RainbowName (MinecraftClient client) {
this.client = client;
this.displayName = client.getSession().getUsername();
}
private void tick () {
try {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
@ -129,25 +85,26 @@ public class RainbowName {
if (!enabled) return;
final GameProfile profile = networkHandler.getProfile();
int hue = startHue;
int increment = (int) (360.0 / Math.max(displayName.length(), 20));
final int increment = (int) (360.0 / Math.max(displayName.length(), 20));
Component component = Component.empty();
StringBuilder essentialsNickname = new StringBuilder();
final StringBuilder essentialsNickname = new StringBuilder();
for (char character : displayName.toCharArray()) {
String color = String.format("%06x", ColorUtilities.hsvToRgb(hue, 100, 100));
for (final char character : displayName.toCharArray()) {
final String color = String.format("%06x", ColorUtilities.hsvToRgb(hue, 100, 100));
component = component.append(Component.text(character).color(TextColor.fromHexString("#" + color)));
essentialsNickname.append("\u00a7#").append(color).append(character != ' ' ? character : '_');
essentialsNickname.append("§#").append(color).append(character != ' ' ? character : '_');
hue = (hue + increment) % 360;
}
CommandCore.INSTANCE.run("minecraft:team modify " + String.join("", team) + " prefix " + GsonComponentSerializer.gson().serialize(component));
CommandCore.INSTANCE.run("essentials:nick " + client.getSession().getUsername() + " " + essentialsNickname);
CommandCore.INSTANCE.run("minecraft:team modify " + team + " prefix " + GsonComponentSerializer.gson().serialize(component));
CommandCore.INSTANCE.run("essentials:nick " + profile.getId() + " " + essentialsNickname);
startHue = (startHue + increment) % 360;
} catch (Exception e) {
e.printStackTrace();
} catch (final Exception e) {
ChipmunkMod.LOGGER.error("Error while ticking rainbow name", e);
}
}

View file

@ -1,161 +1,137 @@
package land.chipmunk.chipmunkmod.modules;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
import net.minecraft.network.packet.s2c.play.GameStateChangeS2CPacket;
import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket;
import net.minecraft.text.Text;
import java.util.Timer;
import java.util.TimerTask;
import static land.chipmunk.chipmunkmod.util.ServerUtilities.serverHasCommand;
public class SelfCare extends Listener {
private final MinecraftClient client;
public final long interval;
public final long chatInterval;
public boolean opEnabled = true;
public boolean gamemodeEnabled = true;
public boolean cspyEnabled = true;
public boolean icuEnabled = true;
private int gameMode;
public String skin;
private Timer timer;
private Timer chatTimer;
private boolean cspy = false;
public boolean hasSkin = false;
private int positionPacketsPerSecond = 0;
public static final SelfCare INSTANCE = new SelfCare(MinecraftClient.getInstance(), 70L, 500L); // make the intervals in config?
public SelfCare (MinecraftClient client, long interval, long chatInterval) {
this.client = client;
this.interval = interval;
this.chatInterval = chatInterval;
this.skin = ChipmunkMod.CONFIG.autoSkinUsername == null ? "off" : ChipmunkMod.CONFIG.autoSkinUsername; // can this be null?
ListenerManager.addListener(this);
}
public void init () {}
public void onJoin () {
final TimerTask task = new TimerTask() {
public void run () {
tick();
}
};
final TimerTask chatTask = new TimerTask() {
public void run () {
chatTick();
}
};
timer = new Timer();
chatTimer = new Timer();
timer.schedule(task, interval, interval);
chatTimer.schedule(chatTask, chatInterval, chatInterval);
}
public void cleanup () {
if (timer == null || chatTimer == null) return;
timer.cancel();
timer.purge();
chatTimer.cancel();
chatTimer.purge();
gameMode = -1;
hasSkin = false;
cspy = false;
// cspy too mabe?
// why was cspy not here lol
}
@Override
public void chatMessageReceived (Text message) {
final String stringMessage = message.getString();
if (stringMessage.equals("Successfully enabled CommandSpy")) cspy = true;
else if (stringMessage.equals("Successfully disabled CommandSpy")) cspy = false;
else if (stringMessage.equals("Successfully set your skin to " + skin + "'s")) hasSkin = true;
else if (
stringMessage.equals("Successfully removed your skin") ||
stringMessage.startsWith("Successfully set your skin to ")
) hasSkin = false;
}
public void tick () {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) {
cleanup();
return;
}
final ClientPlayerEntity player = client.player;
if (player != null && !player.hasPermissionLevel(2) && opEnabled) { if (serverHasCommand("op")) networkHandler.sendChatCommand("op @s[type=player]"); }
else if (gameMode != 1 && gamemodeEnabled) networkHandler.sendChatCommand("gamemode creative");
else if (positionPacketsPerSecond >= 10 && icuEnabled) CommandCore.INSTANCE.run("sudo * icu stop");
}
public void chatTick () {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (!cspy && cspyEnabled) { if (serverHasCommand("c")) networkHandler.sendChatCommand("c on"); }
else if (!hasSkin && !skin.equals("off")) { if (serverHasCommand("skin")) networkHandler.sendChatCommand("skin " + skin); }
}
@Override
public void packetReceived(Packet<?> packet) {
if (packet instanceof GameJoinS2CPacket) packetReceived((GameJoinS2CPacket) packet);
else if (packet instanceof GameStateChangeS2CPacket) packetReceived((GameStateChangeS2CPacket) packet);
else if (packet instanceof PlayerPositionLookS2CPacket) packetReceived((PlayerPositionLookS2CPacket) packet);
}
public void packetReceived(GameJoinS2CPacket packet) {
gameMode = packet.commonPlayerSpawnInfo().gameMode().getId();
}
public void packetReceived(GameStateChangeS2CPacket packet) {
if (packet.getReason() != GameStateChangeS2CPacket.GAME_MODE_CHANGED) return;
gameMode = (int) packet.getValue();
}
public void packetReceived(PlayerPositionLookS2CPacket packet) {
if (timer == null) return;
try {
positionPacketsPerSecond++;
timer.schedule(new TimerTask() {
@Override
public void run() {
positionPacketsPerSecond--;
}
}, 1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package land.chipmunk.chipmunkmod.modules;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
import net.minecraft.network.packet.s2c.play.GameStateChangeS2CPacket;
import net.minecraft.text.Text;
import java.util.Timer;
import java.util.TimerTask;
import static land.chipmunk.chipmunkmod.util.ServerUtilities.serverHasCommand;
public class SelfCare implements Listener {
public static final SelfCare INSTANCE = new SelfCare(MinecraftClient.getInstance(), 70L, 500L); // make the intervals in config?
public final long interval;
public final long chatInterval;
private final MinecraftClient client;
public boolean opEnabled = ChipmunkMod.CONFIG.selfCare.op;
public boolean gamemodeEnabled = ChipmunkMod.CONFIG.selfCare.gameMode;
public boolean cspyEnabled = ChipmunkMod.CONFIG.selfCare.cspy;
public String skin;
public boolean hasSkin = false;
private int gameMode;
private Timer timer;
private Timer chatTimer;
private boolean cspy = false;
public SelfCare (final MinecraftClient client, final long interval, final long chatInterval) {
this.client = client;
this.interval = interval;
this.chatInterval = chatInterval;
this.skin = ChipmunkMod.CONFIG.autoSkinUsername == null ? "off" : ChipmunkMod.CONFIG.autoSkinUsername; // can this be null?
ListenerManager.addListener(this);
}
public void init () {
}
public void onJoin () {
final TimerTask task = new TimerTask() {
public void run () {
tick();
}
};
final TimerTask chatTask = new TimerTask() {
public void run () {
chatTick();
}
};
timer = new Timer();
chatTimer = new Timer();
timer.schedule(task, interval, interval);
chatTimer.schedule(chatTask, chatInterval, chatInterval);
}
public void cleanup () {
if (timer == null || chatTimer == null) return;
timer.cancel();
timer.purge();
chatTimer.cancel();
chatTimer.purge();
gameMode = -1;
hasSkin = false;
cspy = false;
}
@Override
public void chatMessageReceived (final Text message) {
final String stringMessage = message.getString();
if (stringMessage.equals("Successfully enabled CommandSpy")) cspy = true;
else if (stringMessage.equals("Successfully disabled CommandSpy")) cspy = false;
else if (stringMessage.equals("Successfully set your skin to " + skin + "'s")) hasSkin = true;
else if (
stringMessage.equals("Successfully removed your skin") ||
stringMessage.startsWith("Successfully set your skin to ")
) hasSkin = false;
}
public void tick () {
final ClientPlayerEntity player = client.player;
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) {
cleanup();
return;
}
if (player != null && !player.hasPermissionLevel(2) && opEnabled && serverHasCommand("op"))
networkHandler.sendChatCommand("op @s[type=player]");
else if (gameMode != 1 && gamemodeEnabled) networkHandler.sendChatCommand("gamemode creative");
}
public void chatTick () {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) return;
if (!cspy && cspyEnabled) {
if (serverHasCommand("c")) networkHandler.sendChatCommand("c on");
} else if (!hasSkin && !skin.equals("off")) {
if (serverHasCommand("skin")) networkHandler.sendChatCommand("skin " + skin);
}
}
@Override
public void packetReceived (final Packet<?> packet) {
if (packet instanceof GameJoinS2CPacket) packetReceived((GameJoinS2CPacket) packet);
else if (packet instanceof GameStateChangeS2CPacket) packetReceived((GameStateChangeS2CPacket) packet);
}
public void packetReceived (final GameJoinS2CPacket packet) {
gameMode = packet.commonPlayerSpawnInfo().gameMode().getId();
}
public void packetReceived (final GameStateChangeS2CPacket packet) {
if (packet.getReason() != GameStateChangeS2CPacket.GAME_MODE_CHANGED) return;
gameMode = (int) packet.getValue();
}
}

View file

@ -5,16 +5,16 @@ import land.chipmunk.chipmunkmod.song.Song;
import land.chipmunk.chipmunkmod.song.SongLoaderException;
import land.chipmunk.chipmunkmod.song.SongLoaderThread;
import land.chipmunk.chipmunkmod.util.MathUtilities;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import java.io.File;
@ -25,65 +25,71 @@ import java.util.Timer;
import java.util.TimerTask;
public class SongPlayer {
public static final String SELECTOR = "@a[tag=!nomusic,tag=!chipmunkmod_nomusic]";
public static final String SELECTOR = "@a[tag=cm_name3_music,tag=!nomusic,tag=!chipmunkmod_nomusic]";
public static final SongPlayer INSTANCE = new SongPlayer(MinecraftClient.getInstance());
public static File SONG_DIR = new File("songs");
static {
if (!SONG_DIR.exists()) {
SONG_DIR.mkdir();
}
}
public static final SongPlayer INSTANCE = new SongPlayer(MinecraftClient.getInstance());
private final MinecraftClient client;
public Song currentSong;
public LinkedList<Song> songQueue = new LinkedList<>();
public Timer playTimer;
public SongLoaderThread loaderThread;
private int ticksUntilPausedActionbar = 20;
public boolean useCore = true;
public boolean actionbar = true;
public float pitch = 0;
private int ticksUntilPausedActionbar = 20;
private final MinecraftClient client;
public SongPlayer (MinecraftClient client) {
public SongPlayer (final MinecraftClient client) {
this.client = client;
}
// TODO: Less duplicate code
public void loadSong (Path location) {
public void loadSong (final Path location) {
final ClientPlayerEntity player = client.player;
if (player == null) return;
if (loaderThread != null) {
((Audience) client.player).sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED));
player.sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED));
return;
}
try {
final SongLoaderThread _loaderThread = new SongLoaderThread(location);
((Audience) client.player).sendMessage(Component.translatable("Loading %s", Component.text(location.getFileName().toString(), NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN));
player.sendMessage(Component.translatable("Loading %s", Component.text(location.toString(), TextColor.fromHexString("#ffccee"))).color(TextColor.fromHexString("#ff99dd")));
_loaderThread.start();
loaderThread = _loaderThread;
} catch (SongLoaderException e) {
((Audience) client.player).sendMessage(Component.translatable("Failed to load song: %s", e.message.getString()).color(NamedTextColor.RED));
} catch (final SongLoaderException e) {
player.sendMessage(Component.translatable("Failed to load song: %s", Component.text(e.message.getString())).color(NamedTextColor.RED));
loaderThread = null;
}
}
public void loadSong (URL location) {
public void loadSong (final URL location) {
final ClientPlayerEntity player = client.player;
if (player == null) return;
if (loaderThread != null) {
((Audience) client.player).sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED));
player.sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED));
return;
}
try {
final SongLoaderThread _loaderThread = new SongLoaderThread(location);
((Audience) client.player).sendMessage(Component.translatable("Loading %s", Component.text(location.toString(), NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN));
player.sendMessage(Component.translatable("Loading %s", Component.text(location.toString(), TextColor.fromHexString("#ffccee"))).color(TextColor.fromHexString("#ff99dd")));
_loaderThread.start();
loaderThread = _loaderThread;
} catch (SongLoaderException e) {
((Audience) client.player).sendMessage(Component.translatable("Failed to load song: %s", e.message.getString()).color(NamedTextColor.RED));
} catch (final SongLoaderException e) {
player.sendMessage(Component.translatable("Failed to load song: %s", Component.text(e.message.getString())).color(NamedTextColor.RED));
loaderThread = null;
}
}
@ -101,12 +107,12 @@ public class SongPlayer {
return;
}
if (loaderThread != null && !loaderThread.isAlive()) {
if (loaderThread != null && !loaderThread.isAlive() && client.player != null) {
if (loaderThread.exception != null) {
((Audience) client.player).sendMessage(Component.translatable("Failed to load song: %s", loaderThread.exception.message.getString()).color(NamedTextColor.RED));
client.player.sendMessage(Component.translatable("Failed to load song: %s", Component.text(loaderThread.exception.message.getString())).color(NamedTextColor.RED));
} else {
songQueue.add(loaderThread.song);
((Audience) client.player).sendMessage(Component.translatable("Added %s to the song queue", Component.empty().append(loaderThread.song.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN));
client.player.sendMessage(Component.translatable("Added %s to the song queue", Component.empty().append(loaderThread.song.name).color(TextColor.fromHexString("#ffccee"))).color(TextColor.fromHexString("#ff99dd")));
}
loaderThread = null;
}
@ -114,8 +120,19 @@ public class SongPlayer {
if (currentSong == null) {
if (songQueue.isEmpty()) return;
CommandCore.INSTANCE.run("tag " + MinecraftClient.getInstance().getSession().getUsername() + " add cm_name3_music");
currentSong = songQueue.poll();
((Audience) client.player).sendMessage(Component.translatable("Now playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN));
if (client.player != null) client.player.sendMessage(
Component
.translatable(
"Now playing %s",
Component.empty()
.append(currentSong.name)
.color(TextColor.fromHexString("#ffccee"))
)
.color(TextColor.fromHexString("#ff99dd"))
);
currentSong.play();
}
@ -123,9 +140,11 @@ public class SongPlayer {
else ticksUntilPausedActionbar = 20;
try {
if (!useCore && actionbar && client.player != null) ((Audience) client.player).sendActionBar(generateActionbar());
else if (actionbar) CommandCore.INSTANCE.run("title " + SELECTOR + " actionbar " + GsonComponentSerializer.gson().serialize(generateActionbar()));
} catch (Exception e) {
if (!useCore && actionbar && client.player != null)
client.player.sendActionBar(generateActionbar());
else if (actionbar)
CommandCore.INSTANCE.run("title " + SELECTOR + " actionbar " + GsonComponentSerializer.gson().serialize(generateActionbar()));
} catch (final Exception e) {
e.printStackTrace();
}
@ -134,7 +153,8 @@ public class SongPlayer {
handlePlaying();
if (currentSong.finished()) {
((Audience) client.player).sendMessage(Component.translatable("Finished playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN));
if (client.player != null)
client.player.sendMessage(Component.translatable("Finished playing %s", Component.empty().append(currentSong.name).color(TextColor.fromHexString("#ffccee"))).color(TextColor.fromHexString("#ff99dd")));
currentSong = null;
}
}
@ -148,37 +168,37 @@ public class SongPlayer {
public Component generateActionbar () {
final ClientPlayerEntity player = client.player;
Component component = Component.empty()
.append(Component.translatable("%s", player.getName().getString()).color(NamedTextColor.GREEN))
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
.append(Component.translatable("Now playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN))
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
.append(Component.translatable("%s / %s", formatTime(currentSong.time).color(NamedTextColor.GREEN), formatTime(currentSong.length).color(NamedTextColor.GREEN)).color(NamedTextColor.GRAY))
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
.append(Component.translatable("%s / %s", Component.text(currentSong.position, NamedTextColor.GREEN), Component.text(currentSong.size(), NamedTextColor.GREEN)).color(NamedTextColor.GRAY));
final Component component = Component.empty()
.append(Component.translatable("%s", player.getName().getString()).color(TextColor.fromHexString("#ff99dd")))
.append(Component.translatable(" | ", NamedTextColor.WHITE))
.append(Component.translatable("Now playing %s", Component.empty().append(currentSong.name).color(TextColor.fromHexString("#ffccee"))).color(TextColor.fromHexString("#ff99dd")))
.append(Component.translatable(" | ", NamedTextColor.WHITE))
.append(Component.translatable("%s / %s", formatTime(currentSong.time).color(TextColor.fromHexString("#ff99dd")), formatTime(currentSong.length).color(TextColor.fromHexString("#ff99dd"))).color(NamedTextColor.WHITE))
.append(Component.translatable(" | ", NamedTextColor.WHITE))
.append(Component.translatable("%s / %s", Component.text(currentSong.position, TextColor.fromHexString("#ff99dd")), Component.text(currentSong.size(), TextColor.fromHexString("#ff99dd"))).color(NamedTextColor.WHITE));
if (currentSong.paused) {
return component
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
.append(Component.translatable("Paused", NamedTextColor.DARK_GREEN));
.append(Component.translatable(" | ", NamedTextColor.WHITE))
.append(Component.translatable("Paused", TextColor.fromHexString("#ffccee")));
}
if (currentSong.looping) {
if (currentSong.loopCount > 0) {
return component
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
.append(Component.translatable("Looping (%s/%s)", Component.text(currentSong.currentLoop), Component.text(currentSong.loopCount)).color(NamedTextColor.DARK_GREEN));
.append(Component.translatable(" | ", NamedTextColor.WHITE))
.append(Component.translatable("Looping (%s/%s)", Component.text(currentSong.currentLoop), Component.text(currentSong.loopCount)).color(TextColor.fromHexString("#ffccee")));
}
return component
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
.append(Component.translatable("Looping", NamedTextColor.DARK_GREEN));
.append(Component.translatable(" | ", NamedTextColor.WHITE))
.append(Component.translatable("Looping", TextColor.fromHexString("#ffccee")));
}
return component;
}
public Component formatTime (long millis) {
public Component formatTime (final long millis) {
final int seconds = (int) millis / 1000;
final String minutePart = String.valueOf(seconds / 60);
@ -211,26 +231,39 @@ public class SongPlayer {
if (!useCore && client.player != null) {
final float floatingPitch = (float) (0.5 * (Math.pow(2, ((note.pitch + (pitch / 10)) / 12))));
final String[] thing = note.instrument.sound.split(":");
if (thing[1] == null) return; // idk if this can be null but ill just protect it for now i guess
final String sound = note.instrument.sound;
client.submit(() -> client.world.playSound(
client.player.getX(),
client.player.getY(),
client.player.getZ(),
SoundEvent.of(Identifier.of(thing[0], thing[1])),
client.player.getX() + note.position.getX(),
client.player.getY() + note.position.getY(),
client.player.getZ() + note.position.getZ(),
SoundEvent.of(Identifier.of(Key.MINECRAFT_NAMESPACE, sound)),
SoundCategory.RECORDS,
note.volume,
floatingPitch,
true
));
} else {
final float floatingPitch = MathUtilities.clamp((float) (0.5 * (Math.pow(2, ((note.pitch + (pitch / 10)) / 12)))), 0F, 2F);
final double floatingPitch = MathUtilities.clamp(0.5 * (Math.pow(2, ((note.pitch + (pitch / 10)) / 12))), 0F, 2F);
CommandCore.INSTANCE.run("execute as " + SELECTOR + " at @s run playsound " + note.instrument.sound + " record @s ~ ~ ~ " + note.volume + " " + floatingPitch);
CommandCore.INSTANCE.run(
String.format(
"execute as %s at @s run playsound %s record @s ^%f ^%f ^%f %f %f",
SELECTOR,
note.instrument.sound,
note.position.getX(),
note.position.getY(),
note.position.getZ(),
note.volume,
floatingPitch
)
);
}
} catch (Exception e) {
} catch (final Exception e) {
e.printStackTrace();
}
}

View file

@ -1,59 +0,0 @@
package land.chipmunk.chipmunkmod.modules;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket;
import net.minecraft.network.packet.s2c.play.CommandSuggestionsS2CPacket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class TabComplete extends Listener {
private final MinecraftClient client;
private final Map<Integer, CompletableFuture<CommandSuggestionsS2CPacket>> transactions = new HashMap<>();
public static TabComplete INSTANCE = new TabComplete(MinecraftClient.getInstance());
public TabComplete (MinecraftClient client) {
this.client = client;
ListenerManager.addListener(this);
}
public void init () {}
public CompletableFuture<CommandSuggestionsS2CPacket> complete (String command) {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) return null;
final ClientConnection connection = networkHandler.getConnection();
if (connection == null) return null;
final int transactionId = TransactionManager.INSTANCE.nextTransactionId();
connection.send(new RequestCommandCompletionsC2SPacket(transactionId, command));
final CompletableFuture<CommandSuggestionsS2CPacket> future = new CompletableFuture<>();
transactions.put(transactionId, future);
return future;
}
@Override
public void packetReceived (Packet<?> packet) {
if (packet instanceof CommandSuggestionsS2CPacket) packetReceived((CommandSuggestionsS2CPacket) packet);
}
public void packetReceived (CommandSuggestionsS2CPacket packet) {
final CompletableFuture<CommandSuggestionsS2CPacket> future = transactions.get(packet.id());
if (future == null) return;
future.complete(packet);
transactions.remove(future);
}
}

View file

@ -1,11 +0,0 @@
package land.chipmunk.chipmunkmod.modules;
public class TransactionManager {
public static final TransactionManager INSTANCE = new TransactionManager();
private int transactionId = 0;
public int transactionId () { return transactionId; }
public int nextTransactionId () { return transactionId++; }
}

View file

@ -0,0 +1,83 @@
package land.chipmunk.chipmunkmod.modules.custom_chat;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.modules.Chat;
import land.chipmunk.chipmunkmod.modules.CommandCore;
import land.chipmunk.chipmunkmod.modules.KaboomCheck;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import java.util.Map;
import java.util.regex.Pattern;
public class CustomChat {
public static final CustomChat INSTANCE = new CustomChat(MinecraftClient.getInstance());
private static final GsonComponentSerializer GSON = GsonComponentSerializer.gson();
private static final CustomChatComponentRenderer RENDERER = new CustomChatComponentRenderer();
private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer
// https://sus.red/abc?a=b&c=d will still break the click events, though
.legacyAmpersand()
.toBuilder()
.extractUrls(
Pattern
.compile("((https?://(ww(w|\\d)\\.)?|ww(w|\\d))[-a-zA-Z0-9@:%._+~#=]{1,256}"
+ "\\.[a-zA-Z0-9]{1,63}\\b([-a-zA-Z0-9@:%_+.~#?&/=]*))"),
Style.style(
NamedTextColor.BLUE,
TextDecoration.UNDERLINED,
HoverEvent.showText(
Component
.text("Click here to open the URL")
.color(NamedTextColor.BLUE)
)
)
)
// > `this.useTerriblyStupidHexFormat = true`
// i know it is stupid indeed,
// but i also want the compatibility to the kaboom chat
.useUnusualXRepeatedCharacterHexFormat() // &x&1&2&3&4&5&6abc
.build();
private final MinecraftClient client;
public boolean enabled = true;
public Component format = ChipmunkMod.CONFIG.customChat.format;
public CustomChat (final MinecraftClient client) {
this.client = client;
}
public void chat (final String message) {
final ClientPlayerEntity player = client.player;
if (player == null) return;
if (!enabled || !player.hasPermissionLevel(2) || !player.isCreative()) {
Chat.sendChatMessage(message, true);
return;
}
final Component styledMessage = SERIALIZER.deserialize(message);
final String username = MinecraftClient.getInstance().getSession().getUsername();
final CustomChatContext context = new CustomChatContext(player.getUuidAsString(), styledMessage,
Map.of("MESSAGE", message, "USERNAME", username));
final Component renderedFormat = RENDERER.render(format, context)
.compact();
final String json = GSON.serialize(renderedFormat);
CommandCore.INSTANCE.run((KaboomCheck.INSTANCE.isKaboom ? "minecraft:tellraw @a " : "tellraw @a ") + json);
}
}

View file

@ -0,0 +1,83 @@
package land.chipmunk.chipmunkmod.modules.custom_chat;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentBuilder;
import net.kyori.adventure.text.SelectorComponent;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.renderer.TranslatableComponentRenderer;
import org.jetbrains.annotations.NotNull;
// We don't do any translatable rendering here, but extending from that makes it easier to work with.
public final class CustomChatComponentRenderer extends TranslatableComponentRenderer<CustomChatContext> {
@Override
protected @NotNull Component renderSelector (final @NotNull SelectorComponent component,
final @NotNull CustomChatContext context) {
final String pattern = component.pattern();
if (pattern.equals("@s")) {
final SelectorComponent.Builder builder = Component.selector()
.pattern(context.uuid());
return this.mergeStyleAndOptionallyDeepRender(component, builder, context);
}
return super.renderSelector(component, context);
}
@Override
protected @NotNull Component renderText (final @NotNull TextComponent component,
final @NotNull CustomChatContext context) {
final String content = component.content();
if (content.equals("MESSAGE")) {
return this.mergeMessage(component, context.message(), context);
}
final String arg = context.args().get(component.content());
if (arg != null) {
final TextComponent.Builder builder = Component.text()
.content(arg);
return this.mergeStyleAndOptionallyDeepRender(component, builder, context);
}
return super.renderText(component, context);
}
@SuppressWarnings("NonExtendableApiUsage") // we're not extending it silly
@Override
protected <B extends ComponentBuilder<?, ?>> void mergeStyle (final Component component, final B builder,
final CustomChatContext context) {
super.mergeStyle(component, builder, context);
// render clickEvent that may contain something like "MESSAGE"
// HoverEvent already handled by super
builder.clickEvent(this.mergeClickEvent(component.clickEvent(), context));
}
private Component mergeMessage (final Component root, final Component msg, final CustomChatContext context) {
Component result = msg.applyFallbackStyle(root.style()); // applyFallbackStyle will apply everything that isn't content
final ClickEvent clickEvent = result.clickEvent();
if (clickEvent != null) {
result = result.clickEvent(mergeClickEvent(clickEvent, context));
}
final HoverEvent<?> hoverEvent = result.hoverEvent();
if (hoverEvent != null) {
result = result.hoverEvent(hoverEvent.withRenderedValue(this, context));
}
return result;
}
private ClickEvent mergeClickEvent (final ClickEvent clickEvent, final CustomChatContext context) {
if (clickEvent == null) return null;
final String value = clickEvent.value();
final String arg = context.args().get(value);
if (arg == null) return clickEvent;
return ClickEvent.clickEvent(clickEvent.action(), arg);
}
}

View file

@ -0,0 +1,8 @@
package land.chipmunk.chipmunkmod.modules.custom_chat;
import net.kyori.adventure.text.Component;
import java.util.Map;
public record CustomChatContext(String uuid, Component message, Map<String, String> args) {
}

View file

@ -1,48 +1,47 @@
package land.chipmunk.chipmunkmod.song;
public class Instrument {
public static final Instrument HARP = new Instrument(0, "harp", 54);
public static final Instrument BASEDRUM = new Instrument(1, "basedrum", 0);
public static final Instrument SNARE = new Instrument(2, "snare", 0);
public static final Instrument HAT = new Instrument(3, "hat", 0);
public static final Instrument BASS = new Instrument(4, "bass", 30);
public static final Instrument FLUTE = new Instrument(5, "flute", 66);
public static final Instrument BELL = new Instrument(6, "bell", 78);
public static final Instrument GUITAR = new Instrument(7, "guitar", 42);
public static final Instrument CHIME = new Instrument(8, "chime", 78);
public static final Instrument XYLOPHONE = new Instrument(9, "xylophone", 78);
public static final Instrument IRON_XYLOPHONE = new Instrument(10, "iron_xylophone", 54);
public static final Instrument COW_BELL = new Instrument(11, "cow_bell", 66);
public static final Instrument DIDGERIDOO = new Instrument(12, "didgeridoo", 30);
public static final Instrument BIT = new Instrument(13, "bit", 54);
public static final Instrument BANJO = new Instrument(14, "banjo", 54);
public static final Instrument PLING = new Instrument(15, "pling", 54);
public static final Instrument HARP = new Instrument(0, "harp", 54);
public static final Instrument BASEDRUM = new Instrument(1, "basedrum", 0);
public static final Instrument SNARE = new Instrument(2, "snare", 0);
public static final Instrument HAT = new Instrument(3, "hat", 0);
public static final Instrument BASS = new Instrument(4, "bass", 30);
public static final Instrument FLUTE = new Instrument(5, "flute", 66);
public static final Instrument BELL = new Instrument(6, "bell", 78);
public static final Instrument GUITAR = new Instrument(7, "guitar", 42);
public static final Instrument CHIME = new Instrument(8, "chime", 78);
public static final Instrument XYLOPHONE = new Instrument(9, "xylophone", 78);
public static final Instrument IRON_XYLOPHONE = new Instrument(10, "iron_xylophone", 54);
public static final Instrument COW_BELL = new Instrument(11, "cow_bell", 66);
public static final Instrument DIDGERIDOO = new Instrument(12, "didgeridoo", 30);
public static final Instrument BIT = new Instrument(13, "bit", 54);
public static final Instrument BANJO = new Instrument(14, "banjo", 54);
public static final Instrument PLING = new Instrument(15, "pling", 54);
private static final Instrument[] VALUES = { HARP, BASEDRUM, SNARE, HAT, BASS, FLUTE, BELL, GUITAR, CHIME, XYLOPHONE, IRON_XYLOPHONE, COW_BELL, DIDGERIDOO, BIT, BANJO, PLING };
public final int id;
public final String name;
public final int offset;
public final String sound;
public final int id;
public final String name;
public final int offset;
public final String sound;
private Instrument (final int id, final String name, final int offset, final String sound) {
this.id = id;
this.name = name;
this.offset = offset;
this.sound = sound;
}
private Instrument (int id, String name, int offset, String sound) {
this.id = id;
this.name = name;
this.offset = offset;
this.sound = sound;
}
private Instrument (final int id, final String name, final int offset) {
this.id = id;
this.name = name;
this.offset = offset;
this.sound = "block.note_block." + name;
}
private Instrument (int id, String name, int offset) {
this.id = id;
this.name = name;
this.offset = offset;
this.sound = "minecraft:block.note_block." + name;
}
public static Instrument of (final String sound) {
return new Instrument(-1, null, 0, sound);
}
public static Instrument of (String sound) {
return new Instrument(-1, null, 0, sound);
}
private static Instrument[] values = {HARP, BASEDRUM, SNARE, HAT, BASS, FLUTE, BELL, GUITAR, CHIME, XYLOPHONE, IRON_XYLOPHONE, COW_BELL, DIDGERIDOO, BIT, BANJO, PLING};
public static Instrument fromId (int id) {
return values[id];
}
public static Instrument fromId (final int id) {
return VALUES[id];
}
}

View file

@ -1,8 +1,14 @@
package land.chipmunk.chipmunkmod.song;
import land.chipmunk.chipmunkmod.util.DownloadUtilities;
import java.io.*;
import java.net.*;
import net.minecraft.util.math.Vec3d;
import javax.sound.midi.*;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Paths;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
@ -10,364 +16,357 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import javax.sound.midi.*;
public class MidiConverter {
public static final int SET_INSTRUMENT = 0xC0;
public static final int SET_TEMPO = 0x51;
public static final int NOTE_ON = 0x90;
public static final int NOTE_OFF = 0x80;
public static final int SET_INSTRUMENT = 0xC0;
public static final int SET_TEMPO = 0x51;
public static final int NOTE_ON = 0x90;
public static final int NOTE_OFF = 0x80;
public static HashMap<Integer, Instrument[]> instrumentMap = new HashMap<>();
public static HashMap<Integer, Integer> percussionMap = new HashMap<>();
public static Song getSongFromUrl(URL url) throws IOException, InvalidMidiDataException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
Sequence sequence = MidiSystem.getSequence(DownloadUtilities.DownloadToInputStream(url));
return getSong(sequence, Paths.get(url.toURI().getPath()).getFileName().toString());
}
static {
// Piano (HARP BASS BELL)
instrumentMap.put(0, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Acoustic Grand Piano
instrumentMap.put(1, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Bright Acoustic Piano
instrumentMap.put(2, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL }); // Electric Grand Piano
instrumentMap.put(3, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Honky-tonk Piano
instrumentMap.put(4, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL }); // Electric Piano 1
instrumentMap.put(5, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL }); // Electric Piano 2
instrumentMap.put(6, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Harpsichord
instrumentMap.put(7, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Clavinet
public static Song getSongFromFile(File file) throws InvalidMidiDataException, IOException {
Sequence sequence = MidiSystem.getSequence(file);
return getSong(sequence, file.getName());
}
// Chromatic Percussion (IRON_XYLOPHONE XYLOPHONE BASS)
instrumentMap.put(8, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Celesta
instrumentMap.put(9, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Glockenspiel
instrumentMap.put(10, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Music Box
instrumentMap.put(11, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Vibraphone
instrumentMap.put(12, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Marimba
instrumentMap.put(13, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Xylophone
instrumentMap.put(14, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Tubular Bells
instrumentMap.put(15, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Dulcimer
public static Song getSongFromBytes(byte[] bytes, String name) throws InvalidMidiDataException, IOException {
Sequence sequence = MidiSystem.getSequence(new ByteArrayInputStream(bytes));
return getSong(sequence, name);
}
public static Song getSong(Sequence sequence, String name) {
Song song = new Song(name);
// Organ (BIT DIDGERIDOO BELL)
instrumentMap.put(16, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Drawbar Organ
instrumentMap.put(17, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Percussive Organ
instrumentMap.put(18, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Rock Organ
instrumentMap.put(19, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Church Organ
instrumentMap.put(20, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Reed Organ
instrumentMap.put(21, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Accordian
instrumentMap.put(22, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Harmonica
instrumentMap.put(23, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Tango Accordian
long tpq = sequence.getResolution();
// Guitar (BIT DIDGERIDOO BELL)
instrumentMap.put(24, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Acoustic Guitar (nylon)
instrumentMap.put(25, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Acoustic Guitar (steel)
instrumentMap.put(26, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Electric Guitar (jazz)
instrumentMap.put(27, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Electric Guitar (clean)
instrumentMap.put(28, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Electric Guitar (muted)
instrumentMap.put(29, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Overdriven Guitar
instrumentMap.put(30, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Distortion Guitar
instrumentMap.put(31, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Guitar Harmonics
ArrayList<MidiEvent> tempoEvents = new ArrayList<>();
for (Track track : sequence.getTracks()) {
for (int i = 0; i < track.size(); i++) {
MidiEvent event = track.get(i);
MidiMessage message = event.getMessage();
if (message instanceof MetaMessage) {
MetaMessage mm = (MetaMessage) message;
if (mm.getType() == SET_TEMPO) {
tempoEvents.add(event);
}
// Bass
instrumentMap.put(32, new Instrument[] { Instrument.BASS, Instrument.HARP, Instrument.BELL }); // Acoustic Bass
instrumentMap.put(33, new Instrument[] { Instrument.BASS, Instrument.HARP, Instrument.BELL }); // Electric Bass (finger)
instrumentMap.put(34, new Instrument[] { Instrument.BASS, Instrument.HARP, Instrument.BELL }); // Electric Bass (pick)
instrumentMap.put(35, new Instrument[] { Instrument.BASS, Instrument.HARP, Instrument.BELL }); // Fretless Bass
instrumentMap.put(36, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Slap Bass 1
instrumentMap.put(37, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Slap Bass 2
instrumentMap.put(38, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Synth Bass 1
instrumentMap.put(39, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Synth Bass 2
// Strings
instrumentMap.put(40, new Instrument[] { Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL }); // Violin
instrumentMap.put(41, new Instrument[] { Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL }); // Viola
instrumentMap.put(42, new Instrument[] { Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL }); // Cello
instrumentMap.put(43, new Instrument[] { Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL }); // Contrabass
instrumentMap.put(44, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL }); // Tremolo Strings
instrumentMap.put(45, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Pizzicato Strings
instrumentMap.put(46, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.CHIME }); // Orchestral Harp
instrumentMap.put(47, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Timpani
// Ensenble
instrumentMap.put(48, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // String Ensemble 1
instrumentMap.put(49, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // String Ensemble 2
instrumentMap.put(50, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Synth Strings 1
instrumentMap.put(51, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Synth Strings 2
instrumentMap.put(52, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Choir Aahs
instrumentMap.put(53, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Voice Oohs
instrumentMap.put(54, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Synth Choir
instrumentMap.put(55, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Orchestra Hit
// Brass
instrumentMap.put(56, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
instrumentMap.put(57, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
instrumentMap.put(58, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
instrumentMap.put(59, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
instrumentMap.put(60, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
instrumentMap.put(61, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
instrumentMap.put(62, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
instrumentMap.put(63, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
// Reed
instrumentMap.put(64, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(65, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(66, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(67, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(68, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(69, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(70, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(71, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
// Pipe
instrumentMap.put(72, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(73, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(74, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(75, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(76, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(77, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(78, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
instrumentMap.put(79, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
// Synth Lead
instrumentMap.put(80, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(81, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(82, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(83, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(84, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(85, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(86, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(87, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
// Synth Pad
instrumentMap.put(88, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(89, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(90, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(91, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(92, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(93, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(94, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(95, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
// Synth Effects
// instrumentMap.put(96, new Instrument[]{});
// instrumentMap.put(97, new Instrument[]{});
instrumentMap.put(98, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
instrumentMap.put(99, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(100, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(101, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(102, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
instrumentMap.put(103, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
// Ethnic
instrumentMap.put(104, new Instrument[] { Instrument.BANJO, Instrument.BASS, Instrument.BELL });
instrumentMap.put(105, new Instrument[] { Instrument.BANJO, Instrument.BASS, Instrument.BELL });
instrumentMap.put(106, new Instrument[] { Instrument.BANJO, Instrument.BASS, Instrument.BELL });
instrumentMap.put(107, new Instrument[] { Instrument.BANJO, Instrument.BASS, Instrument.BELL });
instrumentMap.put(108, new Instrument[] { Instrument.BANJO, Instrument.BASS, Instrument.BELL });
instrumentMap.put(109, new Instrument[] { Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL });
instrumentMap.put(110, new Instrument[] { Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL });
instrumentMap.put(111, new Instrument[] { Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL });
// Percussive
instrumentMap.put(112, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
instrumentMap.put(113, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
instrumentMap.put(114, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
instrumentMap.put(115, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
instrumentMap.put(116, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
instrumentMap.put(117, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
instrumentMap.put(118, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
instrumentMap.put(119, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
}
static {
percussionMap.put(35, 10 + 25 * Instrument.BASEDRUM.id);
percussionMap.put(36, 6 + 25 * Instrument.BASEDRUM.id);
percussionMap.put(37, 6 + 25 * Instrument.HAT.id);
percussionMap.put(38, 8 + 25 * Instrument.SNARE.id);
percussionMap.put(39, 6 + 25 * Instrument.HAT.id);
percussionMap.put(40, 4 + 25 * Instrument.SNARE.id);
percussionMap.put(41, 6 + 25 * Instrument.BASEDRUM.id);
percussionMap.put(42, 22 + 25 * Instrument.SNARE.id);
percussionMap.put(43, 13 + 25 * Instrument.BASEDRUM.id);
percussionMap.put(44, 22 + 25 * Instrument.SNARE.id);
percussionMap.put(45, 15 + 25 * Instrument.BASEDRUM.id);
percussionMap.put(46, 18 + 25 * Instrument.SNARE.id);
percussionMap.put(47, 20 + 25 * Instrument.BASEDRUM.id);
percussionMap.put(48, 23 + 25 * Instrument.BASEDRUM.id);
percussionMap.put(49, 17 + 25 * Instrument.SNARE.id);
percussionMap.put(50, 23 + 25 * Instrument.BASEDRUM.id);
percussionMap.put(51, 24 + 25 * Instrument.SNARE.id);
percussionMap.put(52, 8 + 25 * Instrument.SNARE.id);
percussionMap.put(53, 13 + 25 * Instrument.SNARE.id);
percussionMap.put(54, 18 + 25 * Instrument.HAT.id);
percussionMap.put(55, 18 + 25 * Instrument.SNARE.id);
percussionMap.put(56, 1 + 25 * Instrument.HAT.id);
percussionMap.put(57, 13 + 25 * Instrument.SNARE.id);
percussionMap.put(58, 2 + 25 * Instrument.HAT.id);
percussionMap.put(59, 13 + 25 * Instrument.SNARE.id);
percussionMap.put(60, 9 + 25 * Instrument.HAT.id);
percussionMap.put(61, 2 + 25 * Instrument.HAT.id);
percussionMap.put(62, 8 + 25 * Instrument.HAT.id);
percussionMap.put(63, 22 + 25 * Instrument.BASEDRUM.id);
percussionMap.put(64, 15 + 25 * Instrument.BASEDRUM.id);
percussionMap.put(65, 13 + 25 * Instrument.SNARE.id);
percussionMap.put(66, 8 + 25 * Instrument.SNARE.id);
percussionMap.put(67, 8 + 25 * Instrument.HAT.id);
percussionMap.put(68, 3 + 25 * Instrument.HAT.id);
percussionMap.put(69, 20 + 25 * Instrument.HAT.id);
percussionMap.put(70, 23 + 25 * Instrument.HAT.id);
percussionMap.put(71, 24 + 25 * Instrument.HAT.id);
percussionMap.put(72, 24 + 25 * Instrument.HAT.id);
percussionMap.put(73, 17 + 25 * Instrument.HAT.id);
percussionMap.put(74, 11 + 25 * Instrument.HAT.id);
percussionMap.put(75, 18 + 25 * Instrument.HAT.id);
percussionMap.put(76, 9 + 25 * Instrument.HAT.id);
percussionMap.put(77, 5 + 25 * Instrument.HAT.id);
percussionMap.put(78, 22 + 25 * Instrument.HAT.id);
percussionMap.put(79, 19 + 25 * Instrument.SNARE.id);
percussionMap.put(80, 17 + 25 * Instrument.HAT.id);
percussionMap.put(81, 22 + 25 * Instrument.HAT.id);
percussionMap.put(82, 22 + 25 * Instrument.SNARE.id);
percussionMap.put(83, 24 + 25 * Instrument.CHIME.id);
percussionMap.put(84, 24 + 25 * Instrument.CHIME.id);
percussionMap.put(85, 21 + 25 * Instrument.HAT.id);
percussionMap.put(86, 14 + 25 * Instrument.BASEDRUM.id);
percussionMap.put(87, 7 + 25 * Instrument.BASEDRUM.id);
}
public static Song getSongFromUrl (final URL url) throws IOException, InvalidMidiDataException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
final Sequence sequence = MidiSystem.getSequence(DownloadUtilities.DownloadToInputStream(url));
return getSong(sequence, Paths.get(url.toURI().getPath()).getFileName().toString());
}
public static Song getSongFromFile (final File file) throws InvalidMidiDataException, IOException {
final Sequence sequence = MidiSystem.getSequence(file);
return getSong(sequence, file.getName());
}
public static Song getSongFromBytes (final byte[] bytes, final String name) throws InvalidMidiDataException, IOException {
final Sequence sequence = MidiSystem.getSequence(new ByteArrayInputStream(bytes));
return getSong(sequence, name);
}
public static Song getSong (final Sequence sequence, final String name) {
final Song song = new Song(name);
final long tpq = sequence.getResolution();
final ArrayList<MidiEvent> tempoEvents = new ArrayList<>();
for (final Track track : sequence.getTracks()) {
for (int i = 0; i < track.size(); i++) {
final MidiEvent event = track.get(i);
final MidiMessage message = event.getMessage();
if (message instanceof final MetaMessage mm) {
if (mm.getType() == SET_TEMPO) {
tempoEvents.add(event);
}
}
}
}
}
}
Collections.sort(tempoEvents, (a, b) -> Long.compare(a.getTick(), b.getTick()));
for (Track track : sequence.getTracks()) {
long microTime = 0;
int[] ids = new int[16];
int mpq = 500000;
int tempoEventIdx = 0;
long prevTick = 0;
for (int i = 0; i < track.size(); i++) {
MidiEvent event = track.get(i);
MidiMessage message = event.getMessage();
while (tempoEventIdx < tempoEvents.size() && event.getTick() > tempoEvents.get(tempoEventIdx).getTick()) {
long deltaTick = tempoEvents.get(tempoEventIdx).getTick() - prevTick;
prevTick = tempoEvents.get(tempoEventIdx).getTick();
microTime += (mpq/tpq) * deltaTick;
MetaMessage mm = (MetaMessage) tempoEvents.get(tempoEventIdx).getMessage();
byte[] data = mm.getData();
int new_mpq = (data[2]&0xFF) | ((data[1]&0xFF)<<8) | ((data[0]&0xFF)<<16);
if (new_mpq != 0) mpq = new_mpq;
tempoEventIdx++;
Collections.sort(tempoEvents, (a, b) -> Long.compare(a.getTick(), b.getTick()));
for (final Track track : sequence.getTracks()) {
long microTime = 0;
final int[] ids = new int[16];
int mpq = 500000;
int tempoEventIdx = 0;
long prevTick = 0;
for (int i = 0; i < track.size(); i++) {
final MidiEvent event = track.get(i);
final MidiMessage message = event.getMessage();
while (tempoEventIdx < tempoEvents.size() && event.getTick() > tempoEvents.get(tempoEventIdx).getTick()) {
final long deltaTick = tempoEvents.get(tempoEventIdx).getTick() - prevTick;
prevTick = tempoEvents.get(tempoEventIdx).getTick();
microTime += (mpq / tpq) * deltaTick;
final MetaMessage mm = (MetaMessage) tempoEvents.get(tempoEventIdx).getMessage();
final byte[] data = mm.getData();
final int new_mpq = (data[2] & 0xFF) | ((data[1] & 0xFF) << 8) | ((data[0] & 0xFF) << 16);
if (new_mpq != 0) mpq = new_mpq;
tempoEventIdx++;
}
if (message instanceof final ShortMessage sm) {
if (sm.getCommand() == SET_INSTRUMENT) {
ids[sm.getChannel()] = sm.getData1();
} else if (sm.getCommand() == NOTE_ON) {
if (sm.getData2() == 0) continue;
final int pitch = sm.getData1();
final int velocity = sm.getData2();
final long deltaTick = event.getTick() - prevTick;
prevTick = event.getTick();
microTime += (mpq / tpq) * deltaTick;
final Note note;
if (sm.getChannel() == 9) {
note = getMidiPercussionNote(pitch, velocity, microTime);
} else {
note = getMidiInstrumentNote(ids[sm.getChannel()], pitch, velocity, microTime);
}
if (note != null) {
song.add(note);
}
final long time = microTime / 1000L;
if (time > song.length) {
song.length = time;
}
} else if (sm.getCommand() == NOTE_OFF) {
final long deltaTick = event.getTick() - prevTick;
prevTick = event.getTick();
microTime += (mpq / tpq) * deltaTick;
final long time = microTime / 1000L;
if (time > song.length) {
song.length = time;
}
}
}
}
}
if (message instanceof ShortMessage) {
ShortMessage sm = (ShortMessage) message;
if (sm.getCommand() == SET_INSTRUMENT) {
ids[sm.getChannel()] = sm.getData1();
}
else if (sm.getCommand() == NOTE_ON) {
if (sm.getData2() == 0) continue;
int pitch = sm.getData1();
int velocity = sm.getData2();
long deltaTick = event.getTick() - prevTick;
prevTick = event.getTick();
microTime += (mpq/tpq) * deltaTick;
Note note;
if (sm.getChannel() == 9) {
note = getMidiPercussionNote(pitch, velocity, microTime);
}
else {
note = getMidiInstrumentNote(ids[sm.getChannel()], pitch, velocity, microTime);
}
if (note != null) {
song.add(note);
}
song.sort();
long time = microTime / 1000L;
if (time > song.length) {
song.length = time;
return song;
}
public static Note getMidiInstrumentNote (final int midiInstrument, final int midiPitch, final int velocity, final long microTime) {
Instrument instrument = null;
final Instrument[] instrumentList = instrumentMap.get(midiInstrument);
if (instrumentList != null) {
for (final Instrument candidateInstrument : instrumentList) {
if (midiPitch >= candidateInstrument.offset && midiPitch <= candidateInstrument.offset + 24) {
instrument = candidateInstrument;
break;
}
}
}
else if (sm.getCommand() == NOTE_OFF) {
long deltaTick = event.getTick() - prevTick;
prevTick = event.getTick();
microTime += (mpq/tpq) * deltaTick;
long time = microTime / 1000L;
if (time > song.length) {
song.length = time;
}
}
}
}
}
song.sort();
return song;
}
public static Note getMidiInstrumentNote(int midiInstrument, int midiPitch, int velocity, long microTime) {
Instrument instrument = null;
Instrument[] instrumentList = instrumentMap.get(midiInstrument);
if (instrumentList != null) {
for (Instrument candidateInstrument : instrumentList) {
if (midiPitch >= candidateInstrument.offset && midiPitch <= candidateInstrument.offset+24) {
instrument = candidateInstrument;
break;
if (instrument == null) {
return null;
}
}
final int pitch = midiPitch - instrument.offset;
final float volume = (float) velocity / 127.0f;
final long time = microTime / 1000L;
return new Note(instrument, pitch, volume, time, Vec3d.ZERO);
}
if (instrument == null) {
return null;
private static Note getMidiPercussionNote (final int midiPitch, final int velocity, final long microTime) {
if (percussionMap.containsKey(midiPitch)) {
final int noteId = percussionMap.get(midiPitch);
final int pitch = noteId % 25;
final float volume = (float) velocity / 127.0f;
final Instrument instrument = Instrument.fromId(noteId / 25);
final long time = microTime / 1000L;
return new Note(instrument, pitch, volume, time, Vec3d.ZERO);
}
return null;
}
int pitch = midiPitch-instrument.offset;
float volume = (float) velocity / 127.0f;
long time = microTime / 1000L;
return new Note(instrument, pitch, volume, time);
}
private static Note getMidiPercussionNote (int midiPitch, int velocity, long microTime) {
if (percussionMap.containsKey(midiPitch)) {
int noteId = percussionMap.get(midiPitch);
int pitch = noteId % 25;
float volume = (float) velocity / 127.0f;
Instrument instrument = Instrument.fromId(noteId / 25);
long time = microTime / 1000L;
return new Note(instrument, pitch, volume, time);
}
return null;
}
public static HashMap<Integer, Instrument[]> instrumentMap = new HashMap<>();
static {
// Piano (HARP BASS BELL)
instrumentMap.put(0, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Acoustic Grand Piano
instrumentMap.put(1, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Bright Acoustic Piano
instrumentMap.put(2, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Electric Grand Piano
instrumentMap.put(3, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Honky-tonk Piano
instrumentMap.put(4, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Electric Piano 1
instrumentMap.put(5, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Electric Piano 2
instrumentMap.put(6, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Harpsichord
instrumentMap.put(7, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Clavinet
// Chromatic Percussion (IRON_XYLOPHONE XYLOPHONE BASS)
instrumentMap.put(8, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Celesta
instrumentMap.put(9, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Glockenspiel
instrumentMap.put(10, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Music Box
instrumentMap.put(11, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Vibraphone
instrumentMap.put(12, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Marimba
instrumentMap.put(13, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Xylophone
instrumentMap.put(14, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Tubular Bells
instrumentMap.put(15, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Dulcimer
// Organ (BIT DIDGERIDOO BELL)
instrumentMap.put(16, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Drawbar Organ
instrumentMap.put(17, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Percussive Organ
instrumentMap.put(18, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Rock Organ
instrumentMap.put(19, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Church Organ
instrumentMap.put(20, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Reed Organ
instrumentMap.put(21, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Accordian
instrumentMap.put(22, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Harmonica
instrumentMap.put(23, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Tango Accordian
// Guitar (BIT DIDGERIDOO BELL)
instrumentMap.put(24, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Acoustic Guitar (nylon)
instrumentMap.put(25, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Acoustic Guitar (steel)
instrumentMap.put(26, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Electric Guitar (jazz)
instrumentMap.put(27, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Electric Guitar (clean)
instrumentMap.put(28, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Electric Guitar (muted)
instrumentMap.put(29, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Overdriven Guitar
instrumentMap.put(30, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Distortion Guitar
instrumentMap.put(31, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Guitar Harmonics
// Bass
instrumentMap.put(32, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Acoustic Bass
instrumentMap.put(33, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Electric Bass (finger)
instrumentMap.put(34, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Electric Bass (pick)
instrumentMap.put(35, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Fretless Bass
instrumentMap.put(36, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Slap Bass 1
instrumentMap.put(37, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Slap Bass 2
instrumentMap.put(38, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Synth Bass 1
instrumentMap.put(39, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Synth Bass 2
// Strings
instrumentMap.put(40, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Violin
instrumentMap.put(41, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Viola
instrumentMap.put(42, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Cello
instrumentMap.put(43, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Contrabass
instrumentMap.put(44, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Tremolo Strings
instrumentMap.put(45, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Pizzicato Strings
instrumentMap.put(46, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.CHIME}); // Orchestral Harp
instrumentMap.put(47, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Timpani
// Ensenble
instrumentMap.put(48, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // String Ensemble 1
instrumentMap.put(49, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // String Ensemble 2
instrumentMap.put(50, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Synth Strings 1
instrumentMap.put(51, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Synth Strings 2
instrumentMap.put(52, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Choir Aahs
instrumentMap.put(53, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Voice Oohs
instrumentMap.put(54, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Synth Choir
instrumentMap.put(55, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Orchestra Hit
// Brass
instrumentMap.put(56, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
instrumentMap.put(57, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
instrumentMap.put(58, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
instrumentMap.put(59, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
instrumentMap.put(60, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
instrumentMap.put(61, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
instrumentMap.put(62, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
instrumentMap.put(63, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
// Reed
instrumentMap.put(64, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(65, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(66, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(67, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(68, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(69, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(70, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(71, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
// Pipe
instrumentMap.put(72, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(73, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(74, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(75, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(76, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(77, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(78, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
instrumentMap.put(79, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
// Synth Lead
instrumentMap.put(80, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(81, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(82, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(83, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(84, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(85, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(86, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(87, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
// Synth Pad
instrumentMap.put(88, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(89, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(90, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(91, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(92, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(93, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(94, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(95, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
// Synth Effects
// instrumentMap.put(96, new Instrument[]{});
// instrumentMap.put(97, new Instrument[]{});
instrumentMap.put(98, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
instrumentMap.put(99, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(100, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(101, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(102, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
instrumentMap.put(103, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
// Ethnic
instrumentMap.put(104, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
instrumentMap.put(105, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
instrumentMap.put(106, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
instrumentMap.put(107, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
instrumentMap.put(108, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
instrumentMap.put(109, new Instrument[]{Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL});
instrumentMap.put(110, new Instrument[]{Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL});
instrumentMap.put(111, new Instrument[]{Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL});
// Percussive
instrumentMap.put(112, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
instrumentMap.put(113, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
instrumentMap.put(114, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
instrumentMap.put(115, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
instrumentMap.put(116, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
instrumentMap.put(117, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
instrumentMap.put(118, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
instrumentMap.put(119, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
}
public static HashMap<Integer, Integer> percussionMap = new HashMap<>();
static {
percussionMap.put(35, 10 + 25*Instrument.BASEDRUM.id);
percussionMap.put(36, 6 + 25*Instrument.BASEDRUM.id);
percussionMap.put(37, 6 + 25*Instrument.HAT.id);
percussionMap.put(38, 8 + 25*Instrument.SNARE.id);
percussionMap.put(39, 6 + 25*Instrument.HAT.id);
percussionMap.put(40, 4 + 25*Instrument.SNARE.id);
percussionMap.put(41, 6 + 25*Instrument.BASEDRUM.id);
percussionMap.put(42, 22 + 25*Instrument.SNARE.id);
percussionMap.put(43, 13 + 25*Instrument.BASEDRUM.id);
percussionMap.put(44, 22 + 25*Instrument.SNARE.id);
percussionMap.put(45, 15 + 25*Instrument.BASEDRUM.id);
percussionMap.put(46, 18 + 25*Instrument.SNARE.id);
percussionMap.put(47, 20 + 25*Instrument.BASEDRUM.id);
percussionMap.put(48, 23 + 25*Instrument.BASEDRUM.id);
percussionMap.put(49, 17 + 25*Instrument.SNARE.id);
percussionMap.put(50, 23 + 25*Instrument.BASEDRUM.id);
percussionMap.put(51, 24 + 25*Instrument.SNARE.id);
percussionMap.put(52, 8 + 25*Instrument.SNARE.id);
percussionMap.put(53, 13 + 25*Instrument.SNARE.id);
percussionMap.put(54, 18 + 25*Instrument.HAT.id);
percussionMap.put(55, 18 + 25*Instrument.SNARE.id);
percussionMap.put(56, 1 + 25*Instrument.HAT.id);
percussionMap.put(57, 13 + 25*Instrument.SNARE.id);
percussionMap.put(58, 2 + 25*Instrument.HAT.id);
percussionMap.put(59, 13 + 25*Instrument.SNARE.id);
percussionMap.put(60, 9 + 25*Instrument.HAT.id);
percussionMap.put(61, 2 + 25*Instrument.HAT.id);
percussionMap.put(62, 8 + 25*Instrument.HAT.id);
percussionMap.put(63, 22 + 25*Instrument.BASEDRUM.id);
percussionMap.put(64, 15 + 25*Instrument.BASEDRUM.id);
percussionMap.put(65, 13 + 25*Instrument.SNARE.id);
percussionMap.put(66, 8 + 25*Instrument.SNARE.id);
percussionMap.put(67, 8 + 25*Instrument.HAT.id);
percussionMap.put(68, 3 + 25*Instrument.HAT.id);
percussionMap.put(69, 20 + 25*Instrument.HAT.id);
percussionMap.put(70, 23 + 25*Instrument.HAT.id);
percussionMap.put(71, 24 + 25*Instrument.HAT.id);
percussionMap.put(72, 24 + 25*Instrument.HAT.id);
percussionMap.put(73, 17 + 25*Instrument.HAT.id);
percussionMap.put(74, 11 + 25*Instrument.HAT.id);
percussionMap.put(75, 18 + 25*Instrument.HAT.id);
percussionMap.put(76, 9 + 25*Instrument.HAT.id);
percussionMap.put(77, 5 + 25*Instrument.HAT.id);
percussionMap.put(78, 22 + 25*Instrument.HAT.id);
percussionMap.put(79, 19 + 25*Instrument.SNARE.id);
percussionMap.put(80, 17 + 25*Instrument.HAT.id);
percussionMap.put(81, 22 + 25*Instrument.HAT.id);
percussionMap.put(82, 22 + 25*Instrument.SNARE.id);
percussionMap.put(83, 24 + 25*Instrument.CHIME.id);
percussionMap.put(84, 24 + 25*Instrument.CHIME.id);
percussionMap.put(85, 21 + 25*Instrument.HAT.id);
percussionMap.put(86, 14 + 25*Instrument.BASEDRUM.id);
percussionMap.put(87, 7 + 25*Instrument.BASEDRUM.id);
}
}

View file

@ -1,197 +1,225 @@
package land.chipmunk.chipmunkmod.song;
import net.minecraft.util.math.Vec3d;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
public class NBSConverter {
public static Instrument[] instrumentIndex = new Instrument[] {
Instrument.HARP,
Instrument.BASS,
Instrument.BASEDRUM,
Instrument.SNARE,
Instrument.HAT,
Instrument.GUITAR,
Instrument.FLUTE,
Instrument.BELL,
Instrument.CHIME,
Instrument.XYLOPHONE,
Instrument.IRON_XYLOPHONE,
Instrument.COW_BELL,
Instrument.DIDGERIDOO,
Instrument.BIT,
Instrument.BANJO,
Instrument.PLING,
};
public static Instrument[] instrumentIndex = new Instrument[] {
Instrument.HARP,
Instrument.BASS,
Instrument.BASEDRUM,
Instrument.SNARE,
Instrument.HAT,
Instrument.GUITAR,
Instrument.FLUTE,
Instrument.BELL,
Instrument.CHIME,
Instrument.XYLOPHONE,
Instrument.IRON_XYLOPHONE,
Instrument.COW_BELL,
Instrument.DIDGERIDOO,
Instrument.BIT,
Instrument.BANJO,
Instrument.PLING,
};
private static class NBSNote {
public int tick;
public short layer;
public byte instrument;
public byte key;
public byte velocity = 100;
public byte panning = 100;
public short pitch = 0;
}
public static Song getSongFromBytes (final byte[] bytes, final String fileName) throws IOException {
final ByteBuffer buffer = ByteBuffer.wrap(bytes);
buffer.order(ByteOrder.LITTLE_ENDIAN);
private static class NBSLayer {
public String name;
public byte lock = 0;
public byte volume;
public byte stereo = 100;
}
short songLength = 0;
byte format = 0;
byte vanillaInstrumentCount = 0;
songLength = buffer.getShort(); // If it's not 0, then it uses the old format
if (songLength == 0) {
format = buffer.get();
}
private static class NBSCustomInstrument {
public String name;
public String file;
public byte pitch = 0;
public boolean key = false;
}
if (format >= 1) {
vanillaInstrumentCount = buffer.get();
}
if (format >= 3) {
songLength = buffer.getShort();
}
public static Song getSongFromBytes(byte[] bytes, String fileName) throws IOException {
ByteBuffer buffer = ByteBuffer.wrap(bytes);
buffer.order(ByteOrder.LITTLE_ENDIAN);
final short layerCount = buffer.getShort();
final String songName = getString(buffer, bytes.length);
final String songAuthor = getString(buffer, bytes.length);
final String songOriginalAuthor = getString(buffer, bytes.length);
final String songDescription = getString(buffer, bytes.length);
final short tempo = buffer.getShort();
final byte autoSaving = buffer.get();
final byte autoSavingDuration = buffer.get();
final byte timeSignature = buffer.get();
final int minutesSpent = buffer.getInt();
final int leftClicks = buffer.getInt();
final int rightClicks = buffer.getInt();
final int blocksAdded = buffer.getInt();
final int blocksRemoved = buffer.getInt();
final String origFileName = getString(buffer, bytes.length);
short songLength = 0;
byte format = 0;
byte vanillaInstrumentCount = 0;
songLength = buffer.getShort(); // If it's not 0, then it uses the old format
if (songLength == 0) {
format = buffer.get();
}
if (format >= 1) {
vanillaInstrumentCount = buffer.get();
}
if (format >= 3) {
songLength = buffer.getShort();
}
short layerCount = buffer.getShort();
String songName = getString(buffer, bytes.length);
String songAuthor = getString(buffer, bytes.length);
String songOriginalAuthor = getString(buffer, bytes.length);
String songDescription = getString(buffer, bytes.length);
short tempo = buffer.getShort();
byte autoSaving = buffer.get();
byte autoSavingDuration = buffer.get();
byte timeSignature = buffer.get();
int minutesSpent = buffer.getInt();
int leftClicks = buffer.getInt();
int rightClicks = buffer.getInt();
int blocksAdded = buffer.getInt();
int blocksRemoved = buffer.getInt();
String origFileName = getString(buffer, bytes.length);
byte loop = 0;
byte maxLoopCount = 0;
short loopStartTick = 0;
if (format >= 4) {
loop = buffer.get();
maxLoopCount = buffer.get();
loopStartTick = buffer.getShort();
}
ArrayList<NBSNote> nbsNotes = new ArrayList<>();
short tick = -1;
while (true) {
int tickJumps = buffer.getShort();
if (tickJumps == 0) break;
tick += tickJumps;
short layer = -1;
while (true) {
int layerJumps = buffer.getShort();
if (layerJumps == 0) break;
layer += layerJumps;
NBSNote note = new NBSNote();
note.tick = tick;
note.layer = layer;
note.instrument = buffer.get();
note.key = buffer.get();
byte loop = 0;
byte maxLoopCount = 0;
short loopStartTick = 0;
if (format >= 4) {
note.velocity = buffer.get();
note.panning = buffer.get();
note.pitch = buffer.getShort();
loop = buffer.get();
maxLoopCount = buffer.get();
loopStartTick = buffer.getShort();
}
nbsNotes.add(note);
}
}
ArrayList<NBSLayer> nbsLayers = new ArrayList<>();
if (buffer.hasRemaining()) {
for (int i=0; i<layerCount; i++) {
NBSLayer layer = new NBSLayer();
layer.name = getString(buffer, bytes.length);
if (format >= 4) {
layer.lock = buffer.get();
final ArrayList<NBSNote> nbsNotes = new ArrayList<>();
short tick = -1;
while (true) {
final int tickJumps = buffer.getShort();
if (tickJumps == 0) break;
tick += tickJumps;
short layer = -1;
while (true) {
final int layerJumps = buffer.getShort();
if (layerJumps == 0) break;
layer += layerJumps;
final NBSNote note = new NBSNote();
note.tick = tick;
note.layer = layer;
note.instrument = buffer.get();
note.key = buffer.get();
if (format >= 4) {
note.velocity = buffer.get();
note.panning = buffer.get();
note.pitch = buffer.getShort();
}
nbsNotes.add(note);
}
}
layer.volume = buffer.get();
if (format >= 2) {
layer.stereo = buffer.get();
final ArrayList<NBSLayer> nbsLayers = new ArrayList<>();
if (buffer.hasRemaining()) {
for (int i = 0; i < layerCount; i++) {
final NBSLayer layer = new NBSLayer();
layer.name = getString(buffer, bytes.length);
if (format >= 4) {
layer.lock = buffer.get();
}
layer.volume = buffer.get();
if (format >= 2) {
layer.stereo = buffer.get();
}
nbsLayers.add(layer);
}
}
nbsLayers.add(layer);
}
final ArrayList<NBSCustomInstrument> customInstruments = new ArrayList<>();
if (buffer.hasRemaining()) {
final byte customInstrumentCount = buffer.get();
for (int i = 0; i < customInstrumentCount; i++) {
final NBSCustomInstrument customInstrument = new NBSCustomInstrument();
customInstrument.name = getString(buffer, bytes.length);
customInstrument.file = getString(buffer, bytes.length);
customInstrument.pitch = buffer.get();
customInstrument.key = buffer.get() != 0;
customInstruments.add(customInstrument);
}
}
final Song song = new Song(songName.trim().length() > 0 ? songName : fileName);
if (loop > 0) {
song.looping = true;
song.loopPosition = getMilliTime(loopStartTick, tempo);
song.loopCount = maxLoopCount;
}
for (final NBSNote note : nbsNotes) {
final Instrument instrument;
double key;
if (note.instrument < instrumentIndex.length) {
instrument = instrumentIndex[note.instrument];
key = (double) ((note.key * 100) + note.pitch) / 100;
} else {
final int index = note.instrument - instrumentIndex.length;
if (index >= customInstruments.size()) continue;
final NBSCustomInstrument customInstrument = customInstruments.get(index);
instrument = Instrument.of(customInstrument.name);
key = (note.key) + (customInstrument.pitch + (double) note.pitch / 100);
}
byte layerVolume = 100;
if (nbsLayers.size() > note.layer) {
layerVolume = nbsLayers.get(note.layer).volume;
}
while (key < 33) key += 12;
while (key > 57) key -= 12;
final double pitch = key - 33;
final int layerStereo = Byte.toUnsignedInt(nbsLayers.get(note.layer).stereo);
final int notePanning = Byte.toUnsignedInt(note.panning);
final double value;
if (layerStereo == 100 && notePanning != 100) value = notePanning;
else if (notePanning == 100 && layerStereo != 100) value = layerStereo;
else value = (double) (layerStereo + notePanning) / 2;
final double x;
if (value > 100) x = (value - 100) / -100;
else if (value == 100) x = 0;
else x = ((value - 100) * -1) / 100;
final Vec3d position = new Vec3d(x, 0, 0);
song.add(new Note(instrument, pitch, (float) note.velocity * (float) layerVolume / 10000f, getMilliTime(note.tick, tempo), position));
}
song.length = song.get(song.size() - 1).time + 50;
return song;
}
ArrayList<NBSCustomInstrument> customInstruments = new ArrayList<>();
if (buffer.hasRemaining()) {
byte customInstrumentCount = buffer.get();
for (int i = 0; i < customInstrumentCount; i++) {
NBSCustomInstrument customInstrument = new NBSCustomInstrument();
customInstrument.name = getString(buffer, bytes.length);
customInstrument.file = getString(buffer, bytes.length);
customInstrument.pitch = buffer.get();
customInstrument.key = buffer.get() == 0 ? false : true;
customInstruments.add(customInstrument);
}
private static String getString (final ByteBuffer buffer, final int maxSize) throws IOException {
final int length = buffer.getInt();
if (length > maxSize) {
throw new IOException("String is too large");
}
final byte[] arr = new byte[length];
buffer.get(arr, 0, length);
return new String(arr);
}
Song song = new Song(songName.trim().length() > 0 ? songName : fileName);
if (loop > 0) {
song.looping = true;
song.loopPosition = getMilliTime(loopStartTick, tempo);
song.loopCount = maxLoopCount;
}
for (NBSNote note : nbsNotes) {
Instrument instrument;
int key = note.key;
if (note.instrument < instrumentIndex.length) {
instrument = instrumentIndex[note.instrument];
} else {
int index = note.instrument - instrumentIndex.length;
if (index >= customInstruments.size()) continue;
NBSCustomInstrument customInstrument = customInstruments.get(index);
instrument = Instrument.of(customInstrument.name);
key += customInstrument.pitch;
}
byte layerVolume = 100;
if (nbsLayers.size() > note.layer) {
layerVolume = nbsLayers.get(note.layer).volume;
}
int pitch = key-33;
song.add(new Note(instrument, pitch, (float) note.velocity * (float) layerVolume / 10000f, getMilliTime(note.tick, tempo)));
private static int getMilliTime (final int tick, final int tempo) {
return 1000 * tick * 100 / tempo;
}
song.length = song.get(song.size()-1).time + 50;
return song;
}
private static String getString (ByteBuffer buffer, int maxSize) throws IOException {
int length = buffer.getInt();
if (length > maxSize) {
throw new IOException("String is too large");
private static class NBSNote {
public int tick;
public short layer;
public byte instrument;
public byte key;
public byte velocity = 100;
public byte panning = 100;
public short pitch = 0;
}
byte arr[] = new byte[length];
buffer.get(arr, 0, length);
return new String(arr);
}
private static int getMilliTime(int tick, int tempo) {
return 1000 * tick * 100 / tempo;
}
private static class NBSLayer {
public String name;
public byte lock = 0;
public byte volume;
public byte stereo = 100;
}
private static class NBSCustomInstrument {
public String name;
public String file;
public byte pitch = 0;
public boolean key = false;
}
}

View file

@ -1,33 +1,25 @@
package land.chipmunk.chipmunkmod.song;
import net.minecraft.util.math.Vec3d;
public class Note implements Comparable<Note> {
public Instrument instrument;
public int pitch;
public float volume;
public long time;
public Instrument instrument;
public double pitch;
public float volume;
public long time;
public Vec3d position;
public Note (Instrument instrument, int pitch, float volume, long time) {
this.instrument = instrument;
this.pitch = pitch;
this.volume = volume;
this.time = time;
}
public Note (final Instrument instrument, final double pitch, final float volume, final long time, final Vec3d position) {
this.instrument = instrument;
this.pitch = pitch;
this.volume = volume;
this.time = time;
this.position = position;
}
@Override
public int compareTo(Note other) {
if (time < other.time) {
return -1;
@Override
public int compareTo (final Note other) {
return Long.compare(time, other.time);
}
else if (time > other.time) {
return 1;
}
else {
return 0;
}
}
public int noteId () {
return pitch + instrument.id * 25;
}
}

View file

@ -1,131 +1,132 @@
package land.chipmunk.chipmunkmod.song;
import net.kyori.adventure.text.Component;
import java.util.ArrayList;
import java.util.Collections;
public class Song {
public ArrayList<Note> notes = new ArrayList<>();
public Component name;
public int position = 0; // Current note index
public boolean looping = false;
public boolean paused = true;
public long startTime = 0; // Start time in millis since unix epoch
public long length = 0; // Milliseconds in the song
public long time = 0; // Time since start of song
public long loopPosition = 0; // Milliseconds into the song to start looping
public int loopCount = 0; // Number of times to loop
public int currentLoop = 0; // Number of loops so far
public Song (Component name) {
this.name = name;
}
public ArrayList<Note> notes = new ArrayList<>();
public Component name;
public int position = 0; // Current note index
public boolean looping = false;
public boolean paused = true;
public long startTime = 0; // Start time in millis since unix epoch
public long length = 0; // Milliseconds in the song
public long time = 0; // Time since start of song
public long loopPosition = 0; // Milliseconds into the song to start looping
public int loopCount = 0; // Number of times to loop
public int currentLoop = 0; // Number of loops so far
public Song (String name) {
this(Component.text(name));
}
public Note get (int i) {
return notes.get(i);
}
public void add (Note e) {
notes.add(e);
}
public void sort () {
Collections.sort(notes);
}
/**
* Starts playing song (does nothing if already playing)
*/
public void play () {
if (paused) {
paused = false;
startTime = System.currentTimeMillis() - time;
public Song (final Component name) {
this.name = name;
}
}
/**
* Pauses song (does nothing if already paused)
*/
public void pause () {
if (!paused) {
paused = true;
// Recalculates time so that the song will continue playing after the exact point it was paused
advanceTime();
public Song (final String name) {
this(Component.text(name));
}
}
public void setTime (long t) {
time = t;
startTime = System.currentTimeMillis() - time;
position = 0;
while (position < notes.size() && notes.get(position).time < t) {
position++;
public Note get (final int i) {
return notes.get(i);
}
}
public void advanceTime () {
time = System.currentTimeMillis() - startTime;
}
public void add (final Note e) {
notes.add(e);
}
public boolean reachedNextNote () {
if (position < notes.size()) {
return notes.get(position).time <= time;
} else {
if (time > length && shouldLoop()) {
loop();
if (position < notes.size()) {
return notes.get(position).time <= time;
} else {
return false;
public void sort () {
Collections.sort(notes);
}
/**
* Starts playing song (does nothing if already playing)
*/
public void play () {
if (paused) {
paused = false;
startTime = System.currentTimeMillis() - time;
}
} else {
return false;
}
}
}
public Note getNextNote () {
if (position >= notes.size()) {
if (shouldLoop()) {
loop();
} else {
return null;
}
/**
* Pauses song (does nothing if already paused)
*/
public void pause () {
if (!paused) {
paused = true;
// Recalculates time so that the song will continue playing after the exact point it was paused
advanceTime();
}
}
return notes.get(position++);
}
public boolean finished () {
return time > length && !shouldLoop();
}
private void loop () {
position = 0;
startTime += length - loopPosition;
time -= length - loopPosition;
while (position < notes.size() && notes.get(position).time < loopPosition) {
position++;
public void setTime (final long t) {
time = t;
startTime = System.currentTimeMillis() - time;
position = 0;
while (position < notes.size() && notes.get(position).time < t) {
position++;
}
}
currentLoop++;
}
private boolean shouldLoop () {
if (looping) {
if (loopCount == 0) {
return true;
} else {
return currentLoop < loopCount;
}
} else {
return false;
public void advanceTime () {
time = System.currentTimeMillis() - startTime;
}
}
public int size () {
return notes.size();
}
public boolean reachedNextNote () {
if (position < notes.size()) {
return notes.get(position).time <= time;
} else {
if (time > length && shouldLoop()) {
loop();
if (position < notes.size()) {
return notes.get(position).time <= time;
} else {
return false;
}
} else {
return false;
}
}
}
public Note getNextNote () {
if (position >= notes.size()) {
if (shouldLoop()) {
loop();
} else {
return null;
}
}
return notes.get(position++);
}
public boolean finished () {
return time > length && !shouldLoop();
}
private void loop () {
position = 0;
startTime += length - loopPosition;
time -= length - loopPosition;
while (position < notes.size() && notes.get(position).time < loopPosition) {
position++;
}
currentLoop++;
}
private boolean shouldLoop () {
if (looping) {
if (loopCount == 0) {
return true;
} else {
return currentLoop < loopCount;
}
} else {
return false;
}
}
public int size () {
return notes.size();
}
}

View file

@ -3,20 +3,20 @@ package land.chipmunk.chipmunkmod.song;
import net.minecraft.text.Text;
public class SongLoaderException extends Exception {
public final Text message;
public final Text message;
public SongLoaderException (Text message) {
super();
this.message = message;
}
public SongLoaderException (final Text message) {
super();
this.message = message;
}
public SongLoaderException (Text message, Throwable cause) {
super(null, cause);
this.message = message;
}
public SongLoaderException (final Text message, final Throwable cause) {
super(null, cause);
this.message = message;
}
@Override
public String getMessage () {
return message.getString();
}
@Override
public String getMessage () {
return message.getString();
}
}

View file

@ -6,63 +6,63 @@ import net.minecraft.text.Text;
import java.io.File;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class SongLoaderThread extends Thread {
private String location;
private File songPath;
private URL songUrl;
public SongLoaderException exception;
public Song song;
public SongLoaderException exception;
public Song song;
private String location;
private File songPath;
private URL songUrl;
private final boolean isUrl;
private boolean isUrl;
public SongLoaderThread (URL location) throws SongLoaderException {
isUrl = true;
songUrl = location;
}
public SongLoaderThread (Path location) throws SongLoaderException {
isUrl = false;
songPath = location.toFile();
}
public void run () {
byte[] bytes;
String name;
try {
if (isUrl) {
bytes = DownloadUtilities.DownloadToByteArray(songUrl);
name = Paths.get(songUrl.toURI().getPath()).getFileName().toString();
} else {
bytes = Files.readAllBytes(songPath.toPath());
name = songPath.getName();
}
} catch (Exception e) {
exception = new SongLoaderException(Text.literal(e.getMessage()), e);
return;
public SongLoaderThread (final URL location) throws SongLoaderException {
isUrl = true;
songUrl = location;
}
try {
song = MidiConverter.getSongFromBytes(bytes, name);
} catch (Exception e) {
public SongLoaderThread (final Path location) throws SongLoaderException {
isUrl = false;
songPath = location.toFile();
}
if (song == null) {
try {
song = NBSConverter.getSongFromBytes(bytes, name);
} catch (Exception e) {
}
public void run () {
final byte[] bytes;
final String name;
try {
if (isUrl) {
bytes = DownloadUtilities.DownloadToByteArray(songUrl);
name = Paths.get(songUrl.toURI().getPath()).getFileName().toString();
} else {
bytes = Files.readAllBytes(songPath.toPath());
name = songPath.getName();
}
} catch (final Exception e) {
exception = new SongLoaderException(Text.literal(e.getMessage()), e);
return;
}
try {
song = MidiConverter.getSongFromBytes(bytes, name);
} catch (final Exception e) {
}
if (song == null) {
try {
song = NBSConverter.getSongFromBytes(bytes, name);
} catch (final Exception e) {
e.printStackTrace();
}
}
if (song == null) {
exception = new SongLoaderException(Text.translatable("Invalid song format"));
}
}
if (song == null) {
exception = new SongLoaderException(Text.translatable("Invalid song format"));
private File getSongFile (final String name) {
return new File(SongPlayer.SONG_DIR, name);
}
}
private File getSongFile (String name) {
return new File(SongPlayer.SONG_DIR, name);
}
}

View file

@ -1,9 +0,0 @@
package land.chipmunk.chipmunkmod.util;
import java.util.Arrays;
public class ArrayUtil {
public static String[] removeFirst(String[] original,int index) {
return Arrays.stream(original).toList().subList(index, original.length).toArray(new String[0]);
}
}

View file

@ -1,60 +0,0 @@
package land.chipmunk.chipmunkmod.util;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.attribute.EntityAttribute;
import net.minecraft.entity.attribute.EntityAttributeInstance;
import net.minecraft.entity.attribute.EntityAttributeModifier;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.Identifier;
public class AttributeModifier {
/*
EntityAttributeInstance movementSpeedAttribute = MC.player.getAttributeInstance(EntityAttributes.GENERIC_MOVEMENT_SPEED);
EntityAttributeModifier tempModifier = new EntityAttributeModifier(
"TestClient@Speed", // Modifier name
3, // Modifier value
EntityAttributeModifier.Operation.MULTIPLY_TOTAL); // Modifier operation
movementSpeedAttribute.addPersistentModifier(tempModifier);
*/
String name;
EntityAttribute attribute;
float value;
EntityAttributeModifier.Operation operation;
EntityAttributeModifier modifier;
EntityAttributeInstance instance;
public AttributeModifier(EntityAttribute attribute, float value, EntityAttributeModifier.Operation operation) {
this.attribute = attribute;
this.value = value;
this.operation = operation;
name = "TestClient@"+(new Throwable().getStackTrace()[1].getClassName())+"."+(new Throwable().getStackTrace()[1].getMethodName());
// Chat.send("Created new attribute modifier " + name);
instance = MinecraftClient.getInstance().player.getAttributeInstance(new RegistryEntry.Direct<>(attribute));
modifier = new EntityAttributeModifier(Identifier.of(name), value, operation);
}
public void add() {
instance.addPersistentModifier(modifier);
}
public void remove() {
instance.removeModifier(modifier);
}
public boolean isOnPlayer() {
return instance.hasModifier(modifier.id());
}
public void setValue(float value) {
this.value = value;
modifier = new EntityAttributeModifier(Identifier.of(name), value, operation);
// remove and add multiplier to refresh value
if(isOnPlayer()){
remove();
add();
}
}
public float getValue() {
return value;
}
}

View file

@ -2,41 +2,41 @@ package land.chipmunk.chipmunkmod.util;
import com.mojang.brigadier.Command;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.Configuration;
import land.chipmunk.chipmunkmod.commands.SayCommand;
import land.chipmunk.chipmunkmod.config.Configuration;
import land.chipmunk.chipmunkmod.modules.Chat;
import land.chipmunk.chipmunkmod.modules.CustomChat;
import land.chipmunk.chipmunkmod.modules.custom_chat.CustomChat;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import org.apache.commons.codec.binary.Hex;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class BotValidationUtilities {
public static int hbot (String command) throws RuntimeException {
public static int hbot (final String command) throws RuntimeException {
final Configuration.BotInfo info = ChipmunkMod.CONFIG.bots.hbot;
final MinecraftClient client = MinecraftClient.getInstance();
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
final String prefix = info.prefix;
final String key = info.key;
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
if (key == null)
throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
String time = String.valueOf(System.currentTimeMillis() / 10000);
String input = prefix + command.replaceAll("&[0-9a-fklmnor]", "") + ";" + client.player.getName().getString() + ";" + time + ";" + key;
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
String stringHash = bigInt.toString(Character.MAX_RADIX);
final MessageDigest md = MessageDigest.getInstance("SHA-256");
final String time = String.valueOf(System.currentTimeMillis() / 10000);
final String input = prefix + command.replaceAll("&[0-9a-fklmnor]", "") + ";" + client.player.getUuidAsString() + ";" + time + ";" + key;
final byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
final BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
final String stringHash = bigInt.toString(Character.MAX_RADIX);
Chat.sendChatMessage(prefix + command + " " + stringHash, true);
} catch (NoSuchAlgorithmException e) {
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
}
@ -57,7 +57,7 @@ public class BotValidationUtilities {
String time = String.valueOf(System.currentTimeMillis() / 10000);
String input = "babyboom:" + key + ":" + client.player.getUuidAsString() + ":" + command.replaceAll("&[0-9a-fklmnor]", "") + ":" + time;
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
String stringHash = Hexadecimal.encode(hash);
String stringHash = new String(Hex.encodeHex(hash));
Chat.sendChatMessage(prefix + command + " " + stringHash, true);
} catch (NoSuchAlgorithmException e) {
@ -81,7 +81,7 @@ public class BotValidationUtilities {
String time = String.valueOf(System.currentTimeMillis() / 10000);
String input = "babyboom:" + key + ":" + client.player.getUuidAsString() + ":" + command.replaceAll("&[0-9a-fklmnor]", "") + ":" + time;
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
String stringHash = Hexadecimal.encode(hash);
String stringHash = new String(Hex.encodeHex(hash));
Chat.sendChatMessage(prefix + command + " " + stringHash, true);
} catch (NoSuchAlgorithmException e) {
@ -91,33 +91,34 @@ public class BotValidationUtilities {
return Command.SINGLE_SUCCESS;
}
public static int sbot (String command) throws RuntimeException {
public static int sbot (final String command) throws RuntimeException {
final Configuration.BotInfo info = ChipmunkMod.CONFIG.bots.sbot;
final MinecraftClient client = MinecraftClient.getInstance();
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
final String prefix = info.prefix;
final String key = info.key;
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
if (key == null)
throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
try {
MessageDigest md = MessageDigest.getInstance("MD5");
String time = String.valueOf(System.currentTimeMillis() / 20000);
String input = prefix + command.replaceAll("&[0-9a-fklmnorx]", "") + ";" + client.player.getName().getString() + ";" + time + ";" + key;
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
String stringHash = bigInt.toString(Character.MAX_RADIX);
final MessageDigest md = MessageDigest.getInstance("MD5");
final String time = String.valueOf(System.currentTimeMillis() / 20000);
final String input = prefix + command.replaceAll("&[0-9a-fklmnorx]", "") + ";" + client.player.getName().getString() + ";" + time + ";" + key;
final byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
final BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
final String stringHash = bigInt.toString(Character.MAX_RADIX);
Chat.sendChatMessage(prefix + command + " " + stringHash, true);
} catch (NoSuchAlgorithmException e) {
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
}
return Command.SINGLE_SUCCESS;
}
public static int chomens (String command) throws RuntimeException {
final Configuration.ChomeNSBotInfo info = ChipmunkMod.CONFIG.bots.chomens;
public static int chomens (final String command) throws RuntimeException {
final Configuration.BotInfo info = ChipmunkMod.CONFIG.bots.chomens;
final MinecraftClient client = MinecraftClient.getInstance();
@ -125,24 +126,25 @@ public class BotValidationUtilities {
final String prefix = info.prefix;
final String key = info.key;
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
if (key == null)
throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
try {
String[] arguments = command.split(" ");
final String[] arguments = command.split(" ");
MessageDigest md = MessageDigest.getInstance("SHA-256");
String time = String.valueOf(System.currentTimeMillis() / 5_000);
String input = client.player.getUuidAsString() + arguments[0] + time + key;
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
String stringHash = Hexadecimal.encode(hash).substring(0, 16);
final MessageDigest md = MessageDigest.getInstance("SHA-256");
final String time = String.valueOf(System.currentTimeMillis() / 5_000);
final String input = client.player.getUuidAsString() + arguments[0] + time + key;
final byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
String stringHash = new String(Hex.encodeHex(hash)).substring(0, 16);
final boolean shouldSectionSign = CustomChat.INSTANCE.enabled && player.hasPermissionLevel(2) && player.isCreative();
if (shouldSectionSign) {
stringHash = String.join("",
Arrays.stream(stringHash.split(""))
.map((letter) -> "§" + letter)
.toArray(String[]::new)
Arrays.stream(stringHash.split(""))
.map((letter) -> "§" + letter)
.toArray(String[]::new)
);
}
@ -157,68 +159,43 @@ public class BotValidationUtilities {
String.join(" ", restArguments);
Chat.sendChatMessage(toSend);
} catch (NoSuchAlgorithmException e) {
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
}
return Command.SINGLE_SUCCESS;
}
public static int fnfboyfriend (String command) {
try {
final String prefix = ChipmunkMod.CONFIG.bots.fnfboyfriend.prefix;
String[] arguments = command.split(" ");
long currentTime = System.currentTimeMillis() / 1000;
final String key = ChipmunkMod.CONFIG.bots.fnfboyfriend.key;
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
String input = currentTime + key;
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(input.getBytes());
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
final String[] restArguments = Arrays.copyOfRange(arguments, 1, arguments.length);
final String result = hexString.substring(0, 16);
Chat.sendChatMessage(prefix + arguments[0] + " " + result + " " + String.join(" ", restArguments));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return Command.SINGLE_SUCCESS;
}
public static int nbot (String command) throws RuntimeException {
public static int nbot (final String command) throws RuntimeException {
final Configuration.BotInfo info = ChipmunkMod.CONFIG.bots.nbot;
final MinecraftClient client = MinecraftClient.getInstance();
final String prefix = info.prefix;
final String key = info.key;
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
if (key == null)
throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
try {
String[] arguments = command.split(" ");
final String[] arguments = command.split(" ");
MessageDigest md = MessageDigest.getInstance("SHA-256");
final MessageDigest md = MessageDigest.getInstance("SHA-256");
String time = String.valueOf(System.currentTimeMillis() / 5_000);
String input = arguments[0].replaceAll("&[0-9a-fklmnor]", "") + ";" + client.player.getUuidAsString() + ";" + time + ";" + key;
final long time = Math.floorDiv(System.currentTimeMillis(), 250);
md.update(input.getBytes(StandardCharsets.UTF_8));
// yep it is very raw code indeed.
final String input = "ThisCodeIsRaw;" + client.player.getUuidAsString() + ";" + time + ";" + key;
byte[] hash = md.digest();
final byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
final byte[] positiveDigest = new byte[digest.length + 1];
ByteBuffer buffer = ByteBuffer.wrap(hash, 0, 4);
long bigInt = (buffer.getInt() & 0xFFFFFFFFL);;
String stringHash = Long.toString(bigInt, 36);
System.arraycopy(digest, 0, positiveDigest, 1, digest.length);
final BigInteger bi = new BigInteger(positiveDigest);
final String b36 = bi.toString(36);
final String stringHash = b36.length() > 16 ? b36.substring(0, 16) : b36;
final String[] restArguments = Arrays.copyOfRange(arguments, 1, arguments.length);
@ -230,31 +207,32 @@ public class BotValidationUtilities {
String.join(" ", restArguments);
Chat.sendChatMessage(toSend, true);
} catch (NoSuchAlgorithmException e) {
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
}
return Command.SINGLE_SUCCESS;
}
public static int kittycorp (String command) throws RuntimeException {
public static int kittycorp (final String command) throws RuntimeException {
final Configuration.BotInfo info = ChipmunkMod.CONFIG.bots.kittycorp;
final ClientPlayNetworkHandler networkHandler = MinecraftClient.getInstance().getNetworkHandler();
final String prefix = info.prefix;
final String key = info.key;
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
if (key == null)
throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
String time = String.valueOf(System.currentTimeMillis() / 10000);
String input = prefix + command.replaceAll("&[0-9a-fklmnorx]", "") + ";" + time + ";" + key;
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
String stringHash = bigInt.toString(Character.MAX_RADIX);
final MessageDigest md = MessageDigest.getInstance("SHA-256");
final String time = String.valueOf(System.currentTimeMillis() / 10000);
final String input = prefix + command.replaceAll("&[0-9a-fklmnorx]", "") + ";" + time + ";" + key;
final byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
final BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
final String stringHash = bigInt.toString(Character.MAX_RADIX);
Chat.sendChatMessage(prefix + command + " " + stringHash, true);
} catch (NoSuchAlgorithmException e) {
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
}

View file

@ -3,8 +3,8 @@ package land.chipmunk.chipmunkmod.util;
import java.awt.*;
public class ColorUtilities {
public static int hsvToRgb (int hue, int saturation, int value) {
Color color = Color.getHSBColor(hue / 360.0f, saturation / 100.0f, value / 100.0f);
public static int hsvToRgb (final int hue, final int saturation, final int value) {
final Color color = Color.getHSBColor(hue / 360.0f, saturation / 100.0f, value / 100.0f);
return color.getRGB() & 0xFFFFFF;
}
}

View file

@ -1,14 +0,0 @@
package land.chipmunk.chipmunkmod.util;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import java.util.ArrayList;
public class Debug {
public static ArrayList<String> known = new ArrayList<>();
public static ArrayList<String> selected = new ArrayList<>();
public static void debug(String string, String caller) {
if(selected.contains(caller)) ChipmunkMod.LOGGER.info(String.format("[DEBUG|%s] %s", caller, string));
if(!known.contains(caller)) known.add(caller);
}
}

View file

@ -14,46 +14,48 @@ import java.security.cert.X509Certificate;
public class DownloadUtilities {
private static class DefaultTrustManager implements X509TrustManager {
public static byte[] DownloadToByteArray (final URL url) throws IOException, KeyManagementException, NoSuchAlgorithmException {
final SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager() }, new SecureRandom());
SSLContext.setDefault(ctx);
final URLConnection conn = url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.4; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0");
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) {}
try (final BufferedInputStream downloadStream = new BufferedInputStream(conn.getInputStream())) {
final ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
final byte[] buf = new byte[1024];
int n;
while ((n = downloadStream.read(buf)) > 0) {
byteArrayStream.write(buf, 0, n);
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) {}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
public static byte[] DownloadToByteArray(URL url) throws IOException, KeyManagementException, NoSuchAlgorithmException {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
SSLContext.setDefault(ctx);
URLConnection conn = url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0");
try (BufferedInputStream downloadStream = new BufferedInputStream(conn.getInputStream())) {
ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int n;
while ((n = downloadStream.read(buf)) > 0) {
byteArrayStream.write(buf, 0, n);
if (Thread.interrupted()) {
return null;
if (Thread.interrupted()) {
return null;
}
}
return byteArrayStream.toByteArray();
}
}
return byteArrayStream.toByteArray();
// Closing a ByteArrayInputStream has no effect, so I do not close it.
}
// Closing a ByteArrayInputStream has no effect, so I do not close it.
}
public static InputStream DownloadToInputStream(URL url) throws KeyManagementException, NoSuchAlgorithmException, IOException {
return new ByteArrayInputStream(DownloadToByteArray(url));
}
public static InputStream DownloadToInputStream (final URL url) throws KeyManagementException, NoSuchAlgorithmException, IOException {
return new ByteArrayInputStream(DownloadToByteArray(url));
}
private static class DefaultTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted (final X509Certificate[] arg0, final String arg1) {
}
@Override
public void checkServerTrusted (final X509Certificate[] arg0, final String arg1) {
}
@Override
public X509Certificate[] getAcceptedIssuers () {
return null;
}
}
}

View file

@ -1,13 +0,0 @@
package land.chipmunk.chipmunkmod.util;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Executor {
public static ExecutorService service = Executors.newFixedThreadPool(20);
public static ExecutorService antiChatSpamService = Executors.newFixedThreadPool(1);
public static Future<?> submit(Runnable runnable) {
return service.submit(runnable);
}
}

View file

@ -1,15 +0,0 @@
package land.chipmunk.chipmunkmod.util;
public interface Hexadecimal {
static String encode (byte b) {
return "" + Character.forDigit((b >> 4) & 0xF, 16) + Character.forDigit((b & 0xF), 16);
}
static String encode (byte[] array) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < array.length; i++) sb.append(encode(array[i]));
return sb.toString();
}
// TODO: Decode
}

Some files were not shown because too many files have changed in this diff Show more