Skip to content

Commit

Permalink
Fix #7164: Optimize quartz fiber performance in deeply nested networks (
Browse files Browse the repository at this point in the history
#7258)

Co-authored-by: Sebastian Hartte <shartte@users.noreply.github.com>
  • Loading branch information
Technici4n and shartte committed Jul 15, 2023
1 parent c7403fd commit ad0c7f0
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 238 deletions.
116 changes: 0 additions & 116 deletions src/main/java/appeng/api/networking/energy/IEnergyGridProvider.java

This file was deleted.

12 changes: 2 additions & 10 deletions src/main/java/appeng/api/networking/energy/IEnergyService.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,11 @@ public interface IEnergyService extends IGridService, IEnergySource {
boolean isNetworkPowered();

/**
* AE will accept any power, and store it, to maintain sanity please don't send more then 10,000 at a time.
* <p>
* IMPORTANT: Network power knows no bounds, for less spamy power flow, networks can store more then their allotted
* storage, however, it should be kept to a minimum, to help with this, this method returns the networks current
* OVERFLOW, this is not energy you can store some where else, its already stored in the network, you can extract it
* if you want, however it it owned by the network, this is different then IAEEnergyStore
* <p>
* Another important note, is that if a network that had overflow is deleted, its power is gone, this is one of the
* reasons why keeping overflow to a minimum is important.
* Inject power in the network. Note that each network has some power storage even if there are no energy cells.
*
* @param amt power to inject into the network
* @param mode should the action be simulated or performed?
* @return the amount of power that the network has OVER the limit.
* @return the amount of power that the network could not accept
*/
double injectPower(double amt, Actionable mode);

Expand Down
50 changes: 50 additions & 0 deletions src/main/java/appeng/me/energy/IEnergyGridProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2013 AlgorithmX2
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package appeng.me.energy;

import java.util.Collection;

import appeng.api.networking.IGridNodeService;
import appeng.api.networking.energy.IEnergyService;
import appeng.me.service.EnergyService;

/**
* internal use only.
*/
public interface IEnergyGridProvider extends IGridNodeService {
/**
* internal use only
*
* Can return a list of providers behind the current.
*
* An example would be something acting as proxy between different {@link IEnergyService}s.
*
* This can contain duplicate entries, AE will ensure that each provider is only visited once.
*
* Call {@link EnergyService#invalidatePowerGraph()} if this changes.
*
* internal use only
*/
Collection<EnergyService> providers();
}
81 changes: 81 additions & 0 deletions src/main/java/appeng/me/service/EnergyOverlayGrid.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package appeng.me.service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;

import appeng.core.AELog;

/**
* This class caches all energy services that are part of the overlay energy grid. This overlay grid can span multiple
* normal {@linkplain appeng.me.Grid grids} if they are connected by {@link appeng.parts.networking.QuartzFiberPart
* quartz fibers}.
*/
class EnergyOverlayGrid {
/**
* Prefer grids with high energy storage for operations by sorting them to the front of the list.
*/
private static final Comparator<EnergyService> SERVICE_COMPARATOR = Comparator
.comparingDouble(EnergyService::getMaxStoredPower)
.reversed();

final List<EnergyService> energyServices;

private EnergyOverlayGrid(List<EnergyService> energyServices) {
this.energyServices = energyServices;
}

void invalidate() {
for (var service : energyServices) {
service.overlayGrid = null;
}
}

/**
* Build a new overlay energy grid by discovering all accessible {@linkplain EnergyService energy services} starting
* with the given grid.
*/
static void buildCache(EnergyService startingService) {
var connectedServices = new ReferenceOpenHashSet<EnergyService>();

// Walk graph
var services = new ObjectArrayList<EnergyService>();
services.add(startingService);

while (!services.isEmpty()) {
var service = services.pop();

// If the service was not already processed, add it and also discover other services
// reachable via its grid.
if (connectedServices.add(service)) {
for (var provider : service.providers()) {
for (var connectedService : provider.providers()) {
// Usually the provider will also provide the service we're just now visiting.
// Don't add it again to the open set.
if (connectedService != service) {
services.add(connectedService);
}
}
}
}
}

// Sort services by capacity
var sortedServices = new ArrayList<>(connectedServices);
sortedServices.sort(SERVICE_COMPARATOR);
var overlayGrid = new EnergyOverlayGrid(List.copyOf(sortedServices));

// Associate all grids that are part of the overlay grid with this instance
for (var service : sortedServices) {
// A previous overlay grid should have been invalidated before building a new one
if (service.overlayGrid != null) {
AELog.error("Grid %s energy service already has a power graph assigned to it!", service.grid);
}

service.overlayGrid = overlayGrid;
}
}
}

0 comments on commit ad0c7f0

Please sign in to comment.