rewrote F3 HUD with new Information system

This commit is contained in:
FlorianMichael 2023-03-15 17:07:17 +01:00
parent ec312148db
commit 10754a59cd
12 changed files with 459 additions and 32 deletions

View File

@ -26,6 +26,7 @@ import de.florianmichael.viafabricplus.definition.c0_30.command.ClassicProtocolC
import de.florianmichael.viafabricplus.definition.v1_8_x.ArmorPointsDefinition;
import de.florianmichael.viafabricplus.event.FinishMinecraftLoadCallback;
import de.florianmichael.viafabricplus.event.PreLoadCallback;
import de.florianmichael.viafabricplus.information.InformationSystem;
import de.florianmichael.viafabricplus.settings.SettingsSystem;
import de.florianmichael.viafabricplus.vialoadingbase.ViaLoadingBaseStartup;
@ -36,10 +37,12 @@ public class ViaFabricPlus {
public final static ViaFabricPlus INSTANCE = new ViaFabricPlus();
private final SettingsSystem settingsSystem = new SettingsSystem();
private final InformationSystem informationSystem = new InformationSystem();
public void init() {
FinishMinecraftLoadCallback.EVENT.register(() -> {
settingsSystem.init();
informationSystem.init();
// General definitions
PackFormatsDefinition.load();
@ -60,4 +63,8 @@ public class ViaFabricPlus {
public SettingsSystem getSettingsSystem() {
return settingsSystem;
}
public InformationSystem getInformationSystem() {
return informationSystem;
}
}

View File

@ -0,0 +1,37 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/MrLookAtMe (EnZaXD) and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.information;
import com.viaversion.viaversion.api.connection.UserConnection;
import de.florianmichael.vialoadingbase.platform.ProtocolRange;
import java.util.List;
public abstract class AbstractInformationGroup {
private final ProtocolRange protocolRange;
public AbstractInformationGroup(final ProtocolRange protocolRange) {
this.protocolRange = protocolRange;
}
public abstract void applyInformation(final UserConnection userConnection, final List<String> output);
public ProtocolRange getProtocolRange() {
return protocolRange;
}
}

View File

@ -0,0 +1,51 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/MrLookAtMe (EnZaXD) and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.information;
import de.florianmichael.viafabricplus.information.impl.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class InformationSystem {
private final List<AbstractInformationGroup> groups = new ArrayList<>();
public void init() {
addGroup(
new GeneralInformation(),
new BedrockInformation(),
new V1_7_10Information(),
new V1_5_2Information(),
new V1_2_4_5Information(),
new V1_1Information(),
new C0_30CPEInformation()
);
}
public void addGroup(final AbstractInformationGroup... groups) {
Collections.addAll(this.groups, groups);
}
public List<AbstractInformationGroup> getGroups() {
return groups;
}
}

View File

@ -0,0 +1,84 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/MrLookAtMe (EnZaXD) and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.information.impl;
import com.viaversion.viaversion.api.connection.UserConnection;
import de.florianmichael.viafabricplus.information.AbstractInformationGroup;
import de.florianmichael.viafabricplus.util.ScreenUtil;
import de.florianmichael.vialoadingbase.platform.ProtocolRange;
import net.lenni0451.reflect.stream.RStream;
import net.lenni0451.reflect.stream.field.FieldStream;
import net.raphimc.viabedrock.api.BedrockProtocolVersion;
import net.raphimc.viabedrock.api.chunk.BedrockChunk;
import net.raphimc.viabedrock.api.model.entity.Entity;
import net.raphimc.viabedrock.protocol.storage.BlobCache;
import net.raphimc.viabedrock.protocol.storage.ChunkTracker;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class BedrockInformation extends AbstractInformationGroup {
public BedrockInformation() {
super(ProtocolRange.singleton(BedrockProtocolVersion.bedrockLatest));
}
@Override
public void applyInformation(UserConnection userConnection, List<String> output) {
final BlobCache blobCache = userConnection.get(BlobCache.class);
if (blobCache != null) {
final long totalSize = blobCache.getTotalSize();
final int blobCount = blobCache.getBlobCount();
final int pendingCount = blobCache.getPendingCount();
if (totalSize != 0 || blobCount != 0 || pendingCount != 0) {
output.add("Blob Cache:");
}
if (totalSize != 0) output.add("Total size: " + ScreenUtil.formatBytes(totalSize));
if (blobCount != 0) output.add("Blob count: " + blobCount);
if (pendingCount != 0) output.add("Pending count: " + pendingCount);
}
final ChunkTracker chunkTracker = userConnection.get(ChunkTracker.class);
if (chunkTracker != null) {
final FieldStream fields = RStream.of(chunkTracker).fields();
final int subChunkRequests = fields.by("subChunkRequests").<Set<Object>>get().size();
final int pendingSubChunks = fields.by("pendingSubChunks").<Set<Object>>get().size();
final int chunks = fields.by("chunks").<Map<Long, BedrockChunk>>get().size();
if (subChunkRequests != 0 || pendingSubChunks != 0 || chunks != 0) {
if (!output.isEmpty()) output.add("");
output.add("Chunk Tracker:");
}
if (subChunkRequests != 0) output.add("Sub-chunk requests: " + subChunkRequests);
if (pendingSubChunks != 0) output.add("Pending Sub-chunks: " + pendingSubChunks);
if (chunks != 0) output.add("Chunks: " + chunks);
}
final net.raphimc.viabedrock.protocol.storage.EntityTracker entityTracker = userConnection.get(net.raphimc.viabedrock.protocol.storage.EntityTracker.class);
if (entityTracker != null) {
if (!output.isEmpty()) output.add("");
final int entities = RStream.of(entityTracker).fields().by("entities").<Map<Long, Entity>>get().size();
if (entities != 0) {
output.add("Entity Tracker: " + entities);
}
}
}
}

View File

@ -0,0 +1,38 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/MrLookAtMe (EnZaXD) and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.information.impl;
import com.viaversion.viaversion.api.connection.UserConnection;
import de.florianmichael.viafabricplus.information.AbstractInformationGroup;
import de.florianmichael.vialoadingbase.platform.ProtocolRange;
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
import net.raphimc.vialegacy.protocols.classic.protocolc0_28_30toc0_28_30cpe.storage.ExtensionProtocolMetadataStorage;
import java.util.List;
public class C0_30CPEInformation extends AbstractInformationGroup {
public C0_30CPEInformation() {
super(ProtocolRange.singleton(LegacyProtocolVersion.c0_30cpe));
}
@Override
public void applyInformation(UserConnection userConnection, List<String> output) {
if (userConnection.has(ExtensionProtocolMetadataStorage.class)) output.add("Classic extensions: " + userConnection.get(ExtensionProtocolMetadataStorage.class).getExtensionCount());
}
}

View File

@ -0,0 +1,37 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/MrLookAtMe (EnZaXD) and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.information.impl;
import com.viaversion.viaversion.api.connection.UserConnection;
import de.florianmichael.viafabricplus.information.AbstractInformationGroup;
import de.florianmichael.vialoadingbase.ViaLoadingBase;
import java.util.List;
public class GeneralInformation extends AbstractInformationGroup {
public GeneralInformation() {
super(null);
}
@Override
public void applyInformation(UserConnection userConnection, List<String> output) {
output.add("Pipeline count: " + userConnection.getProtocolInfo().getPipeline().pipes().size());
output.add("Target version: " + ViaLoadingBase.getClassWrapper().getTargetVersion().getName() + " (" + ViaLoadingBase.getClassWrapper().getTargetVersion().getVersion() + ")");
}
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/MrLookAtMe (EnZaXD) and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.information.impl;
import com.viaversion.viaversion.api.connection.UserConnection;
import de.florianmichael.viafabricplus.information.AbstractInformationGroup;
import de.florianmichael.vialoadingbase.platform.ProtocolRange;
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
import net.raphimc.vialegacy.protocols.release.protocol1_2_1_3to1_1.storage.SeedStorage;
import java.util.List;
public class V1_1Information extends AbstractInformationGroup {
public V1_1Information() {
super(ProtocolRange.andOlder(LegacyProtocolVersion.r1_1));
}
@Override
public void applyInformation(UserConnection userConnection, List<String> output) {
if (userConnection.has(SeedStorage.class)) {
final long seed = userConnection.get(SeedStorage.class).seed;
if (seed != 0) output.add("World Seed: " + seed);
}
}
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/MrLookAtMe (EnZaXD) and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.information.impl;
import com.viaversion.viaversion.api.connection.UserConnection;
import de.florianmichael.viafabricplus.information.AbstractInformationGroup;
import de.florianmichael.vialoadingbase.platform.ProtocolRange;
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
import net.raphimc.vialegacy.protocols.release.protocol1_3_1_2to1_2_4_5.storage.EntityTracker;
import java.util.List;
public class V1_2_4_5Information extends AbstractInformationGroup {
public V1_2_4_5Information() {
super(ProtocolRange.andOlder(LegacyProtocolVersion.r1_2_4tor1_2_5));
}
@Override
public void applyInformation(UserConnection userConnection, List<String> output) {
if (userConnection.has(EntityTracker.class)) {
final int entities = userConnection.get(EntityTracker.class).getTrackedEntities().size();
if (entities != 0) output.add("Entity Tracker: " + entities);
}
}
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/MrLookAtMe (EnZaXD) and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.information.impl;
import com.viaversion.viaversion.api.connection.UserConnection;
import de.florianmichael.viafabricplus.information.AbstractInformationGroup;
import de.florianmichael.vialoadingbase.platform.ProtocolRange;
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
import net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.storage.EntityTracker;
import java.util.List;
public class V1_5_2Information extends AbstractInformationGroup {
public V1_5_2Information() {
super(ProtocolRange.andOlder(LegacyProtocolVersion.r1_5_2));
}
@Override
public void applyInformation(UserConnection userConnection, List<String> output) {
if (userConnection.has(net.raphimc.vialegacy.protocols.release.protocol1_3_1_2to1_2_4_5.storage.EntityTracker.class)) {
final int entities = userConnection.get(EntityTracker.class).getTrackedEntities().size();
if (entities != 0) output.add("Entity Tracker: " + entities);
}
}
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/MrLookAtMe (EnZaXD) and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.information.impl;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.florianmichael.viafabricplus.information.AbstractInformationGroup;
import de.florianmichael.vialoadingbase.platform.ProtocolRange;
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.storage.EntityTracker;
import java.util.List;
public class V1_7_10Information extends AbstractInformationGroup {
public V1_7_10Information() {
super(ProtocolRange.andOlder(ProtocolVersion.v1_7_6));
}
@Override
public void applyInformation(UserConnection userConnection, List<String> output) {
if (userConnection.has(net.raphimc.vialegacy.protocols.release.protocol1_3_1_2to1_2_4_5.storage.EntityTracker.class)) {
final int entities = userConnection.get(EntityTracker.class).getTrackedEntities().size();
if (entities != 0) output.add("Entity Tracker: " + entities);
}
}
}

View File

@ -20,12 +20,21 @@ package de.florianmichael.viafabricplus.injection.mixin.bridge;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.florianmichael.viafabricplus.ViaFabricPlus;
import de.florianmichael.viafabricplus.information.AbstractInformationGroup;
import de.florianmichael.viafabricplus.settings.groups.BridgeSettings;
import de.florianmichael.viafabricplus.util.ScreenUtil;
import de.florianmichael.viafabricplus.vialoadingbase.ViaLoadingBaseStartup;
import de.florianmichael.vialoadingbase.ViaLoadingBase;
import net.lenni0451.reflect.stream.RStream;
import net.lenni0451.reflect.stream.field.FieldStream;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.hud.DebugHud;
import net.raphimc.viabedrock.api.BedrockProtocolVersion;
import net.raphimc.viabedrock.api.chunk.BedrockChunk;
import net.raphimc.viabedrock.api.model.entity.Entity;
import net.raphimc.viabedrock.protocol.BedrockProtocol;
import net.raphimc.viabedrock.protocol.storage.BlobCache;
import net.raphimc.viabedrock.protocol.storage.ChunkTracker;
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
import net.raphimc.vialegacy.protocols.classic.protocolc0_28_30toc0_28_30cpe.storage.ExtensionProtocolMetadataStorage;
import net.raphimc.vialegacy.protocols.release.protocol1_2_1_3to1_1.storage.SeedStorage;
@ -37,6 +46,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Mixin(DebugHud.class)
public class MixinDebugHud {
@ -49,40 +60,19 @@ public class MixinDebugHud {
if (MinecraftClient.getInstance().getNetworkHandler() != null) {
final UserConnection userConnection = MinecraftClient.getInstance().getNetworkHandler().getConnection().channel.attr(ViaLoadingBaseStartup.LOCAL_VIA_CONNECTION).get();
information.add("Pipeline count: " + userConnection.getProtocolInfo().getPipeline().pipes().size());
information.add("Target version: " + ViaLoadingBase.getClassWrapper().getTargetVersion().getName() + " (" + ViaLoadingBase.getClassWrapper().getTargetVersion().getVersion() + ")");
information.add("");
information.add(ScreenUtil.prefixedMessage("").trim());
if (ViaLoadingBase.getClassWrapper().getTargetVersion().isOlderThanOrEqualTo(ProtocolVersion.v1_7_6)) {
final EntityTracker entityTracker1_7_10 = userConnection.get(EntityTracker.class);
if (entityTracker1_7_10 != null) {
information.add("Entity Tracker (" + ProtocolVersion.v1_7_6.getName() + "): " + entityTracker1_7_10.getTrackedEntities().size());
}
if (ViaLoadingBase.getClassWrapper().getTargetVersion().isOlderThanOrEqualTo(LegacyProtocolVersion.r1_5_2)) {
final net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.storage.EntityTracker entityTracker1_5_2 = userConnection.get(net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.storage.EntityTracker.class);
if (entityTracker1_5_2 != null) {
information.add("Entity Tracker (" + LegacyProtocolVersion.r1_5_2.getName() + "): " + entityTracker1_5_2.getTrackedEntities().size());
}
if (ViaLoadingBase.getClassWrapper().getTargetVersion().isOlderThanOrEqualTo(LegacyProtocolVersion.r1_2_4tor1_2_5)) {
final net.raphimc.vialegacy.protocols.release.protocol1_3_1_2to1_2_4_5.storage.EntityTracker entityTracker1_2_4_5 = userConnection.get(net.raphimc.vialegacy.protocols.release.protocol1_3_1_2to1_2_4_5.storage.EntityTracker.class);
if (entityTracker1_2_4_5 != null) {
information.add("Entity Tracker (" + LegacyProtocolVersion.r1_2_4tor1_2_5.getName() + "): " + entityTracker1_2_4_5.getTrackedEntities().size());
}
if (ViaLoadingBase.getClassWrapper().getTargetVersion().isOlderThanOrEqualTo(LegacyProtocolVersion.r1_1)) {
final SeedStorage seedStorage = userConnection.get(SeedStorage.class);
if (seedStorage != null) {
information.add("World Seed (" + LegacyProtocolVersion.r1_1.getName() + "): " + seedStorage.seed);
}
if (ViaLoadingBase.getClassWrapper().getTargetVersion().isEqualTo(LegacyProtocolVersion.c0_30cpe)) {
final ExtensionProtocolMetadataStorage extensionProtocolMetadataStorage = userConnection.get(ExtensionProtocolMetadataStorage.class);
if (extensionProtocolMetadataStorage != null) {
information.add("Classic extensions (" + LegacyProtocolVersion.c0_30cpe.getName() + "): " + extensionProtocolMetadataStorage.getExtensionCount());
}
}
}
}
}
for (AbstractInformationGroup group : ViaFabricPlus.INSTANCE.getInformationSystem().getGroups()) {
final List<String> groupInformation = new ArrayList<>();
group.applyInformation(userConnection, groupInformation);
if (groupInformation.isEmpty()) continue;
information.add(group.getProtocolRange() == null ? "General" : group.getProtocolRange().toString());
information.addAll(groupInformation);
information.add("");
}
}
cir.getReturnValue().addAll(information.stream().map(ScreenUtil::prefixedMessage).toList());
cir.getReturnValue().addAll(information);
}
}

View File

@ -31,4 +31,23 @@ public class ScreenUtil {
public static String prefixedMessage(final String message) {
return Formatting.GOLD + "[ViaFabricPlus] " + Formatting.WHITE + message;
}
public static String format(double a) {
return String.format("%.2f", a);
}
public static String formatBytes(long value) {
final double bytes = value;
if (value < 1024L)
return value + " B";
else if (value < 1024L * 1024L)
return format((bytes / 1024.0)) + " Kb";
else if (value < 1024L * 1024L * 1024L)
return format((bytes / 1024.0 / 1024.0)) + " Mb";
else if (value < 1024L * 1024L * 1024L * 1024L)
return format((bytes / 1024.0 / 1024.0 / 1024.0)) + " Gb";
else
return format((bytes / 1024.0 / 1024.0 / 1024.0 / 1024.0)) + " Tb";
}
}