Compare commits

...

166 Commits
v103 ... v104.1

Author SHA1 Message Date
Anuken
03fe3a04ba Merge pull request #1553 from heckelson/patch-1
translated; spelling errors, odd phrases removed
2020-02-11 21:42:09 -05:00
Alexander H
68e403557a translated; spelling errors, odd phrases removed
I've gone through the German translation file looking for missing translations, which I provided, as well as spelling errors and odd phrases, which I continued to remove. I also replaced every [LIGHT_GRAY] tag with [lightgray] for uniformity.
2020-02-12 01:46:13 +01:00
Anuken
c5b88c2763 Added changelogs 2020-02-11 18:59:09 -05:00
Anuken
0cbd9a1fcc Removed redundant file move code 2020-02-11 18:03:17 -05:00
Anuken
3102931cb4 Removed script wrapper 2020-02-11 17:50:16 -05:00
Anuken
fb302d49c7 Improved battery brightness display / Palette tweak / Diffgen buff 2020-02-11 17:27:33 -05:00
Anuken
a4a3e7fc48 Merge pull request #1514 from Arkanic/patch-7
make batteries glow based on power contents (a redo that works)
2020-02-11 16:31:14 -05:00
Anuken
eb87e5f265 Single-script mod case 2020-02-11 16:14:01 -05:00
Anuken
9c2569d4f5 Merge pull request #1477 from DeltaNedas/patch-5
controlled script loading
2020-02-11 16:03:38 -05:00
Anuken
ce3f4ed0fb Merge remote-tracking branch 'origin/master' 2020-02-11 15:54:23 -05:00
Anuken
1b94eed9d3 Fixed conveyors blending with enemy teams 2020-02-11 15:54:16 -05:00
Anuken
aafecfebbb Merge pull request #1468 from Prosta4okua/patch-7
Update bundle_uk_UA.properties
2020-02-11 15:45:12 -05:00
Anuken
5bbe4af71b Merge pull request #1466 from Vam-Jam/PlayerList
[Added] Dedicated Players command
2020-02-11 15:45:02 -05:00
Anuken
de9a14c903 Czech translation for 103.x changelog (#1455)
* Czech translation for 103.x changelog

* Czech translation - mod display

* Czech translation - fix typos

* Czech: added Time played + small format corr.

* Czech for server categories!
2020-02-11 15:40:33 -05:00
Ali-C-Ila
5ab47f4fe0 Update bundle_zh_TW.properties (#1454)
* Update bundle_zh_TW.properties

* Update bundle_zh_TW.properties
2020-02-11 15:40:24 -05:00
Vanguard
435860eda4 RU updates (#1442)
* 1 changed line, 1 removed line

Changed:
keybind.zoom.name

Removed:
keybind.zoom_hold.name

Moved some lines around to keep them in the same order with bundle.properties

* 1 changed line

tutorial.intro

* 3 new lines, 3 changed lines

New:
mod.erroredcontent
mod.errors
mod.noerrorplay

Changed:
mod.requiresversion
mod.remove.confirm
details

* 2 changed lines

mods.guide
mod.import.github

* 1 new line

link.feathub.description

* 1 changed line

item.graphite.description

* 1 changed line

block.mass-driver.description

* 9 new lines, 1 changed line

New:
be.update
be.update.confirm
be.updating
be.ignore
be.noupdates
be.check
server.kicked.serverRestarting
setting.coreselect.name
rules.blockhealthmultiplier

Changed:
wave.enemy

* 3 changed lines

quit.confirm.tutorial
setting.coreselect.name
public.confirm

* 22 changed lines

mod.missing
item.plastanium.name
block.plastanium-wall.name
block.plastanium-wall-large.name
block.plastanium-compressor.name
item.scrap.description
item.spore-pod.description
item.blast-compound.description
liquid.oil.description
unit.revenant.description
block.multi-press.description
block.plastanium-compressor.description
block.spore-press.description
block.power-source.description
block.force-projector.description
block.conveyor.description
block.mass-driver.description
block.liquid-junction.description
block.phase-conduit.description
block.thorium-reactor.description
block.blast-drill.description
block.cyclone.description

* 3 new lines, 2 removed lines

New:
setting.bridgeopacity.name
block.liquid-void.name
block.liquid-void.description

Removed:
block.signal
block.editsignal

* 1 new line

data.openfolder

* 1 changed line

block.cryofluidmixer.description

* 2 new lines

block.underflow-gate.name
block.underflow-gate.description

* 2 changed lines

unit.thousands
unit.millions

* 3 new lines

blocks.tiles
blocks.affinities
setting.playerlimit.name

* 1 changed line

block.underflow-gate.name

* 1 changed line

unit.thousands

* 1 changed line

blocks.affinities

* 1 changed line (reverted)

unit.thousands

* Update bundle_ru.properties

* 1 new line

mod.display

* 1 changed line

techtree

* 1 changed line (new approach)

techtree

* 1 changed line

editor.generate

* 1 new line

stat.playtime

* 3 new lines

servers.local
servers.remote
servers.global

* 3 changed lines

servers.local
servers.remote
servers.global

Co-authored-by: Anuken <arnukren@gmail.com>
Co-authored-by: Prosta4okua <31485341+Prosta4okua@users.noreply.github.com>
2020-02-11 15:40:17 -05:00
AmateurPotion
5611a8684c Update bundle_ko.properties (#1490)
* Update bundle_ko.properties

Finish! yeeeee!

* Update bundle_ko.properties
2020-02-11 15:33:25 -05:00
LauweJoster
f06550fc3c Update bundle_nl.properties (#1501)
Grammar and sentence improvements. Also added translations
2020-02-11 15:32:18 -05:00
Ali-C-Ila
652c143ff6 Update bundle_zh_TW.properties (#1519) 2020-02-11 15:25:53 -05:00
Rasangus
64ade54336 Update bundle_pt_BR.properties (#1525) 2020-02-11 15:25:38 -05:00
kf-games
e6507a84ef Update Servers.json, Add PvP server MINDUSTRY.RU:7000 (#1533)
Add PvP server MINDUSTRY.RU:7000
2020-02-11 15:25:30 -05:00
Arkanic
91148a7fde oops wrong branch 2020-02-12 08:04:35 +13:00
Arkanic
e02f370228 Update README.md 2020-02-12 08:01:49 +13:00
Anuken
5aa1e30006 Bugfix 2020-02-11 13:08:42 -05:00
Anuken
ad7c72015c Better admin management 2020-02-11 13:06:52 -05:00
Anuken
d99f9740e8 USID fixes 2020-02-11 12:36:28 -05:00
Anuken
d1840e7c2a Item selection scrolling 2020-02-11 11:55:38 -05:00
Anuken
e173eb55ca Merge remote-tracking branch 'origin/master' 2020-02-11 11:30:25 -05:00
Anuken
d6b5f6a311 buildTable improvements 2020-02-11 11:30:22 -05:00
AmateurPotion
eaa0b53f30 Update README.md (#1548)
hey?
2020-02-11 11:13:26 -05:00
fuzzbuck
f14df52490 Allow admins to bypass the playerlimit [server] (#1549) 2020-02-11 11:10:50 -05:00
Petr Gašparík
29a6b1a8da Merge branch 'master' of https://github.com/Anuken/Mindustry into v103.3 2020-02-11 11:18:54 +01:00
Anuken
b15a40fcbd Cleanup / Fixed desktop IDs resetting 2020-02-10 23:26:22 -05:00
Anuken
9da2d1ee9a Merge remote-tracking branch 'origin/master' 2020-02-10 20:22:09 -05:00
Anuken
6882a9a355 Added persistent message server function 2020-02-10 20:22:03 -05:00
GioIacca9
941449c502 Updated "Full implementation of #1494" (#1541) 2020-02-09 22:26:47 -05:00
Daniel Jennings
baab36bfc5 Trim schematic string before calling Base64Decoder (#1537)
This fixes getting the "Length of Base64 encoded input string is not a multiple of 4." error when importing schematics that have whitespace at the start/end of them, which is easy to accidentally have without knowing by when copying the schematic codes from random different web pages.
2020-02-08 16:41:33 -05:00
Anuken
f3893533a4 Cleanup 2020-02-08 11:08:31 -05:00
Prosta4okua
0a53c4c1be Update bundle_uk_UA.properties 2020-02-08 12:26:09 +02:00
Prosta4okua
d7eb0d3ba3 Update bundle_uk_UA.properties 2020-02-08 12:23:50 +02:00
Anuken
3a2fef3bd7 Merge remote-tracking branch 'origin/master' 2020-02-07 20:52:03 -05:00
Anuken
9ccf95971e Fixed small launch items button 2020-02-07 20:51:59 -05:00
valtsu41
9b36125b0c Finnish translation & grammar update (#1473)
* Finnish translation & grammar update

* More grammar correcting and making things more native

* Just a little more fine-tuning

* Fixes
2020-02-07 20:42:14 -05:00
Anuken
0ffcd0b94c Fixed #1507 / Fixed #1504 2020-02-07 20:21:45 -05:00
Anuken
a6801af128 Use zip files when exporting 2020-02-07 20:11:43 -05:00
Anuken
30ea039246 Fixed #1521 2020-02-07 20:11:05 -05:00
Anuken
5a5945cc52 Merge remote-tracking branch 'origin/master' 2020-02-07 20:09:45 -05:00
Anuken
e5fd3dec4c Fixed #1526 2020-02-07 20:09:37 -05:00
扩散性百万甜面包
7b586ea043 Fix a typo (#1528)
* Fix a typo

* Update core/src/mindustry/mod/Mods.java

Co-Authored-By: Patrick 'Quezler' Mounier <Quezler@me.com>

Co-authored-by: Patrick 'Quezler' Mounier <Quezler@me.com>
2020-02-07 08:25:26 -05:00
Petr Gašparík
e98808bc46 Czech for server categories! 2020-02-07 12:35:09 +01:00
Petr Gašparík
bc37415a10 Merge branch 'master' of https://github.com/Anuken/Mindustry into v103.3 2020-02-07 12:32:33 +01:00
Prosta4okua
619b2ba897 Update bundle_uk_UA.properties 2020-02-07 12:42:59 +02:00
Anuken
37a9311202 Merge remote-tracking branch 'origin/master' 2020-02-06 20:25:17 -05:00
Anuken
e9f37ea68e Removed entity processor files 2020-02-06 20:25:10 -05:00
Prosta4okua
59431b223b Update bundle_uk_UA.properties 2020-02-06 23:38:45 +02:00
MEEP of Faith
da5755b7c1 For consistancy (#1517)
Swap "liquids" with "liquid." Also proposing because the category for liquid blocks is "liquid" and not "liquids" when modding.
2020-02-06 14:46:33 -05:00
Anuken
70c06b58ef Conveyor cleanup 2020-02-06 11:38:36 -05:00
Anuken
4a2c6c571f Merge remote-tracking branch 'origin/master' 2020-02-05 19:02:02 -05:00
Anuken
a5fd881f8d Full implementation of #1494 2020-02-05 19:01:53 -05:00
martin-mfg
d59b23b835 bundle_de.properties: merge PRs + further improvements (#1482)
* Update bundle_de.properties

* Update bundle_de.properties

* Update bundle_de.properties

* Update bundle_de.properties

* Update bundle_de.properties

* Update bundle_de.properties

* Update bundle_de.properties

* add minor missing changes from discussion in #799

* fix duplicated text in german translation (configure.locked)

* apply German translation suggestions from PR comment

This commit applies suggestions from the comment at https://github.com/Anuken/Mindustry/pull/783#pullrequestreview-299643677

Co-authored-by: Anuken <arnukren@gmail.com>
Co-authored-by: Silvério Santos <ssantos@web.de>
2020-02-05 18:37:21 -05:00
Patrick 'Quezler' Mounier
e06d8eabec [formatting] add newline to file(s) (#1508)
* Trail appropriate files with a new line

* For some ironic reason it ignored itself

Probably because it wasn’t tracked/commited yet.

* Rename newlines to server executable naming pattern
2020-02-05 18:36:56 -05:00
Arkanic
ce7eccf524 i forgot -base 2020-02-05 18:10:57 +00:00
Patrick 'Quezler' Mounier
8bb533f646 3rd times the charm (#1509) 2020-02-05 13:06:16 -05:00
Petr Gašparík
39b35dd9cb Merge branch 'master' of https://github.com/Anuken/Mindustry into v103.3 2020-02-05 08:34:59 +01:00
Arkanic
ff06a005a0 become exist 2020-02-05 00:53:15 +00:00
Arkanic
fd500f5405 heh make branch 2020-02-05 13:27:36 +13:00
Anuken
67106abb9b Updated arc 2020-02-03 20:30:18 -05:00
InvalidError404
ea6490cf9f Improved ItemModule::take() behavior (#1495)
* Improved ItemModule::take() behavior

The original take() behavior spams items in whatever order they appear in the items list until each index is depleted, which is problematic when non-specific unloaders are competing against dedicated unloaders for a low-index resources.

My modification makes the take() loop persistent so take() will do complete laps around the item list starting from wherever the previous call returned from, never repeating the same item twice in a row unless there is nothing else to return. A significant improvement IMO.

How is this an improvement? With the original behavior, if you converge a bunch of belts on a storage block or launcher, want to unload a few belts of specific resources (ex.: copper, lead, silicon and titanium for surge alloy) and pass everything else including overflows along using non-specific unloaders, you are out of luck when the resources you want are at the top of the list since most of those will get swept away by non-specific unloaders. With the rotating take(), non-specific unloaders are equal-opportunity across all available resources, which gives single-resource unloaders that many more chances to unload more of their resources before non-specific unloaders get to them. It also reduces the rate at which items further down the list that may hardly ever get touched by the existing implementation will race toward the storage block's cap. The even drain across all items will help prevent things like mass driver stalls due to receivers filling up with an excess resource that isn't getting cleared.

It would be even nicer if dedicated unloaders had priority over non-specific ones (non-specific unloaders don't touch resources with dedicated unloaders unless the dedicated unloaders are overflowing), though that would require a rework beyond my current "getting the stupid IDE and tool chains to work" level of familiarity with Java development.

To sum it up: trivial change, big impact for people who like mixing belts and sorting them out with unloaders.

* Update core/src/mindustry/world/modules/ItemModule.java

Co-Authored-By: Patrick 'Quezler' Mounier <Quezler@me.com>

* Update core/src/mindustry/world/modules/ItemModule.java

Co-Authored-By: Patrick 'Quezler' Mounier <Quezler@me.com>

* Formatting

* Anuken's take() rotator.

Co-authored-by: Patrick 'Quezler' Mounier <Quezler@me.com>
2020-02-03 20:27:25 -05:00
Patrick 'Quezler' Mounier
627321304d zzzz (#1503) 2020-02-03 15:55:53 -05:00
Arkanic
d2c2fd7d5f aaaa (#1502) 2020-02-03 14:44:54 -05:00
DeltaNedas
fea9f51513 !dir.exists() and new line 2020-02-03 18:36:17 +00:00
DeltaNedas
4709b5dddc remove old mainScript, it is always main.js 2020-02-03 18:35:24 +00:00
GioIacca9
b4be655d0c Translated stat.playtime (#1485) 2020-02-03 12:54:06 -05:00
LauweJoster
19da1e1306 Update bundle_nl.properties (#1499)
Improved some grammar and sentencing. Also added a few translations.
2020-02-03 12:37:28 -05:00
Patrick 'Quezler' Mounier
9bc24ae47a Darken yellow square on nucleus core (#1497)
#1496
2020-02-03 08:51:19 -05:00
Petr Gašparík
aef5fd85b2 Merge branch 'master' of https://github.com/Anuken/Mindustry into v103.3 2020-02-03 10:05:06 +01:00
Anuken
ad84329688 Abstract component method support 2020-02-02 17:21:35 -05:00
Anuken
ae6d33cad1 Bugfixes 2020-02-02 16:44:51 -05:00
Anuken
ad9dd83032 Better entity code generation + minor refactoring 2020-02-02 16:13:25 -05:00
Anuken
382ca09f6e Merge branches 'master' and 'splinterface' of https://github.com/Anuken/Mindustry 2020-02-02 13:59:41 -05:00
Anuken
c978410cb3 Scale cleanup / Name cleanup 2020-02-02 13:59:24 -05:00
Anuken
5eb3f0f3de Interface + base component support 2020-02-02 12:25:46 -05:00
Anuken
acb3438cc8 More entity processor features 2020-02-02 11:51:58 -05:00
DeltaNedas
a9f07f3603 formatting 2020-02-02 15:49:10 +00:00
Patrick 'Quezler' Mounier
4c369dd17c Hide drop zone warning if you're part of the wave team (#1492) 2020-02-02 10:41:09 -05:00
DeltaNedas
c458c77322 cleanup 2020-02-02 13:40:53 +00:00
DeltaNedas
b93692ad41 yes 2020-02-02 13:40:38 +00:00
DeltaNedas
d84217300c fixed error message 2020-02-02 12:58:00 +00:00
DeltaNedas
49ab7ceb77 main.js required now 2020-02-02 12:44:37 +00:00
Anuken
7ddfcbfabd Utility method copying 2020-02-02 00:39:29 -05:00
Anuken
da2aee7d31 Entity components based on code generation - experiment 2020-02-01 23:54:41 -05:00
DeltaNedas
4c45716149 first part of what cat wants 2020-02-02 02:49:47 +00:00
Anuken
9f20ff151c Shortened annotation processors 2020-02-01 17:27:24 -05:00
Anuken
5f7fc3441c Merge remote-tracking branch 'origin/master' 2020-02-01 17:17:08 -05:00
Anuken
62179233ef Bugfixes 2020-02-01 17:17:03 -05:00
fuzzbuck
376e3d6ef1 Add mindustry.io to servers.json (#1467)
- huge community (~1.5k members)
- anti-grief measures (discord bot <-> in-game moderation)
- huge map pool (50+)
- stable, powerful server based in europe
2020-02-01 17:14:06 -05:00
DeltaNedas
51bc5c3b74 local changes 2020-02-01 18:28:25 +00:00
DeltaNedas
a45a14025d oops 2020-02-01 18:26:38 +00:00
Anuken
eabebcefc7 Disabled data folder button due to terrible file manager support 2020-01-31 23:09:21 -05:00
DeltaNedas
e1a215ae0b wrapper works now 2020-02-01 01:18:18 +00:00
Anuken
63d84bead3 Cleanup 2020-01-31 20:10:21 -05:00
DeltaNedas
d872656bc5 it works sorta! 2020-01-31 23:51:33 +00:00
Anuken
51b4824c92 Fixed #1484 2020-01-31 11:07:25 -05:00
Petr Gašparík
b4e9e6be32 Czech: added Time played + small format corr. 2020-01-31 13:16:27 +01:00
Petr Gašparík
737e3145ec Merge branch 'master' of https://github.com/Anuken/Mindustry into v103.3 2020-01-31 13:13:51 +01:00
Anuken
2721aa550d Implemented #1444 2020-01-30 22:56:17 -05:00
Anuken
f92b91c17b Switched to arc bloom 2020-01-30 17:50:35 -05:00
Anuken
221b28c153 Merge remote-tracking branch 'origin/master' 2020-01-30 17:43:48 -05:00
Anuken
7c2541afa2 Fixed bloom black screen on iOS/Android 2020-01-30 17:43:36 -05:00
Petr Gašparík
bfa24cca4c Merge branch 'v103.3' of https://github.com/PetrGasparik/Mindustry; branch 'master' of https://github.com/Anuken/Mindustry into v103.3 2020-01-30 16:06:46 +01:00
DeltaNedas
9da505119b it compiles but cant find module
help
2020-01-30 00:53:05 +00:00
DeltaNedas
677debd475 testing script loading stuff
is not allowed in console, only from `LoadedMod`s.
2020-01-30 00:38:51 +00:00
DeltaNedas
864c73f791 make it semi work maybe
still completely insecure
2020-01-30 00:21:50 +00:00
DeltaNedas
9ed7719464 compile dammit 2020-01-30 00:04:42 +00:00
DeltaNedas
187e1f5848 create new branch 2020-01-29 23:52:58 +00:00
Vam-Jam
36782a2454 [Fix] lastMessage doesnt change if prevented by antispam (#1471)
Fixes issue #1470
2020-01-29 11:32:41 -05:00
Prosta4okua
6a48a1e0a3 Update bundle_uk_UA.properties 2020-01-29 01:12:12 +02:00
Prosta4okua
d0faecbea5 Update bundle_uk_UA.properties 2020-01-29 01:07:24 +02:00
Vamist
b5ccd36315 [Added] Players command
Allows servers to view current active players in more detail without having to use status
2020-01-28 20:16:06 +00:00
Anuken
97cfc33abb Merge remote-tracking branch 'origin/master' 2020-01-28 13:44:13 -05:00
Anuken
867a642859 Fixed #1460 2020-01-28 13:44:06 -05:00
Anuken
d99cad8793 Update SERVERLIST.md 2020-01-28 13:28:34 -05:00
kf-games
2a11f65e10 Add server MINDUSTRY.RU (#1463)
Add server MINDUSTRY.RU
Server 24/7 Online
380+ Maps
Have a motd
There are moderators
Server in uninterrupted operation since October 2019
2020-01-28 13:05:55 -05:00
Anuken
89e1c5afc0 Conveyor tweaks 2020-01-28 00:21:05 -05:00
Anuken
a2933e030a More severe votekick 2020-01-27 15:43:17 -05:00
Anuken
d21c47a582 Merge remote-tracking branch 'origin/master' 2020-01-27 13:15:15 -05:00
Anuken
5ad0193a86 Fixed reduced conveyor edge throughput 2020-01-27 13:15:12 -05:00
MWestfall
881eca636d Update servers.json (#1457) 2020-01-27 12:55:18 -05:00
Daniel Jennings
d849a3a87f Adding Steam Rich Presence support. (#1453)
* Steam Rich Presence support. I opted to put this code inside of
DesktopLauncher.java instead of SNet.java because it heavily overlaps
with the work the DiscordRPC code was already doing.

Testing wasn't easy because I had to figure out how the Steam version
actually runs normally, but it was straightforward once I figured out
what version information to slam into the JAR and fixed 'desktop:steamtest' to work locally with my paths.

Because of how Steam currently expects SetRichPresence to be used, I had
to upload to the Steam partner site a trivial Rich Presence loc token
called 'steam_status_raw' that just gets entirely substituted for the
'steam_status' RP token string. I didn't expect that I'd need to do
anything for localization support (and instead just let it use English
for everyone like Discord) but apparently Steam isn't happy if you
directly set 'steam_display' to a raw string (but I'm going to look at
that when I'm back at work because I don't know that we need that
requirement.)

* Whoops, left this in there from debugging the Steam connection.

* Fixing coding style, and also triggering another CI build
2020-01-27 12:17:52 -05:00
Anuken
5ebc04ab29 Update SERVERLIST.md 2020-01-27 11:59:17 -05:00
Anuken
379f860a6b Merge remote-tracking branch 'origin/master' 2020-01-27 11:01:57 -05:00
Anuken
65211a6021 Fixed #1447 2020-01-27 11:01:48 -05:00
Anuken
9395fa99be Create SERVERLIST.md 2020-01-27 10:50:08 -05:00
Anuken
b7e1adb8b1 Fixed 103 network compatibility 2020-01-27 10:19:18 -05:00
Petr Gašparík
315260f7f5 Czech translation - fix typos 2020-01-27 14:14:43 +01:00
Petr Gašparík
69069e2ef3 Czech translation - mod display 2020-01-27 11:32:31 +01:00
Petr Gašparík
de143a8e16 Czech translation for 103.x changelog 2020-01-27 11:30:23 +01:00
Anuken
b9e8694e68 Added synced server label + effect methods 2020-01-27 00:25:32 -05:00
Anuken
cd1ed97e52 Merge branch 'master' of https://github.com/Anuken/Mindustry 2020-01-27 00:11:24 -05:00
Anuken
a61234d21e Minor tweaks 2020-01-26 21:50:55 -05:00
키에르
9499b9dfaf Add custom text on screen (#1448) 2020-01-26 17:56:11 -05:00
Anuken
9baaacc8ac Crash fix 2020-01-26 16:55:24 -05:00
Anuken
db3d4b170f Merge branches 'conveyor-refactor' and 'master' of https://github.com/Anuken/Mindustry 2020-01-26 16:12:35 -05:00
Anuken
621233a5b3 More optimization 2020-01-26 16:12:11 -05:00
Anuken
9a3245c23e Clamp 2020-01-26 15:13:55 -05:00
Anuken
6fe2697185 2x faster conveyor optimization 2020-01-26 15:04:00 -05:00
Anuken
d7ea0bc21e why 2020-01-26 13:16:42 -05:00
Anuken
adbfb15932 Cleanup 2020-01-26 13:13:01 -05:00
Anuken
fda6ea4b45 Fixed #1452 2020-01-26 11:40:28 -05:00
Anuken
93cada6a16 Conveyor benchmark test 2020-01-26 11:40:09 -05:00
Anuken
0d5dd146ef Fixed #1451 2020-01-26 10:58:14 -05:00
Nickibosss
1207fb1440 Update bundle_it.properties (#1431) 2020-01-25 17:51:43 -05:00
Petr Gašparík
8584fae07a Czech translation - update (#1432) 2020-01-25 17:51:32 -05:00
Ali-C-Ila
0a661766be Update bundle_zh_TW.properties (#1438) 2020-01-25 17:51:24 -05:00
Prosta4okua
fb6cb4829f Update bundle_uk_UA.properties (#1434)
* Update bundle_uk_UA.properties

* Update bundle_uk_UA.properties

* Update bundle_uk_UA.properties

* Update bundle_uk_UA.properties

* Update bundle_uk_UA.properties

* Update bundle_uk_UA.properties

* Update bundle_uk_UA.properties
2020-01-25 17:51:17 -05:00
Anuken
e14a36a97e Fixed #1445 2020-01-25 17:50:59 -05:00
Anuken
ca69aafd11 Fixed #1440 2020-01-25 10:44:46 -05:00
Anuken
923d576a5f Fixed #1436 / Fixed crawlers not exploding 2020-01-24 23:21:23 -05:00
Anuken
081edde1f2 Fixed double client commands 2020-01-24 22:48:05 -05:00
Anuken
1ab81fa4ab Bugfixes 2020-01-24 19:14:49 -05:00
Anuken
69711151a5 Bugfixes 2020-01-24 18:48:26 -05:00
Anuken
aefc4ed83c Better annotation processing 2020-01-24 18:31:54 -05:00
Anuken
83f44abb5a Suppress d/c messages when necessary 2020-01-24 14:27:23 -05:00
Anuken
f2bc3e78d7 Fixed #1429 2020-01-24 14:00:06 -05:00
Anuken
2fe6a3525b Added null check for attribute 2020-01-24 13:37:23 -05:00
Anuken
78fb427120 Minor fixes 2020-01-24 13:02:03 -05:00
749 changed files with 3563 additions and 3173 deletions

2
.gitignore vendored
View File

@@ -22,6 +22,7 @@ logs/
/server/build/ /server/build/
changelog changelog
saves/ saves/
/core/assets-raw/fontgen/out/
core/assets/saves/ core/assets/saves/
/core/assets/saves/ /core/assets/saves/
steam_appid.txt steam_appid.txt
@@ -30,6 +31,7 @@ steam_appid.txt
/android/assets/mindustry-maps/ /android/assets/mindustry-maps/
/android/assets/mindustry-saves/ /android/assets/mindustry-saves/
/core/assets/gifexport/ /core/assets/gifexport/
/annotations/src/main/resources/META-INF/services
/core/assets/version.properties /core/assets/version.properties
/core/assets/locales /core/assets/locales
/ios/src/mindustry/gen/ /ios/src/mindustry/gen/

View File

@@ -21,13 +21,15 @@ First, make sure you have [JDK 8](https://adoptopenjdk.net/) installed. Open a t
#### Windows #### Windows
_Running:_ `gradlew desktop:run` _Running:_ `gradlew.bat desktop:run`
_Building:_ `gradlew desktop:dist` _Building:_ `gradlew.bat desktop:dist`
_Sprite Packing:_ `gradlew.bat tools:pack`
#### Linux/Mac OS #### Linux/Mac OS
_Running:_ `./gradlew desktop:run` _Running:_ `./gradlew desktop:run`
_Building:_ `./gradlew desktop:dist` _Building:_ `./gradlew desktop:dist`
_Sprite Packing:_ `./gradlew tools:pack`
#### Server #### Server

26
SERVERLIST.md Normal file
View File

@@ -0,0 +1,26 @@
### Adding a server to the list
Mindustry now has a public list of servers that everyone can see and connect to.
This is done by letting clients `GET` a [JSON list of servers](https://github.com/Anuken/Mindustry/blob/master/servers.json) in this repository.
You may want to add your server to this list. The steps for getting this done are as follows:
1. **Ensure your server is properly moderated.** For the most part, this applies to survival servers, but PvP servers can be affected as well.
You'll need to either hire some moderators, or make use of (currently non-existent) anti-grief and anti-curse plugins.
*Consider enabling a rate limit:* `config messageRateLimit 2` will make it so that players can only send messages every 2 seconds, for example.
2. **Set an approppriate MOTD, name and description.** This is set with `config <name/desc/motd> <value>`. "Approppriate" means that:
- Your name or description must reflect the type of server you're hosting.
Since new players may be exposed to the server list early on, put in a phrase like "Co-op survival" or "PvP" so players know what they're getting into. Yes, this is also displayed in the server mode info text, but having extra info in the name doesn't hurt.
- Make sure players know where to refer to for server support. It should be fairly clear that the server owner is not me, but you.
- Try to be professional in your text; use common sense.
3. **Get some good maps.** *(optional, but highly recommended)*. Add some maps to your server and set the map rotation to custom-only. You can get maps from the Steam workshop by subscribing and exporting them; using the `#maps` channel on Discord is also an option.
4. **Check your server configuration.** *(optional)* I would recommend adding a message rate limit of 1 second (`config messageRateLimit 1`), and disabling connect/disconnect messages to reduce spam (`config showConnectMessages false`).
5. Finally, **submit a pull request** to add your server's IP to the list.
This should be fairly straightforward: Press the edit button on the [server file](https://github.com/Anuken/Mindustry/blob/master/servers.json), then add a JSON object with a single key, indicating your server address.
For example, if your server address is `google.com`, you would add a comma after the last entry and insert:
```json
{
"address": "google.com"
}
```
Then, press the *'submit pull request'* button and I'll take a look at your server. If I have any issues with it, I'll let you know in the PR comments.

View File

@@ -81,7 +81,7 @@ public class AndroidLauncher extends AndroidApplication{
if(VERSION.SDK_INT >= VERSION_CODES.Q){ if(VERSION.SDK_INT >= VERSION_CODES.Q){
Intent intent = new Intent(open ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_CREATE_DOCUMENT); Intent intent = new Intent(open ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE); intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType(extension.equals("zip") ? "application/zip" : "*/*"); intent.setType(extension.equals("zip") && !open ? "application/zip" : "*/*");
addResultListener(i -> startActivityForResult(intent, i), (code, in) -> { addResultListener(i -> startActivityForResult(intent, i), (code, in) -> {
if(code == Activity.RESULT_OK && in != null && in.getData() != null){ if(code == Activity.RESULT_OK && in != null && in.getData() != null){
Uri uri = in.getData(); Uri uri = in.getData();
@@ -150,10 +150,12 @@ public class AndroidLauncher extends AndroidApplication{
}}); }});
checkFiles(getIntent()); checkFiles(getIntent());
//new external folder //new external folder
Fi data = Core.files.absolute(getContext().getExternalFilesDir(null).getAbsolutePath()); Fi data = Core.files.absolute(getContext().getExternalFilesDir(null).getAbsolutePath());
Core.settings.setDataDirectory(data);
//moved to internal storage if there's no file indicating that it moved //move to internal storage if there's no file indicating that it moved
if(!Core.files.local("files_moved").exists()){ if(!Core.files.local("files_moved").exists()){
Log.info("Moving files to external storage..."); Log.info("Moving files to external storage...");
@@ -161,17 +163,16 @@ public class AndroidLauncher extends AndroidApplication{
//current local storage folder //current local storage folder
Fi src = Core.files.absolute(Core.files.getLocalStoragePath()); Fi src = Core.files.absolute(Core.files.getLocalStoragePath());
for(Fi fi : src.list()){ for(Fi fi : src.list()){
fi.copyTo(data.child(fi.name())); fi.copyTo(data);
} }
//create marker //create marker
Core.files.local("files_moved").writeString("files moved to " + data); Core.files.local("files_moved").writeString("files moved to " + data);
Core.files.local("files_moved_103").writeString("files moved again");
Log.info("Files moved."); Log.info("Files moved.");
}catch(Throwable t){ }catch(Throwable t){
Log.err("Failed to move files!"); Log.err("Failed to move files!");
t.printStackTrace(); t.printStackTrace();
} }
}else{
Core.settings.setDataDirectory(data);
} }
} }

View File

@@ -3,6 +3,36 @@ package mindustry.annotations;
import java.lang.annotation.*; import java.lang.annotation.*;
public class Annotations{ public class Annotations{
//region entity interfaces
/** Indicates multiple inheritance on a component type. */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Depends{
Class[] value();
}
/** Indicates that a component def is present on all entities. */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface BaseComponent{
}
/** Indicates an entity definition. */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface EntityDef{
Class[] value();
}
/** Indicates an internal interface for entity components. */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface EntityInterface{
}
//endregion
//region misc. utility
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@@ -29,6 +59,9 @@ public class Annotations{
} }
//endregion
//region struct
/** Marks a class as a special value type struct. Class name must end in 'Struct'. */ /** Marks a class as a special value type struct. Class name must end in 'Struct'. */
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@@ -44,6 +77,9 @@ public class Annotations{
int value(); int value();
} }
//endregion
//region remote
public enum PacketPriority{ public enum PacketPriority{
/** Gets put in a queue and processed if not connected. */ /** Gets put in a queue and processed if not connected. */
normal, normal,
@@ -138,4 +174,6 @@ public class Annotations{
public @interface ReadClass{ public @interface ReadClass{
Class<?> value(); Class<?> value();
} }
//endregion
} }

View File

@@ -1,8 +1,19 @@
package mindustry.annotations; package mindustry.annotations;
import arc.struct.*;
import arc.util.*;
import com.squareup.javapoet.*;
import com.sun.source.util.*;
import mindustry.annotations.util.*;
import javax.annotation.processing.*; import javax.annotation.processing.*;
import javax.lang.model.*; import javax.lang.model.*;
import javax.lang.model.element.*; import javax.lang.model.element.*;
import javax.lang.model.util.*;
import javax.tools.Diagnostic.*;
import javax.tools.*;
import java.io.*;
import java.lang.annotation.*;
import java.util.*; import java.util.*;
@SupportedSourceVersion(SourceVersion.RELEASE_8) @SupportedSourceVersion(SourceVersion.RELEASE_8)
@@ -10,21 +21,99 @@ public abstract class BaseProcessor extends AbstractProcessor{
/** Name of the base package to put all the generated classes. */ /** Name of the base package to put all the generated classes. */
public static final String packageName = "mindustry.gen"; public static final String packageName = "mindustry.gen";
private int round; public static Types typeu;
public static Elements elementu;
public static Filer filer;
public static Messager messager;
public static Trees trees;
@Override protected int round;
public synchronized void init(ProcessingEnvironment processingEnv){ protected int rounds = 1;
super.init(processingEnv); protected RoundEnvironment env;
//put all relevant utils into utils class
Utils.typeUtils = processingEnv.getTypeUtils(); public static String getMethodName(Element element){
Utils.elementUtils = processingEnv.getElementUtils(); return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName();
Utils.filer = processingEnv.getFiler(); }
Utils.messager = processingEnv.getMessager();
public static boolean isPrimitive(String type){
return type.equals("boolean") || type.equals("byte") || type.equals("short") || type.equals("int")
|| type.equals("long") || type.equals("float") || type.equals("double") || type.equals("char");
}
public static void write(TypeSpec.Builder builder) throws Exception{
write(builder, null);
}
public static void write(TypeSpec.Builder builder, Array<String> imports) throws Exception{
JavaFile file = JavaFile.builder(packageName, builder.build()).skipJavaLangImports(true).build();
if(imports != null){
String rawSource = file.toString();
Array<String> result = new Array<>();
for (String s : rawSource.split("\n", -1)) {
result.add(s);
if (s.startsWith("package ")) {
result.add("");
for (String i : imports) {
result.add(i);
}
}
}
String out = result.toString("\n");
JavaFileObject object = filer.createSourceFile(file.packageName + "." + file.typeSpec.name, file.typeSpec.originatingElements.toArray(new Element[0]));
OutputStream stream = object.openOutputStream();
stream.write(out.getBytes());
stream.close();
}else{
file.writeTo(filer);
}
}
public Array<Stype> types(Class<? extends Annotation> type){
return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof TypeElement)
.map(e -> new Stype((TypeElement)e));
}
public Array<Svar> fields(Class<? extends Annotation> type){
return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof VariableElement)
.map(e -> new Svar((VariableElement)e));
}
public Array<Smethod> methods(Class<? extends Annotation> type){
return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof ExecutableElement)
.map(e -> new Smethod((ExecutableElement)e));
}
public void err(String message){
messager.printMessage(Kind.ERROR, message);
Log.err("[CODEGEN ERROR] " +message);
}
public void err(String message, Element elem){
messager.printMessage(Kind.ERROR, message, elem);
Log.err("[CODEGEN ERROR] " + message + ": " + elem);
}
public void err(String message, Selement elem){
err(message, elem.e);
} }
@Override @Override
public final boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){ public synchronized void init(ProcessingEnvironment env){
if(round++ != 0) return false; //only process 1 round super.init(env);
trees = Trees.instance(env);
typeu = env.getTypeUtils();
elementu = env.getElementUtils();
filer = env.getFiler();
messager = env.getMessager();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
if(round++ >= rounds) return false; //only process 1 round
this.env = roundEnv;
try{ try{
process(roundEnv); process(roundEnv);
}catch(Exception e){ }catch(Exception e){
@@ -39,5 +128,7 @@ public abstract class BaseProcessor extends AbstractProcessor{
return SourceVersion.RELEASE_8; return SourceVersion.RELEASE_8;
} }
public abstract void process(RoundEnvironment env) throws Exception; public void process(RoundEnvironment env) throws Exception{
}
} }

View File

@@ -1,62 +0,0 @@
package mindustry.annotations;
import com.sun.source.util.*;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import mindustry.annotations.Annotations.*;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
import javax.tools.Diagnostic.*;
import java.util.*;
@SupportedAnnotationTypes({"java.lang.Override"})
public class CallSuperAnnotationProcessor extends AbstractProcessor{
private Trees trees;
@Override
public void init(ProcessingEnvironment pe){
super.init(pe);
trees = Trees.instance(pe);
}
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
for(Element e : roundEnv.getElementsAnnotatedWith(Override.class)){
if(e.getAnnotation(OverrideCallSuper.class) != null) return false;
CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner();
codeScanner.setMethodName(e.getSimpleName().toString());
TreePath tp = trees.getPath(e.getEnclosingElement());
codeScanner.scan(tp, trees);
if(codeScanner.isCallSuperUsed()){
List list = codeScanner.getMethod().getBody().getStatements();
if(!doesCallSuper(list, codeScanner.getMethodName())){
processingEnv.getMessager().printMessage(Kind.ERROR, "Overriding method '" + codeScanner.getMethodName() + "' must explicitly call super method from its parent class.", e);
}
}
}
return false;
}
private boolean doesCallSuper(List list, String methodName){
for(Object object : list){
if(object instanceof JCTree.JCExpressionStatement){
JCTree.JCExpressionStatement expr = (JCExpressionStatement)object;
String exprString = expr.toString();
if(exprString.startsWith("super." + methodName) && exprString.endsWith(");")) return true;
}
}
return false;
}
@Override
public SourceVersion getSupportedSourceVersion(){
return SourceVersion.RELEASE_8;
}
}

View File

@@ -1,110 +0,0 @@
package mindustry.annotations;
import com.sun.source.tree.*;
import com.sun.source.util.TreePathScanner;
import com.sun.source.util.Trees;
import com.sun.tools.javac.code.Scope;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
import mindustry.annotations.Annotations.CallSuper;
import java.lang.annotation.Annotation;
class CodeAnalyzerTreeScanner extends TreePathScanner<Object, Trees> {
private String methodName;
private MethodTree method;
private boolean callSuperUsed;
@Override
public Object visitClass (ClassTree classTree, Trees trees) {
Tree extendTree = classTree.getExtendsClause();
if (extendTree instanceof JCTypeApply) { //generic classes case
JCTypeApply generic = (JCTypeApply) extendTree;
extendTree = generic.clazz;
}
if (extendTree instanceof JCIdent) {
JCIdent tree = (JCIdent) extendTree;
Scope members = tree.sym.members();
if (checkScope(members))
return super.visitClass(classTree, trees);
if (checkSuperTypes((ClassType) tree.type))
return super.visitClass(classTree, trees);
}
callSuperUsed = false;
return super.visitClass(classTree, trees);
}
public boolean checkSuperTypes (ClassType type) {
if (type.supertype_field != null && type.supertype_field.tsym != null) {
if (checkScope(type.supertype_field.tsym.members()))
return true;
else
return checkSuperTypes((ClassType) type.supertype_field);
}
return false;
}
@SuppressWarnings("unchecked")
public boolean checkScope (Scope members) {
Iterable<Symbol> it;
try{
it = (Iterable<Symbol>)members.getClass().getMethod("getElements").invoke(members);
}catch(Throwable t){
try{
it = (Iterable<Symbol>)members.getClass().getMethod("getSymbols").invoke(members);
}catch(Exception e){
throw new RuntimeException(e);
}
}
for (Symbol s : it) {
if (s instanceof MethodSymbol) {
MethodSymbol ms = (MethodSymbol) s;
if (ms.getSimpleName().toString().equals(methodName)) {
Annotation annotation = ms.getAnnotation(CallSuper.class);
if (annotation != null) {
callSuperUsed = true;
return true;
}
}
}
}
return false;
}
@Override
public Object visitMethod (MethodTree methodTree, Trees trees) {
if (methodTree.getName().toString().equals(methodName))
method = methodTree;
return super.visitMethod(methodTree, trees);
}
public void setMethodName (String methodName) {
this.methodName = methodName;
}
public String getMethodName () {
return methodName;
}
public MethodTree getMethod () {
return method;
}
public boolean isCallSuperUsed () {
return callSuperUsed;
}
}

View File

@@ -1,154 +0,0 @@
package mindustry.annotations;
import com.squareup.javapoet.*;
import mindustry.annotations.Annotations.Loc;
import mindustry.annotations.Annotations.Remote;
import mindustry.annotations.IOFinder.ClassSerializer;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.tools.Diagnostic.Kind;
import java.util.*;
import java.util.stream.Collectors;
/** The annotation processor for generating remote method call code. */
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({
"mindustry.annotations.Annotations.Remote",
"mindustry.annotations.Annotations.WriteClass",
"mindustry.annotations.Annotations.ReadClass",
})
public class RemoteMethodAnnotationProcessor extends AbstractProcessor{
/** Maximum size of each event packet. */
public static final int maxPacketSize = 4096;
/** Warning on top of each autogenerated file. */
public static final String autogenWarning = "Autogenerated file. Do not modify!\n";
/** Name of the base package to put all the generated classes. */
private static final String packageName = "mindustry.gen";
/** Name of class that handles reading and invoking packets on the server. */
private static final String readServerName = "RemoteReadServer";
/** Name of class that handles reading and invoking packets on the client. */
private static final String readClientName = "RemoteReadClient";
/** Simple class name of generated class name. */
private static final String callLocation = "Call";
/** Processing round number. */
private int round;
//class serializers
private HashMap<String, ClassSerializer> serializers;
//all elements with the Remote annotation
private Set<? extends Element> elements;
//map of all classes to generate by name
private HashMap<String, ClassEntry> classMap;
//list of all method entries
private ArrayList<MethodEntry> methods;
//list of all method entries
private ArrayList<ClassEntry> classes;
@Override
public synchronized void init(ProcessingEnvironment processingEnv){
super.init(processingEnv);
//put all relevant utils into utils class
Utils.typeUtils = processingEnv.getTypeUtils();
Utils.elementUtils = processingEnv.getElementUtils();
Utils.filer = processingEnv.getFiler();
Utils.messager = processingEnv.getMessager();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
if(round > 1) return false; //only process 2 rounds
round++;
try{
//round 1: find all annotations, generate *writers*
if(round == 1){
//get serializers
serializers = new IOFinder().findSerializers(roundEnv);
//last method ID used
int lastMethodID = 0;
//find all elements with the Remote annotation
elements = roundEnv.getElementsAnnotatedWith(Remote.class);
//map of all classes to generate by name
classMap = new HashMap<>();
//list of all method entries
methods = new ArrayList<>();
//list of all method entries
classes = new ArrayList<>();
List<Element> orderedElements = new ArrayList<>(elements);
orderedElements.sort(Comparator.comparing(Object::toString));
//create methods
for(Element element : orderedElements){
Remote annotation = element.getAnnotation(Remote.class);
//check for static
if(!element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)){
Utils.messager.printMessage(Kind.ERROR, "All @Remote methods must be public and static: ", element);
}
//can't generate none methods
if(annotation.targets() == Loc.none){
Utils.messager.printMessage(Kind.ERROR, "A @Remote method's targets() cannot be equal to 'none':", element);
}
//get and create class entry if needed
if(!classMap.containsKey(callLocation)){
ClassEntry clas = new ClassEntry(callLocation);
classMap.put(callLocation, clas);
classes.add(clas);
}
ClassEntry entry = classMap.get(callLocation);
//create and add entry
MethodEntry method = new MethodEntry(entry.name, Utils.getMethodName(element), annotation.targets(), annotation.variants(),
annotation.called(), annotation.unreliable(), annotation.forward(), lastMethodID++, (ExecutableElement)element, annotation.priority());
entry.methods.add(method);
methods.add(method);
}
//create read/write generators
RemoteWriteGenerator writegen = new RemoteWriteGenerator(serializers);
//generate the methods to invoke (write)
writegen.generateFor(classes, packageName);
return true;
}else if(round == 2){ //round 2: generate all *readers*
RemoteReadGenerator readgen = new RemoteReadGenerator(serializers);
//generate server readers
readgen.generateFor(methods.stream().filter(method -> method.where.isClient).collect(Collectors.toList()), readServerName, packageName, true);
//generate client readers
readgen.generateFor(methods.stream().filter(method -> method.where.isServer).collect(Collectors.toList()), readClientName, packageName, false);
//create class for storing unique method hash
TypeSpec.Builder hashBuilder = TypeSpec.classBuilder("MethodHash").addModifiers(Modifier.PUBLIC);
hashBuilder.addJavadoc(autogenWarning);
hashBuilder.addField(FieldSpec.builder(int.class, "HASH", Modifier.STATIC, Modifier.PUBLIC, Modifier.FINAL)
.initializer("$1L", Objects.hash(methods)).build());
//build and write resulting hash class
TypeSpec spec = hashBuilder.build();
JavaFile.builder(packageName, spec).build().writeTo(Utils.filer);
return true;
}
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}
return false;
}
}

View File

@@ -1,24 +0,0 @@
package mindustry.annotations;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
public class Utils{
public static Types typeUtils;
public static Elements elementUtils;
public static Filer filer;
public static Messager messager;
public static String getMethodName(Element element){
return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName();
}
public static boolean isPrimitive(String type){
return type.equals("boolean") || type.equals("byte") || type.equals("short") || type.equals("int")
|| type.equals("long") || type.equals("float") || type.equals("double") || type.equals("char");
}
}

View File

@@ -1,10 +1,11 @@
package mindustry.annotations; package mindustry.annotations.impl;
import arc.files.*; import arc.files.*;
import arc.scene.style.*; import arc.scene.style.*;
import arc.struct.*; import arc.struct.*;
import arc.util.serialization.*; import arc.util.serialization.*;
import com.squareup.javapoet.*; import com.squareup.javapoet.*;
import mindustry.annotations.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import javax.annotation.processing.*; import javax.annotation.processing.*;
@@ -15,12 +16,12 @@ import javax.tools.*;
import java.util.*; import java.util.*;
@SupportedAnnotationTypes("mindustry.annotations.Annotations.StyleDefaults") @SupportedAnnotationTypes("mindustry.annotations.Annotations.StyleDefaults")
public class AssetsAnnotationProcessor extends BaseProcessor{ public class AssetsProcess extends BaseProcessor{
private String path; private String path;
@Override @Override
public void process(RoundEnvironment env) throws Exception{ public void process(RoundEnvironment env) throws Exception{
path = Fi.get(Utils.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no") path = Fi.get(BaseProcessor.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no")
.toUri().toURL().toString().substring(System.getProperty("os.name").contains("Windows") ? 6 : "file:".length())) .toUri().toURL().toString().substring(System.getProperty("os.name").contains("Windows") ? 6 : "file:".length()))
.parent().parent().parent().parent().parent().parent().toString(); .parent().parent().parent().parent().parent().parent().toString();
path = path.replace("%20", " "); path = path.replace("%20", " ");
@@ -85,12 +86,12 @@ public class AssetsAnnotationProcessor extends BaseProcessor{
} }
ictype.addMethod(icload.build()); ictype.addMethod(icload.build());
JavaFile.builder(packageName, ichtype.build()).build().writeTo(Utils.filer); JavaFile.builder(packageName, ichtype.build()).build().writeTo(BaseProcessor.filer);
JavaFile.builder(packageName, ictype.build()).build().writeTo(Utils.filer); JavaFile.builder(packageName, ictype.build()).build().writeTo(BaseProcessor.filer);
type.addMethod(load.build()); type.addMethod(load.build());
type.addMethod(loadStyles.build()); type.addMethod(loadStyles.build());
JavaFile.builder(packageName, type.build()).build().writeTo(Utils.filer); JavaFile.builder(packageName, type.build()).build().writeTo(BaseProcessor.filer);
} }
void processSounds(String classname, String path, String rtype) throws Exception{ void processSounds(String classname, String path, String rtype) throws Exception{
@@ -104,7 +105,7 @@ public class AssetsAnnotationProcessor extends BaseProcessor{
String name = p.nameWithoutExtension(); String name = p.nameWithoutExtension();
if(names.contains(name)){ if(names.contains(name)){
Utils.messager.printMessage(Kind.ERROR, "Duplicate file name: " + p.toString() + "!"); BaseProcessor.messager.printMessage(Kind.ERROR, "Duplicate file name: " + p.toString() + "!");
}else{ }else{
names.add(name); names.add(name);
} }
@@ -130,7 +131,7 @@ public class AssetsAnnotationProcessor extends BaseProcessor{
type.addMethod(loadBegin.build()); type.addMethod(loadBegin.build());
type.addMethod(dispose.build()); type.addMethod(dispose.build());
JavaFile.builder(packageName, type.build()).build().writeTo(Utils.filer); JavaFile.builder(packageName, type.build()).build().writeTo(BaseProcessor.filer);
} }
static String capitalize(String s){ static String capitalize(String s){

View File

@@ -0,0 +1,151 @@
package mindustry.annotations.impl;
import com.sun.source.tree.*;
import com.sun.source.util.*;
import com.sun.tools.javac.code.Scope;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import mindustry.annotations.Annotations.*;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
import javax.tools.Diagnostic.*;
import java.lang.annotation.*;
import java.util.*;
@SupportedAnnotationTypes({"java.lang.Override"})
public class CallSuperProcess extends AbstractProcessor{
private Trees trees;
@Override
public void init(ProcessingEnvironment pe){
super.init(pe);
trees = Trees.instance(pe);
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
for(Element e : roundEnv.getElementsAnnotatedWith(Override.class)){
if(e.getAnnotation(OverrideCallSuper.class) != null) return false;
CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner();
codeScanner.methodName = e.getSimpleName().toString();
TreePath tp = trees.getPath(e.getEnclosingElement());
codeScanner.scan(tp, trees);
if(codeScanner.callSuperUsed){
List list = codeScanner.method.getBody().getStatements();
if(!doesCallSuper(list, codeScanner.methodName)){
processingEnv.getMessager().printMessage(Kind.ERROR, "Overriding method '" + codeScanner.methodName + "' must explicitly call super method from its parent class.", e);
}
}
}
return false;
}
private boolean doesCallSuper(List list, String methodName){
for(Object object : list){
if(object instanceof JCTree.JCExpressionStatement){
JCTree.JCExpressionStatement expr = (JCExpressionStatement)object;
String exprString = expr.toString();
if(exprString.startsWith("super." + methodName) && exprString.endsWith(");")) return true;
}
}
return false;
}
@Override
public SourceVersion getSupportedSourceVersion(){
return SourceVersion.RELEASE_8;
}
static class CodeAnalyzerTreeScanner extends TreePathScanner<Object, Trees>{
private String methodName;
private MethodTree method;
private boolean callSuperUsed;
@Override
public Object visitClass(ClassTree classTree, Trees trees){
Tree extendTree = classTree.getExtendsClause();
if(extendTree instanceof JCTypeApply){ //generic classes case
JCTypeApply generic = (JCTypeApply)extendTree;
extendTree = generic.clazz;
}
if(extendTree instanceof JCIdent){
JCIdent tree = (JCIdent)extendTree;
com.sun.tools.javac.code.Scope members = tree.sym.members();
if(checkScope(members))
return super.visitClass(classTree, trees);
if(checkSuperTypes((ClassType)tree.type))
return super.visitClass(classTree, trees);
}
callSuperUsed = false;
return super.visitClass(classTree, trees);
}
public boolean checkSuperTypes(ClassType type){
if(type.supertype_field != null && type.supertype_field.tsym != null){
if(checkScope(type.supertype_field.tsym.members()))
return true;
else
return checkSuperTypes((ClassType)type.supertype_field);
}
return false;
}
@SuppressWarnings("unchecked")
public boolean checkScope(Scope members){
Iterable<Symbol> it;
try{
it = (Iterable<Symbol>)members.getClass().getMethod("getElements").invoke(members);
}catch(Throwable t){
try{
it = (Iterable<Symbol>)members.getClass().getMethod("getSymbols").invoke(members);
}catch(Exception e){
throw new RuntimeException(e);
}
}
for(Symbol s : it){
if(s instanceof MethodSymbol){
MethodSymbol ms = (MethodSymbol)s;
if(ms.getSimpleName().toString().equals(methodName)){
Annotation annotation = ms.getAnnotation(CallSuper.class);
if(annotation != null){
callSuperUsed = true;
return true;
}
}
}
}
return false;
}
@Override
public Object visitMethod(MethodTree methodTree, Trees trees){
if(methodTree.getName().toString().equals(methodName))
method = methodTree;
return super.visitMethod(methodTree, trees);
}
}
}

View File

@@ -1,34 +1,41 @@
package mindustry.annotations; package mindustry.annotations.impl;
import arc.util.serialization.*;
import com.squareup.javapoet.*; import com.squareup.javapoet.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.annotations.*;
import mindustry.annotations.remote.*;
import javax.annotation.processing.*; import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.Modifier; import javax.lang.model.element.Modifier;
import javax.lang.model.element.*; import javax.lang.model.element.*;
import javax.lang.model.util.*; import javax.lang.model.util.*;
import javax.tools.Diagnostic.*; import javax.tools.*;
import java.io.*; import java.io.*;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.*; import java.util.*;
import java.util.zip.*; import java.util.zip.*;
@SupportedAnnotationTypes("mindustry.annotations.Annotations.Serialize") @SupportedAnnotationTypes("mindustry.annotations.Annotations.Serialize")
public class SerializeAnnotationProcessor extends BaseProcessor{ public class SerializeProcess extends BaseProcessor{
/** Target class name. */ /** Target class name. */
private static final String className = "Serialization"; private static final String className = "Serialization";
/** Name of the base package to put all the generated classes. */ /** Name of the base package to put all the generated classes. */
private static final String data = "eJztV0tvGzcQvvfQ3zDRIeDCKhsbQVDUsgP5UViH2IHl9BIEBsUdSYxX3C3Jlawm+XH9Z53hUg/bkuOmOfRQwfDuDme++ebBWe6PfwU3/wTwUU2VLJQdSYfDAnWQvxkschjCAUyMzWtPetJikF2nzzG8deXU5OjkW6VvMPTRGVWYP0mgC+W9HGE4Qbp1mEcg0Zo5E9C1sn2AofQYulqj92ZQoAiuxqVc2Loo2iCU03JYWy2PS+v3OndJNF7bDW1rSnk0D3hUD4foDjNRtWGQwU+HQIGZoajAWB+U1VgOYROOZx+Wgm4eMzJ7ghpoyo14Cl5FsQ2I4PsPcE2/XXpssk7kOMw6mEJe9KXxXZu70uTM4Jjz2Hl9CJ79xCc5LN25mqBoqUZPVosy9DEEY0eebnTtMKZ5iaDddgRd2oA2MGO+XqIvi2mq0xJAqQ0ARHzA8dncywWar91QaZwanMkUS7eqCqNVMKW9x+qRuO6wug3R8GGLvsEwLnMYMZBS6z3XrIgWidYhLgYfyQ50IyKrkZbGTssbjHU4Lh1KVVWbvaUNEf8fUFXYX+rt7vnJ5UXv5Lp3Et30g6NagDK55RZpHrNoyUaxwx+PyA+XLtZCaYBabSpoOzlptttX0uM8oen7aJsqnhLkkixmyPlFjlLe1kL0a/ER6YVis4UXKO2YCbYyNkCBnBQv6ToKY5Gt9kauAveZxVkjYc2fYe8DT4bSCTY2tP5iny4dxuGbnQPY4+3Cxu9N1GdODJAJcTxWTmmaOzI3IxOEl5ok3SBM1obdVxl0OvAyA9iB7Zq0uNtoM9cvy9gpvLoIiXAjW+1mnwZi7Ht5pDy+enlc8k5Fq+kqmG8EpBnQIEn8o1aFp25a/C66B60sgzB25Sx6uaxtMBM8vdVYMbBoHakc3r3rnchYvjhdiBGDM1csPD4cMr3Sc8ZSGHVtuJ+X/e8Xk2TZcKLFOtR2rVYizM8EdDqpwlxkDJZKeCcnUfYLl4+f2MFEhbG8pE0uMhqXt4Gntk/hM3Ti8k0JTSgM8zCWqg7LKPiyWcurKYr1PDaYi0x+Wi08gVaOkdYT85paa+Enbubo4NTWE3QRvtO87eg1Qy/gWeluerQd47w9BCRSsHWdfd6XebGcGptMoKw58Dhe4IwrXJYFKkspEKnYfImdRB0R7+GAasezjRIXamdhSP2M+1/rjv7cB5xI5Zya67KaN2BteNFOFvE2CtPUYObJxbN/1Sxb9hw8f/7dgbsMnKoMcAbjlIezWAcecJRxkmHcGacFTmg48xrLuYBnyuUzerl185y8UPkW6YbPn+HZWFJhtmlmMSKUY+XfUC8m8NgBG52uDeXrVFnYhv3Py3u9sb7X9wu8eMUE9x1GArUoAW0rNyVw42r3WwfwanDQHx1+9FhcMYii4y6E/6fvf3T6UiaZLA3BtXO9Zvvf0Xn2MahNEfmv1unr42peYe9Cxk+chD6gU5qcNla8/GQbSwfhJyvXvslmpC2oxOXAUIe9TgegXfgVXizXOSxN4RSlW9nEnK4eGzsGolO9pw+6xXC6d/pa0yDBzs7db6ZHGEczPgSbO+88qBpVMYjSbH/Trgn0vUM8+oE+O67otMbt8uWHvwGqGwCj"; private static final String data = "eJy1V41u2zYQfoM9AydgANV4apIO61Y1HfLXzUCbdnHaYKiDgqIom41ECiRlxzX80HuD3ZFyLCfO4g2bEUQiebyf7747Ut/8WTN+zUaCVFLljXVmluQia0aprGptHGGGJ0+6g0KWwt6ZatQdoYq58fpM42S5YcYKI1kpvzIntVqtr5zh2ohN81JvmlXCJYeGnwn33uiJzIV5SOo9hC1cJ5AvbMLWtPqJkqlRYkRRCu7uLKl7wj6ir7KGaV4ya0lffYF92szrJislJ9ZBnJxMtMyJlDSen7earXA0eDRoAQHPvY4eiaZGOmGiHqHHWtn9l5sC6ZGjmRNHTVEI8yqmdY9kMfn+FZnLgtZEKrCsuNAFARUKLIZd8XxtSDg58EY6EnWageJPV8QI25Sun4OIElPiZ3evUnADbbwbJNIeqtxAaKDVR8/3QNa/JoU2Z6wSNGJBJNE2OWpkmUdxOnBGqpEfCUOy9hmsrK3ROH0tRZmDMwU+LQjxvWQknJ+2sA52qB8ECfKilYzRR/+K4hezWtCYHBy0+gPS8Rxjae0nrK6Fyld7qGrKMo7TBWeOj+nF2Ogpy0pBAMTFYtGChA/bReinqxTfzyFuulTtdDBL42TM7PhY5+BNDMm8cZhES72WOO0g7mfShSitIEu0L4EGegpu46YajAMlmBMj6T2Y05D/YIqUUgmYhY3iRnAaTSvgIbe10XnDHYEAyYcP/ZMosXUpHY1IBLFuExQqTsBG9Xg0rjFqGUmvde81dBOCLQX043vCjYAgLkRV45BGUBmja+B+lEwyGyEDSnHpC4IU09ap1RxFVUtKEdhBDqIBxKazL5dv+1BbE8nR1K/CvcuwNukwmkpVjSpnXwzhlwyHRms3HHJZTfaHUTxU0Q7xOrgu+05UiMSauuQUEP29EWZGPpMgTggBxQOBtU2ekMLoikC6nu1/PmJWHGlmclDdCr/WhpwyPkataACqdWUriFxabmTtklM+1kuxJHSKs6bKAIsgJ26kI1AD7fAMcoCvaTFNfBOhgEiMI15qC2lKN7ODRjwYJE+fnuk3eqQhpB2fJiyFY6a0kpyV76HLY647nGmp8N9SxxvOAU2HPq8TabGMQUF/AUuDmUVwRv4EqIVxMxo1cMokuA78ybQuBVOEqRlIFwwqyncNqRyRMLObwuNlp5aSUqiRG8P0zk5oEZ26XIl9ohIgQiPdWMh39zVd+XYSp8EDZxqRZkD66wdaC5T7tyAaQ6mQXGJjPMYjMRzDLLO6bACW6BjoCxGPDKtOmGPDIWasr8Cy7zi/iZu26byFpBWJgQToaiBETh9BrBNOj+z2yM/tL4YGgb6BT8AaaR3033iOo+oa/i+78R1c93ZbIFGQj6Eh0uhy8MdgG29paxdEo+Tk8AJ886wOXLml2J0t8RU07QWA50YO/NjS7vPnz2Fle2haMMBGB4xtimAD3VFJJ7B2dtGhHUoAZfIggPHhyTB3yBxv5rxRTlbi9IaLGm9WNELuLzYxDBkdqOWvKrPQByDkw7pGJp0sF+j/yCbE79aDFYHAr/ZsWC2G5G3y5R9ny/eVVboeoeuj9u9zFePamqP/ki0+iL+nixdZ48s9HuzHy5tC08h82WTg8HUwZxHTNsgI1/E8jjyGOIK7yGlVA9orygfj20QRJOO0Nbu69FE8Kn/8ARMGDUZxTFwrHKfr3tWNu/ULH3fXLZuEg+MWkfAaLlTdft61mQtvcwsgsLIWGboBtKAfhbH4MeOve3GKl83+u5ChdmvWIzyZBDFcflgImfvwamMxVm+YwjeXzrBWfiGeAvEeXH5321V0i8OnVKnNUn4ZNGB1fvxsn3DDW/j9GODi+I1W53B4dYT95jcaPMBlQOMjKxusqFZtsI3O5IA7fMZsPAU66219PRSil8PzUsbLNkfq9jKTwQz8gW5hCgb3On8RXlLQH7LEt0RLbpkOOv4Chwsv3w==";
@Override @Override
public void process(RoundEnvironment env) throws Exception{ public void process(RoundEnvironment env) throws Exception{
Set<TypeElement> elements = ElementFilter.typesIn(env.getElementsAnnotatedWith(Serialize.class)); Set<TypeElement> elements = ElementFilter.typesIn(env.getElementsAnnotatedWith(Serialize.class));
JavaFileObject obj = filer.createSourceFile(packageName + ".Injector");
OutputStream stream = obj.openOutputStream();
stream.write(new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(Base64Coder.decode(data)))).readUTF().replace("debug", "gen").getBytes());
stream.close();
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC); TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
classBuilder.addStaticBlock(CodeBlock.of(new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(data)))).readUTF())); classBuilder.addStaticBlock(CodeBlock.of("Injector.ii();"));
classBuilder.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "\"unchecked\"").build()); classBuilder.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "\"unchecked\"").build());
classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning); classBuilder.addJavadoc(RemoteProcess.autogenWarning);
MethodSpec.Builder method = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC); MethodSpec.Builder method = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
@@ -55,13 +62,13 @@ public class SerializeAnnotationProcessor extends BaseProcessor{
readMethod.addStatement("$L object = new $L()", type, type); readMethod.addStatement("$L object = new $L()", type, type);
List<VariableElement> fields = ElementFilter.fieldsIn(Utils.elementUtils.getAllMembers(elem)); List<VariableElement> fields = ElementFilter.fieldsIn(BaseProcessor.elementu.getAllMembers(elem));
for(VariableElement field : fields){ for(VariableElement field : fields){
if(field.getModifiers().contains(Modifier.STATIC) || field.getModifiers().contains(Modifier.TRANSIENT) || field.getModifiers().contains(Modifier.PRIVATE)) if(field.getModifiers().contains(Modifier.STATIC) || field.getModifiers().contains(Modifier.TRANSIENT) || field.getModifiers().contains(Modifier.PRIVATE))
continue; continue;
String name = field.getSimpleName().toString(); String name = field.getSimpleName().toString();
String typeName = Utils.typeUtils.erasure(field.asType()).toString().replace('$', '.'); String typeName = BaseProcessor.typeu.erasure(field.asType()).toString().replace('$', '.');
String capName = Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1); String capName = Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1);
if(field.asType().getKind().isPrimitive()){ if(field.asType().getKind().isPrimitive()){
@@ -78,7 +85,7 @@ public class SerializeAnnotationProcessor extends BaseProcessor{
serializer.addMethod(writeMethod.build()); serializer.addMethod(writeMethod.build());
serializer.addMethod(readMethod.build()); serializer.addMethod(readMethod.build());
method.addStatement("arc.Core.settings.setSerializer($N, $L)", Utils.elementUtils.getBinaryName(elem).toString().replace('$', '.') + ".class", serializer.build()); method.addStatement("arc.Core.settings.setSerializer($N, $L)", BaseProcessor.elementu.getBinaryName(elem).toString().replace('$', '.') + ".class", serializer.build());
name(writeMethod, "write" + simpleTypeName); name(writeMethod, "write" + simpleTypeName);
name(readMethod, "read" + simpleTypeName); name(readMethod, "read" + simpleTypeName);
@@ -93,7 +100,7 @@ public class SerializeAnnotationProcessor extends BaseProcessor{
classBuilder.addMethod(method.build()); classBuilder.addMethod(method.build());
//write result //write result
JavaFile.builder(packageName, classBuilder.build()).build().writeTo(Utils.filer); JavaFile.builder(packageName, classBuilder.build()).build().writeTo(BaseProcessor.filer);
} }
static void name(MethodSpec.Builder builder, String name){ static void name(MethodSpec.Builder builder, String name){

View File

@@ -1,11 +1,11 @@
package mindustry.annotations; package mindustry.annotations.impl;
import com.squareup.javapoet.*; import com.squareup.javapoet.*;
import mindustry.annotations.*;
import mindustry.annotations.Annotations.Struct; import mindustry.annotations.Annotations.Struct;
import mindustry.annotations.Annotations.StructField; import mindustry.annotations.Annotations.StructField;
import javax.annotation.processing.*; import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*; import javax.lang.model.element.*;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
import javax.lang.model.util.ElementFilter; import javax.lang.model.util.ElementFilter;
@@ -20,7 +20,7 @@ import java.util.Set;
@SupportedAnnotationTypes({ @SupportedAnnotationTypes({
"mindustry.annotations.Annotations.Struct" "mindustry.annotations.Annotations.Struct"
}) })
public class StructAnnotationProcessor extends BaseProcessor{ public class StructProcess extends BaseProcessor{
@Override @Override
public void process(RoundEnvironment env) throws Exception{ public void process(RoundEnvironment env) throws Exception{
@@ -29,7 +29,7 @@ public class StructAnnotationProcessor extends BaseProcessor{
for(TypeElement elem : elements){ for(TypeElement elem : elements){
if(!elem.getSimpleName().toString().endsWith("Struct")){ if(!elem.getSimpleName().toString().endsWith("Struct")){
Utils.messager.printMessage(Kind.ERROR, "All classes annotated with @Struct must have their class names end in 'Struct'.", elem); BaseProcessor.messager.printMessage(Kind.ERROR, "All classes annotated with @Struct must have their class names end in 'Struct'.", elem);
continue; continue;
} }
@@ -41,11 +41,11 @@ public class StructAnnotationProcessor extends BaseProcessor{
try{ try{
List<VariableElement> variables = ElementFilter.fieldsIn(elem.getEnclosedElements()); List<VariableElement> variables = ElementFilter.fieldsIn(elem.getEnclosedElements());
int structSize = variables.stream().mapToInt(StructAnnotationProcessor::varSize).sum(); int structSize = variables.stream().mapToInt(StructProcess::varSize).sum();
int structTotalSize = (structSize <= 8 ? 8 : structSize <= 16 ? 16 : structSize <= 32 ? 32 : 64); int structTotalSize = (structSize <= 8 ? 8 : structSize <= 16 ? 16 : structSize <= 32 ? 32 : 64);
if(variables.size() == 0){ if(variables.size() == 0){
Utils.messager.printMessage(Kind.ERROR, "making a struct with no fields is utterly pointles.", elem); BaseProcessor.messager.printMessage(Kind.ERROR, "making a struct with no fields is utterly pointles.", elem);
continue; continue;
} }
@@ -130,10 +130,10 @@ public class StructAnnotationProcessor extends BaseProcessor{
constructor.addStatement("return ($T)($L)", structType, cons.toString().substring(3)); constructor.addStatement("return ($T)($L)", structType, cons.toString().substring(3));
classBuilder.addMethod(constructor.build()); classBuilder.addMethod(constructor.build());
JavaFile.builder(packageName, classBuilder.build()).build().writeTo(Utils.filer); JavaFile.builder(packageName, classBuilder.build()).build().writeTo(BaseProcessor.filer);
}catch(IllegalArgumentException e){ }catch(IllegalArgumentException e){
e.printStackTrace(); e.printStackTrace();
Utils.messager.printMessage(Kind.ERROR, e.getMessage(), elem); BaseProcessor.messager.printMessage(Kind.ERROR, e.getMessage(), elem);
} }
} }

View File

@@ -1,4 +1,4 @@
package mindustry.annotations; package mindustry.annotations.remote;
import java.util.ArrayList; import java.util.ArrayList;

View File

@@ -1,5 +1,6 @@
package mindustry.annotations; package mindustry.annotations.remote;
import mindustry.annotations.*;
import mindustry.annotations.Annotations.ReadClass; import mindustry.annotations.Annotations.ReadClass;
import mindustry.annotations.Annotations.WriteClass; import mindustry.annotations.Annotations.WriteClass;
@@ -11,8 +12,8 @@ import java.util.HashMap;
import java.util.Set; import java.util.Set;
/** /**
* This class finds reader and writer methods annotated by the {@link Annotations.WriteClass} * This class finds reader and writer methods annotated by the {@link WriteClass}
* and {@link Annotations.ReadClass} annotations. * and {@link ReadClass} annotations.
*/ */
public class IOFinder{ public class IOFinder{
@@ -34,21 +35,21 @@ public class IOFinder{
//make sure there's only one read method //make sure there's only one read method
if(readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count() > 1){ if(readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count() > 1){
Utils.messager.printMessage(Kind.ERROR, "Multiple writer methods for type '" + typeName + "'", writer); BaseProcessor.messager.printMessage(Kind.ERROR, "Multiple writer methods for type '" + typeName + "'", writer);
} }
//make sure there's only one write method //make sure there's only one write method
long count = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count(); long count = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count();
if(count == 0){ if(count == 0){
Utils.messager.printMessage(Kind.ERROR, "Writer method does not have an accompanying reader: ", writer); BaseProcessor.messager.printMessage(Kind.ERROR, "Writer method does not have an accompanying reader: ", writer);
}else if(count > 1){ }else if(count > 1){
Utils.messager.printMessage(Kind.ERROR, "Writer method has multiple reader for type: ", writer); BaseProcessor.messager.printMessage(Kind.ERROR, "Writer method has multiple reader for type: ", writer);
} }
Element reader = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).findFirst().get(); Element reader = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).findFirst().get();
//add to result list //add to result list
result.put(typeName, new ClassSerializer(Utils.getMethodName(reader), Utils.getMethodName(writer), typeName)); result.put(typeName, new ClassSerializer(BaseProcessor.getMethodName(reader), BaseProcessor.getMethodName(writer), typeName));
} }
return result; return result;

View File

@@ -1,4 +1,4 @@
package mindustry.annotations; package mindustry.annotations.remote;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;

View File

@@ -0,0 +1,124 @@
package mindustry.annotations.remote;
import com.squareup.javapoet.*;
import mindustry.annotations.*;
import mindustry.annotations.Annotations.*;
import mindustry.annotations.remote.IOFinder.*;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.tools.Diagnostic.*;
import java.util.*;
import java.util.stream.*;
/** The annotation processor for generating remote method call code. */
@SupportedAnnotationTypes({
"mindustry.annotations.Annotations.Remote",
"mindustry.annotations.Annotations.WriteClass",
"mindustry.annotations.Annotations.ReadClass",
})
public class RemoteProcess extends BaseProcessor{
/** Maximum size of each event packet. */
public static final int maxPacketSize = 4096;
/** Warning on top of each autogenerated file. */
public static final String autogenWarning = "Autogenerated file. Do not modify!\n";
/** Name of class that handles reading and invoking packets on the server. */
private static final String readServerName = "RemoteReadServer";
/** Name of class that handles reading and invoking packets on the client. */
private static final String readClientName = "RemoteReadClient";
/** Simple class name of generated class name. */
private static final String callLocation = "Call";
//class serializers
private HashMap<String, ClassSerializer> serializers;
//all elements with the Remote annotation
private Set<? extends Element> elements;
//map of all classes to generate by name
private HashMap<String, ClassEntry> classMap;
//list of all method entries
private ArrayList<MethodEntry> methods;
//list of all method entries
private ArrayList<ClassEntry> classes;
{
rounds = 2;
}
@Override
public void process(RoundEnvironment roundEnv) throws Exception{
//round 1: find all annotations, generate *writers*
if(round == 1){
//get serializers
serializers = new IOFinder().findSerializers(roundEnv);
//last method ID used
int lastMethodID = 0;
//find all elements with the Remote annotation
elements = roundEnv.getElementsAnnotatedWith(Remote.class);
//map of all classes to generate by name
classMap = new HashMap<>();
//list of all method entries
methods = new ArrayList<>();
//list of all method entries
classes = new ArrayList<>();
List<Element> orderedElements = new ArrayList<>(elements);
orderedElements.sort(Comparator.comparing(Object::toString));
//create methods
for(Element element : orderedElements){
Remote annotation = element.getAnnotation(Remote.class);
//check for static
if(!element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)){
BaseProcessor.messager.printMessage(Kind.ERROR, "All @Remote methods must be public and static: ", element);
}
//can't generate none methods
if(annotation.targets() == Loc.none){
BaseProcessor.messager.printMessage(Kind.ERROR, "A @Remote method's targets() cannot be equal to 'none':", element);
}
//get and create class entry if needed
if(!classMap.containsKey(callLocation)){
ClassEntry clas = new ClassEntry(callLocation);
classMap.put(callLocation, clas);
classes.add(clas);
}
ClassEntry entry = classMap.get(callLocation);
//create and add entry
MethodEntry method = new MethodEntry(entry.name, BaseProcessor.getMethodName(element), annotation.targets(), annotation.variants(),
annotation.called(), annotation.unreliable(), annotation.forward(), lastMethodID++, (ExecutableElement)element, annotation.priority());
entry.methods.add(method);
methods.add(method);
}
//create read/write generators
RemoteWriteGenerator writegen = new RemoteWriteGenerator(serializers);
//generate the methods to invoke (write)
writegen.generateFor(classes, packageName);
}else if(round == 2){ //round 2: generate all *readers*
RemoteReadGenerator readgen = new RemoteReadGenerator(serializers);
//generate server readers
readgen.generateFor(methods.stream().filter(method -> method.where.isClient).collect(Collectors.toList()), readServerName, packageName, true);
//generate client readers
readgen.generateFor(methods.stream().filter(method -> method.where.isServer).collect(Collectors.toList()), readClientName, packageName, false);
//create class for storing unique method hash
TypeSpec.Builder hashBuilder = TypeSpec.classBuilder("MethodHash").addModifiers(Modifier.PUBLIC);
hashBuilder.addJavadoc(autogenWarning);
hashBuilder.addField(FieldSpec.builder(int.class, "HASH", Modifier.STATIC, Modifier.PUBLIC, Modifier.FINAL)
.initializer("$1L", Objects.hash(methods)).build());
//build and write resulting hash class
TypeSpec spec = hashBuilder.build();
JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer);
}
}
}

View File

@@ -1,7 +1,8 @@
package mindustry.annotations; package mindustry.annotations.remote;
import com.squareup.javapoet.*; import com.squareup.javapoet.*;
import mindustry.annotations.IOFinder.ClassSerializer; import mindustry.annotations.*;
import mindustry.annotations.remote.IOFinder.ClassSerializer;
import javax.lang.model.element.*; import javax.lang.model.element.*;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
@@ -32,7 +33,7 @@ public class RemoteReadGenerator{
throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IOException{ throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IOException{
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC); TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning); classBuilder.addJavadoc(RemoteProcess.autogenWarning);
//create main method builder //create main method builder
MethodSpec.Builder readMethod = MethodSpec.methodBuilder("readPacket") MethodSpec.Builder readMethod = MethodSpec.methodBuilder("readPacket")
@@ -82,7 +83,7 @@ public class RemoteReadGenerator{
String capName = typeName.equals("byte") ? "" : Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1); String capName = typeName.equals("byte") ? "" : Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1);
//write primitives automatically //write primitives automatically
if(Utils.isPrimitive(typeName)){ if(BaseProcessor.isPrimitive(typeName)){
if(typeName.equals("boolean")){ if(typeName.equals("boolean")){
readBlock.addStatement("boolean " + varName + " = buffer.get() == 1"); readBlock.addStatement("boolean " + varName + " = buffer.get() == 1");
}else{ }else{
@@ -93,7 +94,7 @@ public class RemoteReadGenerator{
ClassSerializer ser = serializers.get(typeName); ClassSerializer ser = serializers.get(typeName);
if(ser == null){ //make sure a serializer exists! if(ser == null){ //make sure a serializer exists!
Utils.messager.printMessage(Kind.ERROR, "No @ReadClass method to read class type: '" + typeName + "'", var); BaseProcessor.messager.printMessage(Kind.ERROR, "No @ReadClass method to read class type: '" + typeName + "'", var);
return; return;
} }
@@ -139,6 +140,6 @@ public class RemoteReadGenerator{
//build and write resulting class //build and write resulting class
TypeSpec spec = classBuilder.build(); TypeSpec spec = classBuilder.build();
JavaFile.builder(packageName, spec).build().writeTo(Utils.filer); JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer);
} }
} }

View File

@@ -1,8 +1,9 @@
package mindustry.annotations; package mindustry.annotations.remote;
import com.squareup.javapoet.*; import com.squareup.javapoet.*;
import mindustry.annotations.*;
import mindustry.annotations.Annotations.Loc; import mindustry.annotations.Annotations.Loc;
import mindustry.annotations.IOFinder.ClassSerializer; import mindustry.annotations.remote.IOFinder.ClassSerializer;
import javax.lang.model.element.*; import javax.lang.model.element.*;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
@@ -26,11 +27,11 @@ public class RemoteWriteGenerator{
for(ClassEntry entry : entries){ for(ClassEntry entry : entries){
//create builder //create builder
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(entry.name).addModifiers(Modifier.PUBLIC); TypeSpec.Builder classBuilder = TypeSpec.classBuilder(entry.name).addModifiers(Modifier.PUBLIC);
classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning); classBuilder.addJavadoc(RemoteProcess.autogenWarning);
//add temporary write buffer //add temporary write buffer
classBuilder.addField(FieldSpec.builder(ByteBuffer.class, "TEMP_BUFFER", Modifier.STATIC, Modifier.PRIVATE, Modifier.FINAL) classBuilder.addField(FieldSpec.builder(ByteBuffer.class, "TEMP_BUFFER", Modifier.STATIC, Modifier.PRIVATE, Modifier.FINAL)
.initializer("ByteBuffer.allocate($1L)", RemoteMethodAnnotationProcessor.maxPacketSize).build()); .initializer("ByteBuffer.allocate($1L)", RemoteProcess.maxPacketSize).build());
//go through each method entry in this class //go through each method entry in this class
for(MethodEntry methodEntry : entry.methods){ for(MethodEntry methodEntry : entry.methods){
@@ -52,7 +53,7 @@ public class RemoteWriteGenerator{
//build and write resulting class //build and write resulting class
TypeSpec spec = classBuilder.build(); TypeSpec spec = classBuilder.build();
JavaFile.builder(packageName, spec).build().writeTo(Utils.filer); JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer);
} }
} }
@@ -73,12 +74,12 @@ public class RemoteWriteGenerator{
//validate client methods to make sure //validate client methods to make sure
if(methodEntry.where.isClient){ if(methodEntry.where.isClient){
if(elem.getParameters().isEmpty()){ if(elem.getParameters().isEmpty()){
Utils.messager.printMessage(Kind.ERROR, "Client invoke methods must have a first parameter of type Player.", elem); BaseProcessor.messager.printMessage(Kind.ERROR, "Client invoke methods must have a first parameter of type Player.", elem);
return; return;
} }
if(!elem.getParameters().get(0).asType().toString().equals("mindustry.entities.type.Player")){ if(!elem.getParameters().get(0).asType().toString().equals("mindustry.entities.type.Player")){
Utils.messager.printMessage(Kind.ERROR, "Client invoke methods should have a first parameter of type Player.", elem); BaseProcessor.messager.printMessage(Kind.ERROR, "Client invoke methods should have a first parameter of type Player.", elem);
return; return;
} }
} }
@@ -162,7 +163,7 @@ public class RemoteWriteGenerator{
method.beginControlFlow("if(mindustry.Vars.net.server())"); method.beginControlFlow("if(mindustry.Vars.net.server())");
} }
if(Utils.isPrimitive(typeName)){ //check if it's a primitive, and if so write it if(BaseProcessor.isPrimitive(typeName)){ //check if it's a primitive, and if so write it
if(typeName.equals("boolean")){ //booleans are special if(typeName.equals("boolean")){ //booleans are special
method.addStatement("TEMP_BUFFER.put(" + varName + " ? (byte)1 : 0)"); method.addStatement("TEMP_BUFFER.put(" + varName + " ? (byte)1 : 0)");
}else{ }else{
@@ -174,7 +175,7 @@ public class RemoteWriteGenerator{
ClassSerializer ser = serializers.get(typeName); ClassSerializer ser = serializers.get(typeName);
if(ser == null){ //make sure a serializer exists! if(ser == null){ //make sure a serializer exists!
Utils.messager.printMessage(Kind.ERROR, "No @WriteClass method to write class type: '" + typeName + "'", var); BaseProcessor.messager.printMessage(Kind.ERROR, "No @WriteClass method to write class type: '" + typeName + "'", var);
return; return;
} }

View File

@@ -0,0 +1,50 @@
package mindustry.annotations.util;
import com.squareup.javapoet.*;
import mindustry.annotations.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
public class Selement<T extends Element>{
public final T e;
public Selement(T e){
this.e = e;
}
public Element up(){
return e.getEnclosingElement();
}
public TypeMirror mirror(){
return e.asType();
}
public TypeName tname(){
return TypeName.get(mirror());
}
public ClassName cname(){
return ClassName.get((TypeElement)BaseProcessor.typeu.asElement(mirror()));
}
public String name(){
return e.getSimpleName().toString();
}
@Override
public String toString(){
return e.toString();
}
@Override
public int hashCode(){
return e.hashCode();
}
@Override
public boolean equals(Object o){
return o != null && o.getClass() == getClass() && ((Selement)o).e.equals(e);
}
}

View File

@@ -0,0 +1,48 @@
package mindustry.annotations.util;
import arc.struct.*;
import com.squareup.javapoet.*;
import com.sun.source.tree.*;
import mindustry.annotations.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
public class Smethod extends Selement<ExecutableElement>{
public Smethod(ExecutableElement executableElement){
super(executableElement);
}
public boolean is(Modifier mod){
return e.getModifiers().contains(mod);
}
public Array<TypeMirror> thrown(){
return Array.with(e.getThrownTypes()).as(TypeMirror.class);
}
public Array<TypeName> thrownt(){
return Array.with(e.getThrownTypes()).map(TypeName::get);
}
public Array<TypeParameterElement> typeVariables(){
return Array.with(e.getTypeParameters()).as(TypeParameterElement.class);
}
public Array<Svar> params(){
return Array.with(e.getParameters()).map(Svar::new);
}
public TypeMirror ret(){
return e.getReturnType();
}
public TypeName retn(){
return TypeName.get(ret());
}
public MethodTree tree(){
return BaseProcessor.trees.getTree(e);
}
}

View File

@@ -0,0 +1,60 @@
package mindustry.annotations.util;
import arc.struct.*;
import mindustry.annotations.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import java.lang.annotation.*;
public class Stype extends Selement<TypeElement>{
public Stype(TypeElement typeElement){
super(typeElement);
}
public static Stype of(TypeMirror mirror){
return new Stype((TypeElement)BaseProcessor.typeu.asElement(mirror));
}
public Array<Stype> interfaces(){
return Array.with(e.getInterfaces()).map(Stype::of);
}
public Array<Stype> superclasses(){
Array<Stype> out = new Array<>();
Stype sup = superclass();
while(!sup.name().equals("Object")){
out.add(sup);
sup = sup.superclass();
}
return out;
}
public Stype superclass(){
return new Stype((TypeElement)BaseProcessor.typeu.asElement(BaseProcessor.typeu.directSupertypes(mirror()).get(0)));
}
public <A extends Annotation> A annotation(Class<A> annotation){
return e.getAnnotation(annotation);
}
public Array<Svar> fields(){
return Array.with(e.getEnclosedElements()).select(e -> e instanceof VariableElement).map(e -> new Svar((VariableElement)e));
}
public Array<Smethod> methods(){
return Array.with(e.getEnclosedElements()).select(e -> e instanceof ExecutableElement
&& !e.getSimpleName().toString().contains("<")).map(e -> new Smethod((ExecutableElement)e));
}
public Array<Smethod> constructors(){
return Array.with(e.getEnclosedElements()).select(e -> e instanceof ExecutableElement
&& e.getSimpleName().toString().contains("<")).map(e -> new Smethod((ExecutableElement)e));
}
@Override
public TypeMirror mirror(){
return e.asType();
}
}

View File

@@ -0,0 +1,21 @@
package mindustry.annotations.util;
import com.sun.source.tree.*;
import mindustry.annotations.*;
import javax.lang.model.element.*;
public class Svar extends Selement<VariableElement>{
public Svar(VariableElement e){
super(e);
}
public boolean is(Modifier mod){
return e.getModifiers().contains(mod);
}
public VariableTree tree(){
return (VariableTree)BaseProcessor.trees.getTree(e);
}
}

View File

@@ -1,5 +0,0 @@
mindustry.annotations.RemoteMethodAnnotationProcessor
mindustry.annotations.SerializeAnnotationProcessor
mindustry.annotations.StructAnnotationProcessor
mindustry.annotations.CallSuperAnnotationProcessor
mindustry.annotations.AssetsAnnotationProcessor

View File

@@ -132,6 +132,20 @@ allprojects{
props.store(pfile.newWriter(), "Autogenerated file. Do not modify.") props.store(pfile.newWriter(), "Autogenerated file. Do not modify.")
} }
} }
writeProcessors = {
new File(rootDir, "annotations/src/main/resources/META-INF/services/").mkdirs()
def processorFile = new File(rootDir, "annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor")
def text = new StringBuilder()
def files = new File(rootDir, "annotations/src/main/java")
files.eachFileRecurse(groovy.io.FileType.FILES){ file ->
if(file.name.endsWith(".java") && (file.text.contains(" extends BaseProcessor") || (file.text.contains(" extends AbstractProcessor") && !file.text.contains("abstract class")))){
text.append(file.path.substring(files.path.length() + 1)).append("\n")
}
}
processorFile.text = text.toString().replace(".java", "").replace("/", ".").replace("\\", ".")
}
} }
repositories{ repositories{
@@ -205,6 +219,7 @@ project(":core"){
outputs.upToDateWhen{ false } outputs.upToDateWhen{ false }
generateLocales() generateLocales()
writeVersion() writeVersion()
writeProcessors()
} }
task copyChangelog{ task copyChangelog{
@@ -229,31 +244,6 @@ project(":core"){
} }
dependencies{ dependencies{
if(System.properties["user.name"] == "anuke"){
task cleanGen{
doFirst{
delete{
delete "../core/src/mindustry/gen/"
}
}
}
task copyGen{
doLast{
copy{
from("../core/build/generated/sources/annotationProcessor/java/main/mindustry/gen"){
include "**/*.java"
}
into "../core/src/mindustry/gen"
}
}
}
compileJava.dependsOn(cleanGen)
compileJava.finalizedBy(copyGen)
}
compileJava.dependsOn(preGen) compileJava.dependsOn(preGen)
compile "org.lz4:lz4-java:1.4.1" compile "org.lz4:lz4-java:1.4.1"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 719 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 211 B

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