NoCheatPlus/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/changetracker/BlockChangeReference.java

171 lines
6.7 KiB
Java

/*
* 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 fr.neatmonster.nocheatplus.compat.blocks.changetracker;
import fr.neatmonster.nocheatplus.compat.blocks.changetracker.BlockChangeTracker.BlockChangeEntry;
import fr.neatmonster.nocheatplus.utilities.location.RichBoundsLocation;
/**
* Simple class for helping with query functionality. Reference a
* BlockChangeEntry and contain more information, such as validity for further
* use/effects. This is meant for storing the state of last-consumed block
* change entries for a context within some data.
*
* @author asofold
*
*/
public class BlockChangeReference {
// TODO: IBlockChangeReference ?
/*
* TODO: public BlockChangeEntry firstUsedEntry = null; // Would the
* span suffice? Consider using span + timing or just the span during
* one check covering multiple blocks.
*/
/** First used (oldest) entry during checking. */
public BlockChangeEntry firstSpanEntry = null;
/** Last used (newest) entry during checking. */
public BlockChangeEntry lastSpanEntry = null;
/**
* Last used block change entry, set after a complete iteration of
* checking, update with updateFinal.
*/
public BlockChangeEntry lastUsedEntry = null;
// TODO: Consider to store the tick of when lastUsedEntry had been used, to allow invalidation.
/**
* Indicate if the timing of the last entry is still regarded as valid.
*/
public boolean valid = false;
/**
* Check if this reference can be updated with the given entry, considering
* set validity information. By default, the given tick either must be
* greater than the stored one, or the tick are the same and valid is set to
* true. The internal state is not changed by calling this.
*
* @param entry
* @return
*/
public boolean canUpdateWith(final BlockChangeEntry entry) {
// Formerly: return this.lastUsedEntry == null || entry.id > this.lastUsedEntry.id || entry.id == this.lastUsedEntry.id && valid;
// TODO: Consider: Allow the same tick if id is higher. (order of ids doesn't really help too much though)
// TODO: Consider: A tick-tolerance value [needs storing the tick of setting/altering].
// TODO: Consider keeping a map/set of used entries + allow reuse depending on context.
/*
* TODO: Alternative context def.: Hard invalidation via lastUsedEntry
* and soft invalidation via TBA span. E.g. hard for on ground and
* passable, soft for push/pull.
*/
// TODO: There'll be a span of validity, perhaps.
/*
* Using ticks seems more appropriate, as ids are not necessarily
* ordered in a relevant way, if they reference the same tick. Even
* one tick may be too narrow.
*/
// TODO: ONCE STUFF WORKS: reinstate invalidation and boil it down to something useful.
//return this.lastUsedEntry == null || entry.tick > this.lastUsedEntry.tick || entry.tick == this.lastUsedEntry.tick && valid;
return true; // TODO: TEST
}
/**
* Update the span during checking. Ensure to test canUpdateWith(entry)
* before calling this.
*
* @param entry
*/
public void updateSpan(final BlockChangeEntry entry) {
if (firstSpanEntry == null || entry.id < firstSpanEntry.id) {
firstSpanEntry = entry;
}
if (lastSpanEntry == null || entry.id > lastSpanEntry.id) {
lastSpanEntry = entry;
}
}
/**
* Update lastUsedEntry by the set span, assuming <i>to</i> to be the
* move end-point to continue from next time. This is meant to finalize
* prepared changes/span for use with the next move.
*
* @param to
* If not null, allows keeping the latest entry valid, if
* intersecting with the bounding box of <i>to</i>.
*/
public void updateFinal(final RichBoundsLocation to) {
if (firstSpanEntry == null) {
return;
}
// TODO: Consider a span margin, for which we set last used to first span.
/*
* TODO: What with latest entries, that stay valid until half round
* trip time? Should perhaps keep validity also if entries are the
* latest ones, needs updating in span already - can/should do
* without bounds?
*/
if (lastSpanEntry != null && (lastUsedEntry == null || lastSpanEntry.id > lastUsedEntry.id)) {
lastUsedEntry = lastSpanEntry;
if (to != null && to.isBlockIntersecting(
lastSpanEntry.x, lastSpanEntry.y, lastSpanEntry.z, lastSpanEntry.direction.blockFace)) {
valid = true;
}
else {
valid = false;
}
}
firstSpanEntry = lastSpanEntry = null;
}
/**
* Retrieve a shallow copy of this object.
*
* @return
*/
public BlockChangeReference copy() {
final BlockChangeReference copy = new BlockChangeReference();
copy.firstSpanEntry = this.firstSpanEntry;
copy.lastSpanEntry = this.lastSpanEntry;
copy.lastUsedEntry = this.lastUsedEntry;
copy.valid = this.valid;
return copy;
}
public void clear() {
firstSpanEntry = lastSpanEntry = lastUsedEntry = null;
valid = false;
}
@Override
public boolean equals(final Object obj) {
if (obj == null || !(obj instanceof BlockChangeReference)) {
return false;
}
final BlockChangeReference other = (BlockChangeReference) obj;
return valid == other.valid &&
(lastUsedEntry != null && lastUsedEntry.equals(other.lastUsedEntry)
|| lastUsedEntry == null && other.lastUsedEntry == null)
&& (firstSpanEntry != null && firstSpanEntry.equals(other.firstSpanEntry)
|| firstSpanEntry == null && other.firstSpanEntry == null)
&& (lastSpanEntry != null && lastSpanEntry.equals(other.lastSpanEntry)
|| lastSpanEntry == null && other.lastSpanEntry == null)
;
}
}