Bugfixes / Tutorial cleanup

This commit is contained in:
Anuken 2020-11-21 15:50:44 -05:00
parent 96b55c6b1c
commit b09dc47aad
8 changed files with 110 additions and 80 deletions

View File

@ -591,7 +591,7 @@ sector.saltFlats.description = On the outskirts of the desert lie the Salt Flats
sector.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills. sector.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills.
sector.ruinousShores.description = Past the wastes, is the shoreline. Once, this location housed a coastal defense array. Not much of it remains. Only the most basic defense structures have remained unscathed, everything else reduced to scrap.\nContinue the expansion outwards. Rediscover the technology. sector.ruinousShores.description = Past the wastes, is the shoreline. Once, this location housed a coastal defense array. Not much of it remains. Only the most basic defense structures have remained unscathed, everything else reduced to scrap.\nContinue the expansion outwards. Rediscover the technology.
sector.stainedMountains.description = Further inland lie the mountains, yet untainted by spores.\nExtract the abundant titanium in this area. Learn how to use it.\n\nThe enemy presence is greater here. Do not give them time to send their strongest units. sector.stainedMountains.description = Further inland lie the mountains, yet untainted by spores.\nExtract the abundant titanium in this area. Learn how to use it.\n\nThe enemy presence is greater here. Do not give them time to send their strongest units.
sector.overgrowth.description = This area is overgrown, closer to the source of the spores.\nThe enemy has established an outpost here. Build Titan units. Destroy it. Reclaim that which was lost. sector.overgrowth.description = This area is overgrown, closer to the source of the spores.\nThe enemy has established an outpost here. Build Mace units. Destroy it.
sector.tarFields.description = The outskirts of an oil production zone, between the mountains and desert. One of the few areas with usable tar reserves.\nAlthough abandoned, this area has some dangerous enemy forces nearby. Do not underestimate them.\n\n[lightgray]Research oil processing technology if possible. sector.tarFields.description = The outskirts of an oil production zone, between the mountains and desert. One of the few areas with usable tar reserves.\nAlthough abandoned, this area has some dangerous enemy forces nearby. Do not underestimate them.\n\n[lightgray]Research oil processing technology if possible.
sector.desolateRift.description = An extremely dangerous zone. Plentiful resources, but little space. High risk of destruction. Leave as soon as possible. Do not be fooled by the long spacing between enemy attacks. sector.desolateRift.description = An extremely dangerous zone. Plentiful resources, but little space. High risk of destruction. Leave as soon as possible. Do not be fooled by the long spacing between enemy attacks.
sector.nuclearComplex.description = A former facility for the production and processing of thorium, reduced to ruins.\n[lightgray]Research the thorium and its many uses.\n\nThe enemy is present here in great numbers, constantly scouting for attackers. sector.nuclearComplex.description = A former facility for the production and processing of thorium, reduced to ruins.\n[lightgray]Research the thorium and its many uses.\n\nThe enemy is present here in great numbers, constantly scouting for attackers.
@ -1240,24 +1240,24 @@ team.purple.name = purple
hint.skip = Skip hint.skip = Skip
hint.desktopMove = Use [accent][[WASD][] to move. hint.desktopMove = Use [accent][[WASD][] to move.
hint.zoom = [accent]Scroll[] to zoom in or out. hint.zoom = [accent]Scroll[] to zoom in or out.
hint.mine = Move near the \uf8c4 copper ore and [accent]tap[] it to start mining. hint.mine = Move near the \uf8c4 copper ore and [accent]tap[] it to mine manually.
hint.desktopShoot = [accent][[Left-click][] to shoot. hint.desktopShoot = [accent][[Left-click][] to shoot.
hint.depositItems = To transfer items, drag from your ship to the core. hint.depositItems = To transfer items, drag from your ship to the core.
hint.respawn = To respawn as a ship, press [accent][[V][]. hint.respawn = To respawn as a ship, press [accent][[V][].
hint.respawn.mobile = You have switched control a unit/structure. To respawn as a ship, tap the avatar in the top left. hint.respawn.mobile = You have switched control a unit/structure. To respawn as a ship, [accent]tap the avatar in the top left.[]
hint.desktopPause = Press [accent][[Space][] to pause and unpause the game. hint.desktopPause = Press [accent][[Space][] to pause and unpause the game.
hint.placeDrill = Select the \ue85e [accent]Drill[] tab in the menu at the bottom right, then select a \uf870 [accent]Drill[] and click on a copper patch to place it. hint.placeDrill = Select the \ue85e [accent]Drill[] tab in the menu at the bottom right, then select a \uf870 [accent]Drill[] and click on a copper patch to place it.
hint.placeDrill.mobile = Select the \ue85e[accent]Drill[] tab in the menu at the bottom right, then select a \uf870 [accent]Drill[] and tap on a copper patch to place it.\n\nPress the [accent]checkmark[] at the bottom left to confirm. hint.placeDrill.mobile = Select the \ue85e[accent]Drill[] tab in the menu at the bottom right, then select a \uf870 [accent]Drill[] and tap on a copper patch to place it.\n\nPress the \ue800 [accent]checkmark[] at the bottom right to confirm.
hint.placeConveyor = Conveyors move items from drills into other blocks. Select a \uf896 [accent]Conveyor[] from the \ue814 [accent]Distribution[] tab.\n\nClick and drag to place multiple conveyors.\n[accent]Scroll[] to rotate. hint.placeConveyor = Conveyors move items from drills into other blocks. Select a \uf896 [accent]Conveyor[] from the \ue814 [accent]Distribution[] tab.\n\nClick and drag to place multiple conveyors.\n[accent]Scroll[] to rotate.
hint.placeConveyor.mobile = Conveyors move items from drills into other blocks. Select a \uf896 [accent]Conveyor[] from the \ue814 [accent]Distribution[] tab.\n\nHold down your finger for a second and drag to place multiple conveyors. hint.placeConveyor.mobile = Conveyors move items from drills into other blocks. Select a \uf896 [accent]Conveyor[] from the \ue814 [accent]Distribution[] tab.\n\nHold down your finger for a second and drag to place multiple conveyors.
hint.placeTurret = Place \uf861 [accent]Turrets[] to defend your base from enemies.\n\nTurrets require ammo - in this case, \uf838copper.\nUse conveyors and drills to supply them. hint.placeTurret = Place \uf861 [accent]Turrets[] to defend your base from enemies.\n\nTurrets require ammo - in this case, \uf838copper.\nUse conveyors and drills to supply them.
hint.breaking = [accent]Right-click[] and drag to break blocks. hint.breaking = [accent]Right-click[] and drag to break blocks.
hint.breaking.mobile = Activate the \ue817 hammer in the bottom left and tap to break blocks.\nHold down your finger for a second and drag to break in a selection. hint.breaking.mobile = Activate the \ue817 [accent]hammer[] in the bottom right and tap to break blocks.\n\nHold down your finger for a second and drag to break in a selection.
hint.research = Use the \ue875 [accent]Research[] button to research new technology. hint.research = Use the \ue875 [accent]Research[] button to research new technology.
hint.research.mobile = Use the \ue875 [accent]Research[] button in the \ue88c [accent]Menu[] to research new technology. hint.research.mobile = Use the \ue875 [accent]Research[] button in the \ue88c [accent]Menu[] to research new technology.
hint.unitControl = Hold [accent][[L-ctrl][] and [accent]click[] to control friendly units or turrets. hint.unitControl = Hold [accent][[L-ctrl][] and [accent]click[] to control friendly units or turrets.
hint.unitControl.mobile = [accent][Double-tap[] to control friendly units or turrets. hint.unitControl.mobile = [accent][Double-tap[] to control friendly units or turrets.
hint.launch = Once you collect enough resources, you can [accent]Launch[] by selecting nearby sectors from the \ue827 [accent]Map[] in the bottom left. hint.launch = Once you collect enough resources, you can [accent]Launch[] by selecting nearby sectors from the \ue827 [accent]Map[] in the bottom right.
hint.launch.mobile = Once you collect enough resources, you can [accent]Launch[] by selecting nearby sectors from the \ue827 [accent]Map[] in the \ue88c [accent]Menu[]. hint.launch.mobile = Once you collect enough resources, you can [accent]Launch[] by selecting nearby sectors from the \ue827 [accent]Map[] in the \ue88c [accent]Menu[].
tutorial.next = [lightgray]<Tap to continue> tutorial.next = [lightgray]<Tap to continue>

View File

@ -19,28 +19,28 @@ let modName = "none"
const print = text => log(modName + "/" + scriptName, text); const print = text => log(modName + "/" + scriptName, text);
// js 'extend(Base, ..., {})' = java 'new Base(...) {}' //js 'extend(Base, ..., {})' = java 'new Base(...) {}'
function extend(/*Base, ..., def*/) { function extend(/*Base, ..., def*/){
const Base = arguments[0]; const Base = arguments[0]
const def = arguments[arguments.length - 1]; const def = arguments[arguments.length - 1]
// swap order from Base, def, ... to Base, ..., def //swap order from Base, def, ... to Base, ..., def
const args = [Base, def].concat(Array.from(arguments).splice(1, arguments.length - 2)); const args = [Base, def].concat(Array.from(arguments).splice(1, arguments.length - 2))
// forward constructor arguments to new JavaAdapter //forward constructor arguments to new JavaAdapter
const instance = JavaAdapter.apply(null, args); const instance = JavaAdapter.apply(null, args)
// JavaAdapter only overrides functions; set fields too //JavaAdapter only overrides functions; set fields too
for (var i in def) { for(var i in def){
if (typeof(def[i]) != "function") { if(typeof(def[i]) != "function"){
instance[i] = def[i]; instance[i] = def[i]
} }
} }
return instance; return instance
} }
// For backwards compatibility, use extend instead //For backwards compatibility, use extend instead
const extendContent = extend; const extendContent = extend;
//these are not sctrictly necessary, but are kept for edge cases //these are not strictly necessary, but are kept for edge cases
const run = method => new java.lang.Runnable(){run: method} const run = method => new java.lang.Runnable(){run: method}
const boolf = method => new Boolf(){get: method} const boolf = method => new Boolf(){get: method}
const boolp = method => new Boolp(){get: method} const boolp = method => new Boolp(){get: method}

View File

@ -3,13 +3,13 @@
"use strict"; "use strict";
function log(context, obj){ function log(context, obj){
Vars.mods.getScripts().log(context, String(obj)) Vars.mods.scripts.log(context, String(obj))
} }
const readString = path => Vars.mods.getScripts().readString(path) const readString = path => Vars.mods.scripts.readString(path)
const readBytes = path => Vars.mods.getScripts().readBytes(path) const readBytes = path => Vars.mods.scripts.readBytes(path)
const loadMusic = path => Vars.mods.getScripts().loadMusic(path) const loadMusic = path => Vars.mods.scripts.loadMusic(path)
const loadSound = path => Vars.mods.getScripts().loadSound(path) const loadSound = path => Vars.mods.scripts.loadSound(path)
const readFile = (purpose, ext, cons) => Vars.mods.scripts.readFile(purpose, ext, cons); const readFile = (purpose, ext, cons) => Vars.mods.scripts.readFile(purpose, ext, cons);
const readBinFile = (purpose, ext, cons) => Vars.mods.scripts.readBinFile(purpose, ext, cons); const readBinFile = (purpose, ext, cons) => Vars.mods.scripts.readBinFile(purpose, ext, cons);
@ -21,28 +21,28 @@ let modName = "none"
const print = text => log(modName + "/" + scriptName, text); const print = text => log(modName + "/" + scriptName, text);
// js 'extend(Base, ..., {})' = java 'new Base(...) {}' //js 'extend(Base, ..., {})' = java 'new Base(...) {}'
function extend(/*Base, ..., def*/) { function extend(/*Base, ..., def*/){
const Base = arguments[0]; const Base = arguments[0]
const def = arguments[arguments.length - 1]; const def = arguments[arguments.length - 1]
// swap order from Base, def, ... to Base, ..., def //swap order from Base, def, ... to Base, ..., def
const args = [Base, def].concat(Array.from(arguments).splice(1, arguments.length - 2)); const args = [Base, def].concat(Array.from(arguments).splice(1, arguments.length - 2))
// forward constructor arguments to new JavaAdapter //forward constructor arguments to new JavaAdapter
const instance = JavaAdapter.apply(null, args); const instance = JavaAdapter.apply(null, args)
// JavaAdapter only overrides functions; set fields too //JavaAdapter only overrides functions; set fields too
for (var i in def) { for(var i in def){
if (typeof(def[i]) != "function") { if(typeof(def[i]) != "function"){
instance[i] = def[i]; instance[i] = def[i]
} }
} }
return instance; return instance
} }
// For backwards compatibility, use extend instead //For backwards compatibility, use extend instead
const extendContent = extend; const extendContent = extend;
//these are not sctrictly necessary, but are kept for edge cases //these are not strictly necessary, but are kept for edge cases
const run = method => new java.lang.Runnable(){run: method} const run = method => new java.lang.Runnable(){run: method}
const boolf = method => new Boolf(){get: method} const boolf = method => new Boolf(){get: method}
const boolp = method => new Boolp(){get: method} const boolp = method => new Boolp(){get: method}
@ -86,6 +86,7 @@ importPackage(Packages.mindustry.entities)
importPackage(Packages.mindustry.entities.abilities) importPackage(Packages.mindustry.entities.abilities)
importPackage(Packages.mindustry.entities.bullet) importPackage(Packages.mindustry.entities.bullet)
importPackage(Packages.mindustry.entities.comp) importPackage(Packages.mindustry.entities.comp)
importPackage(Packages.mindustry.entities.effect)
importPackage(Packages.mindustry.entities.units) importPackage(Packages.mindustry.entities.units)
importPackage(Packages.mindustry.game) importPackage(Packages.mindustry.game)
importPackage(Packages.mindustry.gen) importPackage(Packages.mindustry.gen)
@ -147,6 +148,8 @@ const UnlockEvent = Packages.mindustry.game.EventType.UnlockEvent
const StateChangeEvent = Packages.mindustry.game.EventType.StateChangeEvent const StateChangeEvent = Packages.mindustry.game.EventType.StateChangeEvent
const TileChangeEvent = Packages.mindustry.game.EventType.TileChangeEvent const TileChangeEvent = Packages.mindustry.game.EventType.TileChangeEvent
const GameOverEvent = Packages.mindustry.game.EventType.GameOverEvent const GameOverEvent = Packages.mindustry.game.EventType.GameOverEvent
const UnitControlEvent = Packages.mindustry.game.EventType.UnitControlEvent
const PickupEvent = Packages.mindustry.game.EventType.PickupEvent
const TapEvent = Packages.mindustry.game.EventType.TapEvent const TapEvent = Packages.mindustry.game.EventType.TapEvent
const ConfigEvent = Packages.mindustry.game.EventType.ConfigEvent const ConfigEvent = Packages.mindustry.game.EventType.ConfigEvent
const DepositEvent = Packages.mindustry.game.EventType.DepositEvent const DepositEvent = Packages.mindustry.game.EventType.DepositEvent
@ -155,6 +158,8 @@ const SectorCaptureEvent = Packages.mindustry.game.EventType.SectorCaptureEvent
const PlayerChatEvent = Packages.mindustry.game.EventType.PlayerChatEvent const PlayerChatEvent = Packages.mindustry.game.EventType.PlayerChatEvent
const ClientPreConnectEvent = Packages.mindustry.game.EventType.ClientPreConnectEvent const ClientPreConnectEvent = Packages.mindustry.game.EventType.ClientPreConnectEvent
const CommandIssueEvent = Packages.mindustry.game.EventType.CommandIssueEvent const CommandIssueEvent = Packages.mindustry.game.EventType.CommandIssueEvent
const SchematicCreateEvent = Packages.mindustry.game.EventType.SchematicCreateEvent
const SectorLaunchEvent = Packages.mindustry.game.EventType.SectorLaunchEvent
const LaunchItemEvent = Packages.mindustry.game.EventType.LaunchItemEvent const LaunchItemEvent = Packages.mindustry.game.EventType.LaunchItemEvent
const SectorInvasionEvent = Packages.mindustry.game.EventType.SectorInvasionEvent const SectorInvasionEvent = Packages.mindustry.game.EventType.SectorInvasionEvent
const SectorLoseEvent = Packages.mindustry.game.EventType.SectorLoseEvent const SectorLoseEvent = Packages.mindustry.game.EventType.SectorLoseEvent

View File

@ -1694,8 +1694,8 @@ public class UnitTypes implements ContentList{
bullet = new RailBulletType(){{ bullet = new RailBulletType(){{
shootEffect = Fx.railShoot; shootEffect = Fx.railShoot;
speed = 67f; length = 500;
lifetime = 8f; updateEffectSeg = 60f;
pierceEffect = Fx.railHit; pierceEffect = Fx.railHit;
updateEffect = Fx.railTrail; updateEffect = Fx.railTrail;
hitEffect = Fx.massiveExplosion; hitEffect = Fx.massiveExplosion;

View File

@ -25,6 +25,7 @@ public class Damage{
private static Rect rect = new Rect(); private static Rect rect = new Rect();
private static Rect hitrect = new Rect(); private static Rect hitrect = new Rect();
private static Vec2 tr = new Vec2(); private static Vec2 tr = new Vec2();
private static Seq<Unit> units = new Seq<>();
private static GridBits bits = new GridBits(30, 30); private static GridBits bits = new GridBits(30, 30);
private static IntQueue propagation = new IntQueue(); private static IntQueue propagation = new IntQueue();
private static IntSet collidedBlocks = new IntSet(); private static IntSet collidedBlocks = new IntSet();
@ -117,14 +118,16 @@ public class Damage{
Building tile = world.build(cx, cy); Building tile = world.build(cx, cy);
boolean collide = tile != null && collidedBlocks.add(tile.pos()); boolean collide = tile != null && collidedBlocks.add(tile.pos());
if(collide && tile.team != team && tile.collide(hitter)){ if(hitter.damage > 0){
tile.collision(hitter); if(collide && tile.team != team && tile.collide(hitter)){
hitter.type.hit(hitter, tile.x, tile.y); tile.collision(hitter);
} hitter.type.hit(hitter, tile.x, tile.y);
}
//try to heal the tile //try to heal the tile
if(collide && hitter.type.collides(hitter, tile)){ if(collide && hitter.type.collides(hitter, tile)){
hitter.type.hitTile(hitter, tile, 0f, false); hitter.type.hitTile(hitter, tile, tile.health, false);
}
} }
}; };
@ -161,20 +164,27 @@ public class Damage{
rect.height += expand * 2; rect.height += expand * 2;
Cons<Unit> cons = e -> { Cons<Unit> cons = e -> {
if(!e.checkTarget(hitter.type.collidesAir, hitter.type.collidesGround)) return;
e.hitbox(hitrect); e.hitbox(hitrect);
Vec2 vec = Geometry.raycastRect(x, y, x2, y2, hitrect.grow(expand * 2)); Vec2 vec = Geometry.raycastRect(x, y, x2, y2, hitrect.grow(expand * 2));
if(vec != null){ if(vec != null && hitter.damage > 0){
effect.at(vec.x, vec.y); effect.at(vec.x, vec.y);
e.collision(hitter, vec.x, vec.y); e.collision(hitter, vec.x, vec.y);
hitter.collision(e, vec.x, vec.y); hitter.collision(e, vec.x, vec.y);
} }
}; };
Units.nearbyEnemies(team, rect, cons); units.clear();
Units.nearbyEnemies(team, rect, u -> {
if(u.checkTarget(hitter.type.collidesAir, hitter.type.collidesGround)){
units.add(u);
}
});
units.sort(u -> u.dst2(hitter));
units.each(cons);
} }
/** /**

View File

@ -1,5 +1,7 @@
package mindustry.entities.bullet; package mindustry.entities.bullet;
import arc.math.geom.*;
import arc.util.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.gen.*; import mindustry.gen.*;
@ -15,36 +17,54 @@ public class RailBulletType extends BulletType{
/** Multiplier of damage decreased per health pierced. */ /** Multiplier of damage decreased per health pierced. */
public float pierceDamageFactor = 1f; public float pierceDamageFactor = 1f;
public float length = 100f;
public float updateEffectSeg = 20f;
public RailBulletType(){ public RailBulletType(){
pierceBuilding = true; pierceBuilding = true;
pierce = true; pierce = true;
reflectable = false; reflectable = false;
hitEffect = Fx.none; hitEffect = Fx.none;
despawnEffect = Fx.none; despawnEffect = Fx.none;
collides = false;
lifetime = 1f;
}
@Override
public float range(){
return length;
} }
void handle(Bullet b, Posc pos, float initialHealth){ void handle(Bullet b, Posc pos, float initialHealth){
float sub = initialHealth*pierceDamageFactor; float sub = initialHealth*pierceDamageFactor;
if(sub >= b.damage){ if(b.damage <= 0){
//cause a despawn b.fdata = Math.min(b.fdata, b.dst(pos));
b.remove(); return;
}
if(b.damage > 0){
pierceEffect.at(pos.getX(), pos.getY(), b.rotation());
hitEffect.at(pos.getX(), pos.getY());
} }
//subtract health from each consecutive pierce //subtract health from each consecutive pierce
b.damage -= Math.min(b.damage, sub); b.damage -= Math.min(b.damage, sub);
if(b.damage > 0){
pierceEffect.at(pos.getX(), pos.getY(), b.rotation());
}
hitEffect.at(pos.getX(), pos.getY());
} }
@Override @Override
public void update(Bullet b){ public void init(Bullet b){
if(b.timer(1, 0.9f)){ super.init(b);
updateEffect.at(b.x, b.y, b.rotation());
b.fdata = length;
Damage.collideLine(b, b.team, b.type.hitEffect, b.x, b.y, b.rotation(), length, false);
float resultLen = b.fdata;
Vec2 nor = Tmp.v1.set(b.vel).nor();
for(float i = 0; i <= resultLen; i += updateEffectSeg){
updateEffect.at(b.x + nor.x * i, b.y + nor.y * i, b.rotation());
} }
} }

View File

@ -698,19 +698,15 @@ public class HudFragment extends Fragment{
float bw = 40f; float bw = 40f;
float pad = -20; float pad = -20;
t.margin(0); t.margin(0);
t.clicked(() -> {
t.add(new SideBar(() -> player.unit().healthf(), () -> true, true)).width(bw).growY().padRight(pad); if(!player.dead() && mobile){
t.image(() -> player.icon()).scaling(Scaling.bounded).grow().maxWidth(54f).with(i -> { Call.unitClear(player);
if(mobile){ control.input.controlledType = null;
//on mobile, cause a respawn on tap
i.clicked(() -> {
if(!player.unit().spawnedByCore && !player.dead()){
Call.unitClear(player);
control.input.controlledType = null;
}
});
} }
}); });
t.add(new SideBar(() -> player.unit().healthf(), () -> true, true)).width(bw).growY().padRight(pad);
t.image(() -> player.icon()).scaling(Scaling.bounded).grow().maxWidth(54f);
t.add(new SideBar(() -> player.dead() ? 0f : player.displayAmmo() ? player.unit().ammof() : player.unit().healthf(), () -> !player.displayAmmo(), false)).width(bw).growY().padLeft(pad).update(b -> { t.add(new SideBar(() -> player.dead() ? 0f : player.displayAmmo() ? player.unit().ammof() : player.unit().healthf(), () -> !player.displayAmmo(), false)).width(bw).growY().padLeft(pad).update(b -> {
b.color.set(player.displayAmmo() ? player.dead() || player.unit() instanceof BlockUnitc ? Pal.ammo : player.unit().type.ammoType.color : Pal.health); b.color.set(player.displayAmmo() ? player.dead() || player.unit() instanceof BlockUnitc ? Pal.ammo : player.unit().type.ammoType.color : Pal.health);
}); });
@ -760,8 +756,6 @@ public class HudFragment extends Fragment{
return builder; return builder;
}).growX().pad(8f); }).growX().pad(8f);
table.touchable(() -> state.rules.waves ? Touchable.enabled : Touchable.disabled);
return table; return table;
} }

View File

@ -37,7 +37,8 @@ public class ScriptMainGenerator{
getClasses("arc.func"), getClasses("arc.func"),
getClasses("arc.struct"), getClasses("arc.struct"),
getClasses("arc.scene"), getClasses("arc.scene"),
getClasses("arc.math") getClasses("arc.math"),
getClasses("arc.audio")
); );
classes.addAll(whitelist); classes.addAll(whitelist);
classes.sort(Structs.comparing(Class::getName)); classes.sort(Structs.comparing(Class::getName));