Merge pull request #508 from Talia-12/1.20.1

pulling in more bug fixes, Falkory's new textures, and Cypher's EnvironmentExtensions
This commit is contained in:
petrak@ 2023-08-06 11:00:11 -04:00 committed by GitHub
commit 7bebb94fcb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 232 additions and 70 deletions

View file

@ -16,22 +16,59 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;
import static at.petrak.hexcasting.api.HexAPI.modLoc;
import static at.petrak.hexcasting.api.casting.eval.CastingEnvironmentComponent.*;
/**
* Environment within which hexes are cast.
* <p>
* Stuff like "the player with a staff," "the player with a trinket," "spell circles,"
*/
public abstract class CastingEnvironment {
/**
* Stores all listeners that should be notified whenever a CastingEnvironment is initialised.
*/
private static final List<Consumer<CastingEnvironment>> createEventListeners = new ArrayList<>();
/**
* Add a listener that will be called whenever a new CastingEnvironment is created.
*/
public static void addCreateEventListener(Consumer<CastingEnvironment> listener) {
createEventListeners.add(listener);
}
private boolean createEventTriggered = false;
public final void triggerCreateEvent() {
if (!createEventTriggered) {
for (var listener : createEventListeners)
listener.accept(this);
createEventTriggered = true;
}
}
protected final ServerLevel world;
protected Map<CastingEnvironmentComponent.Key<?>, @NotNull CastingEnvironmentComponent> componentMap = new HashMap<>();
private final List<PostExecution> postExecutions = new ArrayList<>();
private final List<ExtractMedia> extractMedias = new ArrayList<>();
private final List<IsVecInRange> isVecInRanges = new ArrayList<>();
private final List<HasEditPermissionsAt> hasEditPermissionsAts = new ArrayList<>();
protected CastingEnvironment(ServerLevel world) {
this.world = world;
}
@ -54,6 +91,39 @@ public abstract class CastingEnvironment {
*/
public abstract MishapEnvironment getMishapEnvironment();
public <T extends CastingEnvironmentComponent> void addExtension(@NotNull T extension) {
componentMap.put(extension.getKey(), extension);
if (extension instanceof PostExecution postExecution)
postExecutions.add(postExecution);
if (extension instanceof ExtractMedia extractMedia)
extractMedias.add(extractMedia);
if (extension instanceof IsVecInRange isVecInRange)
isVecInRanges.add(isVecInRange);
if (extension instanceof HasEditPermissionsAt hasEditPermissionsAt)
hasEditPermissionsAts.add(hasEditPermissionsAt);
}
public void removeExtension(@NotNull CastingEnvironmentComponent.Key<?> key) {
var extension = componentMap.remove(key);
if (extension == null)
return;
if (extension instanceof PostExecution postExecution)
postExecutions.remove(postExecution);
if (extension instanceof ExtractMedia extractMedia)
extractMedias.remove(extractMedia);
if (extension instanceof IsVecInRange isVecInRange)
isVecInRanges.remove(isVecInRange);
if (extension instanceof HasEditPermissionsAt hasEditPermissionsAt)
hasEditPermissionsAts.remove(hasEditPermissionsAt);
}
@Nullable
@SuppressWarnings("unchecked")
public <T extends CastingEnvironmentComponent> T getExtension(@NotNull CastingEnvironmentComponent.Key<T> key) {
return (T) componentMap.get(key);
}
/**
* If something about this ARE itself is invalid, mishap.
* <p>
@ -87,7 +157,10 @@ public abstract class CastingEnvironment {
/**
* Do whatever you like after a pattern is executed.
*/
public abstract void postExecution(CastResult result);
public void postExecution(CastResult result) {
for (var postExecutionComponent : postExecutions)
postExecutionComponent.onPostExecution(result);
}
public abstract Vec3 mishapSprayPos();
@ -95,7 +168,15 @@ public abstract class CastingEnvironment {
* Return whether this env can cast great spells.
*/
public boolean isEnlightened() {
return false;
var caster = this.getCaster();
if (caster == null)
return false;
var adv = this.world.getServer().getAdvancements().getAdvancement(modLoc("enlightenment"));
if (adv == null)
return false;
return caster.getAdvancements().getOrStartProgress(adv).isDone();
}
/**
@ -104,19 +185,53 @@ public abstract class CastingEnvironment {
* If there was enough media found, it will return less or equal to zero; if there wasn't, it will be
* positive.
*/
public abstract long extractMedia(long cost);
public long extractMedia(long cost) {
for (var extractMediaComponent : extractMedias)
cost = extractMediaComponent.onExtractMedia(cost);
return extractMediaEnvironment(cost);
}
/**
* Attempt to extract the given amount of media. Returns the amount of media left in the cost.
* <p>
* If there was enough media found, it will return less or equal to zero; if there wasn't, it will be
* positive.
*/
protected abstract long extractMediaEnvironment(long cost);
/**
* Get if the vec is close enough, to the player or sentinel ...
* <p>
* Doesn't take into account being out of the <em>world</em>.
*/
public abstract boolean isVecInRange(Vec3 vec);
public boolean isVecInRange(Vec3 vec) {
boolean isInRange = isVecInRangeEnvironment(vec);
for (var isVecInRangeComponent : isVecInRanges)
isInRange = isVecInRangeComponent.onIsVecInRange(vec, isInRange);
return isInRange;
}
/**
* Get if the vec is close enough, to the player or sentinel ...
* <p>
* Doesn't take into account being out of the <em>world</em>.
*/
protected abstract boolean isVecInRangeEnvironment(Vec3 vec);
/**
* Return whether the caster can edit blocks at the given permission (i.e. not adventure mode, etc.)
*/
public abstract boolean hasEditPermissionsAt(BlockPos vec);
public boolean hasEditPermissionsAt(BlockPos pos) {
boolean hasEditPermissionsAt = hasEditPermissionsAtEnvironment(pos);
for (var hasEditPermissionsAtComponent : hasEditPermissionsAts)
hasEditPermissionsAt = hasEditPermissionsAtComponent.onHasEditPermissionsAt(pos, hasEditPermissionsAt);
return hasEditPermissionsAt;
}
/**
* Return whether the caster can edit blocks at the given permission (i.e. not adventure mode, etc.)
*/
protected abstract boolean hasEditPermissionsAtEnvironment(BlockPos pos);
public final boolean isVecInWorld(Vec3 vec) {
return this.world.isInWorldBounds(BlockPos.containing(vec))
@ -128,7 +243,7 @@ public abstract class CastingEnvironment {
}
public final boolean isEntityInRange(Entity e) {
return this.isVecInRange(e.position());
return e instanceof Player || this.isVecInRange(e.position());
}
/**

View file

@ -0,0 +1,41 @@
package at.petrak.hexcasting.api.casting.eval;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.Vec3;
public interface CastingEnvironmentComponent {
Key<?> getKey();
interface Key<C extends CastingEnvironmentComponent> {}
interface PostExecution extends CastingEnvironmentComponent {
/**
* Do whatever you like after a pattern is executed.
*/
void onPostExecution(CastResult result);
}
interface ExtractMedia extends CastingEnvironmentComponent {
/**
* Receives the cost that is being extracted, should return the
* remaining cost after deducting whatever cost source this component
* is responsible for (should be >= 0). All Components are executed
* before the CastingEnvironment's extractMedia is executed.
*/
long onExtractMedia(long cost);
}
interface IsVecInRange extends CastingEnvironmentComponent {
/**
* Receives the vec, and the current return value, and returns the new return value.
*/
boolean onIsVecInRange(Vec3 vec, boolean current);
}
interface HasEditPermissionsAt extends CastingEnvironmentComponent {
/**
* Receives the vec, and the current return value, and returns the new return value.
*/
boolean onHasEditPermissionsAt(BlockPos pos, boolean current);
}
}

View file

@ -73,6 +73,8 @@ public class CircleCastEnv extends CastingEnvironment {
@Override
public void postExecution(CastResult result) {
super.postExecution(result);
// we always want to play this sound one at a time
var sound = result.getSound().sound();
if (sound != null) {
@ -103,7 +105,7 @@ public class CircleCastEnv extends CastingEnvironment {
}
@Override
public long extractMedia(long cost) {
public long extractMediaEnvironment(long cost) {
var entity = this.getImpetus();
if (entity == null)
return cost;
@ -120,7 +122,7 @@ public class CircleCastEnv extends CastingEnvironment {
}
@Override
public boolean isVecInRange(Vec3 vec) {
public boolean isVecInRangeEnvironment(Vec3 vec) {
var caster = this.execState.getCaster(this.world);
if (caster != null) {
var sentinel = HexAPI.instance().getSentinel(caster);
@ -137,7 +139,7 @@ public class CircleCastEnv extends CastingEnvironment {
}
@Override
public boolean hasEditPermissionsAt(BlockPos vec) {
public boolean hasEditPermissionsAtEnvironment(BlockPos pos) {
return true;
}

View file

@ -37,12 +37,14 @@ public class PackagedItemCastEnv extends PlayerBasedCastEnv {
}
@Override
public long extractMedia(long costLeft) {
public long extractMediaEnvironment(long costLeft) {
if (this.caster.isCreative())
return 0;
var casterStack = this.caster.getItemInHand(this.castingHand);
var casterHexHolder = IXplatAbstractions.INSTANCE.findHexHolder(casterStack);
if (casterHexHolder == null)
return costLeft;
var canCastFromInv = casterHexHolder.canDrawMediaFromInventory();
var casterMediaHolder = IXplatAbstractions.INSTANCE.findMediaHolder(casterStack);
@ -69,6 +71,8 @@ public class PackagedItemCastEnv extends PlayerBasedCastEnv {
public FrozenPigment getPigment() {
var casterStack = this.caster.getItemInHand(this.castingHand);
var casterHexHolder = IXplatAbstractions.INSTANCE.findHexHolder(casterStack);
if (casterHexHolder == null)
return IXplatAbstractions.INSTANCE.getPigment(this.caster);
var hexHolderPigment = casterHexHolder.getPigment();
if (hexHolderPigment != null)
return hexHolderPigment;

View file

@ -53,6 +53,8 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
@Override
public void postExecution(CastResult result) {
super.postExecution(result);
for (var sideEffect : result.getSideEffects()) {
if (sideEffect instanceof OperatorSideEffect.DoMishap doMishap) {
this.sendMishapMsgToPlayer(doMishap);
@ -165,7 +167,7 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
}
@Override
public boolean isVecInRange(Vec3 vec) {
public boolean isVecInRangeEnvironment(Vec3 vec) {
var sentinel = HexAPI.instance().getSentinel(this.caster);
if (sentinel != null
&& sentinel.extendsRange()
@ -179,8 +181,8 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
}
@Override
public boolean hasEditPermissionsAt(BlockPos vec) {
return this.caster.gameMode.getGameModeForPlayer() != GameType.ADVENTURE && this.world.mayInteract(this.caster, vec);
public boolean hasEditPermissionsAtEnvironment(BlockPos pos) {
return this.caster.gameMode.getGameModeForPlayer() != GameType.ADVENTURE && this.world.mayInteract(this.caster, pos);
}
/**

View file

@ -52,7 +52,7 @@ public class StaffCastEnv extends PlayerBasedCastEnv {
}
@Override
public long extractMedia(long cost) {
public long extractMediaEnvironment(long cost) {
if (this.caster.isCreative())
return 0;

View file

@ -2,7 +2,6 @@ package at.petrak.hexcasting.api.casting.eval.sideeffects
import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.RenderedSpell
import at.petrak.hexcasting.api.casting.eval.env.PlayerBasedCastEnv
import at.petrak.hexcasting.api.casting.eval.vm.CastingVM
import at.petrak.hexcasting.api.casting.mishaps.Mishap
import at.petrak.hexcasting.api.mod.HexStatistics

View file

@ -23,6 +23,10 @@ import net.minecraft.server.level.ServerLevel
* [CastingEnvironment] to affect the world.
*/
class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
init {
env.triggerCreateEvent()
}
/**
* Execute a single iota.
*/

View file

@ -33,6 +33,7 @@ public class PatternTooltipComponent implements ClientTooltipComponent {
public static final ResourceLocation SLATE_BG = modLoc("textures/gui/slate.png");
private static final float RENDER_SIZE = 128f;
private static final int TEXTURE_SIZE = 48;
private final HexPattern pattern;
private final List<Vec2> zappyPoints;
@ -103,11 +104,13 @@ public class PatternTooltipComponent implements ClientTooltipComponent {
}
private static void renderBG(GuiGraphics graphics, ResourceLocation background) {
// RenderSystem.setShaderColor(1f, 1f, 1f, 1f);
// RenderSystem.setShaderTexture(0, background);
// x y blitoffset sw sh w h ... ?
// parchment doesn't have this mapped
graphics.blit(background, 0, 0, 0, 0, (int) RENDER_SIZE, (int) RENDER_SIZE);
graphics.blit(
background, // texture
0, 0, // x, y
(int) RENDER_SIZE, (int) RENDER_SIZE, // renderWidth, renderHeight
0f, 0f, // u, v (textureCoords)
TEXTURE_SIZE, TEXTURE_SIZE, // regionWidth, regionHeight (texture sample dimensions)
TEXTURE_SIZE, TEXTURE_SIZE); // textureWidth, textureHeight (total dimensions of texture)
}
@Override

View file

@ -11,10 +11,10 @@ import net.minecraft.world.phys.Vec3
class OpCircleBounds(val max: Boolean) : ConstMediaAction {
override val argc = 0
override fun execute(args: List<Iota>, ctx: CastingEnvironment): List<Iota> {
if (ctx !is CircleCastEnv)
override fun execute(args: List<Iota>, env: CastingEnvironment): List<Iota> {
if (env !is CircleCastEnv)
throw MishapNoSpellCircle()
val circle = ctx.impetus ?: throw MishapNoSpellCircle()
val circle = env.impetus ?: throw MishapNoSpellCircle()
val aabb = circle.executionState!!.bounds // the circle should have an execution state since it's executing this.

View file

@ -24,7 +24,7 @@ class SpecialHandlerMask(val mask: BooleanList) : SpecialHandler {
}
override fun getName(): Component {
val key = IXplatAbstractions.INSTANCE.specialHandlerRegistry.getResourceKey(HexSpecialHandlers.NUMBER).get()
val key = IXplatAbstractions.INSTANCE.specialHandlerRegistry.getResourceKey(HexSpecialHandlers.MASK).get()
val fingerprint = mask.map { if (it) '-' else 'v' }.joinToString("")
return HexAPI.instance().getSpecialHandlerI18nKey(key)
.asTranslatedComponent(fingerprint)

View file

@ -13,6 +13,7 @@ object OperatorIndexOf : Operator(2, IotaMultiPredicate.pair(IotaPredicate.ofTyp
override fun apply(iotas: Iterable<Iota>, env: CastingEnvironment): Iterable<Iota> {
val it = iotas.iterator().withIndex()
val list = it.nextList(arity).toList()
return list.indexOf(it.next().value).asActionResult
val toFind = it.next().value
return list.indexOfFirst { Iota.tolerates(toFind, it) }.asActionResult
}
}

View file

@ -71,10 +71,12 @@ public class HexBlocks {
private static BlockBehaviour.Properties papery(MapColor color) {
return BlockBehaviour.Properties
.copy(Blocks.TALL_GRASS)
.of()
.mapColor(color)
.sound(SoundType.GRASS)
.instabreak();
.instabreak()
.ignitedByLava()
.pushReaction(PushReaction.DESTROY);
}
private static BlockBehaviour.Properties akashicWoodyHard() {

View file

@ -1,17 +1,12 @@
package at.petrak.hexcasting.common.lib;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.worldgen.BootstapContext;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.damagesource.DamageType;
public class HexDamageTypes {
public static final ResourceKey<DamageType> OVERCAST = ResourceKey.create(Registries.DAMAGE_TYPE, new ResourceLocation("overcast"));
public static final ResourceKey<DamageType> SHAME_ON_YOU = ResourceKey.create(Registries.DAMAGE_TYPE, new ResourceLocation("overcast"));
import static at.petrak.hexcasting.api.HexAPI.modLoc;
public static void bootstrap(BootstapContext<DamageType> context) {
context.register(OVERCAST, new DamageType("hexcasting.overcast", 0f));
context.register(SHAME_ON_YOU, new DamageType("hexcasting.shame", 0f));
}
public class HexDamageTypes {
public static final ResourceKey<DamageType> OVERCAST = ResourceKey.create(Registries.DAMAGE_TYPE, modLoc("overcast"));
public static final ResourceKey<DamageType> SHAME_ON_YOU = ResourceKey.create(Registries.DAMAGE_TYPE, modLoc("overcast"));
}

View file

@ -17,6 +17,14 @@
"quenched": "Quenched Shard Staff",
"mindsplice": "Mindsplice Staff"
},
tags: {
"tag.item.hexcasting:brainswept_circle_components": "Brainswept Circle Components",
"tag.item.hexcasting:directrices": "Directrices",
"tag.item.hexcasting:grants_root_advancement": "Grants Rood Advancement",
"tag.item.hexcasting:impeti": "Impeti",
"tag.item.hexcasting:seal_materials": "Seal Materials",
},
"amethyst_dust": "Amethyst Dust",
"charged_amethyst": "Charged Amethyst",
@ -328,7 +336,9 @@
"list_contents": "[%s]",
"null_iota": "Null",
"jump_iota": "[Jump]",
"pattern_iota": "HexPattern(%s)"
"pattern_iota": "HexPattern(%s)",
"boolean_true": "True",
"boolean_false": "False"
},
// ^ tooltip
spelldata: {

View file

@ -1,26 +0,0 @@
{
"name": "hexcasting.entry.interop.gravity",
"icon": "minecraft:anvil",
"category": "hexcasting:interop",
"advancement": "hexcasting:root",
"flag": "mod:gravity_api",
"pages": [
"hexcasting.page.interop.gravity.1",
{
"type": "hexcasting:pattern",
"op_id": "hexcasting:interop/gravity/get",
"anchor": "hexcasting:interop/gravity/get",
"input": "entity",
"output": "vector",
"text": "hexcasting.page.interop.gravity.get"
},
{
"type": "hexcasting:pattern",
"op_id": "hexcasting:interop/gravity/set",
"anchor": "hexcasting:interop/gravity/set",
"input": "entity, vector",
"output": "",
"text": "hexcasting.page.interop.gravity.set"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 B

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 B

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 399 B

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 B

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 283 B

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 389 B

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 417 B

After

Width:  |  Height:  |  Size: 498 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 B

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 405 B

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 B

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 380 B

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 B

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 B

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 283 B

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 B

After

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 B

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 B

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 B

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 B

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 B

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 283 B

After

Width:  |  Height:  |  Size: 266 B

View file

@ -0,0 +1,5 @@
{
"exhaustion": 0,
"message_id": "hexcasting.overcast",
"scaling": "when_caused_by_living_non_player"
}

View file

@ -0,0 +1,5 @@
{
"exhaustion": 0,
"message_id": "hexcasting.shame",
"scaling": "when_caused_by_living_non_player"
}

View file

@ -1,6 +1,6 @@
fabricVersion=0.85.0+1.20.1
fabricLoaderVersion=0.14.21
fabricLanguageKotlinVersion=1.9.5+kotlin.1.8.22
fabricLanguageKotlinVersion=1.9.4+kotlin.1.8.21
# These are all included
cardinalComponentsVersion=5.2.1

View file

@ -50,13 +50,13 @@
"java": ">=17",
"fabricloader": ">=0.14",
"fabric": ">=0.84",
"fabric-language-kotlin": ">=1.9.5+kotlin.1.8.22",
"fabric-language-kotlin": ">=1.9.4+kotlin.1.8.21",
"cardinal-components-base": "~5.2.1",
"cardinal-components-entity": "~5.2.1",
"cardinal-components-item": "~5.2.1",
"cardinal-components-block": "~5.2.1",
"paucal": "0.6.x",
"cloth-config": "11.0.x",
"paucal": "0.6.*",
"cloth-config": "11.0.*",
"patchouli": ">=1.20.1-80"
},
"suggests": {

View file

@ -1,4 +1,4 @@
forgeVersion=47.0.3
forgeVersion=47.1.43
kotlinForForgeVersion=4.3.0

View file

@ -13,7 +13,7 @@ kotlinVersion=1.7.20
modVersion=0.11.1-7
paucalVersion=0.6.0
patchouliVersion=80
patchouliVersion=82
jeiVersion=15.0.0.12
pehkuiVersion=3.7.6
pehkuiVersion=3.7.7