New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PhaseTracker 1.14 Upgrade #2476
Conversation
Signed-off-by: Gabriel Harris-Rouquette <gabizou@me.com>
…umenting the block physics process to re-re-re-re-re-rewrite the core of logging these changes. Signed-off-by: Gabriel Harris-Rouquette <gabizou@me.com>
…tarted WorldMixin and ServerWorldMixin. Signed-off-by: Gabriel Harris-Rouquette <gabizou@me.com>
src/main/java/org/spongepowered/common/event/tracking/PooledPhaseState.java
Outdated
Show resolved
Hide resolved
@SuppressWarnings("UnstableApiUsage") | ||
public class EventContextKeySupplier { | ||
|
||
public static Stream<EventContextKey<?>> stream() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Zidane if you can, please tell me this is the correct way of doing it for Sponge provided types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would go into the Stream package and be named like the other stream classes are.
src/main/java/org/spongepowered/common/event/tracking/PooledPhaseState.java
Outdated
Show resolved
Hide resolved
public SpongeSpawnType(CatalogKey key) { | ||
private boolean isForced = false; | ||
|
||
public SpongeSpawnType(CatalogKey key, String name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delete name parameter unless it is a NamedCatalogType.
} | ||
|
||
public SpongeEventContextKey(String id, String name, Class<T> allowed) { | ||
public SpongeEventContextKey(CatalogKey id, TypeToken<T> allowed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
id -> key
import java.util.Map; | ||
import java.util.StringJoiner; | ||
|
||
public final class BlockChangeFlagManager { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are not catalogs, correct?
final Map<String, Boolean> autoFixedTiles = trackerConfig.getAutoFixedTiles(); | ||
final boolean contained = autoFixedTiles.containsKey(type.getId()); | ||
final boolean contained = autoFixedTiles.containsKey(type.toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type.getKey().getFormatted()
} | ||
} catch (final Throwable throwable) { | ||
final CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Exception while updating neighbours"); | ||
final CrashReportCategory crashreportcategory = crashreport.makeCategory("Block being updated"); | ||
crashreportcategory.addDetail("Source block type", () -> { | ||
try { | ||
return String.format("ID #%d (%s // %s)", Block.getIdFromBlock(sourceBlock), | ||
return String.format("ID #%d (%s // %s)", Registry.BLOCK.getId(sourceBlock), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not pass back IDs to crash reports, pass their keys
* | ||
* @param pos The position of the block state to set | ||
* @param newState The new state | ||
* @param flag The notification flags | ||
* @return True if the block was successfully set (or captured) | ||
*/ | ||
@SuppressWarnings("rawtypes") | ||
public boolean setBlockState(final ServerWorldBridge mixinWorld, final BlockPos pos, final net.minecraft.block.BlockState newState, final BlockChangeFlag flag) { | ||
public boolean setBlockState(final ServerWorldBridge mixinWorld, final BlockPos pos, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mixinWorld -> worldBridge
} | ||
|
||
// Sponge Start - At this point, we can stop and check for captures. | ||
// Sponge Start - At this point, we can stop and check for captures; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.
@@ -1169,115 +857,21 @@ public boolean spawnEntityWithCause(final World world, final Entity entity) { | |||
* @return True if the entity spawn is on the main thread. | |||
*/ | |||
public static boolean isEntitySpawnInvalid(final Entity entity) { | |||
if (Sponge.isServerAvailable() && (Sponge.getServer().isMainThread() || SpongeImpl.getServer().isServerStopped())) { | |||
if (Sponge.isServerAvailable() && (Sponge.getServer().onMainThread() || SpongeImpl.getServer().isServerStopped())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use SpongeImpl method to collapse first two branches
@@ -84,25 +85,19 @@ | |||
import org.spongepowered.common.event.tracking.phase.tick.NeighborNotificationContext; | |||
import org.spongepowered.common.event.tracking.phase.tick.TickPhase; | |||
import org.spongepowered.common.mixin.accessor.world.server.ServerWorldAccessor; | |||
import org.spongepowered.common.registry.type.event.SpawnTypeRegistryModule; | |||
import org.spongepowered.common.registry.builtin.supplier.SpawnTypeSupplier; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not reference supplier classes in common code. Simply do SpawnTypes.BLAH.get()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't if the spawn type is an internal one. It's not exposed to the API for the reason that it's internal use only but still detectable for plugins to interpret for their own uses.
public static void tickEntity(final Consumer<net.minecraft.entity.Entity> consumer, final net.minecraft.entity.Entity entity) { | ||
checkArgument(entity instanceof Entity, "Entity %s is not an instance of SpongeAPI's Entity!", entity); | ||
checkNotNull(entity, "Cannot capture on a null ticking entity!"); | ||
final EntityBridge mixinEntity = (EntityBridge) entity; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mixinEntity -> entityBridge
import java.util.function.Supplier; | ||
import java.util.stream.Stream; | ||
|
||
public class SpawnTypeSupplier { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, stream package and named like the stream classes.
In all honesty, the supplier classes are simply for supplying Vanilla registry entries.
|
||
public class SpawnTypeSupplier { | ||
|
||
public static SpawnType FORCED = new SpongeSpawnType(CatalogKey.sponge("forced"), "Forced").forced(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason this is here? Why isn't this in the API?
Signed-off-by: Gabriel Harris-Rouquette <gabizou@me.com>
…n thread on server controlled worlds. Signed-off-by: Gabriel Harris-Rouquette <gabizou@me.com>
This leaves a lot to be desired currently as it's a WIP.
What's the update?
The
PhaseTracker
is essentially an adaptation of pairing server-focused changes occurring in aWorld
to anEvent
factory with specificCause
population based on the processing of aIPhaseState
. If that's enough to make you ask "huh??" then it might be recommended to read a little bit about Events and their causes. ThePhaseTracker
is a wedged implementation of loggingBlockState
,BlockEntity
,Entity
, andItemStack
changes within aWorld
during specific operations, such as:Entity
performing work during a Game tickPlayer
interacting with a blockBlock
"growing" into a differentBlock
etc.
Because of how intrinsically "wired" the system is to the engine, it needs hooks in various areas of the Game logic to say "hey, we're gonna be ticking an
Entity
here!" Currently, forstable-7
or Minecraft 1.12, it's doing this mostly well (sans some incompatibility with some mods and their design, no fault of theirs, just differences in how the system needs to be improved), but as it's shown, it's still very much tied to the game's core logic.Ok, so update the hooks then?
Of course! How could I be so blind! Just update the tens of thousands of lines that make the system... Ok, it's not really tens of thousands, it's closer to maybe 20k, but short of the hooks, the actual logic processes need to be reviewed and re-analyzed with caution since 1.14's block logic has changed enough that some parts of the system are needing to be re-engineered.
Core concepts of the Update
PhaseTracker per Thread
With the
PhaseTracker
being so integral to many systems in the game logic, and to support client sided effects and events, along with asynchronous world generation events, thePhaseTracker
is redesigned to have two primary instances (CLIENT
andSERVER
) while the purposedgetInstance()
will return aThread
appropriate variant. Because of this, we'll be able to appropriately associate individualPhaseTracker
s to pooledPhaseContext
s viaPooledPhaseState
. What this means is that the pools of recycled contexts will be per-thread, and furthermore be sanity checked to thePhaseTracker
instance that created them. Uniquely, this will sanity check closures ofPhaseContext
s to avoid asynchronous closures without knowing which thread originally entered said state.Splitting the
PhaseTracker
associated code from all Mixins into a separate packageThis is mostly an organizational effort to verify "who does what and why". When looking at WorldServerMixin, it's difficult to read as to what this method is doing and why, except that it's interacting with a "proxy" for some reason. This, on top of several scattered areas where we have
PhaseState
entries, it becomes difficult to see what sections of code are to support thePhaseTracker
, using thePhaseTracker
for context population, or simply using thePhaseTracker
for throwing events. Lastly, because testing of Sponge code without thePhaseTracker
involvement and possible bugs/side effects, there's no "switch" to flip, except by removing the main hooks and hoping nothing else breaks in the process of those missing hooks.Likewise, because the injections/redirects/etc. would now be in a separate Mixin bundle, we can too prefix those with
tracker$
to further identify what methods are coming from where.So here's a laundry list of things I need to have done for the update:
BlockTransaction
to keep track of neighbor "shape updates" being requested, etc.SpongeBlockProxy
to be a simplifiedIWorld
proxy so fewer mixins have to existIWorld
, the contracts for various block methods only actually require anIWorld
instance, allowing us to better track changes andTileEntity
additions.PhaseTracker
without disabling events being thrownBlockChangeFlag
API exposure, we have a bit we can expand on for better plugin control